001 package railo.runtime.tag; 002 003 import java.io.ByteArrayInputStream; 004 import java.io.FileNotFoundException; 005 import java.io.IOException; 006 import java.io.InputStream; 007 import java.io.PrintStream; 008 import java.io.UnsupportedEncodingException; 009 import java.net.MalformedURLException; 010 import java.net.URL; 011 import java.util.ArrayList; 012 import java.util.zip.GZIPInputStream; 013 014 import org.apache.commons.httpclient.Cookie; 015 import org.apache.commons.httpclient.Header; 016 import org.apache.commons.httpclient.HostConfiguration; 017 import org.apache.commons.httpclient.HttpClient; 018 import org.apache.commons.httpclient.HttpConnectionManager; 019 import org.apache.commons.httpclient.HttpMethod; 020 import org.apache.commons.httpclient.HttpState; 021 import org.apache.commons.httpclient.NameValuePair; 022 import org.apache.commons.httpclient.SimpleHttpConnectionManager; 023 import org.apache.commons.httpclient.UsernamePasswordCredentials; 024 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity; 025 import org.apache.commons.httpclient.methods.DeleteMethod; 026 import org.apache.commons.httpclient.methods.EntityEnclosingMethod; 027 import org.apache.commons.httpclient.methods.GetMethod; 028 import org.apache.commons.httpclient.methods.HeadMethod; 029 import org.apache.commons.httpclient.methods.InputStreamRequestEntity; 030 import org.apache.commons.httpclient.methods.OptionsMethod; 031 import org.apache.commons.httpclient.methods.PostMethod; 032 import org.apache.commons.httpclient.methods.PutMethod; 033 import org.apache.commons.httpclient.methods.StringRequestEntity; 034 import org.apache.commons.httpclient.methods.TraceMethod; 035 import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; 036 import org.apache.commons.httpclient.methods.multipart.Part; 037 import org.apache.commons.httpclient.params.HttpMethodParams; 038 import org.apache.commons.httpclient.util.EncodingUtil; 039 040 import railo.commons.io.IOUtil; 041 import railo.commons.io.res.Resource; 042 import railo.commons.io.res.util.ResourceUtil; 043 import railo.commons.lang.StringUtil; 044 import railo.commons.net.CookieUtil; 045 import railo.commons.net.HTTPUtil; 046 import railo.commons.net.RailoStringPart; 047 import railo.commons.net.ResourcePart; 048 import railo.commons.net.ResourcePartSource; 049 import railo.commons.net.URLEncoder; 050 import railo.runtime.config.Config; 051 import railo.runtime.engine.ThreadLocalPageContext; 052 import railo.runtime.exp.ApplicationException; 053 import railo.runtime.exp.ExpressionException; 054 import railo.runtime.exp.HTTPException; 055 import railo.runtime.exp.NativeException; 056 import railo.runtime.exp.PageException; 057 import railo.runtime.ext.tag.BodyTagImpl; 058 import railo.runtime.net.http.ReqRspUtil; 059 import railo.runtime.op.Caster; 060 import railo.runtime.op.Decision; 061 import railo.runtime.text.csv.CSVParser; 062 import railo.runtime.type.Array; 063 import railo.runtime.type.ArrayImpl; 064 import railo.runtime.type.Collection.Key; 065 import railo.runtime.type.KeyImpl; 066 import railo.runtime.type.List; 067 import railo.runtime.type.Query; 068 import railo.runtime.type.Struct; 069 import railo.runtime.type.StructImpl; 070 import railo.runtime.type.util.ArrayUtil; 071 import railo.runtime.util.URLResolver; 072 073 // MUST change behavor of mltiple headers now is a array, it das so? 074 075 /** 076 * Lets you execute HTTP POST and GET operations on files. Using cfhttp, you can execute standard 077 * GET operations and create a query object from a text file. POST operations lets you upload MIME file 078 * types to a server, or post cookie, formfield, URL, file, or CGI variables directly to a specified server. 079 * 080 * 081 * 082 * 083 **/ 084 public final class Http extends BodyTagImpl { 085 086 087 /** 088 * Maximal count of redirects (5) 089 */ 090 public static final short MAX_REDIRECT=15; 091 092 /** 093 * Constant value for HTTP Status Code "moved Permanently 301" 094 */ 095 public static final int STATUS_REDIRECT_MOVED_PERMANENTLY=301; 096 /** 097 * Constant value for HTTP Status Code "Found 302" 098 */ 099 public static final int STATUS_REDIRECT_FOUND=302; 100 /** 101 * Constant value for HTTP Status Code "see other 303" 102 */ 103 public static final int STATUS_REDIRECT_SEE_OTHER=303; 104 105 106 public static final int STATUS_REDIRECT_TEMPORARY_REDIRECT = 307; 107 108 109 110 111 112 113 private static final short METHOD_GET=0; 114 private static final short METHOD_POST=1; 115 private static final short METHOD_HEAD=2; 116 private static final short METHOD_PUT=3; 117 private static final short METHOD_DELETE=4; 118 private static final short METHOD_OPTIONS=5; 119 private static final short METHOD_TRACE=6; 120 121 private static final String NO_MIMETYPE="Unable to determine MIME type of file."; 122 123 private static final int STATUS_OK=200; 124 125 private static final short GET_AS_BINARY_NO=0; 126 private static final short GET_AS_BINARY_YES=1; 127 private static final short GET_AS_BINARY_AUTO=2; 128 129 private static final Key ERROR_DETAIL = KeyImpl.intern("errordetail"); 130 private static final Key STATUSCODE = KeyImpl.intern("statuscode"); 131 private static final Key STATUS_CODE = KeyImpl.intern("status_code"); 132 private static final Key STATUS_TEXT = KeyImpl.intern("status_text"); 133 private static final Key HTTP_VERSION = KeyImpl.intern("http_version"); 134 135 136 private static final Key MIME_TYPE = KeyImpl.intern("mimetype"); 137 private static final Key CHARSET = KeyImpl.intern("charset"); 138 private static final Key FILE_CONTENT = KeyImpl.intern("filecontent"); 139 private static final Key HEADER = KeyImpl.intern("header"); 140 private static final Key TEXT = KeyImpl.intern("text"); 141 private static final Key EXPLANATION = KeyImpl.intern("explanation"); 142 private static final Key RESPONSEHEADER = KeyImpl.intern("responseheader"); 143 private static final Key SET_COOKIE = KeyImpl.intern("set-cookie"); 144 145 146 147 148 static { 149 //Protocol myhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); 150 //Protocol.registerProtocol("https", new Protocol("https", new EasySSLProtocolSocketFactory(), 443)); 151 } 152 153 154 private ArrayList<HttpParamBean> params=new ArrayList<HttpParamBean>(); 155 156 157 /** When required by a server, a valid password. */ 158 private String password; 159 160 /** Required for creating a query. Options are a tab or comma. Default is a comma. */ 161 private char delimiter=','; 162 163 /** Yes or No. Default is No. For GET and POST operations, if Yes, page reference returned into the 164 ** fileContent internal variable has its internal URLs fully resolved, including port number, so that 165 ** links remain intact. */ 166 private boolean resolveurl; 167 168 /** A value, in seconds. When a URL timeout is specified in the browser */ 169 private long timeout=-1; 170 171 /** Host name or IP address of a proxy server. */ 172 private String proxyserver; 173 174 /** The filename to be used for the file that is accessed. For GET operations, defaults to the name 175 ** pecified in url. Enter path information in the path attribute. */ 176 private String strFile; 177 178 /** The path to the directory in which a file is to be stored. If a path is not specified in a POST 179 ** or GET operation, a variable is created (cfhttp.fileContent) that you can use to display the results 180 ** of the POST operation in a cfoutput. */ 181 private String strPath; 182 183 /** Boolean indicating whether to throw an exception that can be caught by using the cftry and 184 ** cfcatch tags. The default is NO. */ 185 private boolean throwonerror; 186 187 /** set the charset for the call. */ 188 private String charset=null; 189 190 /** The port number on the proxy server from which the object is requested. Default is 80. When 191 ** used with resolveURL, the URLs of retrieved documents that specify a port number are automatically 192 ** resolved to preserve links in the retrieved document. */ 193 private int proxyport=80; 194 195 /** Specifies the column names for a query when creating a query as a result of a cfhttp GET. */ 196 private String[] columns; 197 198 /** The port number on the server from which the object is requested. Default is 80. When used with 199 ** resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved to 200 ** preserve links in the retrieved document. If a port number is specified in the url attribute, the port 201 ** value overrides the value of the port attribute. */ 202 private int port=-1; 203 204 /** User agent request header. */ 205 private String useragent="Railo (CFML Engine)"; 206 207 /** Required for creating a query. Indicates the start and finish of a column. Should be 208 ** appropriately escaped when embedded in a column. For example, if the qualifier is a double quotation 209 ** mark, it should be escaped as """". If there is no text qualifier in the file, specify it as " ". 210 ** Default is the double quotation mark ("). */ 211 private char textqualifier='"'; 212 213 /** When required by a server, a valid username. */ 214 private String username; 215 216 /** Full URL of the host name or IP address of the server on which the file resides. The URL must be 217 ** an absolute URL, including the protocol (http or https) and hostname. It may optionally contain a port 218 ** number. Port numbers specified in the url attribute override the port attribute. */ 219 private String url; 220 221 /** Boolean indicating whether to redirect execution or stop execution.*/ 222 private boolean redirect=true; 223 224 225 /** The name to assign to a query if the a query is constructed from a file. */ 226 private String name; 227 228 /** GET or POST. Use GET to download a text or binary file or to create a query from the contents 229 ** of a text file. Use POST to send information to a server page or a CGI program for processing. POST 230 ** requires the use of a cfhttpparam tag. */ 231 private short method=METHOD_GET; 232 233 //private boolean hasBody=false; 234 235 private boolean firstrowasheaders=true; 236 237 private String proxyuser=null; 238 private String proxypassword=""; 239 private boolean multiPart=false; 240 private String multiPartType=MultipartRequestEntityFlex.MULTIPART_FORM_DATA; 241 242 private short getAsBinary=GET_AS_BINARY_NO; 243 private String result="cfhttp"; 244 245 private boolean addtoken=false; 246 247 248 /** 249 * @see javax.servlet.jsp.tagext.Tag#release() 250 */ 251 public void release() { 252 super.release(); 253 params.clear(); 254 password=null; 255 delimiter=','; 256 resolveurl=false; 257 timeout=-1L; 258 proxyserver=null; 259 proxyport=80; 260 proxyuser=null; 261 proxypassword=""; 262 strFile=null; 263 throwonerror=false; 264 charset=null; 265 columns=null; 266 port=-1; 267 useragent="Railo (CFML Engine)"; 268 textqualifier='"'; 269 username=null; 270 url=null; 271 redirect=true; 272 strPath=null; 273 name=null; 274 method=METHOD_GET; 275 //hasBody=false; 276 firstrowasheaders=true; 277 278 getAsBinary=GET_AS_BINARY_NO; 279 multiPart=false; 280 multiPartType=MultipartRequestEntityFlex.MULTIPART_FORM_DATA; 281 result="cfhttp"; 282 addtoken=false; 283 } 284 285 /** 286 * @param firstrowasheaders 287 */ 288 public void setFirstrowasheaders(boolean firstrowasheaders) { 289 this.firstrowasheaders=firstrowasheaders; 290 } 291 292 /** set the value password 293 * When required by a server, a valid password. 294 * @param password value to set 295 **/ 296 public void setPassword(String password) { 297 this.password=password; 298 } 299 /** set the value password 300 * When required by a proxy server, a valid password. 301 * @param proxypassword value to set 302 **/ 303 public void setProxypassword(String proxypassword) { 304 this.proxypassword=proxypassword; 305 } 306 307 /** set the value delimiter 308 * Required for creating a query. Options are a tab or comma. Default is a comma. 309 * @param delimiter value to set 310 **/ 311 public void setDelimiter(String delimiter) { 312 this.delimiter=delimiter.length()==0?',':delimiter.charAt(0); 313 } 314 315 /** set the value resolveurl 316 * Yes or No. Default is No. For GET and POST operations, if Yes, page reference returned into the 317 * fileContent internal variable has its internal URLs fully resolved, including port number, so that 318 * links remain intact. 319 * @param resolveurl value to set 320 **/ 321 public void setResolveurl(boolean resolveurl) { 322 this.resolveurl=resolveurl; 323 } 324 325 /** set the value timeout 326 * @param timeout value to set 327 * @throws ExpressionException 328 **/ 329 public void setTimeout(double timeout) throws ExpressionException { 330 if(timeout<0) 331 throw new ExpressionException("invalid value ["+Caster.toString(timeout)+"] for attribute timeout, value must be a positive integer greater or equal than 0"); 332 333 long requestTimeout = pageContext.getRequestTimeout(); 334 long _timeout=(long)(timeout*1000D); 335 this.timeout=requestTimeout<_timeout?requestTimeout:_timeout; 336 //print.out("this.timeout:"+this.timeout); 337 } 338 339 /** set the value proxyserver 340 * Host name or IP address of a proxy server. 341 * @param proxyserver value to set 342 **/ 343 public void setProxyserver(String proxyserver) { 344 this.proxyserver=proxyserver; 345 } 346 347 /** set the value proxyport 348 * The port number on the proxy server from which the object is requested. Default is 80. When 349 * used with resolveURL, the URLs of retrieved documents that specify a port number are automatically 350 * resolved to preserve links in the retrieved document. 351 * @param proxyport value to set 352 **/ 353 public void setProxyport(double proxyport) { 354 this.proxyport=(int)proxyport; 355 } 356 357 /** set the value file 358 * The filename to be used for the file that is accessed. For GET operations, defaults to the name 359 * pecified in url. Enter path information in the path attribute. 360 * @param file value to set 361 **/ 362 public void setFile(String file) { 363 this.strFile=file; 364 } 365 366 /** set the value throwonerror 367 * Boolean indicating whether to throw an exception that can be caught by using the cftry and 368 * cfcatch tags. The default is NO. 369 * @param throwonerror value to set 370 **/ 371 public void setThrowonerror(boolean throwonerror) { 372 this.throwonerror=throwonerror; 373 } 374 375 /** set the value charset 376 * set the charset for the call. 377 * @param charset value to set 378 **/ 379 public void setCharset(String charset) { 380 this.charset=charset; 381 } 382 383 /** set the value columns 384 * @param columns value to set 385 * @throws PageException 386 **/ 387 public void setColumns(String columns) throws PageException { 388 this.columns=List.toStringArray(List.listToArrayRemoveEmpty(columns,",")); 389 } 390 391 /** set the value port 392 * The port number on the server from which the object is requested. Default is 80. When used with 393 * resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved to 394 * preserve links in the retrieved document. If a port number is specified in the url attribute, the port 395 * value overrides the value of the port attribute. 396 * @param port value to set 397 **/ 398 public void setPort(double port) { 399 this.port=(int) port; 400 } 401 402 /** set the value useragent 403 * User agent request header. 404 * @param useragent value to set 405 **/ 406 public void setUseragent(String useragent) { 407 this.useragent=useragent; 408 } 409 410 /** set the value textqualifier 411 * Required for creating a query. Indicates the start and finish of a column. Should be 412 * appropriately escaped when embedded in a column. For example, if the qualifier is a double quotation 413 * mark, it should be escaped as """". If there is no text qualifier in the file, specify it as " ". 414 * Default is the double quotation mark ("). 415 * @param textqualifier value to set 416 **/ 417 public void setTextqualifier(String textqualifier) { 418 this.textqualifier=textqualifier.length()==0?'"':textqualifier.charAt(0); 419 } 420 421 /** set the value username 422 * When required by a proxy server, a valid username. 423 * @param proxyuser value to set 424 **/ 425 public void setProxyuser(String proxyuser) { 426 this.proxyuser=proxyuser; 427 } 428 429 /** set the value username 430 * When required by a server, a valid username. 431 * @param username value to set 432 **/ 433 public void setUsername(String username) { 434 this.username=username; 435 } 436 437 /** set the value url 438 * Full URL of the host name or IP address of the server on which the file resides. The URL must be 439 * an absolute URL, including the protocol (http or https) and hostname. It may optionally contain a port 440 * number. Port numbers specified in the url attribute override the port attribute. 441 * @param url value to set 442 **/ 443 public void setUrl(String url) { 444 this.url=url; 445 } 446 447 /** set the value redirect 448 * @param redirect value to set 449 **/ 450 public void setRedirect(boolean redirect) { 451 this.redirect=redirect; 452 } 453 454 /** set the value path 455 * The path to the directory in which a file is to be stored. If a path is not specified in a POST 456 * or GET operation, a variable is created (cfhttp.fileContent) that you can use to display the results 457 * of the POST operation in a cfoutput. 458 * @param path value to set 459 **/ 460 public void setPath(String path) { 461 this.strPath=path; 462 } 463 464 /** set the value name 465 * The name to assign to a query if the a query is constructed from a file. 466 * @param name value to set 467 **/ 468 public void setName(String name) { 469 this.name=name; 470 } 471 472 /** set the value method 473 * GET or POST. Use GET to download a text or binary file or to create a query from the contents 474 * of a text file. Use POST to send information to a server page or a CGI program for processing. POST 475 * requires the use of a cfhttpparam tag. 476 * @param method value to set 477 * @throws ApplicationException 478 **/ 479 public void setMethod(String method) throws ApplicationException { 480 method=method.toLowerCase().trim(); 481 if(method.equals("post")) this.method=METHOD_POST; 482 else if(method.equals("get")) this.method=METHOD_GET; 483 else if(method.equals("head")) this.method=METHOD_HEAD; 484 else if(method.equals("delete")) this.method=METHOD_DELETE; 485 else if(method.equals("put")) this.method=METHOD_PUT; 486 else if(method.equals("trace")) this.method=METHOD_TRACE; 487 else if(method.equals("options")) this.method=METHOD_OPTIONS; 488 else throw new ApplicationException("invalid method type ["+(method.toUpperCase())+"], valid types are POST,GET,HEAD,DELETE,PUT,TRACE,OPTIONS"); 489 } 490 491 492 /** 493 * @see javax.servlet.jsp.tagext.Tag#doStartTag() 494 */ 495 public int doStartTag() { 496 if(addtoken) { 497 setParam("cookie","cfid",pageContext.getCFID()); 498 setParam("cookie","cftoken",pageContext.getCFToken()); 499 String jsessionid = pageContext.getJSessionId(); 500 if(jsessionid!=null)setParam("cookie","jsessionid",jsessionid); 501 } 502 503 return EVAL_BODY_INCLUDE; 504 } 505 506 private void setParam(String type, String name, String value) { 507 HttpParamBean hpb = new HttpParamBean(); 508 hpb.setType(type); 509 hpb.setName(name); 510 hpb.setValue(value); 511 setParam(hpb); 512 } 513 514 /** 515 * @throws PageException 516 * @see javax.servlet.jsp.tagext.Tag#doEndTag() 517 */ 518 public int doEndTag() throws PageException { 519 Struct cfhttp=new StructImpl(); 520 cfhttp.setEL(ERROR_DETAIL,""); 521 pageContext.setVariable(result,cfhttp); 522 523 // because commons 524 PrintStream out = System.out; 525 try { 526 //System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM)); 527 _doEndTag(cfhttp); 528 return EVAL_PAGE; 529 } 530 catch (IOException e) { 531 throw Caster.toPageException(e); 532 } 533 finally { 534 System.setOut(out); 535 } 536 537 } 538 539 540 541 private void _doEndTag(Struct cfhttp) throws PageException, IOException { 542 HttpConnectionManager manager=new SimpleHttpConnectionManager();//MultiThreadedHttpConnectionManager(); 543 HttpClient client = new HttpClient(manager); 544 HttpMethod httpMethod=createMethod(pageContext.getConfig(),this,client,url,port); 545 try { 546 547 /////////////////////////////////////////// EXECUTE ///////////////////////////////////////////////// 548 Executor e = new Executor(this,client,httpMethod,redirect); 549 if(timeout<0){ 550 try{ 551 e.execute(); 552 } 553 554 catch(Throwable t){ 555 if(!throwonerror){ 556 setUnknownHost(cfhttp, t); 557 return; 558 } 559 throw toPageException(t); 560 561 } 562 } 563 else { 564 e.start(); 565 try { 566 synchronized(this){//print.err(timeout); 567 this.wait(timeout); 568 } 569 } catch (InterruptedException ie) { 570 throw Caster.toPageException(ie); 571 } 572 if(e.t!=null){ 573 if(!throwonerror){ 574 setUnknownHost(cfhttp,e.t); 575 return; 576 } 577 throw toPageException(e.t); 578 } 579 580 httpMethod=e.httpMethod; 581 582 583 if(!e.done){ 584 httpMethod.abort(); 585 if(throwonerror) 586 throw new HTTPException("408 Request Time-out","a timeout occurred in tag http",408); 587 setRequestTimeout(cfhttp); 588 return; 589 //throw new ApplicationException("timeout"); 590 } 591 } 592 httpMethod=e.httpMethod; 593 /////////////////////////////////////////// EXECUTE ///////////////////////////////////////////////// 594 int status = httpMethod.getStatusCode(); 595 596 String responseCharset=charset; 597 // Write Response Scope 598 //String rawHeader=httpMethod.getStatusLine().toString(); 599 String mimetype=null; 600 String contentEncoding=null; 601 602 // status code 603 cfhttp.set(STATUSCODE,((httpMethod.getStatusCode()+" "+httpMethod.getStatusText()).trim())); 604 cfhttp.set(STATUS_CODE,new Double(httpMethod.getStatusCode())); 605 cfhttp.set(STATUS_TEXT,(httpMethod.getStatusText())); 606 cfhttp.set(HTTP_VERSION,(httpMethod.getStatusLine().getHttpVersion())); 607 608 //responseHeader 609 Header[] headers = httpMethod.getResponseHeaders(); 610 StringBuffer raw=new StringBuffer(httpMethod.getStatusLine().toString()+" "); 611 Struct responseHeader = new StructImpl(); 612 Array setCookie = new ArrayImpl(); 613 614 for(int i=0;i<headers.length;i++) { 615 Header header=headers[i]; 616 //print.ln(header); 617 618 raw.append(header+" "); 619 if(header.getName().equalsIgnoreCase("Set-Cookie")) 620 setCookie.append(header.getValue()); 621 else { 622 //print.ln(header.getName()+"-"+header.getValue()); 623 Object value=responseHeader.get(KeyImpl.getInstance(header.getName()),null); 624 if(value==null) responseHeader.set(KeyImpl.getInstance(header.getName()),header.getValue()); 625 else { 626 Array arr=null; 627 if(value instanceof Array) { 628 arr=(Array) value; 629 } 630 else { 631 arr=new ArrayImpl(); 632 responseHeader.set(KeyImpl.getInstance(header.getName()),arr); 633 arr.appendEL(value); 634 } 635 arr.appendEL(header.getValue()); 636 } 637 } 638 639 // Content-Type 640 if(header.getName().equalsIgnoreCase("Content-Type")) { 641 mimetype=header.getValue(); 642 if(mimetype==null)mimetype=NO_MIMETYPE; 643 } 644 645 // Content-Encoding 646 if(header.getName().equalsIgnoreCase("Content-Encoding")) { 647 contentEncoding=header.getValue(); 648 } 649 650 } 651 cfhttp.set(RESPONSEHEADER,responseHeader); 652 responseHeader.set(STATUS_CODE,new Double(httpMethod.getStatusCode())); 653 responseHeader.set(EXPLANATION,(httpMethod.getStatusText())); 654 if(setCookie.size()>0)responseHeader.set(SET_COOKIE,setCookie); 655 656 // is text 657 boolean isText= 658 mimetype == null || 659 mimetype == NO_MIMETYPE || isText(mimetype); 660 661 662 663 cfhttp.set(TEXT,Caster.toBoolean(isText)); 664 665 // mimetype charset 666 //boolean responseProvideCharset=false; 667 if(!StringUtil.isEmpty(mimetype)){ 668 if(isText) { 669 String[] types=HTTPUtil.splitMimeTypeAndCharset(mimetype); 670 if(types[0]!=null)cfhttp.set(MIME_TYPE,types[0]); 671 if(types[1]!=null)cfhttp.set(CHARSET,types[1]); 672 673 } 674 else cfhttp.set(MIME_TYPE,mimetype); 675 } 676 else cfhttp.set(MIME_TYPE,NO_MIMETYPE); 677 678 // File 679 Resource file=null; 680 681 if(strFile!=null && strPath!=null) { 682 file=ResourceUtil.toResourceNotExisting(pageContext, strPath).getRealResource(strFile); 683 } 684 else if(strFile!=null) { 685 file=ResourceUtil.toResourceNotExisting(pageContext, strFile); 686 } 687 else if(strPath!=null) { 688 file=ResourceUtil.toResourceNotExisting(pageContext, strPath); 689 //Resource dir = file.getParentResource(); 690 if(file.isDirectory()){ 691 file=file.getRealResource(httpMethod.getURI().getName()); 692 } 693 694 } 695 if(file!=null)pageContext.getConfig().getSecurityManager().checkFileLocation(file); 696 697 698 // filecontent 699 //try { 700 //print.ln(">> "+responseCharset); 701 702 InputStream is=null; 703 if(isText && getAsBinary!=GET_AS_BINARY_YES) { 704 String str; 705 try { 706 is = httpMethod.getResponseBodyAsStream(); 707 if(is!=null &&isGzipEncoded(contentEncoding)) 708 is = new GZIPInputStream(is); 709 710 try { 711 str = is==null?"":IOUtil.toString(is,responseCharset); 712 } 713 catch (UnsupportedEncodingException uee) { 714 str = is==null?"":IOUtil.toString(is,null); 715 } 716 } 717 catch (IOException ioe) { 718 throw Caster.toPageException(ioe); 719 } 720 finally { 721 IOUtil.closeEL(is); 722 } 723 724 if(str==null)str=""; 725 if(resolveurl){ 726 //URI uri = httpMethod.getURI(); 727 if(e!=null && e.redirectURL!=null)url=e.redirectURL.toExternalForm(); 728 str=new URLResolver().transform(str,new URL(url),false); 729 } 730 cfhttp.set(FILE_CONTENT,str); 731 try { 732 if(file!=null){ 733 IOUtil.write(file,str,pageContext.getConfig().getWebCharset(),false); 734 } 735 } 736 catch (IOException e1) {} 737 738 if(name!=null) { 739 Query qry = new CSVParser().parse(str,delimiter,textqualifier,columns,firstrowasheaders); 740 pageContext.setVariable(name,qry); 741 } 742 } 743 // Binary 744 else { 745 byte[] barr=null; 746 if(isGzipEncoded(contentEncoding)){ 747 is = new GZIPInputStream(httpMethod.getResponseBodyAsStream()); 748 try { 749 barr = IOUtil.toBytes(is); 750 } 751 catch (IOException t) { 752 throw Caster.toPageException(t); 753 } 754 finally{ 755 IOUtil.closeEL(is); 756 } 757 } 758 else { 759 try { 760 barr = httpMethod.getResponseBody(); 761 } 762 catch (IOException t) { 763 throw Caster.toPageException(t); 764 } 765 } 766 767 cfhttp.set(FILE_CONTENT,barr); 768 769 if(file!=null) { 770 try { 771 if(barr!=null)IOUtil.copy(new ByteArrayInputStream(barr),file,true); 772 } 773 catch (IOException ioe) { 774 throw Caster.toPageException(ioe); 775 } 776 } 777 } 778 779 // header 780 cfhttp.set(HEADER,raw.toString()); 781 782 if(status!=STATUS_OK){ 783 cfhttp.setEL(ERROR_DETAIL,httpMethod.getStatusCode()+" "+httpMethod.getStatusText()); 784 if(throwonerror)throw new HTTPException(httpMethod); 785 } 786 } 787 finally { 788 releaseConnection(httpMethod); 789 } 790 791 } 792 793 public static boolean isText(String mimetype) { 794 if(mimetype==null)mimetype=""; 795 else mimetype=mimetype.trim().toLowerCase(); 796 return StringUtil.startsWithIgnoreCase(mimetype,"text") || 797 StringUtil.startsWithIgnoreCase(mimetype,"application/xml") || 798 StringUtil.startsWithIgnoreCase(mimetype,"application/atom+xml") || 799 StringUtil.startsWithIgnoreCase(mimetype,"application/xhtml") || 800 StringUtil.startsWithIgnoreCase(mimetype,"message") || 801 StringUtil.startsWithIgnoreCase(mimetype,"application/octet-stream") || 802 StringUtil.indexOfIgnoreCase(mimetype, "xml")!=-1 || 803 StringUtil.indexOfIgnoreCase(mimetype, "json")!=-1 || 804 StringUtil.indexOfIgnoreCase(mimetype, "rss")!=-1 || 805 StringUtil.indexOfIgnoreCase(mimetype, "atom")!=-1 || 806 StringUtil.indexOfIgnoreCase(mimetype, "text")!=-1; 807 808 // "application/x-www-form-urlencoded" ??? 809 } 810 811 private PageException toPageException(Throwable t) { 812 PageException pe = Caster.toPageException(t); 813 if(pe instanceof NativeException) { 814 ((NativeException) pe).setAdditional("url", url); 815 } 816 return pe; 817 } 818 819 private void setUnknownHost(Struct cfhttp,Throwable t) { 820 cfhttp.setEL(CHARSET,""); 821 cfhttp.setEL(ERROR_DETAIL,"Unknown host: "+t.getMessage()); 822 cfhttp.setEL(FILE_CONTENT,"Connection Failure"); 823 cfhttp.setEL(HEADER,""); 824 cfhttp.setEL(MIME_TYPE,"Unable to determine MIME type of file."); 825 cfhttp.setEL(RESPONSEHEADER,new StructImpl()); 826 cfhttp.setEL(STATUSCODE,"Connection Failure. Status code unavailable."); 827 cfhttp.setEL(TEXT,Boolean.TRUE); 828 } 829 830 private void setRequestTimeout(Struct cfhttp) { 831 cfhttp.setEL(CHARSET,""); 832 cfhttp.setEL(ERROR_DETAIL,""); 833 cfhttp.setEL(FILE_CONTENT,"Connection Timeout"); 834 cfhttp.setEL(HEADER,""); 835 cfhttp.setEL(MIME_TYPE,"Unable to determine MIME type of file."); 836 cfhttp.setEL(RESPONSEHEADER,new StructImpl()); 837 cfhttp.setEL(STATUSCODE,"408 Request Time-out"); 838 cfhttp.setEL(STATUS_CODE,new Double(408)); 839 cfhttp.setEL(STATUS_TEXT,"Request Time-out"); 840 cfhttp.setEL(TEXT,Boolean.TRUE); 841 } 842 843 /*private static HttpMethod execute(Http http, HttpClient client, HttpMethod httpMethod, boolean redirect) throws PageException { 844 try { 845 // Execute Request 846 short count=0; 847 URL lu; 848 849 while(isRedirect(client.executeMethod(httpMethod)) && redirect && count++ < MAX_REDIRECT) { 850 lu=locationURL(httpMethod); 851 httpMethod=createMethod(http,client,lu.toExternalForm(),-1); 852 } 853 } 854 catch (IOException e) { 855 PageException pe = Caster.toPageException(e); 856 if(pe instanceof NativeException) { 857 ((NativeException) pe).setAdditional("url", HTTPUtil.toURL(httpMethod)); 858 } 859 throw pe; 860 } 861 return httpMethod; 862 }*/ 863 864 public static void releaseConnection(HttpMethod httpMethod) { 865 httpMethod.releaseConnection(); 866 //manager.closeIdleConnections(0); 867 } 868 869 static URL locationURL(HttpMethod method) throws MalformedURLException, ExpressionException { 870 Header location = method.getResponseHeader("location"); 871 872 if(location==null) throw new ExpressionException("missing location header definition"); 873 874 875 HostConfiguration config = method.getHostConfiguration(); 876 URL url; 877 try { 878 url = new URL(location.getValue()); 879 } 880 catch (MalformedURLException e) { 881 url=new URL(config.getProtocol().getScheme(), 882 config.getHost(), 883 config.getPort(), 884 mergePath(method.getPath(),location.getValue())); 885 } 886 887 return url; 888 } 889 890 891 static HttpMethod createMethod(Config cw,Http http, HttpClient client, String url, int port) throws PageException, UnsupportedEncodingException { 892 String _charset=http.charset; 893 if(StringUtil.isEmpty(_charset,true)) _charset=cw.getWebCharset(); 894 else _charset=_charset.trim(); 895 896 897 HttpMethod httpMethod; 898 HostConfiguration config = client.getHostConfiguration(); 899 HttpState state = client.getState(); 900 901 String[] arrQS=new String[0]; 902 // check if has fileUploads 903 boolean doUploadFile=false; 904 for(int i=0;i<http.params.size();i++) { 905 if(((HttpParamBean)http.params.get(i)).getType().equals("file")) { 906 doUploadFile=true; 907 break; 908 } 909 } 910 911 // parse url (also query string) 912 URL _url=null; 913 try { 914 _url = HTTPUtil.toURL(url,port); 915 url=_url.toExternalForm(); 916 917 918 } catch (MalformedURLException mue) { 919 throw Caster.toPageException(mue); 920 } 921 922 923 // QS 924 String strQS=_url.getQuery(); 925 if(strQS!=null) { 926 arrQS=List.toStringArray(List.listToArray(List.trim(strQS,"&"),"&")); 927 } 928 929 // select best matching method (get,post, post multpart (file)) 930 931 boolean isBinary = false; 932 boolean doMultiPart=doUploadFile || http.multiPart; 933 PostMethod post=null; 934 EntityEnclosingMethod eem=null; 935 936 937 if(http.method==METHOD_GET) { 938 httpMethod=new GetMethod(url); 939 } 940 else if(http.method==METHOD_HEAD) { 941 httpMethod=new HeadMethod(url); 942 } 943 else if(http.method==METHOD_DELETE) { 944 isBinary=true; 945 httpMethod=new DeleteMethod(url); 946 } 947 else if(http.method==METHOD_PUT) { 948 isBinary=true; 949 httpMethod=eem=new PutMethod(url); 950 951 } 952 else if(http.method==METHOD_TRACE) { 953 isBinary=true; 954 httpMethod=new TraceMethod(url); 955 } 956 else if(http.method==METHOD_OPTIONS) { 957 isBinary=true; 958 httpMethod=new OptionsMethod(url); 959 } 960 else { 961 isBinary=true; 962 post=new PostMethod(url); 963 httpMethod=eem=post; 964 } 965 // content type 966 if(StringUtil.isEmpty(http.charset))http.charset=http.pageContext.getConfig().getWebCharset(); 967 968 969 boolean hasForm=false; 970 boolean hasBody=false; 971 boolean hasContentType=false; 972 // Set http params 973 ArrayList<NameValuePair> listQS=new ArrayList<NameValuePair>(); 974 ArrayList<Part> parts=new ArrayList<Part>(); 975 int len=http.params.size(); 976 StringBuilder acceptEncoding=new StringBuilder(); 977 for(int i=0;i<len;i++) { 978 HttpParamBean param=(HttpParamBean)http.params.get(i); 979 String type=param.getType(); 980 // URL 981 if(type.equals("url")) { 982 listQS.add(new NameValuePair(translateEncoding(param.getName(), http.charset),translateEncoding(param.getValueAsString(), http.charset))); 983 } 984 // Form 985 else if(type.equals("formfield") || type.equals("form")) { 986 hasForm=true; 987 if(http.method==METHOD_GET) throw new ApplicationException("httpparam type formfield can't only be used, when method of the tag http equal post"); 988 if(post!=null){ 989 if(doMultiPart){ 990 parts.add(new RailoStringPart(param.getName(),param.getValueAsString(),_charset)); 991 } 992 else post.addParameter(new NameValuePair(param.getName(),param.getValueAsString())); 993 } 994 //else if(multi!=null)multi.addParameter(param.getName(),param.getValueAsString()); 995 } 996 // CGI 997 else if(type.equals("cgi")) { 998 if(param.isEncoded()) 999 httpMethod.addRequestHeader( 1000 translateEncoding(param.getName(),http.charset), 1001 translateEncoding(param.getValueAsString(),http.charset)); 1002 else 1003 httpMethod.addRequestHeader(param.getName(),param.getValueAsString()); 1004 } 1005 // Header 1006 else if(type.startsWith("head")) { 1007 if(param.getName().equalsIgnoreCase("content-type")) hasContentType=true; 1008 1009 if(param.getName().equalsIgnoreCase("Accept-Encoding")) { 1010 acceptEncoding.append(headerValue(param.getValueAsString())); 1011 acceptEncoding.append(", "); 1012 } 1013 else httpMethod.addRequestHeader(param.getName(),headerValue(param.getValueAsString())); 1014 } 1015 // Cookie 1016 else if(type.equals("cookie")) { 1017 Cookie c=CookieUtil.toCookie(_url.getHost(),param.getName(),param.getValueAsString(),_charset); 1018 c.setPath("/"); 1019 client.getState().addCookie(c); 1020 } 1021 // File 1022 else if(type.equals("file")) { 1023 hasForm=true; 1024 if(http.method==METHOD_GET) throw new ApplicationException("httpparam type file can't only be used, when method of the tag http equal post"); 1025 if(doMultiPart) { 1026 try { 1027 parts.add(new ResourcePart(param.getName(),new ResourcePartSource(param.getFile()),getContentType(param),_charset)); 1028 } 1029 catch (FileNotFoundException e) { 1030 throw new ApplicationException("can't upload file, path is invalid",e.getMessage()); 1031 } 1032 } 1033 } 1034 // XML 1035 else if(type.equals("xml")) { 1036 hasBody=true; 1037 hasContentType=true; 1038 httpMethod.addRequestHeader("Content-type", "text/xml; charset="+http.charset); 1039 //post.setRequestBody(new NameValuePair [] {new NameValuePair(translateEncoding(param.getName(), charset),translateEncoding(param.getValue(), charset))}); 1040 if(eem==null)throw new ApplicationException("type xml is only supported for type post and put"); 1041 eem.setRequestBody(param.getValueAsString()); 1042 } 1043 // Body 1044 else if(type.equals("body")) { 1045 hasBody=true; 1046 if(eem==null)throw new ApplicationException("type body is only supported for type post and put"); 1047 Object value = param.getValue(); 1048 1049 if(value instanceof InputStream) { 1050 eem.setRequestEntity(new InputStreamRequestEntity((InputStream)value,"application/octet-stream")); 1051 } 1052 else if(Decision.isCastableToBinary(value,false)){ 1053 eem.setRequestEntity(new ByteArrayRequestEntity(Caster.toBinary(value))); 1054 } 1055 else { 1056 eem.setRequestEntity(new StringRequestEntity(param.getValueAsString())); 1057 } 1058 } 1059 else { 1060 throw new ApplicationException("invalid type ["+type+"]"); 1061 } 1062 1063 } 1064 1065 httpMethod.setRequestHeader("Accept-Encoding",acceptEncoding.append("gzip").toString()); 1066 1067 1068 1069 // multipart 1070 if(doMultiPart && eem!=null) { 1071 hasContentType=true; 1072 boolean doIt=true; 1073 if(!http.multiPart && parts.size()==1){ 1074 Part part = parts.get(0); 1075 /* jira 1513 1076 if(part instanceof ResourcePart){ 1077 ResourcePart rp = (ResourcePart) part; 1078 eem.setRequestEntity(new ResourceRequestEntity(rp.getResource(),rp.getContentType())); 1079 doIt=false; 1080 } 1081 else */ 1082 if(part instanceof RailoStringPart){ 1083 RailoStringPart sp = (RailoStringPart) part; 1084 try { 1085 eem.setRequestEntity(new StringRequestEntity(sp.getValue(),sp.getContentType(),sp.getCharSet())); 1086 } catch (IOException e) { 1087 throw Caster.toPageException(e); 1088 } 1089 doIt=false; 1090 } 1091 } 1092 if(doIt) 1093 eem.setRequestEntity(new MultipartRequestEntityFlex(parts.toArray(new Part[parts.size()]), eem.getParams(),http.multiPartType)); 1094 } 1095 1096 1097 1098 if(hasBody && hasForm) 1099 throw new ApplicationException("mixing httpparam type file/formfield and body/XML is not allowed"); 1100 1101 if(!hasContentType) { 1102 if(isBinary) { 1103 if(hasBody) httpMethod.addRequestHeader("Content-type", "application/octet-stream"); 1104 else httpMethod.addRequestHeader("Content-type", "application/x-www-form-urlencoded; charset="+http.charset); 1105 } 1106 else { 1107 if(hasBody) 1108 httpMethod.addRequestHeader("Content-type", "text/html; charset="+http.charset ); 1109 } 1110 } 1111 1112 1113 // set User Agent 1114 httpMethod.setRequestHeader("User-Agent",http.useragent); 1115 1116 // set timeout 1117 if(http.timeout>0L)client.setConnectionTimeout((int)http.timeout); 1118 // for 3.0 client.getParams().setConnectionManagerTimeout(timeout); 1119 1120 // set Query String 1121 //NameValuePair[] qsPairs=new NameValuePair[arrQS.length+listQS.size()]; 1122 java.util.List<NameValuePair> listPairs=new ArrayList<NameValuePair>(); 1123 1124 //int count=0; 1125 // QS from URL 1126 for(int i=0;i<arrQS.length;i++) { 1127 if(StringUtil.isEmpty(arrQS[i])) continue; 1128 1129 String[] pair=List.toStringArray(List.listToArray(arrQS[i],'=')); 1130 if(ArrayUtil.isEmpty(pair)) continue; 1131 1132 String name=pair[0]; 1133 String value=pair.length>1?pair[1]:null; 1134 listPairs.add(new NameValuePair(name,value)); 1135 } 1136 1137 // QS from http Param 1138 len=listQS.size(); 1139 for(int i=0;i<len;i++) { 1140 listPairs.add(listQS.get(i)); 1141 } 1142 1143 // set to method 1144 String qs = toQueryString((NameValuePair[]) listPairs.toArray(new NameValuePair[listPairs.size()])); 1145 if(!StringUtil.isEmpty(qs)) 1146 httpMethod.setQueryString(qs); 1147 1148 1149 // set Username and Password 1150 if(http.username!=null) { 1151 if(http.password==null)http.password=""; 1152 //client.getState().setAuthenticationPreemptive(true); 1153 client.getState().setCredentials(null,null,new UsernamePasswordCredentials(http.username, http.password)); 1154 httpMethod.setDoAuthentication( true ); 1155 client.getState().setAuthenticationPreemptive(true); 1156 1157 } 1158 1159 // set Proxy 1160 if(StringUtil.isEmpty(http.proxyserver) && http.pageContext.getConfig().isProxyEnableFor(_url.getHost())) { 1161 http.proxyserver=http.pageContext.getConfig().getProxyServer(); 1162 http.proxyport=http.pageContext.getConfig().getProxyPort(); 1163 http.proxyuser=http.pageContext.getConfig().getProxyUsername(); 1164 http.proxypassword=http.pageContext.getConfig().getProxyPassword(); 1165 } 1166 if(!StringUtil.isEmpty(http.proxyserver)) { 1167 config.setProxy(http.proxyserver,http.proxyport); 1168 if(!StringUtil.isEmpty(http.proxyuser)) { 1169 state.setProxyCredentials(null,null,new UsernamePasswordCredentials(http.proxyuser,http.proxypassword)); 1170 } 1171 } 1172 1173 1174 1175 httpMethod.setFollowRedirects(false); 1176 return httpMethod; 1177 } 1178 1179 private static String headerValue(String value) { 1180 if(value==null) return null; 1181 value=value.trim(); 1182 int len=value.length(); 1183 char c; 1184 for(int i=0;i<len;i++){ 1185 c=value.charAt(i); 1186 if(c=='\n' || c=='\r') return value.substring(0,i); 1187 } 1188 return value; 1189 } 1190 1191 private static String toQueryString(NameValuePair[] qsPairs) { 1192 StringBuffer sb=new StringBuffer(); 1193 for(int i=0;i<qsPairs.length;i++) { 1194 if(sb.length()>0)sb.append('&'); 1195 sb.append(qsPairs[i].getName()); 1196 if(qsPairs[i].getValue()!=null){ 1197 sb.append('='); 1198 sb.append(qsPairs[i].getValue()); 1199 } 1200 } 1201 return sb.toString(); 1202 } 1203 1204 private static String translateEncoding(String str, String charset) throws UnsupportedEncodingException { 1205 if(!ReqRspUtil.needEncoding(str,false)) return str; 1206 return URLEncoder.encode(str,charset); 1207 } 1208 1209 /** 1210 * @see javax.servlet.jsp.tagext.BodyTag#doInitBody() 1211 */ 1212 public void doInitBody() { 1213 1214 } 1215 1216 /** 1217 * @see javax.servlet.jsp.tagext.BodyTag#doAfterBody() 1218 */ 1219 public int doAfterBody() { 1220 return SKIP_BODY; 1221 } 1222 1223 /** 1224 * sets if has body or not 1225 * @param hasBody 1226 */ 1227 public void hasBody(boolean hasBody) { 1228 1229 } 1230 1231 /** 1232 * @param param 1233 */ 1234 public void setParam(HttpParamBean param) { 1235 params.add(param); 1236 1237 } 1238 1239 1240 /** 1241 * @param getAsBinary The getasbinary to set. 1242 */ 1243 public void setGetasbinary(String getAsBinary) { 1244 // TODO support never, wird das verwendet? 1245 getAsBinary=getAsBinary.toLowerCase().trim(); 1246 if(getAsBinary.equals("yes") || getAsBinary.equals("true")) this.getAsBinary=GET_AS_BINARY_YES; 1247 else if(getAsBinary.equals("no") || getAsBinary.equals("false")) this.getAsBinary=GET_AS_BINARY_NO; 1248 else if(getAsBinary.equals("auto")) this.getAsBinary=GET_AS_BINARY_AUTO; 1249 } 1250 1251 /** 1252 * @param multipart The multipart to set. 1253 */ 1254 public void setMultipart(boolean multiPart) { 1255 this.multiPart = multiPart; 1256 } 1257 1258 /** 1259 * @param multipart The multipart to set. 1260 * @throws ApplicationException 1261 */ 1262 public void setMultiparttype(String multiPartType) throws ApplicationException { 1263 if(StringUtil.isEmpty(multiPartType))return; 1264 multiPartType=multiPartType.trim().toLowerCase(); 1265 1266 if("form-data".equals(multiPartType)) this.multiPartType=MultipartRequestEntityFlex.MULTIPART_FORM_DATA; 1267 //else if("related".equals(multiPartType)) this.multiPartType=MultipartRequestEntityFlex.MULTIPART_RELATED; 1268 else 1269 throw new ApplicationException("invalid value for attribute multiPartType ["+multiPartType+"]", 1270 "attribute must have one of the folloing values [form-data]"); 1271 1272 } 1273 1274 /** 1275 * @param result The result to set. 1276 */ 1277 public void setResult(String result) { 1278 this.result = result; 1279 } 1280 1281 /** 1282 * @param addtoken the addtoken to set 1283 */ 1284 public void setAddtoken(boolean addtoken) { 1285 this.addtoken = addtoken; 1286 } 1287 1288 /** 1289 * checks if status code is a redirect 1290 * @param status 1291 * @return is redirect 1292 */ 1293 1294 static boolean isRedirect(int status) { 1295 return 1296 status==STATUS_REDIRECT_FOUND || 1297 status==STATUS_REDIRECT_MOVED_PERMANENTLY || 1298 status==STATUS_REDIRECT_SEE_OTHER || 1299 status==STATUS_REDIRECT_TEMPORARY_REDIRECT; 1300 1301 1302 } 1303 1304 /** 1305 * merge to pathes to one 1306 * @param current 1307 * @param realPath 1308 * @return 1309 * @throws MalformedURLException 1310 */ 1311 public static String mergePath(String current, String realPath) throws MalformedURLException { 1312 1313 // get current directory 1314 String currDir; 1315 if(current==null || current.indexOf('/')==-1)currDir="/"; 1316 else if(current.endsWith("/"))currDir=current; 1317 else currDir=current.substring(0,current.lastIndexOf('/')+1); 1318 1319 // merge together 1320 String path; 1321 if(realPath.startsWith("./"))path=currDir+realPath.substring(2); 1322 else if(realPath.startsWith("/"))path=realPath; 1323 else if(!realPath.startsWith("../"))path=currDir+realPath; 1324 else { 1325 while(realPath.startsWith("../") || currDir.length()==0) { 1326 realPath=realPath.substring(3); 1327 currDir=currDir.substring(0,currDir.length()-1); 1328 int index = currDir.lastIndexOf('/'); 1329 if(index==-1)throw new MalformedURLException("invalid realpath definition for URL"); 1330 currDir=currDir.substring(0,index+1); 1331 } 1332 path=currDir+realPath; 1333 } 1334 1335 return path; 1336 } 1337 1338 private static String getContentType(HttpParamBean param) { 1339 String mimeType=param.getMimeType(); 1340 if(StringUtil.isEmpty(mimeType,true)) { 1341 mimeType=ResourceUtil.getMymeType(param.getFile(), true, null); 1342 } 1343 return mimeType; 1344 } 1345 1346 public static boolean isGzipEncoded(String contentEncoding) { 1347 return !StringUtil.isEmpty(contentEncoding) && StringUtil.indexOfIgnoreCase(contentEncoding, "gzip")!=-1; 1348 } 1349 1350 public static Object getOutput(InputStream is, String contentType, String contentEncoding, boolean closeIS) { 1351 if(StringUtil.isEmpty(contentType))contentType="text/html"; 1352 1353 // Gzip 1354 if(Http.isGzipEncoded(contentEncoding)){ 1355 try { 1356 is=new GZIPInputStream(is); 1357 } 1358 catch (IOException e) {} 1359 } 1360 1361 try { 1362 // text 1363 if(isText(contentType)) { 1364 String[] tmp = HTTPUtil.splitMimeTypeAndCharset(contentType); 1365 //String mimetype=tmp[0]; 1366 String charset=tmp[1]; 1367 1368 if(StringUtil.isEmpty(charset,true)) { 1369 Config config = ThreadLocalPageContext.getConfig(); 1370 if(config!=null)charset=config.getWebCharset(); 1371 } 1372 1373 try { 1374 return IOUtil.toString(is, charset); 1375 } catch (IOException e) {} 1376 } 1377 // Binary 1378 else { 1379 try { 1380 return IOUtil.toBytes(is); 1381 } 1382 catch (IOException e) {} 1383 } 1384 } 1385 finally{ 1386 if(closeIS)IOUtil.closeEL(is); 1387 } 1388 1389 return ""; 1390 } 1391 1392 } 1393 1394 class MultipartRequestEntityFlex extends MultipartRequestEntity { 1395 1396 1397 public static final String MULTIPART_RELATED = "multipart/related"; 1398 public static final String MULTIPART_FORM_DATA = "multipart/form-data"; 1399 private String multipartType; 1400 1401 1402 /** 1403 * Constructor of the class 1404 * @param parts 1405 * @param params 1406 * @param multipartType use constant MultipartRequestEntityFlex.MULTIPART_FORM_DATA or MultipartRequestEntityFlex.MULTIPART_RELATED 1407 */ 1408 public MultipartRequestEntityFlex(Part[] parts, HttpMethodParams params,String multipartType) { 1409 super(parts, params); 1410 this.multipartType=multipartType; 1411 } 1412 1413 /** 1414 * @see org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity#getContentType() 1415 */ 1416 public String getContentType() { 1417 StringBuilder builder = new StringBuilder(multipartType); 1418 builder.append("; boundary="); 1419 builder.append(EncodingUtil.getAsciiString(getMultipartBoundary())); 1420 1421 return builder.toString(); 1422 1423 //return super.getContentType(); 1424 } 1425 } 1426 1427 class Executor extends Thread { 1428 1429 final Http http; 1430 final HttpClient client; 1431 HttpMethod httpMethod; 1432 final boolean redirect; 1433 Throwable t; 1434 boolean done; 1435 URL redirectURL; 1436 1437 public Executor(Http http, HttpClient client,HttpMethod httpMethod,boolean redirect) { 1438 this.http=http; 1439 this.client=client; 1440 this.httpMethod=httpMethod; 1441 this.redirect=redirect; 1442 } 1443 1444 1445 public void run(){ 1446 try { 1447 execute(); 1448 done=true; 1449 synchronized(http){ 1450 http.notify(); 1451 } 1452 } catch (Throwable t) { 1453 this.t=t; 1454 } 1455 } 1456 1457 public void execute() throws IOException, PageException { 1458 // Execute Request 1459 1460 short count=0; 1461 URL lu; 1462 while(Http.isRedirect(client.executeMethod(httpMethod)) && redirect && count++ < Http.MAX_REDIRECT) { 1463 lu=Http.locationURL(httpMethod); 1464 redirectURL=lu; 1465 HttpMethod oldHttpMethod = httpMethod; 1466 httpMethod=Http.createMethod(ThreadLocalPageContext.getConfig(),http,client,lu.toExternalForm(),-1); 1467 Http.releaseConnection(oldHttpMethod); 1468 } 1469 1470 } 1471 }