package railo.commons.net.http.httpclient3;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpState;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import railo.commons.io.TemporaryStream;
import railo.commons.io.res.Resource;
import railo.commons.lang.ExceptionUtil;
import railo.commons.lang.StringUtil;
import railo.commons.net.http.Entity;
import railo.commons.net.http.HTTPEngine;
import railo.commons.net.http.HTTPResponse;
import railo.commons.net.http.Header;
import railo.commons.net.http.httpclient3.entity.EmptyRequestEntity;
import railo.commons.net.http.httpclient3.entity.ResourceRequestEntity;
import railo.commons.net.http.httpclient3.entity.TemporaryStreamRequestEntity;
import railo.commons.net.http.httpclient3.entity._ByteArrayRequestEntity;
import railo.runtime.exp.PageException;
import railo.runtime.net.proxy.ProxyData;
import railo.runtime.net.proxy.ProxyDataImpl;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
import railo.runtime.type.util.CollectionUtil;
/**
*
*/
public final class HTTPEngine3Impl {
public static HTTPResponse get(URL url, String username, String password, long timeout, int maxRedirect,
String charset, String useragent,ProxyData proxy, Header[] headers) throws IOException {
return _invoke(new GetMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null,null);
}
public static HTTPResponse head(URL url, String username, String password, int timeout, int maxRedirect,
String charset, String useragent,ProxyData proxy, Header[] headers) throws IOException {
return _invoke(new HeadMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null,null);
}
public static HTTPResponse post(URL url, String username, String password, long timeout, int maxRedirect,
String charset, String useragent, ProxyData proxy, Header[] headers, Map<String,String> params) throws IOException {
return _invoke(new PostMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,params,null);
}
public static HTTPResponse put(URL url, String username, String password, int timeout, int maxRedirect,
String charset, String useragent,ProxyData proxy, Header[] headers, Object body) throws IOException {
return _invoke(new PutMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null,body);
}
public static HTTPResponse delete(URL url, String username, String password, int timeout, int maxRedirect,
String charset, String useragent,ProxyData proxy, Header[] headers) throws IOException {
return _invoke(new DeleteMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null,null);
}
private static HTTPResponse _invoke(HttpMethod httpMethod, URL url, String username, String password, long timeout, int maxRedirect,
String charset, String useragent, ProxyData proxy, Header[] headers, Map<String,String> params, Object body) throws IOException {
HttpClient client = new HttpClient();
HostConfiguration config = client.getHostConfiguration();
HttpState state = client.getState();
setHeader(httpMethod,headers);
if(CollectionUtil.isEmpty(params))setContentType(httpMethod,charset);
setUserAgent(httpMethod,useragent);
setTimeout(client,timeout);
setParams(httpMethod,params);
setCredentials(client,httpMethod,username,password);
setProxy(config,state,proxy);
if(body!=null && httpMethod instanceof EntityEnclosingMethod)setBody((EntityEnclosingMethod)httpMethod,body);
return new HTTPResponse3Impl(execute(client,httpMethod,maxRedirect),url);
}
/**
* Execute a HTTTP Client and follow redirect over different hosts
* @param client
* @param method
* @param doRedirect
* @return
* @throws IOException
* @throws HttpException
*/
public static HttpMethod execute(HttpClient client, HttpMethod method, int maxRedirect) throws HttpException, IOException {
short count=0;
method.setFollowRedirects(false);
while(isRedirect(client.executeMethod(method)) && count++ < maxRedirect) {
method=rewrite(method);
}
return method;
}
/**
* rewrite request method
* @param method
* @return
* @throws MalformedURLException
*/
private static HttpMethod rewrite(HttpMethod method) throws MalformedURLException {
org.apache.commons.httpclient.Header location = method.getResponseHeader("location");
if(location==null) return method;
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()));
}
method= clone(method,url);
return method;
}
/**
* FUNKTIONIERT NICHT, HOST WIRD NICHT マBERNOMMEN
* Clones a http method and sets a new url
* @param src
* @param url
* @return
*/
private static HttpMethod clone(HttpMethod src, URL url) {
HttpMethod trg = HttpMethodCloner.clone(src);
HostConfiguration trgConfig = trg.getHostConfiguration();
trgConfig.setHost(url.getHost(),url.getPort(),url.getProtocol());
trg.setPath(url.getPath());
trg.setQueryString(url.getQuery());
return trg;
}
/**
* merge to pathes to one
* @param current
* @param realPath
* @return
* @throws MalformedURLException
*/
private 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;
}
/**
* checks if status code is a redirect
* @param status
* @return is redirect
*/
private static boolean isRedirect(int status) {
return
status==HTTPEngine.STATUS_REDIRECT_FOUND ||
status==HTTPEngine.STATUS_REDIRECT_MOVED_PERMANENTLY ||
status==HTTPEngine.STATUS_REDIRECT_SEE_OTHER;
}
private static void setBody(EntityEnclosingMethod httpMethod, Object body) throws IOException {
if(body!=null)
try {
httpMethod.setRequestEntity(toRequestEntity(body));
} catch (PageException e) {
throw ExceptionUtil.toIOException(e);
}
}
private static void setProxy(HostConfiguration config, HttpState state, ProxyData data) {
// set Proxy
if(ProxyDataImpl.isValid(data)) {
config.setProxy(data.getServer(),data.getPort()<=0?80:data.getPort());
if(ProxyDataImpl.hasCredentials(data)) {
state.setProxyCredentials(null,null,new UsernamePasswordCredentials(data.getUsername(),StringUtil.emptyIfNull(data.getPassword())));
}
}
}
private static void setCredentials(HttpClient client, HttpMethod httpMethod, String username,String password) {
// set Username and Password
if(username!=null) {
if(password==null)password="";
client.getState().setCredentials(null,null,new UsernamePasswordCredentials(username, password));
httpMethod.setDoAuthentication( true );
}
}
private static void setTimeout(HttpClient client, long timeout) {
if(timeout>0){
client.setConnectionTimeout((int)timeout);
client.setTimeout((int)timeout);
}
}
private static void setUserAgent(HttpMethod httpMethod, String useragent) {
if(useragent!=null)httpMethod.setRequestHeader("User-Agent",useragent);
}
private static void setContentType(HttpMethod httpMethod, String charset) {
if(charset!=null)httpMethod.addRequestHeader("Content-type", "text/html; charset="+charset );
}
private static void setHeader(HttpMethod httpMethod,Header[] headers) {
if(headers!=null) {
for(int i=0;i<headers.length;i++)
httpMethod.addRequestHeader(headers[i].getName(), headers[i].getValue());
}
}
private static void setParams(HttpMethod httpMethod, Map<String, String> params) {
if(params==null || !(httpMethod instanceof PostMethod)) return;
PostMethod post=(PostMethod) httpMethod;
Iterator<Entry<String, String>> it = params.entrySet().iterator();
Entry<String, String> e;
while(it.hasNext()){
e = it.next();
post.addParameter(new NameValuePair(e.getKey(),e.getValue()));
}
}
private static RequestEntity toRequestEntity(Object value) throws PageException {
if(value instanceof RequestEntity) return (RequestEntity) value;
else if(value instanceof InputStream) {
return new InputStreamRequestEntity((InputStream)value,"application/octet-stream");
}
else if(Decision.isCastableToBinary(value,false)){
return new ByteArrayRequestEntity(Caster.toBinary(value));
}
else {
return new StringRequestEntity(Caster.toString(value));
}
}
public static Header header(String name, String value) {
return new HeaderImpl(name, value);
}
public static Entity getEmptyEntity(String contentType) {
return new EmptyRequestEntity(contentType);
}
public static Entity getByteArrayEntity(byte[] barr, String contentType) {
return new _ByteArrayRequestEntity(barr, contentType);
}
public static Entity getTemporaryStreamEntity(TemporaryStream ts, String contentType) {
return new TemporaryStreamRequestEntity(ts,contentType);
}
public static Entity getResourceEntity(Resource res, String contentType) {
return new ResourceRequestEntity(res,contentType);
}
}