Mercurial Hosting > luan
view src/org/eclipse/jetty/server/handler/ContextHandler.java @ 993:d9d95acded81
remove ScopedHandler
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Tue, 18 Oct 2016 15:54:54 -0600 |
parents | 0608a6664bee |
children | 4e9d373bf6e9 |
line wrap: on
line source
// // ======================================================================== // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.server.handler; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.security.AccessController; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.EventListener; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.SessionCookieConfig; import javax.servlet.SessionTrackingMode; import javax.servlet.Filter; import javax.servlet.FilterRegistration; import javax.servlet.FilterRegistration.Dynamic; import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpException; import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HandlerContainer; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.util.AttributesMap; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.URIUtil; import org.eclipse.jetty.util.component.AggregateLifeCycle; import org.eclipse.jetty.util.component.Dumpable; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.eclipse.jetty.util.resource.Resource; /* ------------------------------------------------------------ */ /** * ContextHandler. * * This handler wraps a call to handle by setting the context and servlet path, plus setting the context classloader. * * <p> * If the context init parameter "org.eclipse.jetty.server.context.ManagedAttributes" is set to a comma separated list of names, then they are treated as * context attribute names, which if set as attributes are passed to the servers Container so that they may be managed with JMX. * <p> * The maximum size of a form that can be processed by this context is controlled by the system properties org.eclipse.jetty.server.Request.maxFormKeys * and org.eclipse.jetty.server.Request.maxFormContentSize. These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)} * * @org.apache.xbean.XBean description="Creates a basic HTTP context" */ public final class ContextHandler extends HandlerWrapper implements Server.Graceful { private static final Logger LOG = LoggerFactory.getLogger(ContextHandler.class); private static final ThreadLocal<Context> __context = new ThreadLocal<Context>(); /* ------------------------------------------------------------ */ /** * Get the current ServletContext implementation. * * @return ServletContext implementation */ public static ContextHandler getCurrentContext() { Context context = __context.get(); return context==null ? null : context.getContextHandler(); } private Context _scontext; private final AttributesMap _contextAttributes; private String _contextPath = "/"; private Resource _baseResource; private Logger _logger; private boolean _shutdown = false; private volatile int _availability; // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE private final static int __STOPPED = 0, __AVAILABLE = 1, __SHUTDOWN = 2; public ContextHandler() { super(); _scontext = new Context(); _contextAttributes = new AttributesMap(); } public ContextHandler(String contextPath) { this(); setContextPath(contextPath); } public ContextHandler(HandlerContainer parent, String contextPath) { this(); setContextPath(contextPath); if (parent instanceof HandlerWrapper) ((HandlerWrapper)parent).setHandler(this); else if (parent instanceof HandlerCollection) ((HandlerCollection)parent).addHandler(this); } @Override public void dump(Appendable out, String indent) throws IOException { dumpThis(out); dump(out,indent,TypeUtil.asList(getHandlers()),getBeans(), _contextAttributes.getAttributeEntrySet()); } public Context getServletContext() { return _scontext; } public String getContextPath() { return _contextPath; } /* ------------------------------------------------------------ */ /** * Set shutdown status. This field allows for graceful shutdown of a context. A started context may be put into non accepting state so that existing * requests can complete, but no new requests are accepted. * * @param shutdown * true if this context is (not?) accepting new requests */ public void setShutdown(boolean shutdown) { synchronized (this) { _shutdown = shutdown; _availability = isRunning()?(_shutdown?__SHUTDOWN:__AVAILABLE):__STOPPED; } } /* ------------------------------------------------------------ */ public Logger getLogger() { return _logger; } /* ------------------------------------------------------------ */ public void setLogger(Logger logger) { _logger = logger; } /* ------------------------------------------------------------ */ /* * @see org.eclipse.thread.AbstractLifeCycle#doStart() */ @Override protected void doStart() throws Exception { _availability = __STOPPED; if (_contextPath == null) throw new IllegalStateException("Null contextPath"); _logger = LoggerFactory.getLogger(getContextPath()); ClassLoader old_classloader = null; Thread current_thread = null; Context old_context = null; try { old_context = __context.get(); __context.set(_scontext); super.doStart(); synchronized(this) { _availability = _shutdown?__SHUTDOWN:__AVAILABLE; } } finally { __context.set(old_context); } } /* ------------------------------------------------------------ */ /* * @see org.eclipse.thread.AbstractLifeCycle#doStop() */ @Override protected void doStop() throws Exception { _availability = __STOPPED; ClassLoader old_classloader = null; Thread current_thread = null; Context old_context = __context.get(); __context.set(_scontext); try { super.doStop(); } finally { LOG.info("stopped {}",this); __context.set(old_context); } _contextAttributes.clearAttributes(); } private boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException, ServletException { switch (_availability) { case __STOPPED: case __SHUTDOWN: return false; default: if (baseRequest.isHandled()) return false; } // Are we not the root context? if (_contextPath.length() > 1) { // reject requests that are not for us if (!target.startsWith(_contextPath)) return false; if (target.length() > _contextPath.length() && target.charAt(_contextPath.length()) != '/') return false; // redirect null path infos if (_contextPath.length() == target.length()) { // context request must end with / baseRequest.setHandled(true); if (baseRequest.getQueryString() != null) response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString()); else response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH)); return false; } } return true; } @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (LOG.isDebugEnabled()) LOG.debug("scope {}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(),baseRequest.getPathInfo(),this); Context old_context = null; String old_context_path = null; String old_servlet_path = null; String old_path_info = null; ClassLoader old_classloader = null; Thread current_thread = null; String pathInfo = target; old_context = baseRequest.getContext(); // Are we already in this context? if (old_context != _scontext) { if (!checkContext(target,baseRequest,response)) return; if (target.length() > _contextPath.length()) { if (_contextPath.length() > 1) target = target.substring(_contextPath.length()); pathInfo = target; } else if (_contextPath.length() == 1) { target = URIUtil.SLASH; pathInfo = URIUtil.SLASH; } else { target = URIUtil.SLASH; pathInfo = null; } } try { old_context_path = baseRequest.getContextPath(); old_servlet_path = baseRequest.getServletPath(); old_path_info = baseRequest.getPathInfo(); // Update the paths baseRequest.setContext(_scontext); __context.set(_scontext); if (target.startsWith("/")) { if (_contextPath.length() == 1) baseRequest.setContextPath(""); else baseRequest.setContextPath(_contextPath); baseRequest.setServletPath(null); baseRequest.setPathInfo(pathInfo); } if (LOG.isDebugEnabled()) LOG.debug("context={}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(), baseRequest.getPathInfo(),this); try { super.handle(target,baseRequest,request,response); } catch (HttpException e) { LOG.debug("",e); baseRequest.setHandled(true); response.sendError(e.getStatus(),e.getReason()); } } finally { if (old_context != _scontext) { // reset the context and servlet path. baseRequest.setContext(old_context); __context.set(old_context); baseRequest.setContextPath(old_context_path); baseRequest.setServletPath(old_servlet_path); baseRequest.setPathInfo(old_path_info); } } } public void setContextPath(String contextPath) { if (contextPath != null && contextPath.length() > 1 && contextPath.endsWith("/")) throw new IllegalArgumentException("ends with /"); _contextPath = contextPath; } /* ------------------------------------------------------------ */ /** * @return Returns the resourceBase. */ public Resource getBaseResource() { return _baseResource; } /* ------------------------------------------------------------ */ /** * @return Returns the base resource as a string. */ public String getResourceBase() { if (_baseResource == null) return null; return _baseResource.toString(); } /* ------------------------------------------------------------ */ /** * @param base * The resourceBase to set. */ public void setBaseResource(Resource base) { _baseResource = base; } /* ------------------------------------------------------------ */ /** * @param resourceBase * The base resource as a string. */ public void setResourceBase(String resourceBase) { try { setBaseResource(Resource.newResource(resourceBase)); } catch (Exception e) { LOG.warn(e.toString()); LOG.debug("",e); throw new IllegalArgumentException(resourceBase); } } @Override public String toString() { StringBuilder b = new StringBuilder(); Package pkg = getClass().getPackage(); if (pkg != null) { String p = pkg.getName(); if (p != null && p.length() > 0) { String[] ss = p.split("\\."); for (String s : ss) b.append(s.charAt(0)).append('.'); } } b.append(getClass().getSimpleName()); b.append('{').append(getContextPath()).append(',').append(getBaseResource()); b.append('}'); return b.toString(); } /* ------------------------------------------------------------ */ /* */ public Resource getResource(String path) throws MalformedURLException { if (path == null || !path.startsWith(URIUtil.SLASH)) throw new MalformedURLException(path); if (_baseResource == null) return null; try { path = URIUtil.canonicalPath(path); Resource resource = _baseResource.addPath(path); if (resource.getAlias() == null) // check not alias return resource; return null; } catch (Exception e) { LOG.trace("",e); } return null; } public Set<String> getResourcePaths(String path) { try { path = URIUtil.canonicalPath(path); Resource resource = getResource(path); if (resource != null && resource.exists()) { if (!path.endsWith(URIUtil.SLASH)) path = path + URIUtil.SLASH; String[] l = resource.list(); if (l != null) { HashSet<String> set = new HashSet<String>(); for (int i = 0; i < l.length; i++) set.add(path + l[i]); return set; } } } catch (Exception e) { LOG.trace("",e); } return Collections.emptySet(); } /* ------------------------------------------------------------ */ /** * Context. * <p> * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}. * </p> * * */ public final class Context implements ServletContext { protected int _majorVersion = 3; protected int _minorVersion = 0; /* ------------------------------------------------------------ */ protected Context() { } /* ------------------------------------------------------------ */ public ContextHandler getContextHandler() { // TODO reduce visibility of this method return ContextHandler.this; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getContext(java.lang.String) */ @Override public ServletContext getContext(String uripath) { List<ContextHandler> contexts = new ArrayList<ContextHandler>(); Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class); String matched_path = null; for (Handler handler : handlers) { if (handler == null) continue; ContextHandler ch = (ContextHandler)handler; String context_path = ch.getContextPath(); if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/') || "/".equals(context_path)) { if (matched_path == null || context_path.length() > matched_path.length()) { contexts.clear(); matched_path = context_path; } if (matched_path.equals(context_path)) contexts.add(ch); } } if (contexts.size() > 0) return contexts.get(0)._scontext; // try again ignoring virtual hosts matched_path = null; for (Handler handler : handlers) { if (handler == null) continue; ContextHandler ch = (ContextHandler)handler; String context_path = ch.getContextPath(); if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/') || "/".equals(context_path)) { if (matched_path == null || context_path.length() > matched_path.length()) { contexts.clear(); matched_path = context_path; } if (matched_path.equals(context_path)) contexts.add(ch); } } if (contexts.size() > 0) return contexts.get(0)._scontext; return null; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getMajorVersion() */ @Override public int getMajorVersion() { return 3; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getMimeType(java.lang.String) */ @Override public String getMimeType(String file) { return null; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getMinorVersion() */ @Override public int getMinorVersion() { return 0; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String) */ @Override public RequestDispatcher getNamedDispatcher(String name) { throw new UnsupportedOperationException(); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String) */ @Override public RequestDispatcher getRequestDispatcher(String uriInContext) { throw new UnsupportedOperationException(); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getRealPath(java.lang.String) */ @Override public String getRealPath(String path) { if (path == null) return null; if (path.length() == 0) path = URIUtil.SLASH; else if (path.charAt(0) != '/') path = URIUtil.SLASH + path; try { Resource resource = ContextHandler.this.getResource(path); if (resource != null) { File file = resource.getFile(); if (file != null) return file.getCanonicalPath(); } } catch (Exception e) { LOG.trace("",e); } return null; } /* ------------------------------------------------------------ */ @Override public URL getResource(String path) throws MalformedURLException { Resource resource = ContextHandler.this.getResource(path); if (resource != null && resource.exists()) return resource.getURL(); return null; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String) */ @Override public InputStream getResourceAsStream(String path) { try { URL url = getResource(path); if (url == null) return null; Resource r = Resource.newResource(url); return r.getInputStream(); } catch (Exception e) { LOG.trace("",e); return null; } } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) */ @Override public Set getResourcePaths(String path) { return ContextHandler.this.getResourcePaths(path); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getServerInfo() */ @Override public String getServerInfo() { return "jetty/" + Server.version; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getServlet(java.lang.String) */ @Override @Deprecated public Servlet getServlet(String name) throws ServletException { throw new UnsupportedOperationException(); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getServletNames() */ @SuppressWarnings("unchecked") @Override @Deprecated public Enumeration getServletNames() { throw new UnsupportedOperationException(); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getServlets() */ @SuppressWarnings("unchecked") @Override @Deprecated public Enumeration getServlets() { throw new UnsupportedOperationException(); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String) */ @Override public void log(Exception exception, String msg) { _logger.warn(msg,exception); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#log(java.lang.String) */ @Override public void log(String msg) { _logger.info(msg); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable) */ @Override public void log(String message, Throwable throwable) { _logger.warn(message,throwable); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) */ @Override public String getInitParameter(String name) { return null; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getInitParameterNames() */ @SuppressWarnings("unchecked") @Override public Enumeration getInitParameterNames() { return null; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getAttribute(java.lang.String) */ @Override public synchronized Object getAttribute(String name) { if (_contextAttributes != null) return _contextAttributes.getAttribute(name); return null; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getAttributeNames() */ @SuppressWarnings("unchecked") @Override public synchronized Enumeration getAttributeNames() { HashSet<String> set = new HashSet<String>(); if (_contextAttributes != null) { Enumeration<String> e = _contextAttributes.getAttributeNames(); while (e.hasMoreElements()) set.add(e.nextElement()); } return Collections.enumeration(set); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object) */ @Override public synchronized void setAttribute(String name, Object value) { Object old_value = _contextAttributes.getAttribute(name); if (value == null) _contextAttributes.removeAttribute(name); else _contextAttributes.setAttribute(name,value); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) */ @Override public synchronized void removeAttribute(String name) { if (_contextAttributes == null) { // Set it on the handler return; } _contextAttributes.removeAttribute(name); } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getServletContextName() */ @Override public String getServletContextName() { return ContextHandler.this.getContextPath(); } /* ------------------------------------------------------------ */ @Override public String getContextPath() { if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH)) return ""; return _contextPath; } /* ------------------------------------------------------------ */ @Override public String toString() { return "ServletContext@" + ContextHandler.this.toString(); } /* ------------------------------------------------------------ */ @Override public boolean setInitParameter(String name, String value) { return false; } /* ------------------------------------------------------------ */ final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler"; @Override public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass) { throw new UnsupportedOperationException(); } @Override public Dynamic addFilter(String filterName, Filter filter) { throw new UnsupportedOperationException(); } @Override public Dynamic addFilter(String filterName, String className) { throw new UnsupportedOperationException(); } @Override public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass) { throw new UnsupportedOperationException(); } @Override public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { throw new UnsupportedOperationException(); } @Override public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className) { throw new UnsupportedOperationException(); } @Override public <T extends Filter> T createFilter(Class<T> c) throws ServletException { throw new UnsupportedOperationException(); } @Override public <T extends Servlet> T createServlet(Class<T> c) throws ServletException { throw new UnsupportedOperationException(); } @Override public Set<SessionTrackingMode> getDefaultSessionTrackingModes() { throw new UnsupportedOperationException(); } @Override public Set<SessionTrackingMode> getEffectiveSessionTrackingModes() { throw new UnsupportedOperationException(); } @Override public FilterRegistration getFilterRegistration(String filterName) { throw new UnsupportedOperationException(); } @Override public Map<String, ? extends FilterRegistration> getFilterRegistrations() { throw new UnsupportedOperationException(); } @Override public ServletRegistration getServletRegistration(String servletName) { throw new UnsupportedOperationException(); } @Override public Map<String, ? extends ServletRegistration> getServletRegistrations() { throw new UnsupportedOperationException(); } @Override public SessionCookieConfig getSessionCookieConfig() { throw new UnsupportedOperationException(); } @Override public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes) { throw new UnsupportedOperationException(); } @Override public void addListener(String className) { throw new UnsupportedOperationException(); } @Override public <T extends EventListener> void addListener(T t) { throw new UnsupportedOperationException(); } @Override public void addListener(Class<? extends EventListener> listenerClass) { throw new UnsupportedOperationException(); } @Override public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException { try { return clazz.newInstance(); } catch (InstantiationException e) { throw new ServletException(e); } catch (IllegalAccessException e) { throw new ServletException(e); } } @Override public ClassLoader getClassLoader() { AccessController.checkPermission(new RuntimePermission("getClassLoader")); return null; } @Override public int getEffectiveMajorVersion() { return _majorVersion; } @Override public int getEffectiveMinorVersion() { return _minorVersion; } public void setEffectiveMajorVersion (int v) { _majorVersion = v; } public void setEffectiveMinorVersion (int v) { _minorVersion = v; } @Override public JspConfigDescriptor getJspConfigDescriptor() { throw new UnsupportedOperationException(); } public void setJspConfigDescriptor(JspConfigDescriptor d) { throw new UnsupportedOperationException(); } @Override public void declareRoles(String... roleNames) { throw new UnsupportedOperationException(); } } }