package railo.commons.net; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.HashMap; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import railo.commons.io.IOUtil; import railo.commons.lang.StringList; import railo.commons.lang.StringUtil; import railo.commons.lang.mimetype.ContentType; import railo.commons.lang.mimetype.MimeType; import railo.commons.net.http.HTTPEngine; import railo.commons.net.http.HTTPResponse; import railo.runtime.PageContext; import railo.runtime.PageContextImpl; import railo.runtime.PageSource; import railo.runtime.PageSourceImpl; import railo.runtime.config.Config; import railo.runtime.engine.ThreadLocalPageContext; import railo.runtime.exp.ApplicationException; import railo.runtime.exp.PageServletException; import railo.runtime.net.http.HTTPServletRequestWrap; import railo.runtime.net.http.HttpServletResponseWrap; import railo.runtime.net.http.ReqRspUtil; import railo.runtime.type.util.ListUtil; /** * */ public final class HTTPUtil { /** * Field <code>ACTION_POST</code> */ public static final short ACTION_POST=0; /** * Field <code>ACTION_GET</code> */ public static final short ACTION_GET=1; /** * Field <code>STATUS_OK</code> */ public static final int STATUS_OK=200; //private static final String NO_MIMETYPE="Unable to determine MIME type of file."; public static final int MAX_REDIRECT = 15; /*public static HttpMethod invoke(URL url, String username, String password, long timeout, String charset, String useragent, String proxyserver, int proxyport, String proxyuser, String proxypassword, Header[] headers) throws IOException { HttpClient client = new HttpClient(); HttpMethod httpMethod=new GetMethod(url.toExternalForm()); HostConfiguration config = client.getHostConfiguration(); HttpState state = client.getState(); setHeader(httpMethod,headers); setContentType(httpMethod,charset); setUserAgent(httpMethod,useragent); setTimeout(client,timeout); setCredentials(client,httpMethod,username,password); setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword); httpMethod = HttpClientUtil.execute(client,httpMethod,true); return httpMethod; }*/ /*public static HttpMethod post(URL url, String username, String password, long timeout, String charset, String useragent, String proxyserver, int proxyport, String proxyuser, String proxypassword, Header[] headers) throws IOException { HttpClient client = new HttpClient(); HttpMethod httpMethod=new PostMethod(url.toExternalForm()); HostConfiguration config = client.getHostConfiguration(); HttpState state = client.getState(); setHeader(httpMethod,headers); setContentType(httpMethod,charset); setUserAgent(httpMethod,useragent); setTimeout(client,timeout); setCredentials(client,httpMethod,username,password); setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword); httpMethod = HttpClientUtil.execute(client,httpMethod,true); return httpMethod; }*/ /** * cast a string to a url * @param strUrl string represent a url * @return url from string * @throws MalformedURLException */ public static URL toURL(String strUrl,boolean encodeIfNecessary) throws MalformedURLException { return toURL(strUrl,-1,encodeIfNecessary); } public static URL toURL(String strUrl,boolean encodeIfNecessary,URL defaultValue){ try { return toURL(strUrl,-1,encodeIfNecessary); } catch (MalformedURLException e) { return defaultValue; } } public static String validateURL(String strUrl,String defaultValue){ try { return toURL(strUrl,-1,true).toExternalForm(); } catch (MalformedURLException e) { return defaultValue; } } /** * cast a string to a url * @param strUrl string represent a url * @return url from string * @throws MalformedURLException */ public static URL toURL(String strUrl, int port, boolean encodeIfNecessary) throws MalformedURLException { URL url; try { url=new URL(strUrl); } catch(MalformedURLException mue) { url=new URL("http://"+strUrl); } if(!encodeIfNecessary) return url; return encodeURL(url, port); } public static URL encodeURL(URL url) throws MalformedURLException { return encodeURL(url, -1); } public static URL encodeURL(URL url, int port) throws MalformedURLException { // file String path=url.getPath(); //String file=url.getFile(); String query = url.getQuery(); String ref = url.getRef(); String user=url.getUserInfo(); if(port<=0) port=url.getPort(); // decode path if(!StringUtil.isEmpty(path)) { int sqIndex=path.indexOf(';'); String q=null; if(sqIndex!=-1) { q=path.substring(sqIndex+1); path=path.substring(0,sqIndex); } StringBuilder res=new StringBuilder(); StringList list = ListUtil.toListTrim(path, '/'); String str; while(list.hasNext()){ str=list.next(); //str=URLDecoder.decode(str); if(StringUtil.isEmpty(str)) continue; res.append("/"); res.append(escapeQSValue(str)); } if(StringUtil.endsWith(path, '/')) res.append('/'); path=res.toString(); if(sqIndex!=-1) { path+=decodeQuery(q,';'); } } // decode query query=decodeQuery(query,'?'); String file=path+query; // decode ref/anchor if(ref!=null) { file+="#"+escapeQSValue(ref); } // user/pasword if(!StringUtil.isEmpty(user)) { int index=user.indexOf(':'); if(index!=-1) { user=escapeQSValue(user.substring(0,index))+":"+escapeQSValue(user.substring(index+1)); } else user=escapeQSValue(user); String strUrl = getProtocol(url)+"://"+user+"@"+url.getHost(); if(port>0)strUrl+=":"+port; strUrl+=file; return new URL(strUrl); } // port if(port<=0) return new URL(url.getProtocol(),url.getHost(),file); return new URL(url.getProtocol(),url.getHost(),port,file); } private static String decodeQuery(String query,char startDelimiter) { if(!StringUtil.isEmpty(query)) { StringBuilder res=new StringBuilder(); StringList list = ListUtil.toList(query, '&'); String str; int index; char del=startDelimiter; while(list.hasNext()){ res.append(del); del='&'; str=list.next(); index=str.indexOf('='); if(index==-1)res.append(escapeQSValue(str)); else { res.append(escapeQSValue(str.substring(0,index))); res.append('='); res.append(escapeQSValue(str.substring(index+1))); } } query=res.toString(); } else query=""; return query; } public static URI toURI(String strUrl) throws URISyntaxException { return toURI(strUrl,-1); } public static URI toURI(String strUrl, int port) throws URISyntaxException { //print.o((strUrl)); URI uri = new URI(strUrl); String host = uri.getHost(); String fragment = uri.getRawFragment(); String path = uri.getRawPath(); String query= uri.getRawQuery(); String scheme = uri.getScheme(); String userInfo = uri.getRawUserInfo(); if(port<=0) port=uri.getPort(); // decode path if(!StringUtil.isEmpty(path)) { int sqIndex=path.indexOf(';'); String q=null; if(sqIndex!=-1) { q=path.substring(sqIndex+1); path=path.substring(0,sqIndex); } StringBuilder res=new StringBuilder(); StringList list = ListUtil.toListTrim(path, '/'); String str; while(list.hasNext()){ str=list.next(); //str=URLDecoder.decode(str); if(StringUtil.isEmpty(str)) continue; res.append("/"); res.append(escapeQSValue(str)); } if(StringUtil.endsWith(path, '/')) res.append('/'); path=res.toString(); if(sqIndex!=-1) { path+=decodeQuery(q,';'); } } // decode query query=decodeQuery(query,'?'); // decode ref/anchor if(!StringUtil.isEmpty(fragment)) { fragment=escapeQSValue(fragment); } // user/pasword if(!StringUtil.isEmpty(userInfo)) { int index=userInfo.indexOf(':'); if(index!=-1) { userInfo=escapeQSValue(userInfo.substring(0,index))+":"+escapeQSValue(userInfo.substring(index+1)); } else userInfo=escapeQSValue(userInfo); } /*print.o("- fragment:"+fragment); print.o("- host:"+host); print.o("- path:"+path); print.o("- query:"+query); print.o("- scheme:"+scheme); print.o("- userInfo:"+userInfo); print.o("- port:"+port); print.o("- absolute:"+uri.isAbsolute()); print.o("- opaque:"+uri.isOpaque());*/ StringBuilder rtn=new StringBuilder(); if(scheme!=null) { rtn.append(scheme); rtn.append("://"); } if(userInfo!=null) { rtn.append(userInfo); rtn.append("@"); } if(host!=null) { rtn.append(host); } if(port>0) { rtn.append(":"); rtn.append(port); } if(path!=null) { rtn.append(path); } if(query!=null) { //rtn.append("?"); rtn.append(query); } if(fragment!=null) { rtn.append("#"); rtn.append(fragment); } return new URI(rtn.toString()); } /*private static String getProtocol(URI uri) { String p=uri.getRawSchemeSpecificPart(); if(p==null) return null; if(p.indexOf('/')==-1) return p; if(p.indexOf("https")!=-1) return "https"; if(p.indexOf("http")!=-1) return "http"; return p; }*/ private static String getProtocol(URL url) { String p=url.getProtocol().toLowerCase(); if(p.indexOf('/')==-1) return p; if(p.indexOf("https")!=-1) return "https"; if(p.indexOf("http")!=-1) return "http"; return p; } public static String escapeQSValue(String str) { if(!ReqRspUtil.needEncoding(str,true)) return str; Config config = ThreadLocalPageContext.getConfig(); if(config!=null){ try { return URLEncoder.encode(str,config.getWebCharset()); } catch (UnsupportedEncodingException e) {} } return URLEncoder.encode(str); } /*public static HttpMethod put(URL url, String username, String password, int timeout, String charset, String useragent, String proxyserver, int proxyport, String proxyuser, String proxypassword, Header[] headers, Object body) throws IOException { HttpClient client = new HttpClient(); PutMethod httpMethod=new PutMethod(url.toExternalForm()); HostConfiguration config = client.getHostConfiguration(); HttpState state = client.getState(); setHeader(httpMethod,headers); setContentType(httpMethod,charset); setUserAgent(httpMethod,useragent); setTimeout(client,timeout); setCredentials(client,httpMethod,username,password); setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword); setBody(httpMethod,body); return HttpClientUtil.execute(client,httpMethod,true); }*/ /*public static HttpMethod delete(URL url, String username, String password, int timeout, String charset, String useragent, String proxyserver, int proxyport, String proxyuser, String proxypassword, Header[] headers) throws IOException { HttpClient client = new HttpClient(); DeleteMethod httpMethod=new DeleteMethod(url.toExternalForm()); HostConfiguration config = client.getHostConfiguration(); HttpState state = client.getState(); setHeader(httpMethod,headers); setContentType(httpMethod,charset); setUserAgent(httpMethod,useragent); setTimeout(client,timeout); setCredentials(client,httpMethod,username,password); setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword); return HttpClientUtil.execute(client,httpMethod,true); }*/ /*public static HttpMethod head(URL url, String username, String password, int timeout, String charset, String useragent, String proxyserver, int proxyport, String proxyuser, String proxypassword, Header[] headers) throws IOException { HttpClient client = new HttpClient(); HeadMethod httpMethod=new HeadMethod(url.toExternalForm()); HostConfiguration config = client.getHostConfiguration(); HttpState state = client.getState(); setHeader(httpMethod,headers); setContentType(httpMethod,charset); setUserAgent(httpMethod,useragent); setTimeout(client,timeout); setCredentials(client,httpMethod,username,password); setProxy(config,state,proxyserver,proxyport,proxyuser,proxypassword); return HttpClientUtil.execute(client,httpMethod,true); }*/ /*public static RequestEntity toRequestEntity(Object value) throws PageException { if(value instanceof RequestEntity) return (RequestEntity) value; else if(value instanceof InputStream) { return new InputStreamRequestEntity((InputStream)value,"application/octet-stream"); } else if(Decision.isCastableToBinary(value,false)){ return new ByteArrayRequestEntity(Caster.toBinary(value)); } else { return new StringRequestEntity(Caster.toString(value)); } }*/ public static URL removeRef(URL url) throws MalformedURLException{ int port=url.getPort(); if(port==80 && url.getProtocol().equalsIgnoreCase("http")) port=-1; else if(port==443 && url.getProtocol().equalsIgnoreCase("https")) port=-1; URL u=new URL(url.getProtocol(),url.getHost(),port,url.getFile()); return u; } public static String removeRef(String url) throws MalformedURLException{ return removeRef(new URL(url)).toExternalForm(); } /*public static URL toURL(HttpMethod httpMethod) { HostConfiguration config = httpMethod.getHostConfiguration(); try { String qs = httpMethod.getQueryString(); if(StringUtil.isEmpty(qs)) return new URL(config.getProtocol().getScheme(),config.getHost(),config.getPort(),httpMethod.getPath()); return new URL(config.getProtocol().getScheme(),config.getHost(),config.getPort(),httpMethod.getPath()+"?"+qs); } catch (MalformedURLException e) { return null; } }*/ public static String optimizeRealPath(PageContext pc,String realPath) { int index; String requestURI=realPath,queryString=null; if((index=realPath.indexOf('?'))!=-1){ requestURI=realPath.substring(0,index); queryString=realPath.substring(index+1); } PageSource ps = PageSourceImpl.best(((PageContextImpl)pc).getRelativePageSources(requestURI)); requestURI=ps.getFullRealpath(); if(queryString!=null) return requestURI+"?"+queryString; return requestURI; } public static void forward(PageContext pc,String realPath) throws ServletException, IOException { ServletContext context = pc.getServletContext(); realPath=HTTPUtil.optimizeRealPath(pc,realPath); try{ pc.getHttpServletRequest().setAttribute("railo.forward.request_uri", realPath); RequestDispatcher disp = context.getRequestDispatcher(realPath); if(disp==null) throw new PageServletException(new ApplicationException("Page "+realPath+" not found")); //populateRequestAttributes(); disp.forward(removeWrap(pc.getHttpServletRequest()),pc.getHttpServletResponse()); } finally{ ThreadLocalPageContext.register(pc); } } public static ServletRequest removeWrap(ServletRequest req) { while(req instanceof HTTPServletRequestWrap) return ((HTTPServletRequestWrap)req).getOriginalRequest(); return req; } public static void include(PageContext pc,String realPath) throws ServletException,IOException { include(pc, pc.getHttpServletRequest(),pc.getHttpServletResponse(),realPath); } public static void include(PageContext pc,ServletRequest req, ServletResponse rsp, String realPath) throws ServletException,IOException { realPath=optimizeRealPath(pc,realPath); boolean inline=HttpServletResponseWrap.get(); //print.out(rsp+":"+pc.getResponse()); RequestDispatcher disp = getRequestDispatcher(pc,realPath); if(inline) { //RequestDispatcher disp = getRequestDispatcher(pc,realPath); disp.include(req,rsp); return; } try { ByteArrayOutputStream baos=new ByteArrayOutputStream(); HttpServletResponseWrap hsrw=new HttpServletResponseWrap(pc.getHttpServletResponse(),baos); HttpServletResponseWrap.set(true); //RequestDispatcher disp = getRequestDispatcher(pc,realPath); disp.include(req,hsrw); if(!hsrw.isCommitted())hsrw.flushBuffer(); pc.write(IOUtil.toString(baos.toByteArray(), ReqRspUtil.getCharacterEncoding(pc,hsrw))); } finally{ HttpServletResponseWrap.release(); ThreadLocalPageContext.register(pc); } } private static RequestDispatcher getRequestDispatcher(PageContext pc,String realPath) throws PageServletException { RequestDispatcher disp = pc.getServletContext().getRequestDispatcher(realPath); if(disp==null) throw new PageServletException(new ApplicationException("Page "+realPath+" not found")); return disp; } // MUST create a copy from toURL and rename toURI and rewrite for URI, pherhaps it is possible to merge them somehow public static String encode(String realpath) { int qIndex=realpath.indexOf('?'); if(qIndex==-1) return realpath; String file=realpath.substring(0,qIndex); String query=realpath.substring(qIndex+1); int sIndex=query.indexOf('#'); String anker=null; if(sIndex!=-1){ //print.o(sIndex); anker=query.substring(sIndex+1); query=query.substring(0,sIndex); } StringBuilder res=new StringBuilder(file); // query if(!StringUtil.isEmpty(query)){ StringList list = ListUtil.toList(query, '&'); String str; int index; char del='?'; while(list.hasNext()){ res.append(del); del='&'; str=list.next(); index=str.indexOf('='); if(index==-1)res.append(escapeQSValue(str)); else { res.append(escapeQSValue(str.substring(0,index))); res.append('='); res.append(escapeQSValue(str.substring(index+1))); } } } // anker if(anker!=null) { res.append('#'); res.append(escapeQSValue(anker)); } return res.toString(); } public static int getPort(URL url) { if(url.getPort()!=-1) return url.getPort(); if("https".equalsIgnoreCase(url.getProtocol())) return 443; return 80; } /** * return the length of a file defined by a url. * @param dataUrl * @return * @throws IOException */ public static long length(URL url) throws IOException { HTTPResponse http = HTTPEngine.head(url, null, null, -1,HTTPEngine.MAX_REDIRECT,null, "Railo", null,null); return http.getContentLength(); } /*public static ContentType getContentType(HttpMethod http) { Header[] headers = http.getResponseHeaders(); for(int i=0;i<headers.length;i++){ if("Content-Type".equalsIgnoreCase(headers[i].getName())){ String[] mimeCharset = splitMimeTypeAndCharset(headers[i].getValue()); String[] typeSub = splitTypeAndSubType(mimeCharset[0]); return new ContentTypeImpl(typeSub[0],typeSub[1],mimeCharset[1]); } } return null; }*/ public static Map<String, String> parseParameterList(String _str, boolean decode,String charset) { //return railo.commons.net.HTTPUtil.toURI(strUrl,port); Map<String,String> data=new HashMap<String, String>(); StringList list = ListUtil.toList(_str, '&'); String str; int index; while(list.hasNext()){ str=list.next(); index=str.indexOf('='); if(index==-1){ data.put(decode(str,decode), ""); } else { data.put( decode(str.substring(0,index),decode), decode(str.substring(index+1),decode)); } } return data; } private static String decode(String str, boolean encode) { // TODO Auto-generated method stub return str; } public static ContentType toContentType(String str, ContentType defaultValue) { if( StringUtil.isEmpty(str,true)) return defaultValue; String[] types=str.split(";"); ContentType ct=null; if(types.length>0){ ct=new ContentType(types[0]); if(types.length>1) { String tmp=types[types.length-1].trim(); int index=tmp.indexOf("charset="); if(index!=-1) { ct.setCharset(StringUtil.removeQuotes(tmp.substring(index+8),true)); } } } return ct; } public static String[] splitMimeTypeAndCharset(String mimetype, String[] defaultValue) { if( StringUtil.isEmpty(mimetype,true)) return defaultValue; String[] types=mimetype.split(";"); String[] rtn=new String[2]; if(types.length>0){ rtn[0]=types[0].trim(); if(types.length>1) { String tmp=types[types.length-1].trim(); int index=tmp.indexOf("charset="); if(index!=-1) { rtn[1]= StringUtil.removeQuotes(tmp.substring(index+8),true); } } } return rtn; } public static String[] splitTypeAndSubType(String mimetype) { String[] types=ListUtil.listToStringArray(mimetype, '/'); String[] rtn=new String[2]; if(types.length>0){ rtn[0]=types[0].trim(); if(types.length>1) { rtn[1]=types[1].trim(); } } return rtn; } public static boolean isTextMimeType(String mimetype) { if(mimetype==null)mimetype=""; else mimetype=mimetype.trim().toLowerCase(); return StringUtil.startsWithIgnoreCase(mimetype,"text") || StringUtil.startsWithIgnoreCase(mimetype,"application/xml") || StringUtil.startsWithIgnoreCase(mimetype,"application/atom+xml") || StringUtil.startsWithIgnoreCase(mimetype,"application/xhtml") || StringUtil.startsWithIgnoreCase(mimetype,"application/json") || StringUtil.startsWithIgnoreCase(mimetype,"application/cfml") || StringUtil.startsWithIgnoreCase(mimetype,"message") || StringUtil.startsWithIgnoreCase(mimetype,"application/octet-stream") || StringUtil.indexOfIgnoreCase(mimetype, "xml")!=-1 || StringUtil.indexOfIgnoreCase(mimetype, "json")!=-1 || StringUtil.indexOfIgnoreCase(mimetype, "rss")!=-1 || StringUtil.indexOfIgnoreCase(mimetype, "atom")!=-1 || StringUtil.indexOfIgnoreCase(mimetype, "text")!=-1; // "application/x-www-form-urlencoded" ??? } public static boolean isTextMimeType(MimeType mimetype) { if(mimetype==null) return false; if(MimeType.APPLICATION_JSON.same(mimetype)) return true; if(MimeType.APPLICATION_PLAIN.same(mimetype)) return true; if(MimeType.APPLICATION_CFML.same(mimetype)) return true; if(MimeType.APPLICATION_WDDX.same(mimetype)) return true; if(MimeType.APPLICATION_XML.same(mimetype)) return true; return isTextMimeType(mimetype.toString()); } public static boolean isSecure(URL url) { return StringUtil.indexOfIgnoreCase(url.getProtocol(),"https")!=-1; } }