2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
19 package org.eclipse.jetty.server.handler;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.lang.reflect.Method;
25 import java.net.MalformedURLException;
28 import java.net.URLClassLoader;
29 import java.security.AccessController;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.Enumeration;
34 import java.util.EventListener;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.Iterator;
38 import java.util.List;
39 import java.util.Locale;
42 import java.util.concurrent.CopyOnWriteArrayList;
43 import java.util.concurrent.Future;
45 import javax.servlet.DispatcherType;
46 import javax.servlet.Filter;
47 import javax.servlet.FilterRegistration;
48 import javax.servlet.FilterRegistration.Dynamic;
49 import javax.servlet.RequestDispatcher;
50 import javax.servlet.Servlet;
51 import javax.servlet.ServletContext;
52 import javax.servlet.ServletContextAttributeEvent;
53 import javax.servlet.ServletContextAttributeListener;
54 import javax.servlet.ServletContextEvent;
55 import javax.servlet.ServletContextListener;
56 import javax.servlet.ServletException;
57 import javax.servlet.ServletRegistration;
58 import javax.servlet.ServletRequestAttributeListener;
59 import javax.servlet.ServletRequestEvent;
60 import javax.servlet.ServletRequestListener;
61 import javax.servlet.SessionCookieConfig;
62 import javax.servlet.SessionTrackingMode;
63 import javax.servlet.descriptor.JspConfigDescriptor;
64 import javax.servlet.http.HttpServletRequest;
65 import javax.servlet.http.HttpServletResponse;
67 import org.eclipse.jetty.http.MimeTypes;
68 import org.eclipse.jetty.server.ClassLoaderDump;
69 import org.eclipse.jetty.server.Dispatcher;
70 import org.eclipse.jetty.server.Handler;
71 import org.eclipse.jetty.server.HandlerContainer;
72 import org.eclipse.jetty.server.Request;
73 import org.eclipse.jetty.server.Server;
74 import org.eclipse.jetty.util.Attributes;
75 import org.eclipse.jetty.util.AttributesMap;
76 import org.eclipse.jetty.util.FutureCallback;
77 import org.eclipse.jetty.util.Loader;
78 import org.eclipse.jetty.util.StringUtil;
79 import org.eclipse.jetty.util.URIUtil;
80 import org.eclipse.jetty.util.annotation.ManagedAttribute;
81 import org.eclipse.jetty.util.annotation.ManagedObject;
82 import org.eclipse.jetty.util.component.Graceful;
83 import org.eclipse.jetty.util.log.Log;
84 import org.eclipse.jetty.util.log.Logger;
85 import org.eclipse.jetty.util.resource.Resource;
87 /* ------------------------------------------------------------ */
91 * This handler wraps a call to handle by setting the context and servlet path, plus setting the context classloader.
94 * 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
95 * context attribute names, which if set as attributes are passed to the servers Container so that they may be managed with JMX.
97 * 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
98 * and org.eclipse.jetty.server.Request.maxFormContentSize. These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)}
100 * This servers executore is made available via a context attributed "org.eclipse.jetty.server.Executor".
102 * @org.apache.xbean.XBean description="Creates a basic HTTP context"
104 @ManagedObject("URI Context")
105 public class ContextHandler extends ScopedHandler implements Attributes, Graceful
107 public final static int SERVLET_MAJOR_VERSION=3;
108 public final static int SERVLET_MINOR_VERSION=1;
109 public static final Class<?>[] SERVLET_LISTENER_TYPES = new Class[] {ServletContextListener.class,
110 ServletContextAttributeListener.class,
111 ServletRequestListener.class,
112 ServletRequestAttributeListener.class};
114 public static final int DEFAULT_LISTENER_TYPE_INDEX = 1;
115 public static final int EXTENDED_LISTENER_TYPE_INDEX = 0;
118 final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler";
120 private static final Logger LOG = Log.getLogger(ContextHandler.class);
122 private static final ThreadLocal<Context> __context = new ThreadLocal<Context>();
125 * If a context attribute with this name is set, it is interpreted as a comma separated list of attribute name. Any other context attributes that are set
126 * with a name from this list will result in a call to {@link #setManagedAttribute(String, Object)}, which typically initiates the creation of a JMX MBean
127 * for the attribute value.
129 public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
131 /* ------------------------------------------------------------ */
133 * Get the current ServletContext implementation.
135 * @return ServletContext implementation
137 public static Context getCurrentContext()
139 return __context.get();
142 /* ------------------------------------------------------------ */
143 public static ContextHandler getContextHandler(ServletContext context)
145 if(context instanceof ContextHandler.Context)
146 return ((ContextHandler.Context)context).getContextHandler();
147 Context c= getCurrentContext();
149 return c.getContextHandler();
154 protected Context _scontext;
155 private final AttributesMap _attributes;
156 private final Map<String, String> _initParams;
157 private ClassLoader _classLoader;
158 private String _contextPath = "/";
160 private String _displayName;
162 private Resource _baseResource;
163 private MimeTypes _mimeTypes;
164 private Map<String, String> _localeEncodingMap;
165 private String[] _welcomeFiles;
166 private ErrorHandler _errorHandler;
167 private String[] _vhosts;
169 private Logger _logger;
170 private boolean _allowNullPathInfo;
171 private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",-1).intValue();
172 private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",-1).intValue();
173 private boolean _compactPath = false;
175 private final List<EventListener> _eventListeners=new CopyOnWriteArrayList<>();
176 private final List<EventListener> _programmaticListeners=new CopyOnWriteArrayList<>();
177 private final List<ServletContextListener> _contextListeners=new CopyOnWriteArrayList<>();
178 private final List<ServletContextAttributeListener> _contextAttributeListeners=new CopyOnWriteArrayList<>();
179 private final List<ServletRequestListener> _requestListeners=new CopyOnWriteArrayList<>();
180 private final List<ServletRequestAttributeListener> _requestAttributeListeners=new CopyOnWriteArrayList<>();
181 private final List<EventListener> _durableListeners = new CopyOnWriteArrayList<>();
182 private Map<String, Object> _managedAttributes;
183 private String[] _protectedTargets;
184 private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
186 public enum Availability { UNAVAILABLE,STARTING,AVAILABLE,SHUTDOWN,};
187 private volatile Availability _availability;
189 /* ------------------------------------------------------------ */
193 public ContextHandler()
196 _scontext = new Context();
197 _attributes = new AttributesMap();
198 _initParams = new HashMap<String, String>();
199 addAliasCheck(new ApproveNonExistentDirectoryAliases());
202 /* ------------------------------------------------------------ */
206 protected ContextHandler(Context context)
210 _attributes = new AttributesMap();
211 _initParams = new HashMap<String, String>();
212 addAliasCheck(new ApproveNonExistentDirectoryAliases());
215 /* ------------------------------------------------------------ */
219 public ContextHandler(String contextPath)
222 setContextPath(contextPath);
225 /* ------------------------------------------------------------ */
229 public ContextHandler(HandlerContainer parent, String contextPath)
232 setContextPath(contextPath);
233 if (parent instanceof HandlerWrapper)
234 ((HandlerWrapper)parent).setHandler(this);
235 else if (parent instanceof HandlerCollection)
236 ((HandlerCollection)parent).addHandler(this);
239 /* ------------------------------------------------------------ */
241 public void dump(Appendable out, String indent) throws IOException
243 dumpBeans(out,indent,
244 Collections.singletonList(new ClassLoaderDump(getClassLoader())),
245 _initParams.entrySet(),
246 _attributes.getAttributeEntrySet(),
247 _scontext.getAttributeEntrySet());
250 /* ------------------------------------------------------------ */
251 public Context getServletContext()
256 /* ------------------------------------------------------------ */
258 * @return the allowNullPathInfo true if /context is not redirected to /context/
260 @ManagedAttribute("Checks if the /context is not redirected to /context/")
261 public boolean getAllowNullPathInfo()
263 return _allowNullPathInfo;
266 /* ------------------------------------------------------------ */
268 * @param allowNullPathInfo
269 * true if /context is not redirected to /context/
271 public void setAllowNullPathInfo(boolean allowNullPathInfo)
273 _allowNullPathInfo = allowNullPathInfo;
276 /* ------------------------------------------------------------ */
278 public void setServer(Server server)
280 super.setServer(server);
281 if (_errorHandler != null)
282 _errorHandler.setServer(server);
285 /* ------------------------------------------------------------ */
287 * Set the virtual hosts for the context. Only requests that have a matching host header or fully qualified URL will be passed to that context with a
288 * virtual host name. A context with no virtual host names or a null virtual host name is available to all requests that are not served by a context with a
289 * matching virtual host name.
292 * Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be
293 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names. Hosts may start with '@', in which case they
294 * will match the {@link Connector#getName()} for the request.
296 public void setVirtualHosts(String[] vhosts)
304 _vhosts = new String[vhosts.length];
305 for (int i = 0; i < vhosts.length; i++)
306 _vhosts[i] = normalizeHostname(vhosts[i]);
310 /* ------------------------------------------------------------ */
311 /** Either set virtual hosts or add to an existing set of virtual hosts.
313 * @param virtualHosts
314 * Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be
315 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names. Host names may start with '@', in which case they
316 * will match the {@link Connector#getName()} for the request.
318 public void addVirtualHosts(String[] virtualHosts)
320 if (virtualHosts == null) // since this is add, we don't null the old ones
326 List<String> currentVirtualHosts = null;
329 currentVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
333 currentVirtualHosts = new ArrayList<String>();
336 for (int i = 0; i < virtualHosts.length; i++)
338 String normVhost = normalizeHostname(virtualHosts[i]);
339 if (!currentVirtualHosts.contains(normVhost))
341 currentVirtualHosts.add(normVhost);
344 _vhosts = currentVirtualHosts.toArray(new String[0]);
348 /* ------------------------------------------------------------ */
350 * Removes an array of virtual host entries, if this removes all entries the _vhosts will be set to null
352 * @param virtualHosts
353 * Array of virtual hosts that this context responds to. A null host name or null/empty array means any hostname is acceptable. Host names may be
354 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
356 public void removeVirtualHosts(String[] virtualHosts)
358 if (virtualHosts == null)
360 return; // do nothing
362 else if ( _vhosts == null || _vhosts.length == 0)
364 return; // do nothing
368 List<String> existingVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
370 for (int i = 0; i < virtualHosts.length; i++)
372 String toRemoveVirtualHost = normalizeHostname(virtualHosts[i]);
373 if (existingVirtualHosts.contains(toRemoveVirtualHost))
375 existingVirtualHosts.remove(toRemoveVirtualHost);
379 if (existingVirtualHosts.isEmpty())
381 _vhosts = null; // if we ended up removing them all, just null out _vhosts
385 _vhosts = existingVirtualHosts.toArray(new String[0]);
390 /* ------------------------------------------------------------ */
392 * Get the virtual hosts for the context. Only requests that have a matching host header or fully qualified URL will be passed to that context with a
393 * virtual host name. A context with no virtual host names or a null virtual host name is available to all requests that are not served by a context with a
394 * matching virtual host name.
396 * @return Array of virtual hosts that this context responds to. A null host name or empty array means any hostname is acceptable. Host names may be String
397 * representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
399 @ManagedAttribute(value="Virtual hosts accepted by the context", readonly=true)
400 public String[] getVirtualHosts()
405 /* ------------------------------------------------------------ */
407 * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
410 public Object getAttribute(String name)
412 return _attributes.getAttribute(name);
415 /* ------------------------------------------------------------ */
417 * @see javax.servlet.ServletContext#getAttributeNames()
420 public Enumeration<String> getAttributeNames()
422 return AttributesMap.getAttributeNamesCopy(_attributes);
425 /* ------------------------------------------------------------ */
427 * @return Returns the attributes.
429 public Attributes getAttributes()
434 /* ------------------------------------------------------------ */
436 * @return Returns the classLoader.
438 public ClassLoader getClassLoader()
443 /* ------------------------------------------------------------ */
445 * Make best effort to extract a file classpath from the context classloader
447 * @return Returns the classLoader.
449 @ManagedAttribute("The file classpath")
450 public String getClassPath()
452 if (_classLoader == null || !(_classLoader instanceof URLClassLoader))
454 URLClassLoader loader = (URLClassLoader)_classLoader;
455 URL[] urls = loader.getURLs();
456 StringBuilder classpath = new StringBuilder();
457 for (int i = 0; i < urls.length; i++)
461 Resource resource = newResource(urls[i]);
462 File file = resource.getFile();
463 if (file != null && file.exists())
465 if (classpath.length() > 0)
466 classpath.append(File.pathSeparatorChar);
467 classpath.append(file.getAbsolutePath());
470 catch (IOException e)
475 if (classpath.length() == 0)
477 return classpath.toString();
480 /* ------------------------------------------------------------ */
482 * @return Returns the _contextPath.
484 @ManagedAttribute("True if URLs are compacted to replace the multiple '/'s with a single '/'")
485 public String getContextPath()
490 /* ------------------------------------------------------------ */
492 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
494 public String getInitParameter(String name)
496 return _initParams.get(name);
499 /* ------------------------------------------------------------ */
502 public String setInitParameter(String name, String value)
504 return _initParams.put(name,value);
507 /* ------------------------------------------------------------ */
509 * @see javax.servlet.ServletContext#getInitParameterNames()
511 public Enumeration<String> getInitParameterNames()
513 return Collections.enumeration(_initParams.keySet());
516 /* ------------------------------------------------------------ */
518 * @return Returns the initParams.
520 @ManagedAttribute("Initial Parameter map for the context")
521 public Map<String, String> getInitParams()
526 /* ------------------------------------------------------------ */
528 * @see javax.servlet.ServletContext#getServletContextName()
530 @ManagedAttribute(value="Display name of the Context", readonly=true)
531 public String getDisplayName()
536 /* ------------------------------------------------------------ */
537 public EventListener[] getEventListeners()
539 return _eventListeners.toArray(new EventListener[_eventListeners.size()]);
542 /* ------------------------------------------------------------ */
544 * Set the context event listeners.
546 * @param eventListeners
547 * the event listeners
548 * @see ServletContextListener
549 * @see ServletContextAttributeListener
550 * @see ServletRequestListener
551 * @see ServletRequestAttributeListener
553 public void setEventListeners(EventListener[] eventListeners)
555 _contextListeners.clear();
556 _contextAttributeListeners.clear();
557 _requestListeners.clear();
558 _requestAttributeListeners.clear();
559 _eventListeners.clear();
561 if (eventListeners!=null)
562 for (EventListener listener : eventListeners)
563 addEventListener(listener);
566 /* ------------------------------------------------------------ */
568 * Add a context event listeners.
570 * @see ServletContextListener
571 * @see ServletContextAttributeListener
572 * @see ServletRequestListener
573 * @see ServletRequestAttributeListener
575 public void addEventListener(EventListener listener)
577 _eventListeners.add(listener);
579 if (!(isStarted() || isStarting()))
580 _durableListeners.add(listener);
582 if (listener instanceof ServletContextListener)
583 _contextListeners.add((ServletContextListener)listener);
585 if (listener instanceof ServletContextAttributeListener)
586 _contextAttributeListeners.add((ServletContextAttributeListener)listener);
588 if (listener instanceof ServletRequestListener)
589 _requestListeners.add((ServletRequestListener)listener);
591 if (listener instanceof ServletRequestAttributeListener)
592 _requestAttributeListeners.add((ServletRequestAttributeListener)listener);
595 /* ------------------------------------------------------------ */
597 * Remove a context event listeners.
599 * @see ServletContextListener
600 * @see ServletContextAttributeListener
601 * @see ServletRequestListener
602 * @see ServletRequestAttributeListener
604 public void removeEventListener(EventListener listener)
606 _eventListeners.remove(listener);
608 if (listener instanceof ServletContextListener)
609 _contextListeners.remove(listener);
611 if (listener instanceof ServletContextAttributeListener)
612 _contextAttributeListeners.remove(listener);
614 if (listener instanceof ServletRequestListener)
615 _requestListeners.remove(listener);
617 if (listener instanceof ServletRequestAttributeListener)
618 _requestAttributeListeners.remove(listener);
621 /* ------------------------------------------------------------ */
623 * Apply any necessary restrictions on a programmatic added listener.
627 protected void addProgrammaticListener (EventListener listener)
629 _programmaticListeners.add(listener);
632 /* ------------------------------------------------------------ */
633 protected boolean isProgrammaticListener(EventListener listener)
635 return _programmaticListeners.contains(listener);
640 /* ------------------------------------------------------------ */
642 * @return true if this context is accepting new requests
644 @ManagedAttribute("true for graceful shutdown, which allows existing requests to complete")
645 public boolean isShutdown()
647 switch(_availability)
656 /* ------------------------------------------------------------ */
658 * 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
659 * requests can complete, but no new requests are accepted.
663 public Future<Void> shutdown()
665 _availability = isRunning() ? Availability.SHUTDOWN : Availability.UNAVAILABLE;
666 return new FutureCallback(true);
669 /* ------------------------------------------------------------ */
671 * @return false if this context is unavailable (sends 503)
673 public boolean isAvailable()
675 return _availability==Availability.AVAILABLE;
678 /* ------------------------------------------------------------ */
680 * Set Available status.
682 public void setAvailable(boolean available)
686 if (available && isRunning())
687 _availability = Availability.AVAILABLE;
688 else if (!available || !isRunning())
689 _availability = Availability.UNAVAILABLE;
693 /* ------------------------------------------------------------ */
694 public Logger getLogger()
699 /* ------------------------------------------------------------ */
700 public void setLogger(Logger logger)
705 /* ------------------------------------------------------------ */
707 * @see org.eclipse.thread.AbstractLifeCycle#doStart()
710 protected void doStart() throws Exception
712 _availability = Availability.STARTING;
714 if (_contextPath == null)
715 throw new IllegalStateException("Null contextPath");
717 _logger = Log.getLogger(getDisplayName() == null?getContextPath():getDisplayName());
718 ClassLoader old_classloader = null;
719 Thread current_thread = null;
720 Context old_context = null;
722 _attributes.setAttribute("org.eclipse.jetty.server.Executor",getServer().getThreadPool());
726 // Set the classloader
727 if (_classLoader != null)
729 current_thread = Thread.currentThread();
730 old_classloader = current_thread.getContextClassLoader();
731 current_thread.setContextClassLoader(_classLoader);
734 if (_mimeTypes == null)
735 _mimeTypes = new MimeTypes();
737 old_context = __context.get();
738 __context.set(_scontext);
740 // defers the calling of super.doStart()
743 _availability = Availability.AVAILABLE;
744 LOG.info("Started {}", this);
748 __context.set(old_context);
750 // reset the classloader
751 if (_classLoader != null && current_thread!=null)
752 current_thread.setContextClassLoader(old_classloader);
756 /* ------------------------------------------------------------ */
758 * Extensible startContext. this method is called from {@link ContextHandler#doStart()} instead of a call to super.doStart(). This allows derived classes to
759 * insert additional handling (Eg configuration) before the call to super.doStart by this method will start contained handlers.
761 * @see org.eclipse.jetty.server.handler.ContextHandler.Context
763 protected void startContext() throws Exception
765 String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
766 if (managedAttributes != null)
768 _managedAttributes = new HashMap<String, Object>();
769 String[] attributes = managedAttributes.split(",");
770 for (String attribute : attributes)
772 _managedAttributes.put(attribute.trim(),null);
775 Enumeration<String> e = _scontext.getAttributeNames();
776 while (e.hasMoreElements())
778 String name = e.nextElement();
779 Object value = _scontext.getAttribute(name);
780 checkManagedAttribute(name,value);
786 // Call context listeners
787 if (!_contextListeners.isEmpty())
789 ServletContextEvent event = new ServletContextEvent(_scontext);
790 for (ServletContextListener listener:_contextListeners)
791 callContextInitialized(listener, event);
795 /* ------------------------------------------------------------ */
796 protected void callContextInitialized (ServletContextListener l, ServletContextEvent e)
798 if (LOG.isDebugEnabled())
799 LOG.debug("contextInitialized: {}->{}",e,l);
800 l.contextInitialized(e);
803 /* ------------------------------------------------------------ */
804 protected void callContextDestroyed (ServletContextListener l, ServletContextEvent e)
806 if (LOG.isDebugEnabled())
807 LOG.debug("contextDestroyed: {}->{}",e,l);
808 l.contextDestroyed(e);
811 /* ------------------------------------------------------------ */
813 * @see org.eclipse.thread.AbstractLifeCycle#doStop()
816 protected void doStop() throws Exception
818 _availability = Availability.UNAVAILABLE;
820 ClassLoader old_classloader = null;
821 Thread current_thread = null;
823 Context old_context = __context.get();
824 __context.set(_scontext);
827 // Set the classloader
828 if (_classLoader != null)
830 current_thread = Thread.currentThread();
831 old_classloader = current_thread.getContextClassLoader();
832 current_thread.setContextClassLoader(_classLoader);
838 if (!_contextListeners.isEmpty())
840 ServletContextEvent event = new ServletContextEvent(_scontext);
841 for (int i = _contextListeners.size(); i-->0;)
842 callContextDestroyed(_contextListeners.get(i),event);
845 //retain only durable listeners
846 setEventListeners(_durableListeners.toArray(new EventListener[_durableListeners.size()]));
847 _durableListeners.clear();
849 if (_errorHandler != null)
850 _errorHandler.stop();
852 Enumeration<String> e = _scontext.getAttributeNames();
853 while (e.hasMoreElements())
855 String name = e.nextElement();
856 checkManagedAttribute(name,null);
859 for (EventListener l : _programmaticListeners)
860 removeEventListener(l);
861 _programmaticListeners.clear();
865 LOG.info("Stopped {}", this);
866 __context.set(old_context);
867 // reset the classloader
868 if (_classLoader != null && current_thread!=null)
869 current_thread.setContextClassLoader(old_classloader);
872 _scontext.clearAttributes();
875 public boolean checkVirtualHost(final Request baseRequest)
877 if (_vhosts != null && _vhosts.length > 0)
879 String vhost = normalizeHostname(baseRequest.getServerName());
881 boolean match = false;
882 boolean connectorName = false;
883 boolean connectorMatch = false;
885 for (String contextVhost:_vhosts)
887 if (contextVhost == null || contextVhost.length()==0)
889 char c=contextVhost.charAt(0);
893 if (contextVhost.startsWith("*."))
894 // wildcard only at the beginning, and only for one additional subdomain level
895 match = match || contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".") + 1,contextVhost.length() - 2);
899 String name=baseRequest.getHttpChannel().getConnector().getName();
900 boolean m=name!=null && contextVhost.length()==name.length()+1 && contextVhost.endsWith(name);
902 connectorMatch = connectorMatch || m;
905 match = match || contextVhost.equalsIgnoreCase(vhost);
909 if (!match || connectorName && !connectorMatch)
915 public boolean checkContextPath(String uri)
917 // Are we not the root context?
918 if (_contextPath.length() > 1)
920 // reject requests that are not for us
921 if (!uri.startsWith(_contextPath))
923 if (uri.length() > _contextPath.length() && uri.charAt(_contextPath.length()) != '/')
929 /* ------------------------------------------------------------ */
931 * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
933 public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException
935 DispatcherType dispatch = baseRequest.getDispatcherType();
938 if (!checkVirtualHost(baseRequest))
941 if (!checkContextPath(target))
944 // Are we not the root context?
945 // redirect null path infos
946 if (!_allowNullPathInfo && _contextPath.length() == target.length() && _contextPath.length()>1)
948 // context request must end with /
949 baseRequest.setHandled(true);
950 if (baseRequest.getQueryString() != null)
951 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
953 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
957 switch (_availability)
961 baseRequest.setHandled(true);
962 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
965 if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
972 /* ------------------------------------------------------------ */
974 * @see org.eclipse.jetty.server.handler.ScopedHandler#doScope(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
975 * javax.servlet.http.HttpServletResponse)
978 public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
980 if (LOG.isDebugEnabled())
981 LOG.debug("scope {}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(),baseRequest.getPathInfo(),this);
983 Context old_context = null;
984 String old_context_path = null;
985 String old_servlet_path = null;
986 String old_path_info = null;
987 ClassLoader old_classloader = null;
988 Thread current_thread = null;
989 String pathInfo = target;
991 DispatcherType dispatch = baseRequest.getDispatcherType();
993 old_context = baseRequest.getContext();
995 // Are we already in this context?
996 if (old_context != _scontext)
999 if (DispatcherType.REQUEST.equals(dispatch) ||
1000 DispatcherType.ASYNC.equals(dispatch) ||
1001 DispatcherType.ERROR.equals(dispatch) && baseRequest.getHttpChannelState().isAsync())
1004 target = URIUtil.compactPath(target);
1005 if (!checkContext(target,baseRequest,response))
1008 if (target.length() > _contextPath.length())
1010 if (_contextPath.length() > 1)
1011 target = target.substring(_contextPath.length());
1014 else if (_contextPath.length() == 1)
1016 target = URIUtil.SLASH;
1017 pathInfo = URIUtil.SLASH;
1021 target = URIUtil.SLASH;
1026 // Set the classloader
1027 if (_classLoader != null)
1029 current_thread = Thread.currentThread();
1030 old_classloader = current_thread.getContextClassLoader();
1031 current_thread.setContextClassLoader(_classLoader);
1037 old_context_path = baseRequest.getContextPath();
1038 old_servlet_path = baseRequest.getServletPath();
1039 old_path_info = baseRequest.getPathInfo();
1042 baseRequest.setContext(_scontext);
1043 __context.set(_scontext);
1044 if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/"))
1046 if (_contextPath.length() == 1)
1047 baseRequest.setContextPath("");
1049 baseRequest.setContextPath(_contextPath);
1050 baseRequest.setServletPath(null);
1051 baseRequest.setPathInfo(pathInfo);
1054 if (LOG.isDebugEnabled())
1055 LOG.debug("context={}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(), baseRequest.getPathInfo(),this);
1057 // start manual inline of nextScope(target,baseRequest,request,response);
1059 nextScope(target,baseRequest,request,response);
1060 else if (_nextScope != null)
1061 _nextScope.doScope(target,baseRequest,request,response);
1062 else if (_outerScope != null)
1063 _outerScope.doHandle(target,baseRequest,request,response);
1065 doHandle(target,baseRequest,request,response);
1066 // end manual inline (pathentic attempt to reduce stack depth)
1070 if (old_context != _scontext)
1072 // reset the classloader
1073 if (_classLoader != null && current_thread!=null)
1075 current_thread.setContextClassLoader(old_classloader);
1078 // reset the context and servlet path.
1079 baseRequest.setContext(old_context);
1080 __context.set(old_context);
1081 baseRequest.setContextPath(old_context_path);
1082 baseRequest.setServletPath(old_servlet_path);
1083 baseRequest.setPathInfo(old_path_info);
1088 /* ------------------------------------------------------------ */
1090 * @see org.eclipse.jetty.server.handler.ScopedHandler#doHandle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
1091 * javax.servlet.http.HttpServletResponse)
1094 public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
1096 final DispatcherType dispatch = baseRequest.getDispatcherType();
1097 final boolean new_context = baseRequest.takeNewContext();
1102 // Handle the REALLY SILLY request events!
1103 if (!_requestAttributeListeners.isEmpty())
1104 for (ServletRequestAttributeListener l :_requestAttributeListeners)
1105 baseRequest.addEventListener(l);
1107 if (!_requestListeners.isEmpty())
1109 final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
1110 for (ServletRequestListener l : _requestListeners)
1111 l.requestInitialized(sre);
1115 if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target))
1117 response.sendError(HttpServletResponse.SC_NOT_FOUND);
1118 baseRequest.setHandled(true);
1122 // start manual inline of nextHandle(target,baseRequest,request,response);
1123 // noinspection ConstantIfStatement
1125 nextHandle(target,baseRequest,request,response);
1126 else if (_nextScope != null && _nextScope == _handler)
1127 _nextScope.doHandle(target,baseRequest,request,response);
1128 else if (_handler != null)
1129 _handler.handle(target,baseRequest,request,response);
1130 // end manual inline
1134 // Handle more REALLY SILLY request events!
1137 if (!_requestListeners.isEmpty())
1139 final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
1140 for (int i=_requestListeners.size();i-->0;)
1141 _requestListeners.get(i).requestDestroyed(sre);
1144 if (!_requestAttributeListeners.isEmpty())
1146 for (int i=_requestAttributeListeners.size();i-->0;)
1147 baseRequest.removeEventListener(_requestAttributeListeners.get(i));
1153 /* ------------------------------------------------------------ */
1155 * Handle a runnable in this context
1157 public void handle(Runnable runnable)
1159 ClassLoader old_classloader = null;
1160 Thread current_thread = null;
1161 Context old_context = null;
1164 old_context = __context.get();
1165 __context.set(_scontext);
1167 // Set the classloader
1168 if (_classLoader != null)
1170 current_thread = Thread.currentThread();
1171 old_classloader = current_thread.getContextClassLoader();
1172 current_thread.setContextClassLoader(_classLoader);
1179 __context.set(old_context);
1180 if (old_classloader != null && current_thread!=null)
1182 current_thread.setContextClassLoader(old_classloader);
1187 /* ------------------------------------------------------------ */
1189 * Check the target. Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a target within a context is determined. If
1190 * the target is protected, 404 is returned.
1192 /* ------------------------------------------------------------ */
1193 public boolean isProtectedTarget(String target)
1195 if (target == null || _protectedTargets == null)
1198 while (target.startsWith("//"))
1199 target=URIUtil.compactPath(target);
1201 for (int i=0; i<_protectedTargets.length; i++)
1203 String t=_protectedTargets[i];
1204 if (StringUtil.startsWithIgnoreCase(target,t))
1206 if (target.length()==t.length())
1209 // Check that the target prefix really is a path segment, thus
1210 // it can end with /, a query, a target or a parameter
1211 char c=target.charAt(t.length());
1212 if (c=='/'||c=='?'||c=='#'||c==';')
1220 /* ------------------------------------------------------------ */
1222 * @param targets Array of URL prefix. Each prefix is in the form /path and will match
1223 * either /path exactly or /path/anything
1225 public void setProtectedTargets (String[] targets)
1227 if (targets == null)
1229 _protectedTargets = null;
1233 _protectedTargets = Arrays.copyOf(targets, targets.length);
1236 /* ------------------------------------------------------------ */
1237 public String[] getProtectedTargets()
1239 if (_protectedTargets == null)
1242 return Arrays.copyOf(_protectedTargets, _protectedTargets.length);
1246 /* ------------------------------------------------------------ */
1248 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1251 public void removeAttribute(String name)
1253 checkManagedAttribute(name,null);
1254 _attributes.removeAttribute(name);
1257 /* ------------------------------------------------------------ */
1259 * Set a context attribute. Attributes set via this API cannot be overriden by the ServletContext.setAttribute API. Their lifecycle spans the stop/start of
1260 * a context. No attribute listener events are triggered by this API.
1262 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1265 public void setAttribute( String name, Object value)
1267 checkManagedAttribute(name,value);
1268 _attributes.setAttribute(name,value);
1271 /* ------------------------------------------------------------ */
1274 * The attributes to set.
1276 public void setAttributes(Attributes attributes)
1278 _attributes.clearAttributes();
1279 _attributes.addAll(attributes);
1280 Enumeration<String> e = _attributes.getAttributeNames();
1281 while (e.hasMoreElements())
1283 String name = e.nextElement();
1284 checkManagedAttribute(name,attributes.getAttribute(name));
1288 /* ------------------------------------------------------------ */
1290 public void clearAttributes()
1292 Enumeration<String> e = _attributes.getAttributeNames();
1293 while (e.hasMoreElements())
1295 String name = e.nextElement();
1296 checkManagedAttribute(name,null);
1298 _attributes.clearAttributes();
1301 /* ------------------------------------------------------------ */
1302 public void checkManagedAttribute(String name, Object value)
1304 if (_managedAttributes != null && _managedAttributes.containsKey(name))
1306 setManagedAttribute(name,value);
1310 /* ------------------------------------------------------------ */
1311 public void setManagedAttribute(String name, Object value)
1313 Object old = _managedAttributes.put(name,value);
1314 updateBean(old,value);
1317 /* ------------------------------------------------------------ */
1319 * @param classLoader
1320 * The classLoader to set.
1322 public void setClassLoader(ClassLoader classLoader)
1324 _classLoader = classLoader;
1327 /* ------------------------------------------------------------ */
1329 * @param contextPath
1330 * The _contextPath to set.
1332 public void setContextPath(String contextPath)
1334 if (contextPath == null)
1335 throw new IllegalArgumentException("null contextPath");
1337 if (contextPath.endsWith("/*"))
1339 LOG.warn(this+" contextPath ends with /*");
1340 contextPath=contextPath.substring(0,contextPath.length()-2);
1342 else if (contextPath.length()>1 && contextPath.endsWith("/"))
1344 LOG.warn(this+" contextPath ends with /");
1345 contextPath=contextPath.substring(0,contextPath.length()-1);
1348 if (contextPath.length()==0)
1350 LOG.warn("Empty contextPath");
1354 _contextPath = contextPath;
1356 if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
1358 Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
1359 for (int h = 0; contextCollections != null && h < contextCollections.length; h++)
1360 ((ContextHandlerCollection)contextCollections[h]).mapContexts();
1364 /* ------------------------------------------------------------ */
1366 * @param servletContextName
1367 * The servletContextName to set.
1369 public void setDisplayName(String servletContextName)
1371 _displayName = servletContextName;
1374 /* ------------------------------------------------------------ */
1376 * @return Returns the resourceBase.
1378 public Resource getBaseResource()
1380 if (_baseResource == null)
1382 return _baseResource;
1385 /* ------------------------------------------------------------ */
1387 * @return Returns the base resource as a string.
1389 @ManagedAttribute("document root for context")
1390 public String getResourceBase()
1392 if (_baseResource == null)
1394 return _baseResource.toString();
1397 /* ------------------------------------------------------------ */
1399 * Set the base resource for this context.
1400 * @param base The resource used as the base for all static content of this context.
1401 * @see #setResourceBase(String)
1403 public void setBaseResource(Resource base)
1405 _baseResource = base;
1408 /* ------------------------------------------------------------ */
1410 * Set the base resource for this context.
1411 * @param resourceBase A string representing the base resource for the context. Any string accepted
1412 * by {@link Resource#newResource(String)} may be passed and the call is equivalent to
1413 * <code>setBaseResource(newResource(resourceBase));</code>
1415 public void setResourceBase(String resourceBase)
1419 setBaseResource(newResource(resourceBase));
1423 LOG.warn(e.toString());
1425 throw new IllegalArgumentException(resourceBase);
1429 /* ------------------------------------------------------------ */
1431 * @return Returns the mimeTypes.
1433 public MimeTypes getMimeTypes()
1435 if (_mimeTypes == null)
1436 _mimeTypes = new MimeTypes();
1440 /* ------------------------------------------------------------ */
1443 * The mimeTypes to set.
1445 public void setMimeTypes(MimeTypes mimeTypes)
1447 _mimeTypes = mimeTypes;
1450 /* ------------------------------------------------------------ */
1453 public void setWelcomeFiles(String[] files)
1455 _welcomeFiles = files;
1458 /* ------------------------------------------------------------ */
1460 * @return The names of the files which the server should consider to be welcome files in this context.
1461 * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
1462 * @see #setWelcomeFiles
1464 @ManagedAttribute(value="Partial URIs of directory welcome files", readonly=true)
1465 public String[] getWelcomeFiles()
1467 return _welcomeFiles;
1470 /* ------------------------------------------------------------ */
1472 * @return Returns the errorHandler.
1474 @ManagedAttribute("The error handler to use for the context")
1475 public ErrorHandler getErrorHandler()
1477 return _errorHandler;
1480 /* ------------------------------------------------------------ */
1482 * @param errorHandler
1483 * The errorHandler to set.
1485 public void setErrorHandler(ErrorHandler errorHandler)
1487 if (errorHandler != null)
1488 errorHandler.setServer(getServer());
1489 updateBean(_errorHandler,errorHandler);
1490 _errorHandler = errorHandler;
1493 /* ------------------------------------------------------------ */
1494 @ManagedAttribute("The maximum content size")
1495 public int getMaxFormContentSize()
1497 return _maxFormContentSize;
1500 /* ------------------------------------------------------------ */
1502 * Set the maximum size of a form post, to protect against DOS attacks from large forms.
1505 public void setMaxFormContentSize(int maxSize)
1507 _maxFormContentSize = maxSize;
1510 /* ------------------------------------------------------------ */
1511 public int getMaxFormKeys()
1513 return _maxFormKeys;
1516 /* ------------------------------------------------------------ */
1518 * Set the maximum number of form Keys to protect against DOS attack from crafted hash keys.
1521 public void setMaxFormKeys(int max)
1526 /* ------------------------------------------------------------ */
1528 * @return True if URLs are compacted to replace multiple '/'s with a single '/'
1530 public boolean isCompactPath()
1532 return _compactPath;
1535 /* ------------------------------------------------------------ */
1537 * @param compactPath
1538 * True if URLs are compacted to replace multiple '/'s with a single '/'
1540 public void setCompactPath(boolean compactPath)
1542 _compactPath = compactPath;
1545 /* ------------------------------------------------------------ */
1547 public String toString()
1549 String[] vhosts = getVirtualHosts();
1551 StringBuilder b = new StringBuilder();
1553 Package pkg = getClass().getPackage();
1556 String p = pkg.getName();
1557 if (p != null && p.length() > 0)
1559 String[] ss = p.split("\\.");
1561 b.append(s.charAt(0)).append('.');
1564 b.append(getClass().getSimpleName()).append('@').append(Integer.toString(hashCode(),16));
1565 b.append('{').append(getContextPath()).append(',').append(getBaseResource()).append(',').append(_availability);
1567 if (vhosts != null && vhosts.length > 0)
1568 b.append(',').append(vhosts[0]);
1571 return b.toString();
1574 /* ------------------------------------------------------------ */
1575 public synchronized Class<?> loadClass(String className) throws ClassNotFoundException
1577 if (className == null)
1580 if (_classLoader == null)
1581 return Loader.loadClass(this.getClass(),className);
1583 return _classLoader.loadClass(className);
1586 /* ------------------------------------------------------------ */
1587 public void addLocaleEncoding(String locale, String encoding)
1589 if (_localeEncodingMap == null)
1590 _localeEncodingMap = new HashMap<String, String>();
1591 _localeEncodingMap.put(locale,encoding);
1594 /* ------------------------------------------------------------ */
1595 public String getLocaleEncoding(String locale)
1597 if (_localeEncodingMap == null)
1599 String encoding = _localeEncodingMap.get(locale);
1603 /* ------------------------------------------------------------ */
1605 * Get the character encoding for a locale. The full locale name is first looked up in the map of encodings. If no encoding is found, then the locale
1606 * language is looked up.
1609 * a <code>Locale</code> value
1610 * @return a <code>String</code> representing the character encoding for the locale or null if none found.
1612 public String getLocaleEncoding(Locale locale)
1614 if (_localeEncodingMap == null)
1616 String encoding = _localeEncodingMap.get(locale.toString());
1617 if (encoding == null)
1618 encoding = _localeEncodingMap.get(locale.getLanguage());
1622 /* ------------------------------------------------------------ */
1624 * Get all of the locale encodings
1626 * @return a map of all the locale encodings: key is name of the locale and value is the char encoding
1628 public Map<String,String> getLocaleEncodings()
1630 if (_localeEncodingMap == null)
1632 return Collections.unmodifiableMap(_localeEncodingMap);
1635 /* ------------------------------------------------------------ */
1638 public Resource getResource(String path) throws MalformedURLException
1640 if (path == null || !path.startsWith(URIUtil.SLASH))
1641 throw new MalformedURLException(path);
1643 if (_baseResource == null)
1648 path = URIUtil.canonicalPath(path);
1649 Resource resource = _baseResource.addPath(path);
1651 if (checkAlias(path,resource))
1663 /* ------------------------------------------------------------ */
1667 * @return True if the alias is OK
1669 public boolean checkAlias(String path, Resource resource)
1671 // Is the resource aliased?
1672 if (resource.getAlias() != null)
1674 if (LOG.isDebugEnabled())
1675 LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
1678 for (Iterator<AliasCheck> i=_aliasChecks.iterator();i.hasNext();)
1680 AliasCheck check = i.next();
1681 if (check.check(path,resource))
1683 if (LOG.isDebugEnabled())
1684 LOG.debug("Aliased resource: " + resource + " approved by " + check);
1693 /* ------------------------------------------------------------ */
1695 * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
1697 public Resource newResource(URL url) throws IOException
1699 return Resource.newResource(url);
1702 /* ------------------------------------------------------------ */
1704 * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
1706 public Resource newResource(URI uri) throws IOException
1708 return Resource.newResource(uri);
1711 /* ------------------------------------------------------------ */
1713 * Convert a URL or path to a Resource. The default implementation is a wrapper for {@link Resource#newResource(String)}.
1716 * The URL or path to convert
1717 * @return The Resource for the URL/path
1718 * @throws IOException
1719 * The Resource could not be created.
1721 public Resource newResource(String urlOrPath) throws IOException
1723 return Resource.newResource(urlOrPath);
1726 /* ------------------------------------------------------------ */
1729 public Set<String> getResourcePaths(String path)
1733 path = URIUtil.canonicalPath(path);
1734 Resource resource = getResource(path);
1736 if (resource != null && resource.exists())
1738 if (!path.endsWith(URIUtil.SLASH))
1739 path = path + URIUtil.SLASH;
1741 String[] l = resource.list();
1744 HashSet<String> set = new HashSet<String>();
1745 for (int i = 0; i < l.length; i++)
1746 set.add(path + l[i]);
1755 return Collections.emptySet();
1758 /* ------------------------------------------------------------ */
1759 private String normalizeHostname(String host)
1764 if (host.endsWith("."))
1765 return host.substring(0,host.length() - 1);
1770 /* ------------------------------------------------------------ */
1772 * Add an AliasCheck instance to possibly permit aliased resources
1773 * @param check The alias checker
1775 public void addAliasCheck(AliasCheck check)
1777 _aliasChecks.add(check);
1780 /* ------------------------------------------------------------ */
1782 * @return Mutable list of Alias checks
1784 public List<AliasCheck> getAliasChecks()
1786 return _aliasChecks;
1789 /* ------------------------------------------------------------ */
1791 * @param checks list of AliasCheck instances
1793 public void setAliasChecks(List<AliasCheck> checks)
1795 _aliasChecks.clear();
1796 _aliasChecks.addAll(checks);
1799 /* ------------------------------------------------------------ */
1803 * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}.
1808 public class Context extends NoContext
1810 protected boolean _enabled = true; //whether or not the dynamic API is enabled for callers
1811 protected boolean _extendedListenerTypes = false;
1814 /* ------------------------------------------------------------ */
1819 /* ------------------------------------------------------------ */
1820 public ContextHandler getContextHandler()
1822 return ContextHandler.this;
1825 /* ------------------------------------------------------------ */
1827 * @see javax.servlet.ServletContext#getContext(java.lang.String)
1830 public ServletContext getContext(String uripath)
1832 List<ContextHandler> contexts = new ArrayList<ContextHandler>();
1833 Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class);
1834 String matched_path = null;
1836 for (Handler handler : handlers)
1838 if (handler == null)
1840 ContextHandler ch = (ContextHandler)handler;
1841 String context_path = ch.getContextPath();
1843 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
1844 || "/".equals(context_path))
1846 // look first for vhost matching context only
1847 if (getVirtualHosts() != null && getVirtualHosts().length > 0)
1849 if (ch.getVirtualHosts() != null && ch.getVirtualHosts().length > 0)
1851 for (String h1 : getVirtualHosts())
1852 for (String h2 : ch.getVirtualHosts())
1855 if (matched_path == null || context_path.length() > matched_path.length())
1858 matched_path = context_path;
1861 if (matched_path.equals(context_path))
1868 if (matched_path == null || context_path.length() > matched_path.length())
1871 matched_path = context_path;
1874 if (matched_path.equals(context_path))
1880 if (contexts.size() > 0)
1881 return contexts.get(0)._scontext;
1883 // try again ignoring virtual hosts
1884 matched_path = null;
1885 for (Handler handler : handlers)
1887 if (handler == null)
1889 ContextHandler ch = (ContextHandler)handler;
1890 String context_path = ch.getContextPath();
1892 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
1893 || "/".equals(context_path))
1895 if (matched_path == null || context_path.length() > matched_path.length())
1898 matched_path = context_path;
1901 if (matched_path != null && matched_path.equals(context_path))
1906 if (contexts.size() > 0)
1907 return contexts.get(0)._scontext;
1911 /* ------------------------------------------------------------ */
1913 * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
1916 public String getMimeType(String file)
1918 if (_mimeTypes == null)
1920 return _mimeTypes.getMimeByExtension(file);
1923 /* ------------------------------------------------------------ */
1925 * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
1928 public RequestDispatcher getRequestDispatcher(String uriInContext)
1930 if (uriInContext == null)
1933 if (!uriInContext.startsWith("/"))
1938 String query = null;
1940 if ((q = uriInContext.indexOf('?')) > 0)
1942 query = uriInContext.substring(q + 1);
1943 uriInContext = uriInContext.substring(0,q);
1946 String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
1947 if (pathInContext!=null)
1949 String uri = URIUtil.addPaths(getContextPath(),uriInContext);
1950 ContextHandler context = ContextHandler.this;
1951 return new Dispatcher(context,uri,pathInContext,query);
1961 /* ------------------------------------------------------------ */
1963 * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
1966 public String getRealPath(String path)
1970 if (path.length() == 0)
1971 path = URIUtil.SLASH;
1972 else if (path.charAt(0) != '/')
1973 path = URIUtil.SLASH + path;
1977 Resource resource = ContextHandler.this.getResource(path);
1978 if (resource != null)
1980 File file = resource.getFile();
1982 return file.getCanonicalPath();
1993 /* ------------------------------------------------------------ */
1995 public URL getResource(String path) throws MalformedURLException
1997 Resource resource = ContextHandler.this.getResource(path);
1998 if (resource != null && resource.exists())
1999 return resource.getURL();
2003 /* ------------------------------------------------------------ */
2005 * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
2008 public InputStream getResourceAsStream(String path)
2012 URL url = getResource(path);
2015 Resource r = Resource.newResource(url);
2016 return r.getInputStream();
2025 /* ------------------------------------------------------------ */
2027 * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
2030 public Set<String> getResourcePaths(String path)
2032 return ContextHandler.this.getResourcePaths(path);
2035 /* ------------------------------------------------------------ */
2037 * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String)
2040 public void log(Exception exception, String msg)
2042 _logger.warn(msg,exception);
2045 /* ------------------------------------------------------------ */
2047 * @see javax.servlet.ServletContext#log(java.lang.String)
2050 public void log(String msg)
2055 /* ------------------------------------------------------------ */
2057 * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable)
2060 public void log(String message, Throwable throwable)
2062 _logger.warn(message,throwable);
2065 /* ------------------------------------------------------------ */
2067 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
2070 public String getInitParameter(String name)
2072 return ContextHandler.this.getInitParameter(name);
2075 /* ------------------------------------------------------------ */
2077 * @see javax.servlet.ServletContext#getInitParameterNames()
2080 public Enumeration<String> getInitParameterNames()
2082 return ContextHandler.this.getInitParameterNames();
2085 /* ------------------------------------------------------------ */
2087 * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
2090 public synchronized Object getAttribute(String name)
2092 Object o = ContextHandler.this.getAttribute(name);
2094 o = super.getAttribute(name);
2098 /* ------------------------------------------------------------ */
2100 * @see javax.servlet.ServletContext#getAttributeNames()
2103 public synchronized Enumeration<String> getAttributeNames()
2105 HashSet<String> set = new HashSet<String>();
2106 Enumeration<String> e = super.getAttributeNames();
2107 while (e.hasMoreElements())
2108 set.add(e.nextElement());
2109 e = _attributes.getAttributeNames();
2110 while (e.hasMoreElements())
2111 set.add(e.nextElement());
2113 return Collections.enumeration(set);
2116 /* ------------------------------------------------------------ */
2118 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
2121 public synchronized void setAttribute(String name, Object value)
2123 checkManagedAttribute(name,value);
2124 Object old_value = super.getAttribute(name);
2127 super.removeAttribute(name);
2129 super.setAttribute(name,value);
2131 if (!_contextAttributeListeners.isEmpty())
2133 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value == null?value:old_value);
2135 for (ServletContextAttributeListener l : _contextAttributeListeners)
2137 if (old_value == null)
2138 l.attributeAdded(event);
2139 else if (value == null)
2140 l.attributeRemoved(event);
2142 l.attributeReplaced(event);
2147 /* ------------------------------------------------------------ */
2149 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
2152 public synchronized void removeAttribute(String name)
2154 checkManagedAttribute(name,null);
2156 Object old_value = super.getAttribute(name);
2157 super.removeAttribute(name);
2158 if (old_value != null &&!_contextAttributeListeners.isEmpty())
2160 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value);
2162 for (ServletContextAttributeListener l : _contextAttributeListeners)
2163 l.attributeRemoved(event);
2167 /* ------------------------------------------------------------ */
2169 * @see javax.servlet.ServletContext#getServletContextName()
2172 public String getServletContextName()
2174 String name = ContextHandler.this.getDisplayName();
2176 name = ContextHandler.this.getContextPath();
2180 /* ------------------------------------------------------------ */
2182 public String getContextPath()
2184 if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH))
2187 return _contextPath;
2190 /* ------------------------------------------------------------ */
2192 public String toString()
2194 return "ServletContext@" + ContextHandler.this.toString();
2197 /* ------------------------------------------------------------ */
2199 public boolean setInitParameter(String name, String value)
2201 if (ContextHandler.this.getInitParameter(name) != null)
2203 ContextHandler.this.getInitParams().put(name,value);
2208 public void addListener(String className)
2211 throw new UnsupportedOperationException();
2215 @SuppressWarnings("unchecked")
2216 Class<? extends EventListener> clazz = (Class<? extends EventListener>) (_classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className));
2219 catch (ClassNotFoundException e)
2221 throw new IllegalArgumentException(e);
2226 public <T extends EventListener> void addListener(T t)
2229 throw new UnsupportedOperationException();
2231 checkListener(t.getClass());
2233 ContextHandler.this.addEventListener(t);
2234 ContextHandler.this.addProgrammaticListener(t);
2238 public void addListener(Class<? extends EventListener> listenerClass)
2241 throw new UnsupportedOperationException();
2245 EventListener e = createListener(listenerClass);
2248 catch (ServletException e)
2250 throw new IllegalArgumentException(e);
2255 public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
2259 return createInstance(clazz);
2263 throw new ServletException(e);
2268 public void checkListener (Class<? extends EventListener> listener) throws IllegalStateException
2271 int startIndex = (isExtendedListenerTypes()?EXTENDED_LISTENER_TYPE_INDEX:DEFAULT_LISTENER_TYPE_INDEX);
2272 for (int i=startIndex;i<SERVLET_LISTENER_TYPES.length;i++)
2274 if (SERVLET_LISTENER_TYPES[i].isAssignableFrom(listener))
2281 throw new IllegalArgumentException("Inappropriate listener class "+listener.getName());
2284 public void setExtendedListenerTypes (boolean extended)
2286 _extendedListenerTypes = extended;
2289 public boolean isExtendedListenerTypes()
2291 return _extendedListenerTypes;
2296 public ClassLoader getClassLoader()
2299 throw new UnsupportedOperationException();
2301 //no security manager just return the classloader
2302 if (System.getSecurityManager() == null)
2303 return _classLoader;
2306 //check to see if the classloader of the caller is the same as the context
2307 //classloader, or a parent of it
2310 Class<?> reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection");
2311 Method getCallerClass = reflect.getMethod("getCallerClass", Integer.TYPE);
2312 Class<?> caller = (Class<?>)getCallerClass.invoke(null, 2);
2315 ClassLoader callerLoader = caller.getClassLoader();
2316 while (!ok && callerLoader != null)
2318 if (callerLoader == _classLoader)
2321 callerLoader = callerLoader.getParent();
2325 return _classLoader;
2329 LOG.warn("Unable to check classloader of caller",e);
2332 AccessController.checkPermission(new RuntimePermission("getClassLoader"));
2333 return _classLoader;
2338 public JspConfigDescriptor getJspConfigDescriptor()
2340 LOG.warn(__unimplmented);
2344 public void setJspConfigDescriptor(JspConfigDescriptor d)
2350 public void declareRoles(String... roleNames)
2353 throw new IllegalStateException ();
2355 throw new UnsupportedOperationException();
2358 public void setEnabled(boolean enabled)
2363 public boolean isEnabled()
2370 public <T> T createInstance (Class<T> clazz) throws Exception
2372 T o = clazz.newInstance();
2378 public static class NoContext extends AttributesMap implements ServletContext
2380 private int _effectiveMajorVersion = SERVLET_MAJOR_VERSION;
2381 private int _effectiveMinorVersion = SERVLET_MINOR_VERSION;
2383 /* ------------------------------------------------------------ */
2389 public ServletContext getContext(String uripath)
2395 public int getMajorVersion()
2397 return SERVLET_MAJOR_VERSION;
2401 public String getMimeType(String file)
2407 public int getMinorVersion()
2409 return SERVLET_MINOR_VERSION;
2413 public RequestDispatcher getNamedDispatcher(String name)
2419 public RequestDispatcher getRequestDispatcher(String uriInContext)
2425 public String getRealPath(String path)
2431 public URL getResource(String path) throws MalformedURLException
2437 public InputStream getResourceAsStream(String path)
2443 public Set<String> getResourcePaths(String path)
2449 public String getServerInfo()
2451 // NOTE: DO NOT CHANGE
2452 // this is used by weld to detect Jetty
2453 // implementation version
2454 // See: https://github.com/weld/core/blob/master/environments/servlet/core/src/main/java/org/jboss/weld/environment/jetty/JettyContainer.java
2455 // and its touch(ContainerContext) method
2456 return "jetty/" + Server.getVersion();
2461 public Servlet getServlet(String name) throws ServletException
2466 @SuppressWarnings("unchecked")
2469 public Enumeration<String> getServletNames()
2471 return Collections.enumeration(Collections.EMPTY_LIST);
2474 @SuppressWarnings("unchecked")
2477 public Enumeration<Servlet> getServlets()
2479 return Collections.enumeration(Collections.EMPTY_LIST);
2483 public void log(Exception exception, String msg)
2485 LOG.warn(msg,exception);
2489 public void log(String msg)
2495 public void log(String message, Throwable throwable)
2497 LOG.warn(message,throwable);
2501 public String getInitParameter(String name)
2506 @SuppressWarnings("unchecked")
2508 public Enumeration<String> getInitParameterNames()
2510 return Collections.enumeration(Collections.EMPTY_LIST);
2515 public String getServletContextName()
2517 return "No Context";
2521 public String getContextPath()
2528 public boolean setInitParameter(String name, String value)
2534 public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
2536 LOG.warn(__unimplmented);
2541 public Dynamic addFilter(String filterName, Filter filter)
2543 LOG.warn(__unimplmented);
2548 public Dynamic addFilter(String filterName, String className)
2550 LOG.warn(__unimplmented);
2555 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
2557 LOG.warn(__unimplmented);
2562 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
2564 LOG.warn(__unimplmented);
2569 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className)
2571 LOG.warn(__unimplmented);
2576 public <T extends Filter> T createFilter(Class<T> c) throws ServletException
2578 LOG.warn(__unimplmented);
2583 public <T extends Servlet> T createServlet(Class<T> c) throws ServletException
2585 LOG.warn(__unimplmented);
2590 public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
2592 LOG.warn(__unimplmented);
2597 public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
2599 LOG.warn(__unimplmented);
2604 public FilterRegistration getFilterRegistration(String filterName)
2606 LOG.warn(__unimplmented);
2611 public Map<String, ? extends FilterRegistration> getFilterRegistrations()
2613 LOG.warn(__unimplmented);
2618 public ServletRegistration getServletRegistration(String servletName)
2620 LOG.warn(__unimplmented);
2625 public Map<String, ? extends ServletRegistration> getServletRegistrations()
2627 LOG.warn(__unimplmented);
2632 public SessionCookieConfig getSessionCookieConfig()
2634 LOG.warn(__unimplmented);
2639 public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
2641 LOG.warn(__unimplmented);
2645 public void addListener(String className)
2647 LOG.warn(__unimplmented);
2651 public <T extends EventListener> void addListener(T t)
2653 LOG.warn(__unimplmented);
2657 public void addListener(Class<? extends EventListener> listenerClass)
2659 LOG.warn(__unimplmented);
2663 public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
2667 return clazz.newInstance();
2669 catch (InstantiationException e)
2671 throw new ServletException(e);
2673 catch (IllegalAccessException e)
2675 throw new ServletException(e);
2680 public ClassLoader getClassLoader()
2682 AccessController.checkPermission(new RuntimePermission("getClassLoader"));
2683 return ContextHandler.class.getClassLoader();
2687 public int getEffectiveMajorVersion()
2689 return _effectiveMajorVersion;
2693 public int getEffectiveMinorVersion()
2695 return _effectiveMinorVersion;
2698 public void setEffectiveMajorVersion (int v)
2700 _effectiveMajorVersion = v;
2703 public void setEffectiveMinorVersion (int v)
2705 _effectiveMinorVersion = v;
2709 public JspConfigDescriptor getJspConfigDescriptor()
2711 LOG.warn(__unimplmented);
2716 public void declareRoles(String... roleNames)
2718 LOG.warn(__unimplmented);
2722 * @see javax.servlet.ServletContext#getVirtualServerName()
2725 public String getVirtualServerName()
2727 // TODO 3.1 Auto-generated method stub
2733 /* ------------------------------------------------------------ */
2734 /** Interface to check aliases
2736 public interface AliasCheck
2738 /* ------------------------------------------------------------ */
2740 * @param path The path the aliased resource was created for
2741 * @param resource The aliased resourced
2742 * @return True if the resource is OK to be served.
2744 boolean check(String path, Resource resource);
2748 /* ------------------------------------------------------------ */
2749 /** Approve all aliases.
2751 public static class ApproveAliases implements AliasCheck
2754 public boolean check(String path, Resource resource)
2760 /* ------------------------------------------------------------ */
2761 /** Approve Aliases with same suffix.
2762 * Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be
2763 * approved because both the resource and alias end with ".html".
2766 public static class ApproveSameSuffixAliases implements AliasCheck
2769 LOG.warn("ApproveSameSuffixAlias is not safe for production");
2773 public boolean check(String path, Resource resource)
2775 int dot = path.lastIndexOf('.');
2778 String suffix=path.substring(dot);
2779 return resource.toString().endsWith(suffix);
2784 /* ------------------------------------------------------------ */
2785 /** Approve Aliases with a path prefix.
2786 * Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be
2787 * approved because both the resource and alias end with "/foobar.html".
2790 public static class ApprovePathPrefixAliases implements AliasCheck
2793 LOG.warn("ApprovePathPrefixAliases is not safe for production");
2797 public boolean check(String path, Resource resource)
2799 int slash = path.lastIndexOf('/');
2800 if (slash<0 || slash==path.length()-1)
2802 String suffix=path.substring(slash);
2803 return resource.toString().endsWith(suffix);
2807 /* ------------------------------------------------------------ */
2808 /** Approve Aliases of a non existent directory.
2809 * If a directory "/foobar/" does not exist, then the resource is
2810 * aliased to "/foobar". Accept such aliases.
2812 public static class ApproveNonExistentDirectoryAliases implements AliasCheck
2815 public boolean check(String path, Resource resource)
2817 if (resource.exists())
2820 String a=resource.getAlias().toString();
2821 String r=resource.getURL().toString();
2823 if (a.length()>r.length())
2824 return a.startsWith(r) && a.length()==r.length()+1 && a.endsWith("/");
2825 if (a.length()<r.length())
2826 return r.startsWith(a) && r.length()==a.length()+1 && r.endsWith("/");