001    package railo.runtime.net.http;
002    
003    import java.io.IOException;
004    import java.net.MalformedURLException;
005    import java.net.URL;
006    
007    import org.apache.commons.httpclient.Header;
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    
013    // MUST synchronisieren mit HTTP Tag createmethod muss hier rein und dann clone ersetzten
014    
015    /**
016     * Utitlities class for HTTP Client
017     */
018    public final class HttpClientUtil {
019        
020        /**
021         * Maximal count of redirects (5)
022         */
023        public static final short MAX_REDIRECT=15;
024        
025        /**
026         * Constant value for HTTP Status Code "moved Permanently 301"
027         */
028        public static final int STATUS_REDIRECT_MOVED_PERMANENTLY=301;
029        /**
030         * Constant value for HTTP Status Code "Found 302"
031         */
032        public static final int STATUS_REDIRECT_FOUND=302;
033        /**
034         * Constant value for HTTP Status Code "see other 303"
035         */
036        public static final int STATUS_REDIRECT_SEE_OTHER=303;
037        
038        /**
039         * Execute a HTTTP Client and follow redirect over different hosts
040         * @param client
041         * @param method
042         * @param doRedirect
043         * @return
044         * @throws IOException
045         * @throws HttpException
046         */
047        public static HttpMethod execute(HttpClient client, HttpMethod method, boolean doRedirect) throws HttpException, IOException {
048            short count=0;
049            method.setFollowRedirects(false);
050            
051            while(isRedirect(client.executeMethod(method)) && doRedirect && count++ < MAX_REDIRECT) {
052                    method=rewrite(method);
053            }
054            return method;
055        }
056    
057        /**
058         * rewrite request method
059         * @param method
060         * @return
061         * @throws MalformedURLException
062         */
063        private static HttpMethod rewrite(HttpMethod method) throws MalformedURLException {
064            Header location = method.getResponseHeader("location");
065            if(location==null) return method;
066    
067            HostConfiguration config = method.getHostConfiguration();
068            URL url;
069            try {
070                url = new URL(location.getValue());
071            } 
072            catch (MalformedURLException e) {
073                
074                url=new URL(config.getProtocol().getScheme(),
075                        config.getHost(),
076                        config.getPort(),
077                        mergePath(method.getPath(),location.getValue()));
078            }
079            
080            method= clone(method,url);
081            
082            return method;
083        }
084    
085        /**
086         * FUNKTIONIERT NICHT, HOST WIRD NICHT マBERNOMMEN
087         * Clones a http method and sets a new url
088         * @param src
089         * @param url
090         * @return
091         */
092        public static HttpMethod clone(HttpMethod src, URL url) {
093            HttpMethod trg = HttpMethodCloner.clone(src);
094            HostConfiguration trgConfig = trg.getHostConfiguration();
095            trgConfig.setHost(url.getHost(),url.getPort(),url.getProtocol());
096            trg.setPath(url.getPath());
097            trg.setQueryString(url.getQuery());
098            
099            return trg;
100        }
101    
102    
103        /**
104         * checks if status code is a redirect
105         * @param status
106         * @return is redirect
107         */
108        private static boolean isRedirect(int status) {
109            return 
110                    status==STATUS_REDIRECT_FOUND || 
111                    status==STATUS_REDIRECT_MOVED_PERMANENTLY ||
112                    status==STATUS_REDIRECT_SEE_OTHER;
113        }
114        
115        /**
116         * merge to pathes to one
117         * @param current
118         * @param realPath
119         * @return
120         * @throws MalformedURLException
121         */
122        public static String mergePath(String current, String realPath) throws MalformedURLException {
123            
124            // get current directory
125            String currDir;
126            if(current==null || current.indexOf('/')==-1)currDir="/";
127            else if(current.endsWith("/"))currDir=current;
128            else currDir=current.substring(0,current.lastIndexOf('/')+1);
129            
130            // merge together
131            String path;
132            if(realPath.startsWith("./"))path=currDir+realPath.substring(2);
133            else if(realPath.startsWith("/"))path=realPath;
134            else if(!realPath.startsWith("../"))path=currDir+realPath;
135            else {
136                while(realPath.startsWith("../") || currDir.length()==0) {
137                    realPath=realPath.substring(3);
138                    currDir=currDir.substring(0,currDir.length()-1);
139                    int index = currDir.lastIndexOf('/');
140                    if(index==-1)throw new MalformedURLException("invalid realpath definition for URL");
141                    currDir=currDir.substring(0,index+1);
142                }
143                path=currDir+realPath;
144            }
145            
146            return path;
147        }   
148    }