diff options
Diffstat (limited to 'jetty-server/src/main/java/org/eclipse/jetty/server/Request.java')
-rw-r--r-- | jetty-server/src/main/java/org/eclipse/jetty/server/Request.java | 203 |
1 files changed, 195 insertions, 8 deletions
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java index 021e60e77c..b873977d95 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Request.java @@ -19,6 +19,8 @@ package org.eclipse.jetty.server; import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; @@ -37,16 +39,26 @@ import java.util.Locale; import java.util.Map; import java.util.Map.Entry; +import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.DispatcherType; +import javax.servlet.MultipartConfigElement; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; +import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestAttributeEvent; import javax.servlet.ServletRequestAttributeListener; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; import javax.servlet.ServletResponse; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.servlet.http.Part; import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; @@ -61,6 +73,7 @@ import org.eclipse.jetty.http.HttpVersions; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.io.BufferUtil; +import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.nio.DirectNIOBuffer; import org.eclipse.jetty.io.nio.IndirectNIOBuffer; @@ -69,8 +82,11 @@ import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler.Context; import org.eclipse.jetty.util.Attributes; import org.eclipse.jetty.util.AttributesMap; +import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.LazyList; +import org.eclipse.jetty.util.MultiException; import org.eclipse.jetty.util.MultiMap; +import org.eclipse.jetty.util.MultiPartInputStream; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.UrlEncoded; @@ -111,12 +127,51 @@ import org.eclipse.jetty.util.log.Logger; */ public class Request implements HttpServletRequest { + public static final String __MULTIPART_CONFIG_ELEMENT = "org.eclipse.multipartConfig"; + public static final String __MULTIPART_INPUT_STREAM = "org.eclipse.multiPartInputStream"; + public static final String __MULTIPART_CONTEXT = "org.eclipse.multiPartContext"; private static final Logger LOG = Log.getLogger(Request.class); private static final String __ASYNC_FWD = "org.eclipse.asyncfwd"; private static final Collection __defaultLocale = Collections.singleton(Locale.getDefault()); private static final int __NONE = 0, _STREAM = 1, __READER = 2; + public static class MultiPartCleanerListener implements ServletRequestListener + { + + @Override + public void requestDestroyed(ServletRequestEvent sre) + { + //Clean up any tmp files created by MultiPartInputStream + MultiPartInputStream mpis = (MultiPartInputStream)sre.getServletRequest().getAttribute(__MULTIPART_INPUT_STREAM); + if (mpis != null) + { + ContextHandler.Context context = (ContextHandler.Context)sre.getServletRequest().getAttribute(__MULTIPART_CONTEXT); + + //Only do the cleanup if we are exiting from the context in which a servlet parsed the multipart files + if (context == sre.getServletContext()) + { + try + { + mpis.deleteParts(); + } + catch (MultiException e) + { + sre.getServletContext().log("Errors deleting multipart tmp files", e); + } + } + } + } + + @Override + public void requestInitialized(ServletRequestEvent sre) + { + //nothing to do, multipart config set up by ServletHolder.handle() + } + + } + + /* ------------------------------------------------------------ */ public static Request getRequest(HttpServletRequest request) { @@ -170,7 +225,9 @@ public class Request implements HttpServletRequest private Buffer _timeStampBuffer; private HttpURI _uri; - + + private MultiPartInputStream _multiPartInputStream; //if the request is a multi-part mime + /* ------------------------------------------------------------ */ public Request() { @@ -188,7 +245,9 @@ public class Request implements HttpServletRequest if (listener instanceof ServletRequestAttributeListener) _requestAttributeListeners = LazyList.add(_requestAttributeListeners,listener); if (listener instanceof ContinuationListener) - throw new IllegalArgumentException(); + throw new IllegalArgumentException(listener.getClass().toString()); + if (listener instanceof AsyncListener) + throw new IllegalArgumentException(listener.getClass().toString()); } /* ------------------------------------------------------------ */ @@ -306,6 +365,7 @@ public class Request implements HttpServletRequest } } } + } if (_parameters == null) @@ -323,6 +383,28 @@ public class Request implements HttpServletRequest _parameters.add(name,LazyList.get(values,i)); } } + + if (content_type != null && content_type.length()>0 && content_type.startsWith("multipart/form-data") && getAttribute(__MULTIPART_CONFIG_ELEMENT)!=null) + { + try + { + getParts(); + } + catch (IOException e) + { + if (LOG.isDebugEnabled()) + LOG.warn(e); + else + LOG.warn(e.toString()); + } + catch (ServletException e) + { + if (LOG.isDebugEnabled()) + LOG.warn(e); + else + LOG.warn(e.toString()); + } + } } finally { @@ -345,7 +427,7 @@ public class Request implements HttpServletRequest { return _async; } - + /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletRequest#getAttribute(java.lang.String) @@ -401,8 +483,8 @@ public class Request implements HttpServletRequest public String getAuthType() { if (_authentication instanceof Authentication.Deferred) - _authentication = ((Authentication.Deferred)_authentication).authenticate(this); - + setAuthentication(((Authentication.Deferred)_authentication).authenticate(this)); + if (_authentication instanceof Authentication.User) return ((Authentication.User)_authentication).getAuthMethod(); return null; @@ -1279,6 +1361,7 @@ public class Request implements HttpServletRequest UserIdentity user = ((Authentication.User)_authentication).getUserIdentity(); return user.getUserPrincipal(); } + return null; } @@ -1299,6 +1382,12 @@ public class Request implements HttpServletRequest return _handled; } + public boolean isAsyncStarted() + { + return _async.isAsyncStarted(); + } + + /* ------------------------------------------------------------ */ public boolean isAsyncSupported() { @@ -1434,7 +1523,8 @@ public class Request implements HttpServletRequest if (_savedNewSessions != null) _savedNewSessions.clear(); - _savedNewSessions = null; + _savedNewSessions=null; + _multiPartInputStream = null; } /* ------------------------------------------------------------ */ @@ -1915,7 +2005,7 @@ public class Request implements HttpServletRequest { if (!_asyncSupported) throw new IllegalStateException("!asyncSupported"); - _async.suspend(); + _async.startAsync(); return _async; } @@ -1924,7 +2014,7 @@ public class Request implements HttpServletRequest { if (!_asyncSupported) throw new IllegalStateException("!asyncSupported"); - _async.suspend(_context,servletRequest,servletResponse); + _async.startAsync(_context,servletRequest,servletResponse); return _async; } @@ -1936,6 +2026,103 @@ public class Request implements HttpServletRequest } /* ------------------------------------------------------------ */ + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException + { + if (_authentication instanceof Authentication.Deferred) + { + setAuthentication(((Authentication.Deferred)_authentication).authenticate(this,response)); + return !(_authentication instanceof Authentication.ResponseSent); + } + response.sendError(HttpStatus.UNAUTHORIZED_401); + return false; + } + + /* ------------------------------------------------------------ */ + public Part getPart(String name) throws IOException, ServletException + { + getParts(); + return _multiPartInputStream.getPart(name); + } + + /* ------------------------------------------------------------ */ + public Collection<Part> getParts() throws IOException, ServletException + { + if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) + throw new ServletException("Content-Type != multipart/form-data"); + + if (_multiPartInputStream == null) + _multiPartInputStream = (MultiPartInputStream)getAttribute(__MULTIPART_INPUT_STREAM); + + if (_multiPartInputStream == null) + { + MultipartConfigElement config = (MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT); + + if (config == null) + throw new IllegalStateException("No multipart config for servlet"); + + _multiPartInputStream = new MultiPartInputStream(getInputStream(), + getContentType(), config, + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + + setAttribute(__MULTIPART_INPUT_STREAM, _multiPartInputStream); + setAttribute(__MULTIPART_CONTEXT, _context); + Collection<Part> parts = _multiPartInputStream.getParts(); //causes parsing + for (Part p:parts) + { + MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p; + if (mp.getContentDispositionFilename() == null) + { + //Servlet Spec 3.0 pg 23, parts without filenames must be put into init params + String charset = null; + if (mp.getContentType() != null) + charset = MimeTypes.getCharsetFromContentType(new ByteArrayBuffer(mp.getContentType())); + + ByteArrayOutputStream os = null; + InputStream is = mp.getInputStream(); //get the bytes regardless of being in memory or in temp file + try + { + os = new ByteArrayOutputStream(); + IO.copy(is, os); + String content=new String(os.toByteArray(),charset==null?StringUtil.__UTF8:charset); + getParameter(""); //cause params to be evaluated + getParameters().add(mp.getName(), content); + } + finally + { + IO.close(os); + IO.close(is); + } + } + } + } + + return _multiPartInputStream.getParts(); + } + + /* ------------------------------------------------------------ */ + public void login(String username, String password) throws ServletException + { + if (_authentication instanceof Authentication.Deferred) + { + _authentication=((Authentication.Deferred)_authentication).login(username,password,this); + if (_authentication == null) + throw new ServletException(); + } + else + { + throw new ServletException("Authenticated as "+_authentication); + } + } + + /* ------------------------------------------------------------ */ + public void logout() throws ServletException + { + if (_authentication instanceof Authentication.User) + ((Authentication.User)_authentication).logout(); + _authentication=Authentication.UNAUTHENTICATED; + } + + /* ------------------------------------------------------------ */ /** * Merge in a new query string. The query string is merged with the existing parameters and {@link #setParameters(MultiMap)} and * {@link #setQueryString(String)} are called with the result. The merge is according to the rules of the servlet dispatch forward method. |