package railo.runtime.tag; import java.io.ByteArrayInputStream; import java.io.EOFException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.PrintStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Iterator; import java.util.zip.GZIPInputStream; import org.apache.http.HttpEntityEnclosingRequest; import org.apache.http.HttpHost; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpHead; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.methods.HttpTrace; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.StringEntity; import org.apache.http.entity.mime.FormBodyPart; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.ContentBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.BasicHttpParams; import org.apache.http.protocol.BasicHttpContext; import org.apache.http.protocol.HttpContext; import railo.commons.io.CharsetUtil; import railo.commons.io.IOUtil; import railo.commons.io.SystemUtil; import railo.commons.io.res.Resource; import railo.commons.io.res.util.ResourceUtil; import railo.commons.lang.StringUtil; import railo.commons.lang.mimetype.ContentType; import railo.commons.net.HTTPUtil; import railo.commons.net.URLEncoder; import railo.commons.net.http.HTTPEngine; import railo.commons.net.http.Header; import railo.commons.net.http.httpclient4.CachingGZIPInputStream; import railo.commons.net.http.httpclient4.HTTPEngine4Impl; import railo.commons.net.http.httpclient4.HTTPPatchFactory; import railo.commons.net.http.httpclient4.HTTPResponse4Impl; import railo.commons.net.http.httpclient4.ResourceBody; import railo.runtime.config.Config; import railo.runtime.config.ConfigWeb; import railo.runtime.engine.ThreadLocalPageContext; import railo.runtime.exp.ApplicationException; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.HTTPException; import railo.runtime.exp.NativeException; import railo.runtime.exp.PageException; import railo.runtime.ext.tag.BodyTagImpl; import railo.runtime.net.http.MultiPartResponseUtils; import railo.runtime.net.http.ReqRspUtil; import railo.runtime.net.proxy.ProxyData; import railo.runtime.net.proxy.ProxyDataImpl; import railo.runtime.op.Caster; import railo.runtime.text.csv.CSVParser; import railo.runtime.type.Array; import railo.runtime.type.ArrayImpl; import railo.runtime.type.Collection.Key; import railo.runtime.type.KeyImpl; import railo.runtime.type.Query; import railo.runtime.type.QueryImpl; import railo.runtime.type.Struct; import railo.runtime.type.StructImpl; import railo.runtime.type.dt.DateTime; import railo.runtime.type.util.KeyConstants; import railo.runtime.type.util.ListUtil; import railo.runtime.util.URLResolver; // MUST change behavor of mltiple headers now is a array, it das so? /** * Lets you execute HTTP POST and GET operations on files. Using cfhttp, you can execute standard * GET operations and create a query object from a text file. POST operations lets you upload MIME file * types to a server, or post cookie, formfield, URL, file, or CGI variables directly to a specified server. * * * * **/ public final class Http4 extends BodyTagImpl implements Http { public static final String MULTIPART_RELATED = "multipart/related"; public static final String MULTIPART_FORM_DATA = "multipart/form-data"; /** * Maximum redirect count (5) */ public static final short MAX_REDIRECT=15; /** * Constant value for HTTP Status Code "moved Permanently 301" */ public static final int STATUS_REDIRECT_MOVED_PERMANENTLY=301; /** * Constant value for HTTP Status Code "Found 302" */ public static final int STATUS_REDIRECT_FOUND=302; /** * Constant value for HTTP Status Code "see other 303" */ public static final int STATUS_REDIRECT_SEE_OTHER=303; public static final int STATUS_REDIRECT_TEMPORARY_REDIRECT = 307; private static final short METHOD_GET=0; private static final short METHOD_POST=1; private static final short METHOD_HEAD=2; private static final short METHOD_PUT=3; private static final short METHOD_DELETE=4; private static final short METHOD_OPTIONS=5; private static final short METHOD_TRACE=6; private static final short METHOD_PATCH=7; private static final String NO_MIMETYPE="Unable to determine MIME type of file."; private static final short GET_AS_BINARY_NO=0; private static final short GET_AS_BINARY_YES=1; private static final short GET_AS_BINARY_AUTO=2; private static final Key STATUSCODE = KeyConstants._statuscode; private static final Key CHARSET = KeyConstants._charset; private static final Key ERROR_DETAIL = KeyImpl.intern("errordetail"); private static final Key STATUS_CODE = KeyImpl.intern("status_code"); private static final Key STATUS_TEXT = KeyImpl.intern("status_text"); private static final Key HTTP_VERSION = KeyImpl.intern("http_version"); private static final Key FILE_CONTENT = KeyImpl.intern("filecontent"); private static final Key EXPLANATION = KeyImpl.intern("explanation"); private static final Key RESPONSEHEADER = KeyImpl.intern("responseheader"); private static final Key SET_COOKIE = KeyImpl.intern("set-cookie"); private static final short AUTH_TYPE_BASIC = 0; private static final short AUTH_TYPE_NTLM = 1; static { //Protocol myhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443); //Protocol.registerProtocol("https", new Protocol("https", new EasySSLProtocolSocketFactory(), 443)); } private ArrayList<HttpParamBean> params=new ArrayList<HttpParamBean>(); /** When required by a server, a valid password. */ private String password; /** Required for creating a query. Options are a tab or comma. Default is a comma. */ private char delimiter=','; /** Yes or No. Default is No. For GET and POST operations, if Yes, page reference returned into the ** fileContent internal variable has its internal URLs fully resolved, including port number, so that ** links remain intact. */ private boolean resolveurl; /** A value, in seconds. When a URL timeout is specified in the browser */ private long timeout=-1; /** Host name or IP address of a proxy server. */ private String proxyserver; /** The filename to be used for the file that is accessed. For GET operations, defaults to the name ** pecified in url. Enter path information in the path attribute. */ private String strFile; /** The path to the directory in which a file is to be stored. If a path is not specified in a POST ** or GET operation, a variable is created (cfhttp.fileContent) that you can use to display the results ** of the POST operation in a cfoutput. */ private String strPath; /** Boolean indicating whether to throw an exception that can be caught by using the cftry and ** cfcatch tags. The default is NO. */ private boolean throwonerror; /** set the charset for the call. */ private String charset=null; /** The port number on the proxy server from which the object is requested. Default is 80. When ** used with resolveURL, the URLs of retrieved documents that specify a port number are automatically ** resolved to preserve links in the retrieved document. */ private int proxyport=80; /** Specifies the column names for a query when creating a query as a result of a cfhttp GET. */ private String[] columns; /** The port number on the server from which the object is requested. Default is 80. When used with ** resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved to ** preserve links in the retrieved document. If a port number is specified in the url attribute, the port ** value overrides the value of the port attribute. */ private int port=-1; /** User agent request header. */ private String useragent="Railo (CFML Engine)"; /** Required for creating a query. Indicates the start and finish of a column. Should be ** appropriately escaped when embedded in a column. For example, if the qualifier is a double quotation ** mark, it should be escaped as """". If there is no text qualifier in the file, specify it as " ". ** Default is the double quotation mark ("). */ private char textqualifier='"'; /** When required by a server, a valid username. */ private String username; /** Full URL of the host name or IP address of the server on which the file resides. The URL must be ** an absolute URL, including the protocol (http or https) and hostname. It may optionally contain a port ** number. Port numbers specified in the url attribute override the port attribute. */ private String url; /** Boolean indicating whether to redirect execution or stop execution.*/ private boolean redirect=true; /** The name to assign to a query if the a query is constructed from a file. */ private String name; /** GET or POST. Use GET to download a text or binary file or to create a query from the contents ** of a text file. Use POST to send information to a server page or a CGI program for processing. POST ** requires the use of a cfhttpparam tag. */ private short method=METHOD_GET; //private boolean hasBody=false; private boolean firstrowasheaders=true; private String proxyuser=null; private String proxypassword=""; private boolean multiPart=false; private String multiPartType=MULTIPART_FORM_DATA; private short getAsBinary=GET_AS_BINARY_NO; private String result="cfhttp"; private boolean addtoken=false; private short authType=AUTH_TYPE_BASIC; private String workStation=null; private String domain=null; private boolean preauth=true; private boolean encoded=true; private boolean compression=true; @Override public void release() { super.release(); params.clear(); password=null; delimiter=','; resolveurl=false; timeout=-1L; proxyserver=null; proxyport=80; proxyuser=null; proxypassword=""; strFile=null; throwonerror=false; charset=null; columns=null; port=-1; useragent="Railo (CFML Engine)"; textqualifier='"'; username=null; url=null; redirect=true; strPath=null; name=null; method=METHOD_GET; //hasBody=false; firstrowasheaders=true; getAsBinary=GET_AS_BINARY_NO; multiPart=false; multiPartType=MULTIPART_FORM_DATA; result="cfhttp"; addtoken=false; authType=AUTH_TYPE_BASIC; workStation=null; domain=null; preauth=true; encoded=true; compression=true; } /** * @param firstrowasheaders */ public void setFirstrowasheaders(boolean firstrowasheaders) { this.firstrowasheaders=firstrowasheaders; } public void setEncoded(boolean encoded) { this.encoded=encoded; } /** set the value password * When required by a server, a valid password. * @param password value to set **/ public void setPassword(String password) { this.password=password; } /** set the value password * When required by a proxy server, a valid password. * @param proxypassword value to set **/ public void setProxypassword(String proxypassword) { this.proxypassword=proxypassword; } /** set the value delimiter * Required for creating a query. Options are a tab or comma. Default is a comma. * @param delimiter value to set **/ public void setDelimiter(String delimiter) { this.delimiter=delimiter.length()==0?',':delimiter.charAt(0); } /** set the value resolveurl * Yes or No. Default is No. For GET and POST operations, if Yes, page reference returned into the * fileContent internal variable has its internal URLs fully resolved, including port number, so that * links remain intact. * @param resolveurl value to set **/ public void setResolveurl(boolean resolveurl) { this.resolveurl=resolveurl; } public void setPreauth(boolean preauth) { this.preauth=preauth; } /** set the value timeout * @param timeout value to set * @throws ExpressionException **/ public void setTimeout(double timeout) throws ExpressionException { if(timeout<0) throw new ExpressionException("invalid value ["+Caster.toString(timeout)+"] for attribute timeout, value must be a positive integer greater or equal than 0"); long requestTimeout = pageContext.getRequestTimeout(); long _timeout=(long)(timeout*1000D); this.timeout=requestTimeout<_timeout?requestTimeout:_timeout; //print.out("this.timeout:"+this.timeout); } /** set the value proxyserver * Host name or IP address of a proxy server. * @param proxyserver value to set **/ public void setProxyserver(String proxyserver) { this.proxyserver=proxyserver; } /** set the value proxyport * The port number on the proxy server from which the object is requested. Default is 80. When * used with resolveURL, the URLs of retrieved documents that specify a port number are automatically * resolved to preserve links in the retrieved document. * @param proxyport value to set **/ public void setProxyport(double proxyport) { this.proxyport=(int)proxyport; } /** set the value file * The filename to be used for the file that is accessed. For GET operations, defaults to the name * pecified in url. Enter path information in the path attribute. * @param file value to set **/ public void setFile(String file) { this.strFile=file; } /** set the value throwonerror * Boolean indicating whether to throw an exception that can be caught by using the cftry and * cfcatch tags. The default is NO. * @param throwonerror value to set **/ public void setThrowonerror(boolean throwonerror) { this.throwonerror=throwonerror; } /** set the value charset * set the charset for the call. * @param charset value to set **/ public void setCharset(String charset) { this.charset=charset; } /** set the value columns * @param columns value to set * @throws PageException **/ public void setColumns(String columns) throws PageException { this.columns=ListUtil.toStringArray(ListUtil.listToArrayRemoveEmpty(columns,",")); } /** set the value port * The port number on the server from which the object is requested. Default is 80. When used with * resolveURL, the URLs of retrieved documents that specify a port number are automatically resolved to * preserve links in the retrieved document. If a port number is specified in the url attribute, the port * value overrides the value of the port attribute. * @param port value to set **/ public void setPort(double port) { this.port=(int) port; } /** set the value useragent * User agent request header. * @param useragent value to set **/ public void setUseragent(String useragent) { this.useragent=useragent; } /** set the value textqualifier * Required for creating a query. Indicates the start and finish of a column. Should be * appropriately escaped when embedded in a column. For example, if the qualifier is a double quotation * mark, it should be escaped as """". If there is no text qualifier in the file, specify it as " ". * Default is the double quotation mark ("). * @param textqualifier value to set **/ public void setTextqualifier(String textqualifier) { this.textqualifier=textqualifier.length()==0?'"':textqualifier.charAt(0); } /** set the value username * When required by a proxy server, a valid username. * @param proxyuser value to set **/ public void setProxyuser(String proxyuser) { this.proxyuser=proxyuser; } /** set the value username * When required by a server, a valid username. * @param username value to set **/ public void setUsername(String username) { this.username=username; } /** set the value url * Full URL of the host name or IP address of the server on which the file resides. The URL must be * an absolute URL, including the protocol (http or https) and hostname. It may optionally contain a port * number. Port numbers specified in the url attribute override the port attribute. * @param url value to set **/ public void setUrl(String url) { this.url=url; } /** set the value redirect * @param redirect value to set **/ public void setRedirect(boolean redirect) { this.redirect=redirect; } /** set the value path * The path to the directory in which a file is to be stored. If a path is not specified in a POST * or GET operation, a variable is created (cfhttp.fileContent) that you can use to display the results * of the POST operation in a cfoutput. * @param path value to set **/ public void setPath(String path) { this.strPath=path; } /** set the value name * The name to assign to a query if the a query is constructed from a file. * @param name value to set **/ public void setName(String name) { this.name=name; } public void setAuthtype(String strAuthType) throws ExpressionException{ if(StringUtil.isEmpty(strAuthType,true)) return; strAuthType=strAuthType.trim(); if("basic".equalsIgnoreCase(strAuthType)) authType=AUTH_TYPE_BASIC; else if("ntlm".equalsIgnoreCase(strAuthType)) authType=AUTH_TYPE_NTLM; else throw new ExpressionException("invalid value ["+strAuthType+"] for attribute authType, value must be one of the following [basic,ntlm]"); } public void setWorkstation(String workStation) { this.workStation=workStation; } public void setDomain(String domain) { this.domain=domain; } /** set the value method * GET or POST. Use GET to download a text or binary file or to create a query from the contents * of a text file. Use POST to send information to a server page or a CGI program for processing. POST * requires the use of a cfhttpparam tag. * @param method value to set * @throws ApplicationException **/ public void setMethod(String method) throws ApplicationException { method=method.toLowerCase().trim(); if(method.equals("post")) this.method=METHOD_POST; else if(method.equals("get")) this.method=METHOD_GET; else if(method.equals("head")) this.method=METHOD_HEAD; else if(method.equals("delete")) this.method=METHOD_DELETE; else if(method.equals("put")) this.method=METHOD_PUT; else if(method.equals("trace")) this.method=METHOD_TRACE; else if(method.equals("options")) this.method=METHOD_OPTIONS; else if(method.equals("patch")) this.method=METHOD_PATCH; else throw new ApplicationException("invalid method type ["+(method.toUpperCase())+"], valid types are POST,GET,HEAD,DELETE,PUT,TRACE,OPTIONS,PATCH"); } public void setCompression(String strCompression) throws ApplicationException { if(StringUtil.isEmpty(strCompression,true)) return; Boolean b = Caster.toBoolean(strCompression,null); if(b!=null) compression=b.booleanValue(); else if(strCompression.trim().equalsIgnoreCase("none")) compression=false; else throw new ApplicationException("invalid value for attribute compression ["+strCompression+"], valid values are: true,false or none"); } @Override public int doStartTag() { if(addtoken) { setParam("cookie","cfid",pageContext.getCFID()); setParam("cookie","cftoken",pageContext.getCFToken()); String jsessionid = pageContext.getJSessionId(); if(jsessionid!=null)setParam("cookie","jsessionid",jsessionid); } return EVAL_BODY_INCLUDE; } private void setParam(String type, String name, String value) { HttpParamBean hpb = new HttpParamBean(); hpb.setType(type); hpb.setName(name); hpb.setValue(value); setParam(hpb); } @Override public int doEndTag() throws PageException { Struct cfhttp=new StructImpl(); cfhttp.setEL(ERROR_DETAIL,""); pageContext.setVariable(result,cfhttp); // because commons PrintStream out = System.out; try { //System.setOut(new PrintStream(DevNullOutputStream.DEV_NULL_OUTPUT_STREAM)); _doEndTag(cfhttp); return EVAL_PAGE; } catch (IOException e) { throw Caster.toPageException(e); } finally { System.setOut(out); } } private void _doEndTag(Struct cfhttp) throws PageException, IOException { BasicHttpParams params = new BasicHttpParams(); DefaultHttpClient client = HTTPEngine4Impl.createClient(params,redirect?HTTPEngine.MAX_REDIRECT:0); ConfigWeb cw = pageContext.getConfig(); HttpRequestBase req=null; HttpContext httpContext=null; //HttpRequestBase req = init(pageContext.getConfig(),this,client,params,url,port); { if(StringUtil.isEmpty(charset,true)) charset=cw.getWebCharset(); else charset=charset.trim(); // check if has fileUploads boolean doUploadFile=false; for(int i=0;i<this.params.size();i++) { if((this.params.get(i)).getType().equalsIgnoreCase("file")) { doUploadFile=true; break; } } // parse url (also query string) int len=this.params.size(); StringBuilder sbQS=new StringBuilder(); for(int i=0;i<len;i++) { HttpParamBean param=this.params.get(i); String type=param.getType(); // URL if(type.equals("url")) { if(sbQS.length()>0)sbQS.append('&'); sbQS.append(param.getEncoded()?urlenc(param.getName(),charset):param.getName()); sbQS.append('='); sbQS.append(param.getEncoded()?urlenc(param.getValueAsString(), charset):param.getValueAsString()); } } String host=null; HttpHost httpHost; try { URL _url = HTTPUtil.toURL(url,port,encoded); httpHost = new HttpHost(_url.getHost(),_url.getPort()); host=_url.getHost(); url=_url.toExternalForm(); if(sbQS.length()>0){ // no existing QS if(StringUtil.isEmpty(_url.getQuery())) { url+="?"+sbQS; } else { url+="&"+sbQS; } } } catch (MalformedURLException mue) { throw Caster.toPageException(mue); } // select best matching method (get,post, post multpart (file)) boolean isBinary = false; boolean doMultiPart=doUploadFile || this.multiPart; HttpPost post=null; HttpEntityEnclosingRequest eem=null; if(this.method==METHOD_GET) { req=new HttpGet(url); } else if(this.method==METHOD_HEAD) { req=new HttpHead(url); } else if(this.method==METHOD_DELETE) { isBinary=true; req=new HttpDelete(url); } else if(this.method==METHOD_PUT) { isBinary=true; HttpPut put = new HttpPut(url); req=put; eem=put; } else if(this.method==METHOD_TRACE) { isBinary=true; req=new HttpTrace(url); } else if(this.method==METHOD_OPTIONS) { isBinary=true; req=new HttpOptions(url); } else if(this.method==METHOD_PATCH) { isBinary=true; eem = HTTPPatchFactory.getHTTPPatch(url); req=(HttpRequestBase) eem; } else { isBinary=true; post=new HttpPost(url); req=post; eem=post; } boolean hasForm=false; boolean hasBody=false; boolean hasContentType=false; // Set http params ArrayList<FormBodyPart> parts=new ArrayList<FormBodyPart>(); StringBuilder acceptEncoding=new StringBuilder(); java.util.List<NameValuePair> postParam = post!=null?new ArrayList <NameValuePair>():null; for(int i=0;i<len;i++) { HttpParamBean param=this.params.get(i); String type=param.getType(); // URL if(type.equals("url")) { //listQS.add(new BasicNameValuePair(translateEncoding(param.getName(), http.charset),translateEncoding(param.getValueAsString(), http.charset))); } // Form else if(type.equals("formfield") || type.equals("form")) { hasForm=true; if(this.method==METHOD_GET) throw new ApplicationException("httpparam type formfield can't only be used, when method of the tag http equal post"); if(post!=null){ if(doMultiPart) { parts.add( new FormBodyPart( param.getName(), new StringBody( param.getValueAsString(), CharsetUtil.toCharset(charset) ) ) ); } else { postParam.add(new BasicNameValuePair(param.getName(),param.getValueAsString())); } } //else if(multi!=null)multi.addParameter(param.getName(),param.getValueAsString()); } // CGI else if(type.equals("cgi")) { if(param.getEncoded()) req.addHeader( urlenc(param.getName(),charset), urlenc(param.getValueAsString(),charset)); else req.addHeader(param.getName(),param.getValueAsString()); } // Header else if(type.startsWith("head")) { if(param.getName().equalsIgnoreCase("content-type")) hasContentType=true; if(param.getName().equalsIgnoreCase("Content-Length")) {} else if(param.getName().equalsIgnoreCase("Accept-Encoding")) { acceptEncoding.append(headerValue(param.getValueAsString())); acceptEncoding.append(", "); } else req.addHeader(param.getName(),headerValue(param.getValueAsString())); } // Cookie else if(type.equals("cookie")) { HTTPEngine4Impl.addCookie(client,host,param.getName(),param.getValueAsString(),"/",charset); } // File else if(type.equals("file")) { hasForm=true; if(this.method==METHOD_GET) throw new ApplicationException("httpparam type file can't only be used, when method of the tag http equal post"); String strCT = getContentType(param); ContentType ct = HTTPUtil.toContentType(strCT,null); String mt="text/xml"; if(ct!=null && !StringUtil.isEmpty(ct.getMimeType(),true)) mt=ct.getMimeType(); String cs=charset; if(ct!=null && !StringUtil.isEmpty(ct.getCharset(),true)) cs=ct.getCharset(); if(doMultiPart) { try { Resource res = param.getFile(); parts.add(new FormBodyPart( param.getName(), new ResourceBody(res, mt, res.getName(), cs) )); //parts.add(new ResourcePart(param.getName(),new ResourcePartSource(param.getFile()),getContentType(param),_charset)); } catch (FileNotFoundException e) { throw new ApplicationException("can't upload file, path is invalid",e.getMessage()); } } } // XML else if(type.equals("xml")) { ContentType ct = HTTPUtil.toContentType(param.getMimeType(),null); String mt="text/xml"; if(ct!=null && !StringUtil.isEmpty(ct.getMimeType(),true)) mt=ct.getMimeType(); String cs=charset; if(ct!=null && !StringUtil.isEmpty(ct.getCharset(),true)) cs=ct.getCharset(); hasBody=true; hasContentType=true; req.addHeader("Content-type", mt+"; charset="+cs); if(eem==null)throw new ApplicationException("type xml is only supported for type post and put"); HTTPEngine4Impl.setBody(eem, param.getValueAsString(),mt,cs); } // Body else if(type.equals("body")) { ContentType ct = HTTPUtil.toContentType(param.getMimeType(),null); String mt=null; if(ct!=null && !StringUtil.isEmpty(ct.getMimeType(),true)) mt=ct.getMimeType(); String cs=charset; if(ct!=null && !StringUtil.isEmpty(ct.getCharset(),true)) cs=ct.getCharset(); hasBody=true; if(eem==null)throw new ApplicationException("type body is only supported for type post and put"); HTTPEngine4Impl.setBody(eem, param.getValue(),mt,cs); } else { throw new ApplicationException("invalid type ["+type+"]"); } } // post params if(postParam!=null && postParam.size()>0) post.setEntity(new org.apache.http.client.entity.UrlEncodedFormEntity(postParam,charset)); if(compression){ acceptEncoding.append("gzip"); } else { acceptEncoding.append("deflate;q=0"); req.setHeader("TE", "deflate;q=0"); } req.setHeader("Accept-Encoding",acceptEncoding.toString()); // multipart if(doMultiPart && eem!=null) { hasContentType=true; boolean doIt=true; if(!this.multiPart && parts.size()==1){ ContentBody body = parts.get(0).getBody(); if(body instanceof StringBody){ StringBody sb=(StringBody)body; try { org.apache.http.entity.ContentType ct=org.apache.http.entity.ContentType.create(sb.getMimeType(),sb.getCharset()); String str = IOUtil.toString(sb.getReader()); StringEntity entity = new StringEntity(str,ct); eem.setEntity(entity); } catch (IOException e) { throw Caster.toPageException(e); } doIt=false; } } if(doIt) { MultipartEntity mpe = new MultipartEntity(HttpMultipartMode.STRICT); Iterator<FormBodyPart> it = parts.iterator(); while(it.hasNext()) { FormBodyPart part = it.next(); mpe.addPart(part.getName(),part.getBody()); } eem.setEntity(mpe); } //eem.setRequestEntity(new MultipartRequestEntityFlex(parts.toArray(new Part[parts.size()]), eem.getParams(),http.multiPartType)); } if(hasBody && hasForm) throw new ApplicationException("mixing httpparam type file/formfield and body/XML is not allowed"); if(!hasContentType) { if(isBinary) { if(hasBody) req.addHeader("Content-type", "application/octet-stream"); else req.addHeader("Content-type", "application/x-www-form-urlencoded; charset="+charset); } else { if(hasBody) req.addHeader("Content-type", "text/html; charset="+charset ); } } // set User Agent if(!hasHeaderIgnoreCase(req,"User-Agent")) req.setHeader("User-Agent",this.useragent); // set timeout if(this.timeout>0L)HTTPEngine4Impl.setTimeout(params, (int)this.timeout); // set Username and Password if(this.username!=null) { if(this.password==null)this.password=""; if(AUTH_TYPE_NTLM==this.authType) { if(StringUtil.isEmpty(this.workStation,true)) throw new ApplicationException("attribute workstation is required when authentication type is [NTLM]"); if(StringUtil.isEmpty(this.domain,true)) throw new ApplicationException("attribute domain is required when authentication type is [NTLM]"); HTTPEngine4Impl.setNTCredentials(client, this.username, this.password, this.workStation,this.domain); } else httpContext=HTTPEngine4Impl.setCredentials(client, httpHost, this.username, this.password,preauth); } // set Proxy ProxyData proxy=null; if(!StringUtil.isEmpty(this.proxyserver)) { proxy=ProxyDataImpl.getInstance(this.proxyserver, this.proxyport, this.proxyuser, this.proxypassword) ; } if(pageContext.getConfig().isProxyEnableFor(host)) { proxy=pageContext.getConfig().getProxyData(); } HTTPEngine4Impl.setProxy(client, req, proxy); } try { if(httpContext==null)httpContext = new BasicHttpContext(); /////////////////////////////////////////// EXECUTE ///////////////////////////////////////////////// Executor4 e = new Executor4(this,client,httpContext,req,redirect); HTTPResponse4Impl rsp=null; if(timeout<0){ try{ rsp = e.execute(httpContext); } catch(Throwable t){ if(!throwonerror){ setUnknownHost(cfhttp, t); return; } throw toPageException(t); } } else { e.start(); try { synchronized(this){//print.err(timeout); this.wait(timeout); } } catch (InterruptedException ie) { throw Caster.toPageException(ie); } if(e.t!=null){ if(!throwonerror){ setUnknownHost(cfhttp,e.t); return; } throw toPageException(e.t); } rsp=e.response; if(!e.done){ req.abort(); if(throwonerror) throw new HTTPException("408 Request Time-out","a timeout occurred in tag http",408,"Time-out",rsp.getURL()); setRequestTimeout(cfhttp); return; //throw new ApplicationException("timeout"); } } /////////////////////////////////////////// EXECUTE ///////////////////////////////////////////////// Charset responseCharset=CharsetUtil.toCharset(rsp.getCharset()); // Write Response Scope //String rawHeader=httpMethod.getStatusLine().toString(); String mimetype=null; String contentEncoding=null; // status code cfhttp.set(STATUSCODE,((rsp.getStatusCode()+" "+rsp.getStatusText()).trim())); cfhttp.set(STATUS_CODE,new Double(rsp.getStatusCode())); cfhttp.set(STATUS_TEXT,(rsp.getStatusText())); cfhttp.set(HTTP_VERSION,(rsp.getProtocolVersion())); //responseHeader railo.commons.net.http.Header[] headers = rsp.getAllHeaders(); StringBuffer raw=new StringBuffer(rsp.getStatusLine()+" "); Struct responseHeader = new StructImpl(); Struct cookie; Array setCookie = new ArrayImpl(); Query cookies=new QueryImpl(new String[]{"name","value","path","domain","expires","secure","httpOnly"},0,"cookies"); for(int i=0;i<headers.length;i++) { railo.commons.net.http.Header header=headers[i]; //print.ln(header); raw.append(header.toString()+" "); if(header.getName().equalsIgnoreCase("Set-Cookie")) { setCookie.append(header.getValue()); parseCookie(cookies,header.getValue()); } else { //print.ln(header.getName()+"-"+header.getValue()); Object value=responseHeader.get(KeyImpl.getInstance(header.getName()),null); if(value==null) responseHeader.set(KeyImpl.getInstance(header.getName()),header.getValue()); else { Array arr=null; if(value instanceof Array) { arr=(Array) value; } else { arr=new ArrayImpl(); responseHeader.set(KeyImpl.getInstance(header.getName()),arr); arr.appendEL(value); } arr.appendEL(header.getValue()); } } // Content-Type if(header.getName().equalsIgnoreCase("Content-Type")) { mimetype=header.getValue(); if(mimetype==null)mimetype=NO_MIMETYPE; } // Content-Encoding if(header.getName().equalsIgnoreCase("Content-Encoding")) { contentEncoding=header.getValue(); } } cfhttp.set(RESPONSEHEADER,responseHeader); cfhttp.set(KeyConstants._cookies,cookies); responseHeader.set(STATUS_CODE,new Double(rsp.getStatusCode())); responseHeader.set(EXPLANATION,(rsp.getStatusText())); if(setCookie.size()>0)responseHeader.set(SET_COOKIE,setCookie); // is text boolean isText= mimetype == null || mimetype == NO_MIMETYPE || HTTPUtil.isTextMimeType(mimetype); // is multipart boolean isMultipart= MultiPartResponseUtils.isMultipart(mimetype); cfhttp.set(KeyConstants._text,Caster.toBoolean(isText)); // mimetype charset //boolean responseProvideCharset=false; if(!StringUtil.isEmpty(mimetype,true)){ if(isText) { String[] types=HTTPUtil.splitMimeTypeAndCharset(mimetype,null); if(types[0]!=null)cfhttp.set(KeyConstants._mimetype,types[0]); if(types[1]!=null)cfhttp.set(CHARSET,types[1]); } else cfhttp.set(KeyConstants._mimetype,mimetype); } else cfhttp.set(KeyConstants._mimetype,NO_MIMETYPE); // File Resource file=null; if(strFile!=null && strPath!=null) { file=ResourceUtil.toResourceNotExisting(pageContext, strPath).getRealResource(strFile); } else if(strFile!=null) { file=ResourceUtil.toResourceNotExisting(pageContext, strFile); } else if(strPath!=null) { file=ResourceUtil.toResourceNotExisting(pageContext, strPath); //Resource dir = file.getParentResource(); if(file.isDirectory()){ file=file.getRealResource(req.getURI().getPath());// TODO was getName() ->http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/URI.html#getName() } } if(file!=null)pageContext.getConfig().getSecurityManager().checkFileLocation(file); // filecontent InputStream is=null; if(isText && getAsBinary!=GET_AS_BINARY_YES) { String str; try { // read content if(method!=METHOD_HEAD) { is = rsp.getContentAsStream(); if(is!=null &&isGzipEncoded(contentEncoding)) is = rsp.getStatusCode()!=200? new CachingGZIPInputStream(is):new GZIPInputStream(is); } try { try{ str = is==null?"":IOUtil.toString(is,responseCharset); } catch(EOFException eof){ if(is instanceof CachingGZIPInputStream) { str = IOUtil.toString(is=((CachingGZIPInputStream)is).getRawData(),responseCharset); } else throw eof; } } catch (UnsupportedEncodingException uee) { str = IOUtil.toString(is,(Charset)null); } } catch (IOException ioe) { throw Caster.toPageException(ioe); } finally { IOUtil.closeEL(is); } if(str==null)str=""; if(resolveurl){ //if(e.redirectURL!=null)url=e.redirectURL.toExternalForm(); str=new URLResolver().transform(str,e.response.getTargetURL(),false); } cfhttp.set(FILE_CONTENT,str); try { if(file!=null){ IOUtil.write(file,str,pageContext.getConfig().getWebCharset(),false); } } catch (IOException e1) {} if(name!=null) { Query qry = CSVParser.toQuery( str, delimiter, textqualifier, columns, firstrowasheaders ); pageContext.setVariable(name,qry); } } // Binary else { byte[] barr=null; if(isGzipEncoded(contentEncoding)){ if(method!=METHOD_HEAD) { is=rsp.getContentAsStream(); is = rsp.getStatusCode()!=200?new CachingGZIPInputStream(is) :new GZIPInputStream(is); } try { try{ barr = is==null?new byte[0]: IOUtil.toBytes(is); } catch(EOFException eof){ if(is instanceof CachingGZIPInputStream) barr = IOUtil.toBytes(((CachingGZIPInputStream)is).getRawData()); else throw eof; } } catch (IOException t) { throw Caster.toPageException(t); } finally{ IOUtil.closeEL(is); } } else { try { if(method!=METHOD_HEAD) barr = rsp.getContentAsByteArray(); else barr=new byte[0]; } catch (IOException t) { throw Caster.toPageException(t); } } //IF Multipart response get file content and parse parts if(barr!=null) { if(isMultipart) { cfhttp.set(FILE_CONTENT,MultiPartResponseUtils.getParts(barr,mimetype)); } else { cfhttp.set(FILE_CONTENT,barr); } } else cfhttp.set(FILE_CONTENT,""); if(file!=null) { try { if(barr!=null)IOUtil.copy(new ByteArrayInputStream(barr),file,true); } catch (IOException ioe) { throw Caster.toPageException(ioe); } } } // header cfhttp.set(KeyConstants._header,raw.toString()); if(!isStatusOK(rsp.getStatusCode())){ String msg=rsp.getStatusCode()+" "+rsp.getStatusText(); cfhttp.setEL(ERROR_DETAIL,msg); if(throwonerror){ throw new HTTPException(msg,null,rsp.getStatusCode(),rsp.getStatusText(),rsp.getURL()); } } } finally { //rsp.release(); } } private void parseCookie(Query cookies,String raw) { String[] arr =ListUtil.trimItems(ListUtil.trim(ListUtil.listToStringArray(raw, ';'))); if(arr.length==0) return; int row = cookies.addRow(); String item; int index; // name/value if(arr.length>0) { item=arr[0]; index=item.indexOf('='); if(index==-1) // only name cookies.setAtEL(KeyConstants._name,row, dec(item)); else { // name and value cookies.setAtEL(KeyConstants._name,row, dec(item.substring(0,index))); cookies.setAtEL(KeyConstants._value,row, dec(item.substring(index+1))); } } String n,v; cookies.setAtEL("secure",row, Boolean.FALSE); cookies.setAtEL("httpOnly",row, Boolean.FALSE); for(int i=1;i<arr.length;i++){ item=arr[i]; index=item.indexOf('='); if(index==-1) // only name cookies.setAtEL(dec(item),row, Boolean.TRUE); else { // name and value n=dec(item.substring(0,index)); v=dec(item.substring(index+1)); if(n.equalsIgnoreCase("expires")) { DateTime d = Caster.toDate(v, false, null,null); if(d!=null) { cookies.setAtEL(n,row, d); continue; } } cookies.setAtEL(n,row, v); } } } public String dec(String str) { return ReqRspUtil.decode(str, charset, false); } public static boolean isStatusOK(int statusCode) { return statusCode>=200 && statusCode<=299; } private PageException toPageException(Throwable t) { PageException pe = Caster.toPageException(t); if(pe instanceof NativeException) { ((NativeException) pe).setAdditional(KeyConstants._url, url); } return pe; } private void setUnknownHost(Struct cfhttp,Throwable t) { cfhttp.setEL(CHARSET,""); cfhttp.setEL(ERROR_DETAIL,"Unknown host: "+t.getMessage()); cfhttp.setEL(FILE_CONTENT,"Connection Failure"); cfhttp.setEL(KeyConstants._header,""); cfhttp.setEL(KeyConstants._mimetype,"Unable to determine MIME type of file."); cfhttp.setEL(RESPONSEHEADER,new StructImpl()); cfhttp.setEL(STATUSCODE,"Connection Failure. Status code unavailable."); cfhttp.setEL(KeyConstants._text,Boolean.TRUE); } private void setRequestTimeout(Struct cfhttp) { cfhttp.setEL(CHARSET,""); cfhttp.setEL(ERROR_DETAIL,""); cfhttp.setEL(FILE_CONTENT,"Connection Timeout"); cfhttp.setEL(KeyConstants._header,""); cfhttp.setEL(KeyConstants._mimetype,"Unable to determine MIME type of file."); cfhttp.setEL(RESPONSEHEADER,new StructImpl()); cfhttp.setEL(STATUSCODE,"408 Request Time-out"); cfhttp.setEL(STATUS_CODE,new Double(408)); cfhttp.setEL(STATUS_TEXT,"Request Time-out"); cfhttp.setEL(KeyConstants._text,Boolean.TRUE); } /*private static HttpMethod execute(Http http, HttpClient client, HttpMethod httpMethod, boolean redirect) throws PageException { try { // Execute Request short count=0; URL lu; while(isRedirect(client.executeMethod(httpMethod)) && redirect && count++ < MAX_REDIRECT) { lu=locationURL(httpMethod); httpMethod=createMethod(http,client,lu.toExternalForm(),-1); } } catch (IOException e) { PageException pe = Caster.toPageException(e); if(pe instanceof NativeException) { ((NativeException) pe).setAdditional("url", HTTPUtil.toURL(httpMethod)); } throw pe; } return httpMethod; }*/ /*static URL locationURL(HttpMethod method) throws MalformedURLException, ExpressionException { Header location = method.getResponseHeader("location"); if(location==null) throw new ExpressionException("missing location header definition"); HostConfiguration config = method.getHostConfiguration(); URL url; try { url = new URL(location.getValue()); } catch (MalformedURLException e) { url=new URL(config.getProtocol().getScheme(), config.getHost(), config.getPort(), mergePath(method.getPath(),location.getValue())); } return url; }*/ /*static HttpRequestBase init(Config cw,Http4 http, DefaultHttpClient client, HttpParams params, String url, int port) throws PageException, IOException { String charset=http.charset; if(StringUtil.isEmpty(charset,true)) charset=cw.getWebCharset(); else charset=charset.trim(); HttpRequestBase req; // check if has fileUploads boolean doUploadFile=false; for(int i=0;i<http.params.size();i++) { if((http.params.get(i)).getType().equals("file")) { doUploadFile=true; break; } } // parse url (also query string) int len=http.params.size(); StringBuilder sbQS=new StringBuilder(); for(int i=0;i<len;i++) { HttpParamBean param=http.params.get(i); String type=param.getType(); // URL if(type.equals("url")) { if(sbQS.length()>0)sbQS.append('&'); sbQS.append(translateEncoding(param.getName(), charset)); sbQS.append('='); sbQS.append(translateEncoding(param.getValueAsString(), charset)); } } String host=null; HttpHost httpHost; try { URL _url = HTTPUtil.toURL(url,port); httpHost = new HttpHost(_url.getHost(),_url.getPort()); host=_url.getHost(); url=_url.toExternalForm(); if(sbQS.length()>0){ // no existing QS if(StringUtil.isEmpty(_url.getQuery())) { url+="?"+sbQS; } else { url+="&"+sbQS; } } } catch (MalformedURLException mue) { throw Caster.toPageException(mue); } // select best matching method (get,post, post multpart (file)) boolean isBinary = false; boolean doMultiPart=doUploadFile || http.multiPart; HttpPost post=null; HttpEntityEnclosingRequest eem=null; if(http.method==METHOD_GET) { req=new HttpGet(url); } else if(http.method==METHOD_HEAD) { req=new HttpHead(url); } else if(http.method==METHOD_DELETE) { isBinary=true; req=new HttpDelete(url); } else if(http.method==METHOD_PUT) { isBinary=true; HttpPut put = new HttpPut(url); req=put; eem=put; } else if(http.method==METHOD_TRACE) { isBinary=true; req=new HttpTrace(url); } else if(http.method==METHOD_OPTIONS) { isBinary=true; req=new HttpOptions(url); } else { isBinary=true; post=new HttpPost(url); req=post; eem=post; } boolean hasForm=false; boolean hasBody=false; boolean hasContentType=false; // Set http params ArrayList<FormBodyPart> parts=new ArrayList<FormBodyPart>(); StringBuilder acceptEncoding=new StringBuilder(); java.util.List<NameValuePair> postParam = post!=null?new ArrayList <NameValuePair>():null; for(int i=0;i<len;i++) { HttpParamBean param=http.params.get(i); String type=param.getType(); // URL if(type.equals("url")) { //listQS.add(new BasicNameValuePair(translateEncoding(param.getName(), http.charset),translateEncoding(param.getValueAsString(), http.charset))); } // Form else if(type.equals("formfield") || type.equals("form")) { hasForm=true; if(http.method==METHOD_GET) throw new ApplicationException("httpparam type formfield can't only be used, when method of the tag http equal post"); if(post!=null){ if(doMultiPart){ parts.add( new FormBodyPart( param.getName(), new StringBody( param.getValueAsString(), CharsetUtil.toCharset(charset) ) ) ); } else { postParam.add(new BasicNameValuePair(param.getName(),param.getValueAsString())); } } //else if(multi!=null)multi.addParameter(param.getName(),param.getValueAsString()); } // CGI else if(type.equals("cgi")) { if(param.isEncoded()) req.addHeader( translateEncoding(param.getName(),charset), translateEncoding(param.getValueAsString(),charset)); else req.addHeader(param.getName(),param.getValueAsString()); } // Header else if(type.startsWith("head")) { if(param.getName().equalsIgnoreCase("content-type")) hasContentType=true; if(param.getName().equalsIgnoreCase("Accept-Encoding")) { acceptEncoding.append(headerValue(param.getValueAsString())); acceptEncoding.append(", "); } else req.addHeader(param.getName(),headerValue(param.getValueAsString())); } // Cookie else if(type.equals("cookie")) { HTTPEngine4Impl.addCookie(client,host,param.getName(),param.getValueAsString(),"/",charset); } // File else if(type.equals("file")) { hasForm=true; if(http.method==METHOD_GET) throw new ApplicationException("httpparam type file can't only be used, when method of the tag http equal post"); if(doMultiPart) { try { Resource res = param.getFile(); parts.add(new FormBodyPart( param.getName(), new ResourceBody(res, getContentType(param), res.getName(), charset) )); //parts.add(new ResourcePart(param.getName(),new ResourcePartSource(param.getFile()),getContentType(param),_charset)); } catch (FileNotFoundException e) { throw new ApplicationException("can't upload file, path is invalid",e.getMessage()); } } } // XML else if(type.equals("xml")) { hasBody=true; hasContentType=true; req.addHeader("Content-type", "text/xml; charset="+charset); if(eem==null)throw new ApplicationException("type xml is only supported for type post and put"); HTTPEngine4Impl.setBody(eem, param.getValueAsString()); } // Body else if(type.equals("body")) { hasBody=true; if(eem==null)throw new ApplicationException("type body is only supported for type post and put"); HTTPEngine4Impl.setBody(eem, param.getValue()); } else { throw new ApplicationException("invalid type ["+type+"]"); } } // post params if(postParam!=null && postParam.size()>0) post.setEntity(new org.apache.http.client.entity.UrlEncodedFormEntity(postParam,charset)); req.setHeader("Accept-Encoding",acceptEncoding.append("gzip").toString()); // multipart if(doMultiPart && eem!=null) { hasContentType=true; boolean doIt=true; if(!http.multiPart && parts.size()==1){ ContentBody body = parts.get(0).getBody(); if(body instanceof StringBody){ StringBody sb=(StringBody)body; try { String str = IOUtil.toString(sb.getReader()); StringEntity entity = new StringEntity(str,sb.getMimeType(),sb.getCharset()); eem.setEntity(entity); } catch (IOException e) { throw Caster.toPageException(e); } doIt=false; } } if(doIt) { MultipartEntity mpe = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE,null,CharsetUtil.toCharset(charset)); Iterator<FormBodyPart> it = parts.iterator(); while(it.hasNext()) { mpe.addPart(it.next()); } eem.setEntity(mpe); } //eem.setRequestEntity(new MultipartRequestEntityFlex(parts.toArray(new Part[parts.size()]), eem.getParams(),http.multiPartType)); } if(hasBody && hasForm) throw new ApplicationException("mixing httpparam type file/formfield and body/XML is not allowed"); if(!hasContentType) { if(isBinary) { if(hasBody) req.addHeader("Content-type", "application/octet-stream"); else req.addHeader("Content-type", "application/x-www-form-urlencoded; charset="+charset); } else { if(hasBody) req.addHeader("Content-type", "text/html; charset="+charset ); } } // set User Agent if(!hasHeaderIgnoreCase(req,"User-Agent")) req.setHeader("User-Agent",http.useragent); // set timeout if(http.timeout>0L)HTTPEngine4Impl.setTimeout(params, (int)http.timeout); // set Username and Password BasicHttpContext httpContext=null; if(http.username!=null) { if(http.password==null)http.password=""; if(AUTH_TYPE_NTLM==http.authType) { if(StringUtil.isEmpty(http.workStation,true)) throw new ApplicationException("attribute workstation is required when authentication type is [NTLM]"); if(StringUtil.isEmpty(http.domain,true)) throw new ApplicationException("attribute domain is required when authentication type is [NTLM]"); HTTPEngine4Impl.setNTCredentials(client, http.username, http.password, http.workStation,http.domain); } else httpContext=HTTPEngine4Impl.setCredentials(client, httpHost, http.username, http.password); } // set Proxy ProxyData proxy=null; if(!StringUtil.isEmpty(http.proxyserver)) { proxy=ProxyDataImpl.getInstance(http.proxyserver, http.proxyport, http.proxyuser, http.proxypassword) ; } if(http.pageContext.getConfig().isProxyEnableFor(host)) { proxy=http.pageContext.getConfig().getProxyData(); } HTTPEngine4Impl.setProxy(client, req, proxy); return req; }*/ private static boolean hasHeaderIgnoreCase(HttpRequestBase req,String name) { org.apache.http.Header[] headers = req.getAllHeaders(); if(headers==null) return false; for(int i=0;i<headers.length;i++){ if(name.equalsIgnoreCase(headers[i].getName())) return true; } return false; } private static String headerValue(String value) { if(value==null) return null; value=value.trim(); value=value.replace('\n', ' '); value=value.replace('\r', ' '); /*int len=value.length(); char c; for(int i=0;i<len;i++){ c=value.charAt(i); if(c=='\n' || c=='\r') return value.substring(0,i); }*/ return value; } private static String toQueryString(NameValuePair[] qsPairs) { StringBuffer sb=new StringBuffer(); for(int i=0;i<qsPairs.length;i++) { if(sb.length()>0)sb.append('&'); sb.append(qsPairs[i].getName()); if(qsPairs[i].getValue()!=null){ sb.append('='); sb.append(qsPairs[i].getValue()); } } return sb.toString(); } private static String urlenc(String str, String charset) throws UnsupportedEncodingException { if(!ReqRspUtil.needEncoding(str,false)) return str; return URLEncoder.encode(str,charset); } @Override public void doInitBody() { } @Override public int doAfterBody() { return SKIP_BODY; } /** * sets if has body or not * @param hasBody */ public void hasBody(boolean hasBody) { } /** * @param param */ public void setParam(HttpParamBean param) { params.add(param); } /** * @param getAsBinary The getasbinary to set. */ public void setGetasbinary(String getAsBinary) { // TODO support never, wird das verwendet? getAsBinary=getAsBinary.toLowerCase().trim(); if(getAsBinary.equals("yes") || getAsBinary.equals("true")) this.getAsBinary=GET_AS_BINARY_YES; else if(getAsBinary.equals("no") || getAsBinary.equals("false")) this.getAsBinary=GET_AS_BINARY_NO; else if(getAsBinary.equals("auto")) this.getAsBinary=GET_AS_BINARY_AUTO; } /** * @param multipart The multipart to set. */ public void setMultipart(boolean multiPart) { this.multiPart = multiPart; } /** * @param multipart The multipart to set. * @throws ApplicationException */ public void setMultiparttype(String multiPartType) throws ApplicationException { if(StringUtil.isEmpty(multiPartType))return; multiPartType=multiPartType.trim().toLowerCase(); if("form-data".equals(multiPartType)) this.multiPartType=MULTIPART_FORM_DATA; //else if("related".equals(multiPartType)) this.multiPartType=MultipartRequestEntityFlex.MULTIPART_RELATED; else throw new ApplicationException("invalid value for attribute multiPartType ["+multiPartType+"]", "attribute must have one of the following values [form-data]"); } /** * @param result The result to set. */ public void setResult(String result) { this.result = result; } /** * @param addtoken the addtoken to set */ public void setAddtoken(boolean addtoken) { this.addtoken = addtoken; } /** * checks if status code is a redirect * @param status * @return is redirect */ static boolean isRedirect(int status) { return status==STATUS_REDIRECT_FOUND || status==STATUS_REDIRECT_MOVED_PERMANENTLY || status==STATUS_REDIRECT_SEE_OTHER || status==STATUS_REDIRECT_TEMPORARY_REDIRECT; } /** * merge to pathes to one * @param current * @param realPath * @return * @throws MalformedURLException */ public static String mergePath(String current, String realPath) throws MalformedURLException { // get current directory String currDir; if(current==null || current.indexOf('/')==-1)currDir="/"; else if(current.endsWith("/"))currDir=current; else currDir=current.substring(0,current.lastIndexOf('/')+1); // merge together String path; if(realPath.startsWith("./"))path=currDir+realPath.substring(2); else if(realPath.startsWith("/"))path=realPath; else if(!realPath.startsWith("../"))path=currDir+realPath; else { while(realPath.startsWith("../") || currDir.length()==0) { realPath=realPath.substring(3); currDir=currDir.substring(0,currDir.length()-1); int index = currDir.lastIndexOf('/'); if(index==-1)throw new MalformedURLException("invalid realpath definition for URL"); currDir=currDir.substring(0,index+1); } path=currDir+realPath; } return path; } private static String getContentType(HttpParamBean param) { String mimeType=param.getMimeType(); if(StringUtil.isEmpty(mimeType,true)) { mimeType=ResourceUtil.getMimeType(param.getFile(), ResourceUtil.MIMETYPE_CHECK_EXTENSION+ResourceUtil.MIMETYPE_CHECK_HEADER, null); } return mimeType; } public static boolean isGzipEncoded(String contentEncoding) { return !StringUtil.isEmpty(contentEncoding) && StringUtil.indexOfIgnoreCase(contentEncoding, "gzip")!=-1; } public static Object getOutput(InputStream is, String contentType, String contentEncoding, boolean closeIS) { if(StringUtil.isEmpty(contentType))contentType="text/html"; // Gzip if(Http4.isGzipEncoded(contentEncoding)){ try { is=new GZIPInputStream(is); } catch (IOException e) {} } try { // text if(HTTPUtil.isTextMimeType(contentType)) { String[] tmp = HTTPUtil.splitMimeTypeAndCharset(contentType,null); //String mimetype=tmp[0]; String charset=tmp[1]; if(StringUtil.isEmpty(charset,true)) { Config config = ThreadLocalPageContext.getConfig(); if(config!=null)charset=config.getWebCharset(); } try { return IOUtil.toString(is, charset); } catch (IOException e) {} } // Binary else { try { return IOUtil.toBytes(is); } catch (IOException e) {} } } finally{ if(closeIS)IOUtil.closeEL(is); } return ""; } public static URL locationURL(HttpUriRequest req, HttpResponse rsp) { URL url=null; try { url = req.getURI().toURL(); } catch (MalformedURLException e1) { return null; } Header h = HTTPResponse4Impl.getLastHeaderIgnoreCase(rsp, "location"); if(h!=null) { String str = h.getValue(); try { return new URL(str); } catch (MalformedURLException e) { try { return new URL(url.getProtocol(), url.getHost(), url.getPort(), mergePath(url.getFile(), str)); } catch (MalformedURLException e1) { return null; } } } return null; } } class Executor4 extends Thread { final Http4 http; private final DefaultHttpClient client; final boolean redirect; Throwable t; boolean done; //URL redirectURL; HTTPResponse4Impl response; private HttpRequestBase req; private HttpContext context; public Executor4(Http4 http,DefaultHttpClient client, HttpContext context, HttpRequestBase req, boolean redirect) { this.http=http; this.client=client; this.context=context; this.redirect=redirect; this.req=req; } @Override public void run(){ try { response=execute(context); done=true; } catch (Throwable t) { this.t=t; } finally { SystemUtil.notify(http); } } public HTTPResponse4Impl execute(HttpContext context) throws IOException { return response=new HTTPResponse4Impl(null,context,req,client.execute(req,context)); } }