001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.commons.net;
020
021import java.io.ByteArrayOutputStream;
022import java.io.IOException;
023import java.io.UnsupportedEncodingException;
024import java.net.MalformedURLException;
025import java.net.URI;
026import java.net.URISyntaxException;
027import java.net.URL;
028import java.util.HashMap;
029import java.util.Map;
030
031import javax.servlet.RequestDispatcher;
032import javax.servlet.ServletContext;
033import javax.servlet.ServletException;
034import javax.servlet.ServletRequest;
035import javax.servlet.ServletResponse;
036
037import lucee.commons.io.IOUtil;
038import lucee.commons.lang.StringList;
039import lucee.commons.lang.StringUtil;
040import lucee.commons.lang.mimetype.ContentType;
041import lucee.commons.lang.mimetype.MimeType;
042import lucee.commons.net.http.HTTPEngine;
043import lucee.commons.net.http.HTTPResponse;
044import lucee.runtime.PageContext;
045import lucee.runtime.PageContextImpl;
046import lucee.runtime.PageSource;
047import lucee.runtime.PageSourceImpl;
048import lucee.runtime.engine.ThreadLocalPageContext;
049import lucee.runtime.exp.ApplicationException;
050import lucee.runtime.exp.PageServletException;
051import lucee.runtime.net.http.HTTPServletRequestWrap;
052import lucee.runtime.net.http.HttpServletResponseWrap;
053import lucee.runtime.net.http.ReqRspUtil;
054import lucee.runtime.type.util.ListUtil;
055
056/**
057 * 
058 */
059public final class HTTPUtil {
060
061    /**
062     * Field <code>ACTION_POST</code>
063     */
064    public static final short ACTION_POST=0;
065    
066    /**
067     * Field <code>ACTION_GET</code>
068     */
069    public static final short ACTION_GET=1;
070
071        /**
072         * Field <code>STATUS_OK</code>
073         */
074        public static final int STATUS_OK=200;
075        //private static final String NO_MIMETYPE="Unable to determine MIME type of file.";
076
077        public static final int MAX_REDIRECT = 15;
078    
079    /*public static HttpMethod invoke(URL url, String username, String password, long timeout, 
080            String charset, String useragent,
081            String proxyserver, int proxyport, String proxyuser, 
082            String proxypassword, Header[] headers) throws IOException {
083
084        HttpClient client = new HttpClient();
085        HttpMethod httpMethod=new GetMethod(url.toExternalForm());
086        HostConfiguration config = client.getHostConfiguration();
087        
088        HttpState state = client.getState();
089        
090        setHeader(httpMethod,headers);
091        setContentType(httpMethod,charset);
092        setUserAgent(httpMethod,useragent);
093        setTimeout(client,timeout);
094        setCredentials(client,httpMethod,username,password);  
095        setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
096        
097        
098                httpMethod = HttpClientUtil.execute(client,httpMethod,true);
099        
100        return httpMethod;
101    }*/
102    
103    /*public static HttpMethod post(URL url, String username, String password, long timeout, 
104            String charset, String useragent,
105            String proxyserver, int proxyport, String proxyuser, 
106            String proxypassword, Header[] headers) throws IOException {
107
108        HttpClient client = new HttpClient();
109        HttpMethod httpMethod=new PostMethod(url.toExternalForm());
110        HostConfiguration config = client.getHostConfiguration();
111        
112        HttpState state = client.getState();
113        
114        setHeader(httpMethod,headers);
115        setContentType(httpMethod,charset);
116        setUserAgent(httpMethod,useragent);
117        setTimeout(client,timeout);
118        setCredentials(client,httpMethod,username,password);  
119        setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
120        
121        httpMethod = HttpClientUtil.execute(client,httpMethod,true);
122        
123        return httpMethod;
124    }*/
125    
126
127    /**
128     * cast a string to a url
129     * @param strUrl string represent a url
130     * @return url from string
131     * @throws MalformedURLException
132     */
133         public static URL toURL(String strUrl,boolean encodeIfNecessary) throws MalformedURLException {
134                 return toURL(strUrl,-1,encodeIfNecessary);
135         }
136         
137         public static URL toURL(String strUrl,boolean encodeIfNecessary,URL defaultValue){
138                 try {
139                        return toURL(strUrl,-1,encodeIfNecessary);
140                } catch (MalformedURLException e) {
141                        return defaultValue;
142                }
143         }
144         
145
146         public static String validateURL(String strUrl,String defaultValue){
147                 try {
148                        return toURL(strUrl,-1,true).toExternalForm();
149                } catch (MalformedURLException e) {
150                        return defaultValue;
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
161        public static URL toURL(String strUrl, int port, boolean encodeIfNecessary) throws MalformedURLException {
162                URL url;
163                try {
164                        url=new URL(strUrl);
165                }
166                catch(MalformedURLException mue) {
167                        url=new URL("http://"+strUrl);
168                }
169                if(!encodeIfNecessary) return url;
170                return encodeURL(url, port);
171        }
172
173    public static URL encodeURL(URL url) throws MalformedURLException {
174        return encodeURL(url, -1);
175        
176    }
177    public static URL encodeURL(URL url, int port) throws MalformedURLException {
178        
179        // file
180        String path=url.getPath();
181        //String file=url.getFile();
182        String query = url.getQuery();
183        String ref = url.getRef();
184        String user=url.getUserInfo();
185        if(port<=0) port=url.getPort();
186
187        // decode path
188        if(!StringUtil.isEmpty(path)) {
189                int sqIndex=path.indexOf(';');
190                String q=null;
191                if(sqIndex!=-1) {
192                        q=path.substring(sqIndex+1);
193                        path=path.substring(0,sqIndex);
194                } 
195                
196                StringBuilder res=new StringBuilder();
197                
198                StringList list = ListUtil.toListTrim(path, '/');
199                String str;
200                
201                while(list.hasNext()){
202                        str=list.next();
203                        //str=URLDecoder.decode(str);
204                        
205                        if(StringUtil.isEmpty(str)) continue;
206                        res.append("/");
207                        res.append(escapeQSValue(str));
208                }
209                if(StringUtil.endsWith(path, '/')) res.append('/');                     
210                path=res.toString();
211                
212                if(sqIndex!=-1) {
213                        path+=decodeQuery(q,';');
214                }
215        }
216        
217        // decode query 
218        query=decodeQuery(query,'?');
219       
220        
221        
222        String file=path+query;
223        
224     // decode ref/anchor       
225        if(ref!=null) {
226                file+="#"+escapeQSValue(ref);
227        }
228        
229        // user/pasword
230        if(!StringUtil.isEmpty(user)) {
231                int index=user.indexOf(':');
232                if(index!=-1) {
233                        user=escapeQSValue(user.substring(0,index))+":"+escapeQSValue(user.substring(index+1));
234                }
235                else user=escapeQSValue(user);
236                
237                String strUrl = getProtocol(url)+"://"+user+"@"+url.getHost();
238                if(port>0)strUrl+=":"+port;
239                strUrl+=file;
240                return new URL(strUrl);
241        }
242       
243       
244        
245       // port
246       if(port<=0) return new URL(url.getProtocol(),url.getHost(),file);
247       return new URL(url.getProtocol(),url.getHost(),port,file);
248       
249                       
250    }
251    
252    private static String decodeQuery(String query,char startDelimiter) {
253        if(!StringUtil.isEmpty(query)) {
254                StringBuilder res=new StringBuilder();
255                
256                StringList list = ListUtil.toList(query, '&');
257                String str;
258                int index;
259                char del=startDelimiter;
260                while(list.hasNext()){
261                        res.append(del);
262                        del='&';
263                        str=list.next();
264                        index=str.indexOf('=');
265                        if(index==-1)res.append(escapeQSValue(str));
266                        else {
267                                res.append(escapeQSValue(str.substring(0,index)));
268                                res.append('=');
269                                res.append(escapeQSValue(str.substring(index+1)));
270                        }
271                }
272                query=res.toString();
273        }
274        else query="";
275        return query;
276        }
277
278
279        public static URI toURI(String strUrl) throws URISyntaxException {
280                 return toURI(strUrl,-1);
281         }
282    
283    public static URI toURI(String strUrl, int port) throws URISyntaxException {
284        
285        //print.o((strUrl));
286        URI uri = new URI(strUrl);
287        
288        String host = uri.getHost();
289        String fragment = uri.getRawFragment();
290        String path = uri.getRawPath();
291        String query= uri.getRawQuery();
292        
293        String scheme = uri.getScheme();
294        String userInfo = uri.getRawUserInfo();
295        if(port<=0) port=uri.getPort();
296
297    
298        // decode path
299        if(!StringUtil.isEmpty(path)) {
300                
301                int sqIndex=path.indexOf(';');
302                String q=null;
303                if(sqIndex!=-1) {
304                        q=path.substring(sqIndex+1);
305                        path=path.substring(0,sqIndex);
306                } 
307                
308                
309                StringBuilder res=new StringBuilder();
310                
311                StringList list = ListUtil.toListTrim(path, '/');
312                String str;
313                
314                while(list.hasNext()){
315                        str=list.next();
316                        //str=URLDecoder.decode(str);
317                        
318                        if(StringUtil.isEmpty(str)) continue;
319                        res.append("/");
320                        res.append(escapeQSValue(str));
321                }
322                if(StringUtil.endsWith(path, '/')) res.append('/');                     
323                path=res.toString();
324                
325                if(sqIndex!=-1) {
326                        path+=decodeQuery(q,';');
327                }
328        }
329        
330        // decode query 
331        query=decodeQuery(query,'?');
332    
333        
334        
335     // decode ref/anchor       
336        if(!StringUtil.isEmpty(fragment)) {
337                fragment=escapeQSValue(fragment);
338        }
339        
340        // user/pasword
341        if(!StringUtil.isEmpty(userInfo)) {
342                int index=userInfo.indexOf(':');
343                if(index!=-1) {
344                        userInfo=escapeQSValue(userInfo.substring(0,index))+":"+escapeQSValue(userInfo.substring(index+1));
345                }
346                else userInfo=escapeQSValue(userInfo);
347        }
348        
349        /*print.o("- fragment:"+fragment);
350        print.o("- host:"+host);
351        print.o("- path:"+path);
352        print.o("- query:"+query);
353        print.o("- scheme:"+scheme);
354        print.o("- userInfo:"+userInfo);
355        print.o("- port:"+port);
356        print.o("- absolute:"+uri.isAbsolute());
357        print.o("- opaque:"+uri.isOpaque());*/
358        
359        StringBuilder rtn=new StringBuilder();
360        if(scheme!=null) {
361                rtn.append(scheme);
362                rtn.append("://");
363        }
364        if(userInfo!=null) {
365                rtn.append(userInfo);
366                rtn.append("@");
367        }
368        if(host!=null) {
369                rtn.append(host);
370        }
371        if(port>0) {
372                rtn.append(":");
373                rtn.append(port);
374        }
375        if(path!=null) {
376                rtn.append(path);
377        }
378        if(query!=null) {
379                //rtn.append("?");
380                rtn.append(query);
381        }
382        if(fragment!=null) {
383                rtn.append("#");
384                rtn.append(fragment);
385        }
386        
387        return new URI(rtn.toString()); 
388    }
389
390        /*private static String getProtocol(URI uri) {
391        String p=uri.getRawSchemeSpecificPart();
392        if(p==null) return null;
393                if(p.indexOf('/')==-1) return p;
394                if(p.indexOf("https")!=-1) return "https";
395                if(p.indexOf("http")!=-1) return "http";
396                return p;
397        }*/
398    
399    private static String getProtocol(URL url) {
400                String p=url.getProtocol().toLowerCase();
401                if(p.indexOf('/')==-1) return p;
402                if(p.indexOf("https")!=-1) return "https";
403                if(p.indexOf("http")!=-1) return "http";
404                return p;
405        }
406    
407
408    
409    public static String escapeQSValue(String str) {
410        if(!ReqRspUtil.needEncoding(str,false)) return str;
411        PageContextImpl pc = (PageContextImpl) ThreadLocalPageContext.get();
412        if(pc!=null){
413                try {
414                        return URLEncoder.encode(str,pc.getWebCharset());
415                } 
416                catch (UnsupportedEncodingException e) {}
417        }
418        return URLEncoder.encode(str);
419        }
420
421        /*public static HttpMethod put(URL url, String username, String password, int timeout, 
422            String charset, String useragent,
423            String proxyserver, int proxyport, String proxyuser, 
424            String proxypassword, Header[] headers, Object body) throws IOException {
425                
426                
427                HttpClient client = new HttpClient();
428                PutMethod httpMethod=new PutMethod(url.toExternalForm());
429        HostConfiguration config = client.getHostConfiguration();
430        
431        HttpState state = client.getState();
432        
433        setHeader(httpMethod,headers);
434        setContentType(httpMethod,charset);
435        setUserAgent(httpMethod,useragent);
436        setTimeout(client,timeout);
437        setCredentials(client,httpMethod,username,password);    
438        setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
439        setBody(httpMethod,body);
440        
441        
442        return HttpClientUtil.execute(client,httpMethod,true);
443         
444        }*/
445    
446    /*public static HttpMethod delete(URL url, String username, String password, int timeout, 
447            String charset, String useragent,
448            String proxyserver, int proxyport, String proxyuser, 
449            String proxypassword, Header[] headers) throws IOException {
450                
451                
452                HttpClient client = new HttpClient();
453                DeleteMethod httpMethod=new DeleteMethod(url.toExternalForm());
454        HostConfiguration config = client.getHostConfiguration();
455        
456        HttpState state = client.getState();
457        
458        setHeader(httpMethod,headers);
459        setContentType(httpMethod,charset);
460        setUserAgent(httpMethod,useragent);
461        setTimeout(client,timeout);
462        setCredentials(client,httpMethod,username,password);    
463        setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
464        
465        
466        return HttpClientUtil.execute(client,httpMethod,true);
467         
468        }*/
469
470    /*public static HttpMethod head(URL url, String username, String password, int timeout, 
471            String charset, String useragent,
472            String proxyserver, int proxyport, String proxyuser, 
473            String proxypassword, Header[] headers) throws IOException {
474                
475                
476                HttpClient client = new HttpClient();
477                HeadMethod httpMethod=new HeadMethod(url.toExternalForm());
478        HostConfiguration config = client.getHostConfiguration();
479        
480        HttpState state = client.getState();
481        
482        setHeader(httpMethod,headers);
483        setContentType(httpMethod,charset);
484        setUserAgent(httpMethod,useragent);
485        setTimeout(client,timeout);
486        setCredentials(client,httpMethod,username,password);    
487        setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword);
488        
489        
490        return HttpClientUtil.execute(client,httpMethod,true);
491         
492        }*/
493
494    
495
496        
497
498        /*public static RequestEntity toRequestEntity(Object value) throws PageException {
499        if(value instanceof RequestEntity) return (RequestEntity) value;
500        else if(value instanceof InputStream) {
501                        return new InputStreamRequestEntity((InputStream)value,"application/octet-stream");
502                }
503                else if(Decision.isCastableToBinary(value,false)){
504                        return new ByteArrayRequestEntity(Caster.toBinary(value));
505                }
506                else {
507                        return new StringRequestEntity(Caster.toString(value));
508                }
509    }*/
510    
511        
512        public static URL removeRef(URL url) throws MalformedURLException{
513                int port=url.getPort();
514                if(port==80 && url.getProtocol().equalsIgnoreCase("http"))
515                        port=-1;
516                else if(port==443 && url.getProtocol().equalsIgnoreCase("https"))
517                        port=-1;
518                
519                
520                
521                URL u=new URL(url.getProtocol(),url.getHost(),port,url.getFile());
522                return u;
523        }
524        
525        public static String removeRef(String url) throws MalformedURLException{
526                return removeRef(new URL(url)).toExternalForm();
527        }
528        
529                        
530
531        /*public static URL toURL(HttpMethod httpMethod) {
532                HostConfiguration config = httpMethod.getHostConfiguration();
533                
534                try {
535                        String qs = httpMethod.getQueryString();
536                        if(StringUtil.isEmpty(qs))
537                                return new URL(config.getProtocol().getScheme(),config.getHost(),config.getPort(),httpMethod.getPath());
538                        return new URL(config.getProtocol().getScheme(),config.getHost(),config.getPort(),httpMethod.getPath()+"?"+qs);
539                } catch (MalformedURLException e) {
540                        return null;
541                }
542        }*/
543
544        public static String optimizeRelPath(PageContext pc,String relPath) {
545                int index;
546                String requestURI=relPath,queryString=null;
547                if((index=relPath.indexOf('?'))!=-1){
548                        requestURI=relPath.substring(0,index);
549                        queryString=relPath.substring(index+1);
550                }
551                PageSource ps = PageSourceImpl.best(((PageContextImpl)pc).getRelativePageSources(requestURI));
552                requestURI=ps.getFullRealpath();
553                if(queryString!=null) return requestURI+"?"+queryString;
554                return requestURI;
555        }
556
557        public static void forward(PageContext pc,String relPath) throws ServletException, IOException {
558                ServletContext context = pc.getServletContext();
559                relPath=HTTPUtil.optimizeRelPath(pc,relPath);
560                
561                try{
562                        pc.getHttpServletRequest().setAttribute("lucee.forward.request_uri", relPath);
563                        
564                RequestDispatcher disp = context.getRequestDispatcher(relPath);
565                if(disp==null)
566                        throw new PageServletException(new ApplicationException("Page "+relPath+" not found"));
567            
568                //populateRequestAttributes();
569                disp.forward(removeWrap(pc.getHttpServletRequest()),pc.getHttpServletResponse());
570                }
571        finally{
572                ThreadLocalPageContext.register(pc);
573        }
574        }
575        
576        public static ServletRequest removeWrap(ServletRequest req) {
577                while(req instanceof HTTPServletRequestWrap)
578                        return ((HTTPServletRequestWrap)req).getOriginalRequest();
579                return req;
580        }
581        
582
583        public static void include(PageContext pc,String relPath) throws ServletException,IOException  {
584                include(pc, pc.getHttpServletRequest(),pc.getHttpServletResponse(),relPath);
585        }
586
587        public static void include(PageContext pc,ServletRequest req, ServletResponse rsp, String relPath) throws ServletException,IOException  {
588                relPath=optimizeRelPath(pc,relPath);
589                boolean inline=HttpServletResponseWrap.get();
590                //print.out(rsp+":"+pc.getResponse());
591                RequestDispatcher disp = getRequestDispatcher(pc,relPath);
592                
593                if(inline)      {
594                        //RequestDispatcher disp = getRequestDispatcher(pc,relPath);
595                        disp.include(req,rsp);
596                        return;
597                }
598                
599                try     {
600                        ByteArrayOutputStream baos=new ByteArrayOutputStream();
601                        HttpServletResponseWrap hsrw=new HttpServletResponseWrap(pc.getHttpServletResponse(),baos);
602                        HttpServletResponseWrap.set(true);
603                        
604                        //RequestDispatcher disp = getRequestDispatcher(pc,relPath);
605                        
606                disp.include(req,hsrw);
607                if(!hsrw.isCommitted())hsrw.flushBuffer();
608                pc.write(IOUtil.toString(baos.toByteArray(), ReqRspUtil.getCharacterEncoding(pc,hsrw)));
609        }
610        finally{
611                HttpServletResponseWrap.release();
612                ThreadLocalPageContext.register(pc);
613        }
614        }
615
616        private static RequestDispatcher getRequestDispatcher(PageContext pc,String relPath) throws PageServletException {
617                RequestDispatcher disp = pc.getServletContext().getRequestDispatcher(relPath);
618        if(disp==null) throw new PageServletException(new ApplicationException("Page "+relPath+" not found"));
619        return disp;
620        }
621        
622        
623        // MUST create a copy from toURL and rename toURI and rewrite for URI, pherhaps it is possible to merge them somehow
624        public static String encode(String relpath) {
625        
626        
627                int qIndex=relpath.indexOf('?');
628                
629                if(qIndex==-1) return relpath;
630                
631                String file=relpath.substring(0,qIndex);
632                String query=relpath.substring(qIndex+1);
633                int sIndex=query.indexOf('#');
634                
635                String anker=null;
636                if(sIndex!=-1){
637                        //print.o(sIndex);
638                        anker=query.substring(sIndex+1);
639                        query=query.substring(0,sIndex);
640                }
641                
642                StringBuilder res=new StringBuilder(file);
643        
644                
645        // query
646        if(!StringUtil.isEmpty(query)){
647                
648                StringList list = ListUtil.toList(query, '&');
649                String str;
650                int index;
651                char del='?';
652                while(list.hasNext()){
653                        res.append(del);
654                        del='&';
655                        str=list.next();
656                        index=str.indexOf('=');
657                        if(index==-1)res.append(escapeQSValue(str));
658                        else {
659                                res.append(escapeQSValue(str.substring(0,index)));
660                                res.append('=');
661                                res.append(escapeQSValue(str.substring(index+1)));
662                        }
663                }       
664        }
665       
666        // anker
667        if(anker!=null) {
668                res.append('#');
669                res.append(escapeQSValue(anker));
670        }
671       
672        
673       return res.toString();                  
674    }
675
676
677        public static int getPort(URL url) {
678                if(url.getPort()!=-1) return url.getPort();
679                if("https".equalsIgnoreCase(url.getProtocol()))
680                        return 443;
681                return 80;
682        }
683
684        
685        /**
686         * return the length of a file defined by a url.
687         * @param dataUrl
688         * @return
689         * @throws IOException 
690         */
691        public static long length(URL url) throws IOException {
692                HTTPResponse http = HTTPEngine.head(url, null, null, -1,HTTPEngine.MAX_REDIRECT,null, "Lucee", null,null);
693                return http.getContentLength(); 
694        }
695
696        /*public static ContentType getContentType(HttpMethod http) {
697                Header[] headers = http.getResponseHeaders();
698                for(int i=0;i<headers.length;i++){
699                        if("Content-Type".equalsIgnoreCase(headers[i].getName())){
700                                String[] mimeCharset = splitMimeTypeAndCharset(headers[i].getValue());
701                                String[] typeSub = splitTypeAndSubType(mimeCharset[0]);
702                                return new ContentTypeImpl(typeSub[0],typeSub[1],mimeCharset[1]);
703                        }
704                }
705                return null;
706        }*/
707        
708        
709
710        public static Map<String, String> parseParameterList(String _str, boolean decode,String charset) {
711                //return lucee.commons.net.HTTPUtil.toURI(strUrl,port);
712                Map<String,String> data=new HashMap<String, String>();
713                StringList list = ListUtil.toList(_str, '&');
714        String str;
715        int index;
716        while(list.hasNext()){
717                str=list.next();
718                index=str.indexOf('=');
719                if(index==-1){
720                        data.put(decode(str,decode), "");
721                }
722                else {
723                        data.put(
724                                        decode(str.substring(0,index),decode), 
725                                        decode(str.substring(index+1),decode));
726                }
727        }       
728                return data;
729        }
730
731        private static String decode(String str, boolean encode) {
732                // TODO Auto-generated method stub
733                return str;
734        }
735        
736
737        public static ContentType toContentType(String str, ContentType defaultValue) {
738                if( StringUtil.isEmpty(str,true)) return defaultValue;
739                String[] types=str.split(";");
740                ContentType ct=null;
741                if(types.length>0){
742                ct=new ContentType(types[0]);
743                if(types.length>1) {
744                    String tmp=types[types.length-1].trim();
745                    int index=tmp.indexOf("charset=");
746                    if(index!=-1) {
747                        ct.setCharset(StringUtil.removeQuotes(tmp.substring(index+8),true));
748                    }
749                }
750        }
751        return ct;
752        }
753        
754        public static String[] splitMimeTypeAndCharset(String mimetype, String[] defaultValue) {
755                if( StringUtil.isEmpty(mimetype,true)) return defaultValue;
756                String[] types=mimetype.split(";");
757                String[] rtn=new String[2];
758        
759        if(types.length>0){
760                rtn[0]=types[0].trim();
761                if(types.length>1) {
762                    String tmp=types[types.length-1].trim();
763                    int index=tmp.indexOf("charset=");
764                    if(index!=-1) {
765                        rtn[1]= StringUtil.removeQuotes(tmp.substring(index+8),true);
766                    }
767                }
768        }
769        return rtn;
770        }
771        
772
773        public static String[] splitTypeAndSubType(String mimetype) {
774                String[] types=ListUtil.listToStringArray(mimetype, '/');
775                String[] rtn=new String[2];
776        
777        if(types.length>0){
778                rtn[0]=types[0].trim();
779                if(types.length>1) {
780                        rtn[1]=types[1].trim();
781                }
782        }
783        return rtn;
784        }
785
786        public static boolean isTextMimeType(String mimetype) {
787                if(mimetype==null)mimetype="";
788                else mimetype=mimetype.trim().toLowerCase();
789                return StringUtil.startsWithIgnoreCase(mimetype,"text")  || 
790        StringUtil.startsWithIgnoreCase(mimetype,"application/xml")  || 
791        StringUtil.startsWithIgnoreCase(mimetype,"application/atom+xml")  || 
792        StringUtil.startsWithIgnoreCase(mimetype,"application/xhtml")  ||  
793        StringUtil.startsWithIgnoreCase(mimetype,"application/json")  ||  
794        StringUtil.startsWithIgnoreCase(mimetype,"application/cfml")  || 
795        StringUtil.startsWithIgnoreCase(mimetype,"message") || 
796        StringUtil.startsWithIgnoreCase(mimetype,"application/octet-stream") || 
797        StringUtil.indexOfIgnoreCase(mimetype, "xml")!=-1 || 
798        StringUtil.indexOfIgnoreCase(mimetype, "json")!=-1 || 
799        StringUtil.indexOfIgnoreCase(mimetype, "rss")!=-1 || 
800        StringUtil.indexOfIgnoreCase(mimetype, "atom")!=-1 || 
801        StringUtil.indexOfIgnoreCase(mimetype, "text")!=-1;
802                
803                // "application/x-www-form-urlencoded" ???
804        }
805        
806        public static boolean isTextMimeType(MimeType mimetype) {
807                if(mimetype==null) return false;
808                if(MimeType.APPLICATION_JSON.same(mimetype)) return true;
809                if(MimeType.APPLICATION_PLAIN.same(mimetype)) return true;
810                if(MimeType.APPLICATION_CFML.same(mimetype)) return true;
811                if(MimeType.APPLICATION_WDDX.same(mimetype)) return true;
812                if(MimeType.APPLICATION_XML.same(mimetype)) return true;
813                
814                return isTextMimeType(mimetype.toString());
815        }
816
817        public static boolean isSecure(URL url) {
818                return StringUtil.indexOfIgnoreCase(url.getProtocol(),"https")!=-1;
819        }
820}