package railo.runtime.net.http; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; import java.util.Enumeration; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import javax.servlet.RequestDispatcher; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import railo.commons.io.IOUtil; import railo.commons.lang.StringUtil; import railo.commons.net.URLItem; import railo.runtime.PageContext; import railo.runtime.engine.ThreadLocalPageContext; import railo.runtime.type.scope.Form; import railo.runtime.type.scope.FormImpl; import railo.runtime.type.scope.URL; import railo.runtime.type.scope.URLImpl; import railo.runtime.type.scope.UrlFormImpl; import railo.runtime.type.scope.util.ScopeUtil; import railo.runtime.util.EnumerationWrapper; /** * extends a existing {@link HttpServletRequest} with the possibility to reread the input as many you want. */ public final class HTTPServletRequestWrap extends HttpServletRequestWrapper implements Serializable { private boolean firstRead=true; private byte[] barr; private static final int MIN_STORAGE_SIZE=1*1024*1024; private static final int MAX_STORAGE_SIZE=50*1024*1024; private static final int SPACIG=1024*1024; private String servlet_path; private String request_uri; private String context_path; private String path_info; private String query_string; private HashMap<String, Object> disconnectedData; private boolean disconnected; private HttpServletRequest req; //private Request _request; /** * Constructor of the class * @param req * @param max how many is possible to re read */ public HTTPServletRequestWrap(HttpServletRequest req) { super(req); this.req=pure(req); if((servlet_path=attrAsString("javax.servlet.include.servlet_path"))!=null){ request_uri=attrAsString("javax.servlet.include.request_uri"); context_path=attrAsString("javax.servlet.include.context_path"); path_info=attrAsString("javax.servlet.include.path_info"); query_string = attrAsString("javax.servlet.include.query_string"); } //forward /*else if((servlet_path=attr("javax.servlet.forward.servlet_path"))!=null){ request_uri=attr("javax.servlet.forward.request_uri"); context_path=attr("javax.servlet.forward.context_path"); path_info=attr("javax.servlet.forward.path_info"); query_string = attr("javax.servlet.forward.query_string"); }*/ else { servlet_path=super.getServletPath(); request_uri=super.getRequestURI(); context_path=super.getContextPath(); path_info=super.getPathInfo(); query_string = super.getQueryString(); } /*Enumeration names = req.getAttributeNames(); while(names.hasMoreElements()){ String key=(String)names.nextElement(); print.out(key+"+"+req.getAttribute(key)); } print.out("super:"+req.getClass().getName()); print.out("servlet_path:"+servlet_path); print.out("request_uri:"+request_uri); print.out("path_info:"+path_info); print.out("query_string:"+query_string); print.out("servlet_path."+req.getServletPath()); print.out("request_uri."+req.getRequestURI()); print.out("path_info."+req.getPathInfo()); print.out("query_string."+req.getQueryString()); */ } private String attrAsString(String key) { Object res = getAttribute(key); if(res==null) return null; return res.toString(); } public static HttpServletRequest pure(HttpServletRequest req) { HttpServletRequest req2; while(req instanceof HTTPServletRequestWrap){ req2 = ((HTTPServletRequestWrap)req).getOriginalRequest(); if(req2==req) break; req=req2; } return req; } @Override public String getContextPath() { return context_path; } @Override public String getPathInfo() { return path_info; } @Override public StringBuffer getRequestURL() { return new StringBuffer(isSecure()?"https":"http"). append("://"). append(getServerName()). append(':'). append(getServerPort()). append(request_uri.startsWith("/")?request_uri:"/"+request_uri); } @Override public String getQueryString() { return query_string; } @Override public String getRequestURI() { return request_uri; } @Override public String getServletPath() { return servlet_path; } @Override public RequestDispatcher getRequestDispatcher(String realpath) { return new RequestDispatcherWrap(this,realpath); } public RequestDispatcher getOriginalRequestDispatcher(String realpath) { if(disconnected) return null; return req.getRequestDispatcher(realpath); } @Override public void removeAttribute(String name) { if(disconnected) disconnectedData.remove(name); else req.removeAttribute(name); } @Override public void setAttribute(String name, Object value) { if(disconnected) disconnectedData.put(name, value); else req.setAttribute(name, value); } /*public void setAttributes(Request request) { this._request=request; }*/ @Override public Object getAttribute(String name) { if(disconnected) return disconnectedData.get(name); return req.getAttribute(name); } public Enumeration getAttributeNames() { if(disconnected) { return new EnumerationWrapper(disconnectedData); } return req.getAttributeNames(); } @Override public ServletInputStream getInputStream() throws IOException { //if(ba rr!=null) throw new IllegalStateException(); if(barr==null) { if(!firstRead) { PageContext pc = ThreadLocalPageContext.get(); if(pc!=null) { return pc.formScope().getInputStream(); } return new ServletInputStreamDummy(new byte[]{}); //throw new IllegalStateException(); } firstRead=false; if(isToBig(getContentLength())) { return super.getInputStream(); } InputStream is=null; try { barr=IOUtil.toBytes(is=super.getInputStream()); //Resource res = ResourcesImpl.getFileResourceProvider().getResource("/Users/mic/Temp/multipart.txt"); //IOUtil.copy(new ByteArrayInputStream(barr), res, true); } catch(Throwable t) { barr=null; return new ServletInputStreamDummy(new byte[]{}); } finally { IOUtil.closeEL(is); } } return new ServletInputStreamDummy(barr); } @Override public Map<String,String[]> getParameterMap() { PageContext pc = ThreadLocalPageContext.get(); FormImpl form=_form(pc); URLImpl url=_url(pc); return ScopeUtil.getParameterMap( new URLItem[][]{form.getRaw(),url.getRaw()}, new String[]{form.getEncoding(),url.getEncoding()}); } private static URLImpl _url(PageContext pc) { URL u = pc.urlScope(); if(u instanceof UrlFormImpl) { return ((UrlFormImpl) u).getURL(); } return (URLImpl) u; } private static FormImpl _form(PageContext pc) { Form f = pc.formScope(); if(f instanceof UrlFormImpl) { return ((UrlFormImpl) f).getForm(); } return (FormImpl) f; } @Override public Enumeration<String> getParameterNames() { return new ItasEnum<String>(getParameterMap().keySet().iterator()); } @Override public String[] getParameterValues(String name) { return getParameterValues(ThreadLocalPageContext.get(), name); } public static String[] getParameterValues(PageContext pc, String name) { pc = ThreadLocalPageContext.get(pc); FormImpl form = _form(pc); URLImpl url= _url(pc); return ScopeUtil.getParameterValues( new URLItem[][]{form.getRaw(),url.getRaw()}, new String[]{form.getEncoding(),url.getEncoding()},name); } private boolean isToBig(int contentLength) { if(contentLength<MIN_STORAGE_SIZE) return false; if(contentLength>MAX_STORAGE_SIZE) return true; Runtime rt = Runtime.getRuntime(); long av = rt.maxMemory()-rt.totalMemory()+rt.freeMemory(); return (av-SPACIG)<contentLength; } /* * * with this method it is possibiliy to rewrite the input as many you want * @return input stream from request * @throws IOException * / public ServletInputStream getStoredInputStream() throws IOException { if(firstRead || barr!=null) return getInputStream(); return new ServletInputStreamDummy(new byte[]{}); }*/ @Override public BufferedReader getReader() throws IOException { String enc = getCharacterEncoding(); if(StringUtil.isEmpty(enc))enc="iso-8859-1"; return IOUtil.toBufferedReader(IOUtil.getReader(getInputStream(), enc)); } public void clear() { barr=null; } public HttpServletRequest getOriginalRequest() { return req; } public void disconnect() { if(disconnected) return; Enumeration<String> names = req.getAttributeNames(); disconnectedData=new HashMap<String, Object>(); String k; while(names.hasMoreElements()){ k=names.nextElement(); disconnectedData.put(k, req.getAttribute(k)); } disconnected=true; req=null; } static class ItasEnum<E> implements Enumeration<E> { private Iterator<E> it; public ItasEnum(Iterator<E> it){ this.it=it; } @Override public boolean hasMoreElements() { return it.hasNext(); } @Override public E nextElement() { return it.next(); } } }