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