001    package railo.commons.net.http.httpclient3;
002    
003    import java.io.IOException;
004    import java.io.InputStream;
005    import java.net.MalformedURLException;
006    import java.net.URL;
007    
008    import org.apache.commons.httpclient.HostConfiguration;
009    import org.apache.commons.httpclient.HttpClient;
010    import org.apache.commons.httpclient.HttpException;
011    import org.apache.commons.httpclient.HttpMethod;
012    import org.apache.commons.httpclient.HttpState;
013    import org.apache.commons.httpclient.UsernamePasswordCredentials;
014    import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
015    import org.apache.commons.httpclient.methods.DeleteMethod;
016    import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
017    import org.apache.commons.httpclient.methods.GetMethod;
018    import org.apache.commons.httpclient.methods.HeadMethod;
019    import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
020    import org.apache.commons.httpclient.methods.PostMethod;
021    import org.apache.commons.httpclient.methods.PutMethod;
022    import org.apache.commons.httpclient.methods.RequestEntity;
023    import org.apache.commons.httpclient.methods.StringRequestEntity;
024    
025    import railo.commons.io.TemporaryStream;
026    import railo.commons.io.res.Resource;
027    import railo.commons.lang.ExceptionUtil;
028    import railo.commons.lang.StringUtil;
029    import railo.commons.net.http.Entity;
030    import railo.commons.net.http.HTTPEngine;
031    import railo.commons.net.http.HTTPResponse;
032    import railo.commons.net.http.Header;
033    import railo.commons.net.http.httpclient3.entity.EmptyRequestEntity;
034    import railo.commons.net.http.httpclient3.entity.ResourceRequestEntity;
035    import railo.commons.net.http.httpclient3.entity.TemporaryStreamRequestEntity;
036    import railo.commons.net.http.httpclient3.entity._ByteArrayRequestEntity;
037    import railo.runtime.exp.PageException;
038    import railo.runtime.net.proxy.ProxyData;
039    import railo.runtime.net.proxy.ProxyDataImpl;
040    import railo.runtime.op.Caster;
041    import railo.runtime.op.Decision;
042    
043    /**
044     * 
045     */
046    public final class HTTPEngine3Impl {
047            
048    
049        
050        public static HTTPResponse get(URL url, String username, String password, long timeout, int maxRedirect,
051            String charset, String useragent,ProxyData proxy, Header[] headers) throws IOException {
052            return _invoke(new GetMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null);
053        }
054        
055        public static HTTPResponse head(URL url, String username, String password, int timeout, int maxRedirect,
056            String charset, String useragent,ProxyData proxy, Header[] headers) throws IOException {
057                    return _invoke(new HeadMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null);
058            }
059        
060        public static HTTPResponse post(URL url, String username, String password, long timeout, int maxRedirect,
061            String charset, String useragent, ProxyData proxy, Header[] headers) throws IOException {
062            return _invoke(new PostMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null);
063        }
064        
065            public static HTTPResponse put(URL url, String username, String password, int timeout, int maxRedirect,
066            String charset, String useragent,ProxyData proxy, Header[] headers, Object body) throws IOException {
067                    return _invoke(new PutMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,body);     
068            }
069        
070        public static HTTPResponse delete(URL url, String username, String password, int timeout, int maxRedirect,
071            String charset, String useragent,ProxyData proxy, Header[] headers) throws IOException {
072            return _invoke(new DeleteMethod(url.toExternalForm()), url, username, password, timeout,maxRedirect, charset, useragent, proxy, headers,null);
073            }
074        
075    
076            private static HTTPResponse _invoke(HttpMethod httpMethod, URL url, String username, String password, long timeout, int maxRedirect,
077                String charset, String useragent, ProxyData proxy, Header[] headers, Object body) throws IOException {
078    
079            HttpClient client = new HttpClient();
080            HostConfiguration config = client.getHostConfiguration();
081            HttpState state = client.getState();
082            
083            setHeader(httpMethod,headers);
084            setContentType(httpMethod,charset);
085            setUserAgent(httpMethod,useragent);
086            setTimeout(client,timeout);
087            setCredentials(client,httpMethod,username,password);  
088            setProxy(config,state,proxy);
089            if(body!=null && httpMethod instanceof EntityEnclosingMethod)setBody((EntityEnclosingMethod)httpMethod,body);
090            return new HTTPResponse3Impl(execute(client,httpMethod,maxRedirect),url);
091        }
092    
093    
094        /**
095         * Execute a HTTTP Client and follow redirect over different hosts
096         * @param client
097         * @param method
098         * @param doRedirect
099         * @return
100         * @throws IOException
101         * @throws HttpException
102         */
103        public static HttpMethod execute(HttpClient client, HttpMethod method, int maxRedirect) throws HttpException, IOException {
104            short count=0;
105            method.setFollowRedirects(false);
106            
107            while(isRedirect(client.executeMethod(method)) && count++ < maxRedirect) {
108                    method=rewrite(method);
109            }
110            return method;
111        }
112    
113        /**
114         * rewrite request method
115         * @param method
116         * @return
117         * @throws MalformedURLException
118         */
119        private static HttpMethod rewrite(HttpMethod method) throws MalformedURLException {
120            org.apache.commons.httpclient.Header location = method.getResponseHeader("location");
121            if(location==null) return method;
122    
123            HostConfiguration config = method.getHostConfiguration();
124            URL url;
125            try {
126                url = new URL(location.getValue());
127            } 
128            catch (MalformedURLException e) {
129                
130                url=new URL(config.getProtocol().getScheme(),
131                        config.getHost(),
132                        config.getPort(),
133                        mergePath(method.getPath(),location.getValue()));
134            }
135            
136            method= clone(method,url);
137            
138            return method;
139        }
140    
141        /**
142         * FUNKTIONIERT NICHT, HOST WIRD NICHT マBERNOMMEN
143         * Clones a http method and sets a new url
144         * @param src
145         * @param url
146         * @return
147         */
148        private static HttpMethod clone(HttpMethod src, URL url) {
149            HttpMethod trg = HttpMethodCloner.clone(src);
150            HostConfiguration trgConfig = trg.getHostConfiguration();
151            trgConfig.setHost(url.getHost(),url.getPort(),url.getProtocol());
152            trg.setPath(url.getPath());
153            trg.setQueryString(url.getQuery());
154            
155            return trg;
156        }
157        
158        /**
159         * merge to pathes to one
160         * @param current
161         * @param realPath
162         * @return
163         * @throws MalformedURLException
164         */
165        private static String mergePath(String current, String realPath) throws MalformedURLException {
166            
167            // get current directory
168            String currDir;
169            if(current==null || current.indexOf('/')==-1)currDir="/";
170            else if(current.endsWith("/"))currDir=current;
171            else currDir=current.substring(0,current.lastIndexOf('/')+1);
172            
173            // merge together
174            String path;
175            if(realPath.startsWith("./"))path=currDir+realPath.substring(2);
176            else if(realPath.startsWith("/"))path=realPath;
177            else if(!realPath.startsWith("../"))path=currDir+realPath;
178            else {
179                while(realPath.startsWith("../") || currDir.length()==0) {
180                    realPath=realPath.substring(3);
181                    currDir=currDir.substring(0,currDir.length()-1);
182                    int index = currDir.lastIndexOf('/');
183                    if(index==-1)throw new MalformedURLException("invalid realpath definition for URL");
184                    currDir=currDir.substring(0,index+1);
185                }
186                path=currDir+realPath;
187            }
188            
189            return path;
190        }   
191    
192        /**
193         * checks if status code is a redirect
194         * @param status
195         * @return is redirect
196         */
197        private static boolean isRedirect(int status) {
198            return 
199                    status==HTTPEngine.STATUS_REDIRECT_FOUND || 
200                    status==HTTPEngine.STATUS_REDIRECT_MOVED_PERMANENTLY ||
201                    status==HTTPEngine.STATUS_REDIRECT_SEE_OTHER;
202        }
203    
204        
205    
206        private static void setBody(EntityEnclosingMethod httpMethod, Object body) throws IOException {
207            if(body!=null)
208                            try {
209                                    httpMethod.setRequestEntity(toRequestEntity(body));
210                            } catch (PageException e) {
211                                    throw ExceptionUtil.toIOException(e);
212                            }
213            }
214    
215            private static void setProxy(HostConfiguration config, HttpState state, ProxyData data) {
216            // set Proxy
217                if(ProxyDataImpl.isValid(data)) {
218                    config.setProxy(data.getServer(),data.getPort()<=0?80:data.getPort());
219                    if(ProxyDataImpl.hasCredentials(data)) {
220                        state.setProxyCredentials(null,null,new UsernamePasswordCredentials(data.getUsername(),StringUtil.emptyIfNull(data.getPassword())));
221                    }
222                } 
223            }
224    
225            private static void setCredentials(HttpClient client, HttpMethod httpMethod, String username,String password) {
226            // set Username and Password
227                if(username!=null) {
228                    if(password==null)password="";
229                    client.getState().setCredentials(null,null,new UsernamePasswordCredentials(username, password));
230                    httpMethod.setDoAuthentication( true );
231                }
232            }
233    
234            private static void setTimeout(HttpClient client, long timeout) {
235            if(timeout>0){
236                    client.setConnectionTimeout((int)timeout);
237                    client.setTimeout((int)timeout);
238            }
239            }
240    
241            private static void setUserAgent(HttpMethod httpMethod, String useragent) {
242            if(useragent!=null)httpMethod.setRequestHeader("User-Agent",useragent);
243            }
244    
245            private static void setContentType(HttpMethod httpMethod, String charset) {
246            if(charset!=null)httpMethod.addRequestHeader("Content-type", "text/html; charset="+charset );
247            }
248    
249            private static void setHeader(HttpMethod httpMethod,Header[] headers) {
250            if(headers!=null) {
251                    for(int i=0;i<headers.length;i++)
252                            httpMethod.addRequestHeader(headers[i].getName(), headers[i].getValue());
253            }
254            }
255    
256            private static RequestEntity toRequestEntity(Object value) throws PageException {
257            if(value instanceof RequestEntity) return (RequestEntity) value;
258            
259            else if(value instanceof InputStream) {
260                            return new InputStreamRequestEntity((InputStream)value,"application/octet-stream");
261                    }
262                    else if(Decision.isCastableToBinary(value,false)){
263                            return new ByteArrayRequestEntity(Caster.toBinary(value));
264                    }
265                    else {
266                            return new StringRequestEntity(Caster.toString(value));
267                    }
268        }
269    
270            public static Header header(String name, String value) {
271                    return new HeaderImpl(name, value);
272            }
273    
274            public static Entity getEmptyEntity(String contentType) {
275                    return new EmptyRequestEntity(contentType);
276            }
277                    
278            public static Entity getByteArrayEntity(byte[] barr, String contentType) {
279                    return new _ByteArrayRequestEntity(barr, contentType);
280            }
281            
282            public static Entity getTemporaryStreamEntity(TemporaryStream ts, String contentType) {
283                    return new TemporaryStreamRequestEntity(ts,contentType);
284            }
285            
286            public static Entity getResourceEntity(Resource res, String contentType) {
287                    return new ResourceRequestEntity(res,contentType);
288            }
289    }