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));
}
}