001    package railo.commons.net;
002    
003    import java.io.ByteArrayOutputStream;
004    import java.io.IOException;
005    import java.io.InputStream;
006    import java.io.UnsupportedEncodingException;
007    import java.net.MalformedURLException;
008    import java.net.URI;
009    import java.net.URISyntaxException;
010    import java.net.URL;
011    import java.util.HashMap;
012    import java.util.Map;
013    
014    import javax.servlet.RequestDispatcher;
015    import javax.servlet.ServletContext;
016    import javax.servlet.ServletException;
017    import javax.servlet.ServletRequest;
018    import javax.servlet.ServletResponse;
019    
020    import org.apache.commons.httpclient.Header;
021    import org.apache.commons.httpclient.HostConfiguration;
022    import org.apache.commons.httpclient.HttpClient;
023    import org.apache.commons.httpclient.HttpMethod;
024    import org.apache.commons.httpclient.HttpState;
025    import org.apache.commons.httpclient.UsernamePasswordCredentials;
026    import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
027    import org.apache.commons.httpclient.methods.DeleteMethod;
028    import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
029    import org.apache.commons.httpclient.methods.GetMethod;
030    import org.apache.commons.httpclient.methods.HeadMethod;
031    import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
032    import org.apache.commons.httpclient.methods.PostMethod;
033    import org.apache.commons.httpclient.methods.PutMethod;
034    import org.apache.commons.httpclient.methods.RequestEntity;
035    import org.apache.commons.httpclient.methods.StringRequestEntity;
036    
037    import railo.aprint;
038    import railo.commons.io.IOUtil;
039    import railo.commons.io.res.ContentType;
040    import railo.commons.io.res.ContentTypeImpl;
041    import railo.commons.lang.StringList;
042    import railo.commons.lang.StringUtil;
043    import railo.runtime.PageContext;
044    import railo.runtime.PageContextImpl;
045    import railo.runtime.PageSource;
046    import railo.runtime.PageSourceImpl;
047    import railo.runtime.config.Config;
048    import railo.runtime.engine.ThreadLocalPageContext;
049    import railo.runtime.exp.ApplicationException;
050    import railo.runtime.exp.PageException;
051    import railo.runtime.exp.PageServletException;
052    import railo.runtime.net.http.HTTPServletRequestWrap;
053    import railo.runtime.net.http.HttpClientUtil;
054    import railo.runtime.net.http.HttpServletResponseWrap;
055    import railo.runtime.net.http.ReqRspUtil;
056    import railo.runtime.net.proxy.ProxyData;
057    import railo.runtime.net.proxy.ProxyDataImpl;
058    import railo.runtime.op.Caster;
059    import railo.runtime.op.Decision;
060    import railo.runtime.type.List;
061    
062    /**
063     * 
064     */
065    public final class HTTPUtil {
066    
067        /**
068         * Field <code>ACTION_POST</code>
069         */
070        public static final short ACTION_POST=0;
071        
072        /**
073         * Field <code>ACTION_GET</code>
074         */
075        public static final short ACTION_GET=1;
076    
077            /**
078             * Field <code>STATUS_OK</code>
079             */
080            public static final int STATUS_OK=200;
081            //private static final String NO_MIMETYPE="Unable to determine MIME type of file.";
082         
083        /**
084         * make a http requst to given url 
085         * @param url
086         * @param username
087         * @param password
088         * @param timeout
089         * @param charset
090         * @param useragent
091         * @param proxyserver
092         * @param proxyport
093         * @param proxyuser
094         * @param proxypassword
095         * @param headers
096         * @return
097         * @throws IOException
098         */
099        public static HttpMethod invoke(URL url, String username, String password, long timeout, 
100                String charset, String useragent,
101                String proxyserver, int proxyport, String proxyuser, 
102                String proxypassword, Header[] headers) throws IOException {
103    
104            HttpClient client = new HttpClient();
105            HttpMethod httpMethod=new GetMethod(url.toExternalForm());
106            HostConfiguration config = client.getHostConfiguration();
107            
108            HttpState state = client.getState();
109            
110            setHeader(httpMethod,headers);
111            setContentType(httpMethod,charset);
112            setUserAgent(httpMethod,useragent);
113            setTimeout(client,timeout);
114            setCredentials(client,httpMethod,username,password);  
115            setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
116            
117            /*if(followRedirects!=null){
118                    client.executeMethod(httpMethod);
119            }
120            else */
121                    httpMethod = HttpClientUtil.execute(client,httpMethod,true);
122            
123            return httpMethod;
124        }
125        
126        public static HttpMethod post(URL url, String username, String password, long timeout, 
127                String charset, String useragent,
128                String proxyserver, int proxyport, String proxyuser, 
129                String proxypassword, Header[] headers) throws IOException {
130    
131            HttpClient client = new HttpClient();
132            HttpMethod httpMethod=new PostMethod(url.toExternalForm());
133            HostConfiguration config = client.getHostConfiguration();
134            
135            HttpState state = client.getState();
136            
137            setHeader(httpMethod,headers);
138            setContentType(httpMethod,charset);
139            setUserAgent(httpMethod,useragent);
140            setTimeout(client,timeout);
141            setCredentials(client,httpMethod,username,password);  
142            setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
143            
144            /*if(followRedirects!=null){
145                    client.executeMethod(httpMethod);
146            }
147            else */
148                    httpMethod = HttpClientUtil.execute(client,httpMethod,true);
149            
150            return httpMethod;
151        }
152        
153    
154        /**
155         * cast a string to a url
156         * @param strUrl string represent a url
157         * @return url from string
158         * @throws MalformedURLException
159         */
160             public static URL toURL(String strUrl) throws MalformedURLException {
161                     return toURL(strUrl,-1);
162             }
163             
164             public static URL toURL(String strUrl,URL defaultValue){
165                     try {
166                            return toURL(strUrl,-1);
167                    } catch (MalformedURLException e) {
168                            return defaultValue;
169                    }
170             }
171             
172    
173             public static String validateURL(String strUrl,String defaultValue){
174                     try {
175                            return toURL(strUrl,-1).toExternalForm();
176                    } catch (MalformedURLException e) {
177                            return defaultValue;
178                    }
179             }
180        
181        /**
182         * cast a string to a url
183         * @param strUrl string represent a url
184         * @return url from string
185         * @throws MalformedURLException
186         */
187    
188              public static URL toURL(String strUrl, int port) throws MalformedURLException {
189                      URL url;
190                      try {
191                        url=new URL(strUrl);
192                    }
193                    catch(MalformedURLException mue) {
194                        url=new URL("http://"+strUrl);
195                    }
196                      return toURL(url, port);
197              }
198             
199             
200        private static URL toURL(URL url, int port) throws MalformedURLException {
201            
202            
203            
204            
205            
206            
207            // file
208            String path=url.getPath();
209            //String file=url.getFile();
210            String query = url.getQuery();
211            String ref = url.getRef();
212            String user=url.getUserInfo();
213            if(port<=0) port=url.getPort();
214    
215            // decode path
216            if(!StringUtil.isEmpty(path)) {
217                    int sqIndex=path.indexOf(';');
218                    String q=null;
219                    if(sqIndex!=-1) {
220                            q=path.substring(sqIndex+1);
221                            path=path.substring(0,sqIndex);
222                    } 
223                    
224                    StringBuilder res=new StringBuilder();
225                    
226                    StringList list = List.toListTrim(path, '/');
227                    String str;
228                    
229                    while(list.hasNext()){
230                            str=list.next();
231                            //str=URLDecoder.decode(str);
232                            
233                            if(StringUtil.isEmpty(str)) continue;
234                            res.append("/");
235                            res.append(escapeQSValue(str));
236                    }
237                    if(StringUtil.endsWith(path, '/')) res.append('/');                     
238                    path=res.toString();
239                    
240                    if(sqIndex!=-1) {
241                            path+=decodeQuery(q,';');
242                    }
243                    
244            }
245            
246            // decode query 
247            query=decodeQuery(query,'?');
248           
249            
250            
251            String file=path+query;
252            
253         // decode ref/anchor       
254            if(ref!=null) {
255                    file+="#"+escapeQSValue(ref);
256            }
257            
258            // user/pasword
259            if(!StringUtil.isEmpty(user)) {
260                    int index=user.indexOf(':');
261                    if(index!=-1) {
262                            user=escapeQSValue(user.substring(0,index))+":"+escapeQSValue(user.substring(index+1));
263                    }
264                    else user=escapeQSValue(user);
265                    
266                    String strUrl = getProtocol(url)+"://"+user+"@"+url.getHost();
267                    if(port>0)strUrl+=":"+port;
268                    strUrl+=file;
269                    return new URL(strUrl);
270            }
271           
272           
273            
274           // port
275           if(port<=0) return new URL(url.getProtocol(),url.getHost(),file);
276           return new URL(url.getProtocol(),url.getHost(),port,file);
277           
278                           
279        }
280        
281        private static String decodeQuery(String query,char startDelimeter) {
282            if(!StringUtil.isEmpty(query)) {
283                    StringBuilder res=new StringBuilder();
284                    
285                    StringList list = List.toList(query, '&');
286                    String str;
287                    int index;
288                    char del=startDelimeter;
289                    while(list.hasNext()){
290                            res.append(del);
291                            del='&';
292                            str=list.next();
293                            index=str.indexOf('=');
294                            if(index==-1)res.append(escapeQSValue(str));
295                            else {
296                                    res.append(escapeQSValue(str.substring(0,index)));
297                                    res.append('=');
298                                    res.append(escapeQSValue(str.substring(index+1)));
299                            }
300                    }
301                    query=res.toString();
302            }
303            else query="";
304            return query;
305            }
306    
307    
308            public static URI toURI(String strUrl) throws URISyntaxException {
309                     return toURI(strUrl,-1);
310             }
311        
312        public static URI toURI(String strUrl, int port) throws URISyntaxException {
313            
314            //print.o((strUrl));
315            URI uri = new URI(strUrl);
316            
317            String host = uri.getHost();
318            String fragment = uri.getRawFragment();
319            String path = uri.getRawPath();
320            String query= uri.getRawQuery();
321            
322            String scheme = uri.getScheme();
323            String userInfo = uri.getRawUserInfo();
324            if(port<=0) port=uri.getPort();
325    
326        
327            // decode path
328            if(!StringUtil.isEmpty(path)) {
329                    
330                    int sqIndex=path.indexOf(';');
331                    String q=null;
332                    if(sqIndex!=-1) {
333                            q=path.substring(sqIndex+1);
334                            path=path.substring(0,sqIndex);
335                    } 
336                    
337                    
338                    StringBuilder res=new StringBuilder();
339                    
340                    StringList list = List.toListTrim(path, '/');
341                    String str;
342                    
343                    while(list.hasNext()){
344                            str=list.next();
345                            //str=URLDecoder.decode(str);
346                            
347                            if(StringUtil.isEmpty(str)) continue;
348                            res.append("/");
349                            res.append(escapeQSValue(str));
350                    }
351                    if(StringUtil.endsWith(path, '/')) res.append('/');                     
352                    path=res.toString();
353                    
354                    if(sqIndex!=-1) {
355                            path+=decodeQuery(q,';');
356                    }
357            }
358            
359            // decode query 
360            query=decodeQuery(query,'?');
361        
362            
363            
364         // decode ref/anchor       
365            if(!StringUtil.isEmpty(fragment)) {
366                    fragment=escapeQSValue(fragment);
367            }
368            
369            // user/pasword
370            if(!StringUtil.isEmpty(userInfo)) {
371                    int index=userInfo.indexOf(':');
372                    if(index!=-1) {
373                            userInfo=escapeQSValue(userInfo.substring(0,index))+":"+escapeQSValue(userInfo.substring(index+1));
374                    }
375                    else userInfo=escapeQSValue(userInfo);
376            }
377            
378            /*print.o("- fragment:"+fragment);
379            print.o("- host:"+host);
380            print.o("- path:"+path);
381            print.o("- query:"+query);
382            print.o("- scheme:"+scheme);
383            print.o("- userInfo:"+userInfo);
384            print.o("- port:"+port);
385            print.o("- absolute:"+uri.isAbsolute());
386            print.o("- opaque:"+uri.isOpaque());*/
387            
388            StringBuilder rtn=new StringBuilder();
389            if(scheme!=null) {
390                    rtn.append(scheme);
391                    rtn.append("://");
392            }
393            if(userInfo!=null) {
394                    rtn.append(userInfo);
395                    rtn.append("@");
396            }
397            if(host!=null) {
398                    rtn.append(host);
399            }
400            if(port>0) {
401                    rtn.append(":");
402                    rtn.append(port);
403            }
404            if(path!=null) {
405                    rtn.append(path);
406            }
407            if(query!=null) {
408                    //rtn.append("?");
409                    rtn.append(query);
410            }
411            if(fragment!=null) {
412                    rtn.append("#");
413                    rtn.append(fragment);
414            }
415            
416            return new URI(rtn.toString()); 
417        }
418        
419        private static void test(String str) throws URISyntaxException {
420            //print.o(str);
421            int port=-1;
422            String res;
423            try {
424                            res=toURL(new URL(str),port).toString();
425                    } catch (MalformedURLException e) {
426                            res=toURI(str).toString();
427                    }
428            String res2 = encode(str);
429                    
430            if(res.equals(res2)){
431                    aprint.o(res);
432            }
433            else {
434                    aprint.e(str);
435                    aprint.e("- uri:"+res);
436                    aprint.e("- enc:"+res2);
437            }
438            
439                    
440            /*String uri = toURI(str).toString();
441            String url = toURL(str).toString();
442            
443            if(uri.equals(url)){
444                    print.o(uri);
445            }
446            else {
447                    print.e(str);
448                    print.e("uri:"+uri);
449                    print.e("url:"+url);
450            }*/
451                    
452            }
453    
454            public static void main(String[] args) throws Exception {
455                    
456                    // valid urls
457                    test("http://localhost:8080/jm/test/tags/_http.cfm;jsessionid=48lhqe568il0d?CFID=2fa614d8-9deb-4051-92e9-100ed44fd2df&CFTOKEN=0&jsessionid=48lhqe568il0d");
458                    test("http://www.railo.ch");
459                    test("http://www.railo.ch/");
460                    test("http://www.railo.ch/a.cfm");
461                    test("http://www.railo.ch/a.cfm?");
462                    test("http://www.railo.ch/a.cfm?test=1");
463                    test("http://www.railo.ch/a.cfm?test=1&");
464                    test("http://www.railo.ch:80/a.cfm?test=1&");
465                    test("http://hans@www.railo.ch:80/a.cfm?test=1&");
466                    test("http://hans:peter@www.railo.ch:80/a.cfm?test=1&x");
467                    test("http://hans:peter@www.railo.ch:80/a.cfm?test=1&x#");
468                    test("http://hans:peter@www.railo.ch:80/a.cfm?test=1&x#xx");
469                    
470                    test("http://www.railo.ch");
471                    test("http://www.railo.ch/");
472                    test("http://www.railo.ch/�.cfm");
473                    test("http://www.railo.ch/�.cfm?");
474                    test("http://www.railo.ch/�.cfm?test�=�");
475                    test("http://www.railo.ch/�.cfm?test�=�&");
476                    test("http://www.railo.ch:80/�.cfm?test�=�&");
477                    test("http://h�ns@www.railo.ch:80/�.cfm?test�=�&");
478                    test("http://h�ns:p�ter@www.railo.ch:80/�.cfm?test�=�&x");
479                    test("http://h�ns:p�ter@www.railo.ch:80/�.cfm?test�=�&x#");
480                    test("http://h�ns:p�ter@www.railo.ch:80/�.cfm?test�=�&x#�");
481                    
482                    test("/");
483                    test("/a.cfm");
484                    test("/a.cfm?");
485                    test("/a.cfm?test=1");
486                    test("/a.cfm?test=1&");
487                    test("/a.cfm?test=1&");
488                    test("/a.cfm?test=1&");
489                    test("/a.cfm?test=1&x");
490                    test("/a.cfm?test=1&x#");
491                    test("/a.cfm?test=1&x#xx");
492                    
493    
494                    test("/");
495                    test("/�.cfm");
496                    test("/�.cfm?");
497                    test("/�.cfm?test�=1�");
498                    test("/�.cfm?test�=1�&");
499                    test("/�.cfm?test�=1�&");
500                    test("/�.cfm?test�=1�&");
501                    test("/�.cfm?test�=1�&x");
502                    test("/�.cfm?test�=1�&x#");
503                    test("/�.cfm?test�=1�&x#xx�");
504                    //test("http://ha�ns:gehe�im@www.example.org:80/d�emo/example.cgi?lan�d=de&stadt=aa#geschi�chte");
505                    //print.o(toURI("http://www.railo.ch/te�st.cfm?do=p�hoto.view&id=289#commentAdd"));
506                    //print.o(toURI("/test.cfm?do=photo.view&id=289#commentAdd"));
507                    //print.o(toURI("http://localhost/testingapp/index.cfm?do=photo.view&id=289#commentAdd"));
508            }
509        
510        
511    
512    
513            private static String getProtocol(URI uri) {
514            String p=uri.getRawSchemeSpecificPart();
515            if(p==null) return null;
516                    if(p.indexOf('/')==-1) return p;
517                    if(p.indexOf("https")!=-1) return "https";
518                    if(p.indexOf("http")!=-1) return "http";
519                    return p;
520            }
521        
522        private static String getProtocol(URL url) {
523                    String p=url.getProtocol().toLowerCase();
524                    if(p.indexOf('/')==-1) return p;
525                    if(p.indexOf("https")!=-1) return "https";
526                    if(p.indexOf("http")!=-1) return "http";
527                    return p;
528            }
529    
530    
531            /*public static void main(String[] args) throws MalformedURLException {
532            print.o(toURL("http://www.railo.ch/index.cfm#susi"));
533            print.o(toURL("http://www.railo.ch/index.cfm#���"));
534            print.o(toURL("http://hans:geheim@www.example.org:80/demo/example.cgi?land=de&stadt=aa#geschichte"));
535            print.o(toURL("http://ha�ns:gehe�im@www.example.org/d�emo/example.cgi?lan�d=de&stadt=aa#geschi�chte"));
536                    // 
537            }*/
538    
539        
540    
541        
542        public static String escapeQSValue(String str) {
543            if(!ReqRspUtil.needEncoding(str,true)) return str;
544            Config config = ThreadLocalPageContext.getConfig();
545            if(config!=null){
546                    try {
547                            return URLEncoder.encode(str,config.getWebCharset());
548                    } 
549                    catch (UnsupportedEncodingException e) {}
550            }
551            return URLEncoder.encode(str);
552            }
553    
554            public static HttpMethod put(URL url, String username, String password, int timeout, 
555                String charset, String useragent,
556                String proxyserver, int proxyport, String proxyuser, 
557                String proxypassword, Header[] headers, RequestEntity body) throws IOException {
558                    
559                    
560                    HttpClient client = new HttpClient();
561                    PutMethod httpMethod=new PutMethod(url.toExternalForm());
562            HostConfiguration config = client.getHostConfiguration();
563            
564            HttpState state = client.getState();
565            
566            setHeader(httpMethod,headers);
567            setContentType(httpMethod,charset);
568            setUserAgent(httpMethod,useragent);
569            setTimeout(client,timeout);
570            setCredentials(client,httpMethod,username,password);    
571            setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
572            setBody(httpMethod,body);
573            
574            
575            return HttpClientUtil.execute(client,httpMethod,true);
576             
577            }
578        
579        public static HttpMethod delete(URL url, String username, String password, int timeout, 
580                String charset, String useragent,
581                String proxyserver, int proxyport, String proxyuser, 
582                String proxypassword, Header[] headers) throws IOException {
583                    
584                    
585                    HttpClient client = new HttpClient();
586                    DeleteMethod httpMethod=new DeleteMethod(url.toExternalForm());
587            HostConfiguration config = client.getHostConfiguration();
588            
589            HttpState state = client.getState();
590            
591            setHeader(httpMethod,headers);
592            setContentType(httpMethod,charset);
593            setUserAgent(httpMethod,useragent);
594            setTimeout(client,timeout);
595            setCredentials(client,httpMethod,username,password);    
596            setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
597            
598            
599            return HttpClientUtil.execute(client,httpMethod,true);
600             
601            }
602    
603        public static HttpMethod head(URL url, String username, String password, int timeout, 
604                String charset, String useragent,
605                String proxyserver, int proxyport, String proxyuser, 
606                String proxypassword, Header[] headers) throws IOException {
607                    
608                    
609                    HttpClient client = new HttpClient();
610                    HeadMethod httpMethod=new HeadMethod(url.toExternalForm());
611            HostConfiguration config = client.getHostConfiguration();
612            
613            HttpState state = client.getState();
614            
615            setHeader(httpMethod,headers);
616            setContentType(httpMethod,charset);
617            setUserAgent(httpMethod,useragent);
618            setTimeout(client,timeout);
619            setCredentials(client,httpMethod,username,password);    
620            setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
621            
622            
623            return HttpClientUtil.execute(client,httpMethod,true);
624             
625            }
626    
627        
628    
629        private static void setBody(EntityEnclosingMethod httpMethod, RequestEntity body) {
630            // body
631            if(body!=null)httpMethod.setRequestEntity(body);
632            }
633    
634            private static void setProxy(HostConfiguration config, HttpState state, String proxyserver,int proxyport, String proxyuser, String proxypassword) {
635    
636            // set Proxy
637                if(!StringUtil.isEmpty(proxyserver)) {
638                    config.setProxy(proxyserver,proxyport);
639                    if(!StringUtil.isEmpty(proxyuser)) {
640                        if(proxypassword==null)proxypassword="";
641                        state.setProxyCredentials(null,null,new UsernamePasswordCredentials(proxyuser,proxypassword));
642                    }
643                } 
644            }
645    
646            private static void setCredentials(HttpClient client, HttpMethod httpMethod, String username,String password) {
647            // set Username and Password
648                if(username!=null) {
649                    if(password==null)password="";
650                    client.getState().setCredentials(null,null,new UsernamePasswordCredentials(username, password));
651                    httpMethod.setDoAuthentication( true );
652                }
653            }
654    
655            private static void setTimeout(HttpClient client, long timeout) {
656            if(timeout>0){
657                    
658                    client.setConnectionTimeout((int)timeout);
659                    client.setTimeout((int)timeout);
660            }
661            }
662    
663            private static void setUserAgent(HttpMethod httpMethod, String useragent) {
664            if(useragent!=null)httpMethod.setRequestHeader("User-Agent",useragent);
665            }
666    
667            private static void setContentType(HttpMethod httpMethod, String charset) {
668            if(charset!=null)httpMethod.addRequestHeader("Content-type", "text/html; charset="+charset );
669            }
670    
671            private static void setHeader(HttpMethod httpMethod,Header[] headers) {
672            if(headers!=null) {
673                    for(int i=0;i<headers.length;i++)
674                            httpMethod.addRequestHeader(headers[i].getName(), headers[i].getValue());
675            }
676            }
677    
678            public static RequestEntity toRequestEntity(Object value) throws PageException {
679            if(value instanceof RequestEntity) return (RequestEntity) value;
680            else if(value instanceof InputStream) {
681                            return new InputStreamRequestEntity((InputStream)value,"application/octet-stream");
682                    }
683                    else if(Decision.isCastableToBinary(value,false)){
684                            return new ByteArrayRequestEntity(Caster.toBinary(value));
685                    }
686                    else {
687                            return new StringRequestEntity(Caster.toString(value));
688                    }
689        }
690        
691            
692            public static URL removeRef(URL url) throws MalformedURLException{
693                    int port=url.getPort();
694                    if(port==80 && url.getProtocol().equalsIgnoreCase("http"))
695                            port=-1;
696                    else if(port==443 && url.getProtocol().equalsIgnoreCase("https"))
697                            port=-1;
698                    
699                    
700                    
701                    URL u=new URL(url.getProtocol(),url.getHost(),port,url.getFile());
702                    return u;
703            }
704            
705            public static String removeRef(String url) throws MalformedURLException{
706                    return removeRef(new URL(url)).toExternalForm();
707            }
708            
709                            
710    
711            public static URL toURL(HttpMethod httpMethod) {
712                    HostConfiguration config = httpMethod.getHostConfiguration();
713                    
714                    try {
715                            String qs = httpMethod.getQueryString();
716                            if(StringUtil.isEmpty(qs))
717                                    return new URL(config.getProtocol().getScheme(),config.getHost(),config.getPort(),httpMethod.getPath());
718                            return new URL(config.getProtocol().getScheme(),config.getHost(),config.getPort(),httpMethod.getPath()+"?"+qs);
719                    } catch (MalformedURLException e) {
720                            return null;
721                    }
722            }
723    
724            public static String optimizeRealPath(PageContext pc,String realPath) {
725                    int index;
726                    String requestURI=realPath,queryString=null;
727                    if((index=realPath.indexOf('?'))!=-1){
728                            requestURI=realPath.substring(0,index);
729                            queryString=realPath.substring(index+1);
730                    }
731                    PageSource ps = PageSourceImpl.best(((PageContextImpl)pc).getRelativePageSources(requestURI));
732                    requestURI=ps.getFullRealpath();
733                    if(queryString!=null) return requestURI+"?"+queryString;
734                    return requestURI;
735            }
736    
737            public static void forward(PageContext pc,String realPath) throws ServletException, IOException {
738                    ServletContext context = pc.getServletContext();
739                    realPath=HTTPUtil.optimizeRealPath(pc,realPath);
740                    
741                    try{
742                            pc.getHttpServletRequest().setAttribute("railo.forward.request_uri", realPath);
743                            
744                    RequestDispatcher disp = context.getRequestDispatcher(realPath);
745                    if(disp==null)
746                            throw new PageServletException(new ApplicationException("Page "+realPath+" not found"));
747                
748                    //populateRequestAttributes();
749                    disp.forward(removeWrap(pc.getHttpServletRequest()),pc.getHttpServletResponse());
750                    }
751            finally{
752                    ThreadLocalPageContext.register(pc);
753            }
754            }
755            
756            public static ServletRequest removeWrap(ServletRequest req) {
757                    while(req instanceof HTTPServletRequestWrap)
758                            return ((HTTPServletRequestWrap)req).getOriginalRequest();
759                    return req;
760            }
761            
762    
763            public static void include(PageContext pc,String realPath) throws ServletException,IOException  {
764                    include(pc, pc.getHttpServletRequest(),pc.getHttpServletResponse(),realPath);
765            }
766    
767            public static void include(PageContext pc,ServletRequest req, ServletResponse rsp, String realPath) throws ServletException,IOException  {
768                    realPath=optimizeRealPath(pc,realPath);
769                    boolean inline=HttpServletResponseWrap.get();
770                    //print.out(rsp+":"+pc.getResponse());
771                    RequestDispatcher disp = getRequestDispatcher(pc,realPath);
772                    
773                    if(inline)      {
774                            //RequestDispatcher disp = getRequestDispatcher(pc,realPath);
775                            disp.include(req,rsp);
776                            return;
777                    }
778                    
779                    try     {
780                            ByteArrayOutputStream baos=new ByteArrayOutputStream();
781                            HttpServletResponseWrap hsrw=new HttpServletResponseWrap(pc.getHttpServletResponse(),baos);
782                            HttpServletResponseWrap.set(true);
783                            
784                            //RequestDispatcher disp = getRequestDispatcher(pc,realPath);
785                            
786                    disp.include(req,hsrw);
787                    if(!hsrw.isCommitted())hsrw.flushBuffer();
788                    pc.write(IOUtil.toString(baos.toByteArray(), hsrw.getCharacterEncoding()));
789            }
790            finally{
791                    HttpServletResponseWrap.release();
792                    ThreadLocalPageContext.register(pc);
793            }
794            }
795    
796            private static RequestDispatcher getRequestDispatcher(PageContext pc,String realPath) throws PageServletException {
797                    RequestDispatcher disp = pc.getServletContext().getRequestDispatcher(realPath);
798            if(disp==null) throw new PageServletException(new ApplicationException("Page "+realPath+" not found"));
799            return disp;
800            }
801            
802            
803            // MUST create a copy from toURL and rename toURI and rewrite for URI, pherhaps it is possible to merge them somehow
804            public static String encode(String realpath) {
805            
806            
807                    int qIndex=realpath.indexOf('?');
808                    
809                    if(qIndex==-1) return realpath;
810                    
811                    String file=realpath.substring(0,qIndex);
812                    String query=realpath.substring(qIndex+1);
813                    int sIndex=query.indexOf('#');
814                    
815                    String anker=null;
816                    if(sIndex!=-1){
817                            //print.o(sIndex);
818                            anker=query.substring(sIndex+1);
819                            query=query.substring(0,sIndex);
820                    }
821                    
822                    StringBuilder res=new StringBuilder(file);
823            
824                    
825            // query
826            if(!StringUtil.isEmpty(query)){
827                    
828                    StringList list = List.toList(query, '&');
829                    String str;
830                    int index;
831                    char del='?';
832                    while(list.hasNext()){
833                            res.append(del);
834                            del='&';
835                            str=list.next();
836                            index=str.indexOf('=');
837                            if(index==-1)res.append(escapeQSValue(str));
838                            else {
839                                    res.append(escapeQSValue(str.substring(0,index)));
840                                    res.append('=');
841                                    res.append(escapeQSValue(str.substring(index+1)));
842                            }
843                    }       
844            }
845           
846            // anker
847            if(anker!=null) {
848                    res.append('#');
849                    res.append(escapeQSValue(anker));
850            }
851           
852            
853           return res.toString();                  
854        }
855    
856    
857            public static int getPort(URL url) {
858                    if(url.getPort()!=-1) return url.getPort();
859                    if("https".equalsIgnoreCase(url.getProtocol()))
860                            return 443;
861                    return 80;
862            }
863    
864            
865            /**
866             * return the length of a file defined by a url.
867             * @param dataUrl
868             * @return
869             */
870            public static long length(URL url) {
871                    long length=0;
872                    
873                    // check response header "content-length"
874                    ProxyData pd=ProxyDataImpl.NO_PROXY;
875                    try {
876                            HttpMethod http = HTTPUtil.head(url, null, null, -1,null, "Railo", pd.getServer(), pd.getPort(),pd.getUsername(), pd.getPassword(),null);
877                            Header cl = http.getResponseHeader("content-length");
878                            if(cl!=null)    {
879                                    length=Caster.toIntValue(cl.getValue(),-1);
880                                    if(length!=-1) return length;
881                            }
882                    } 
883                    catch (IOException e) {}
884                    
885                    // get it for size
886                    try {
887                            HttpMethod http = HTTPUtil.invoke(url, null, null, -1,null, "Railo", pd.getServer(), pd.getPort(),pd.getUsername(), pd.getPassword(),null);
888                            InputStream is = http.getResponseBodyAsStream();
889                            byte[] buffer = new byte[1024];
890                    int len;
891                    length=0;
892                    while((len = is.read(buffer)) !=-1){
893                      length+=len;
894                    }
895                    } 
896                    catch (IOException e) {}
897                    return length;
898            }
899    
900            public static ContentType getContentType(HttpMethod http) {
901                    Header[] headers = http.getResponseHeaders();
902                    for(int i=0;i<headers.length;i++){
903                            if("Content-Type".equalsIgnoreCase(headers[i].getName())){
904                                    String[] mimeCharset = splitMimeTypeAndCharset(headers[i].getValue());
905                                    String[] typeSub = splitTypeAndSubType(mimeCharset[0]);
906                                    return new ContentTypeImpl(typeSub[0],typeSub[1],mimeCharset[1]);
907                            }
908                    }
909                    return null;
910            }
911            
912            
913    
914            public static Map<String, String> parseParameterList(String _str, boolean decode,String charset) {
915                    //return railo.commons.net.HTTPUtil.toURI(strUrl,port);
916                    Map<String,String> data=new HashMap<String, String>();
917                    StringList list = List.toList(_str, '&');
918            String str;
919            int index;
920            while(list.hasNext()){
921                    str=list.next();
922                    index=str.indexOf('=');
923                    if(index==-1){
924                            data.put(decode(str,decode), "");
925                    }
926                    else {
927                            data.put(
928                                            decode(str.substring(0,index),decode), 
929                                            decode(str.substring(index+1),decode));
930                    }
931            }       
932                    return data;
933            }
934    
935            private static String decode(String str, boolean encode) {
936                    // TODO Auto-generated method stub
937                    return str;
938            }
939            
940            
941            
942            public static String[] splitMimeTypeAndCharset(String mimetype) {
943                    String[] types=mimetype.split(";");
944                    String[] rtn=new String[2];
945            
946            if(types.length>0){
947                    rtn[0]=types[0].trim();
948                    if(types.length>1) {
949                        String tmp=types[types.length-1].trim();
950                        int index=tmp.indexOf("charset=");
951                        if(index!=-1) {
952                            rtn[1]= StringUtil.removeQuotes(tmp.substring(index+8),true);
953                        }
954                    }
955            }
956            return rtn;
957            }
958            
959    
960            public static String[] splitTypeAndSubType(String mimetype) {
961                    String[] types=List.listToStringArray(mimetype, '/');
962                    String[] rtn=new String[2];
963            
964            if(types.length>0){
965                    rtn[0]=types[0].trim();
966                    if(types.length>1) {
967                            rtn[1]=types[1].trim();
968                    }
969            }
970            return rtn;
971            }
972    
973            public static boolean isSecure(URL url) {
974                    return StringUtil.indexOfIgnoreCase(url.getProtocol(),"https")!=-1;
975            }
976    }