2 // ========================================================================
3 // Copyright (c) 1995-2014 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.ListIterator;
40 import java.util.Locale;
43 import java.util.concurrent.CopyOnWriteArrayList;
44 import java.util.concurrent.Future;
46 import javax.servlet.DispatcherType;
47 import javax.servlet.Filter;
48 import javax.servlet.FilterRegistration;
49 import javax.servlet.FilterRegistration.Dynamic;
50 import javax.servlet.RequestDispatcher;
51 import javax.servlet.Servlet;
52 import javax.servlet.ServletContext;
53 import javax.servlet.ServletContextAttributeEvent;
54 import javax.servlet.ServletContextAttributeListener;
55 import javax.servlet.ServletContextEvent;
56 import javax.servlet.ServletContextListener;
57 import javax.servlet.ServletException;
58 import javax.servlet.ServletRegistration;
59 import javax.servlet.ServletRequestAttributeListener;
60 import javax.servlet.ServletRequestEvent;
61 import javax.servlet.ServletRequestListener;
62 import javax.servlet.SessionCookieConfig;
63 import javax.servlet.SessionTrackingMode;
64 import javax.servlet.descriptor.JspConfigDescriptor;
65 import javax.servlet.http.HttpServletRequest;
66 import javax.servlet.http.HttpServletResponse;
68 import org.eclipse.jetty.http.MimeTypes;
69 import org.eclipse.jetty.server.ClassLoaderDump;
70 import org.eclipse.jetty.server.Connector;
71 import org.eclipse.jetty.server.Dispatcher;
72 import org.eclipse.jetty.server.Handler;
73 import org.eclipse.jetty.server.HandlerContainer;
74 import org.eclipse.jetty.server.Request;
75 import org.eclipse.jetty.server.Server;
76 import org.eclipse.jetty.util.Attributes;
77 import org.eclipse.jetty.util.AttributesMap;
78 import org.eclipse.jetty.util.FutureCallback;
79 import org.eclipse.jetty.util.Loader;
80 import org.eclipse.jetty.util.StringUtil;
81 import org.eclipse.jetty.util.URIUtil;
82 import org.eclipse.jetty.util.annotation.ManagedAttribute;
83 import org.eclipse.jetty.util.annotation.ManagedObject;
84 import org.eclipse.jetty.util.component.Graceful;
85 import org.eclipse.jetty.util.log.Log;
86 import org.eclipse.jetty.util.log.Logger;
87 import org.eclipse.jetty.util.resource.Resource;
89 /* ------------------------------------------------------------ */
93 * This handler wraps a call to handle by setting the context and servlet path, plus setting the context classloader.
96 * 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
97 * context attribute names, which if set as attributes are passed to the servers Container so that they may be managed with JMX.
99 * 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
100 * and org.eclipse.jetty.server.Request.maxFormContentSize. These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)}
102 * This servers executore is made available via a context attributed "org.eclipse.jetty.server.Executor".
104 * @org.apache.xbean.XBean description="Creates a basic HTTP context"
106 @ManagedObject("URI Context")
107 public class ContextHandler extends ScopedHandler implements Attributes, Graceful
109 public final static int SERVLET_MAJOR_VERSION=3;
110 public final static int SERVLET_MINOR_VERSION=0;
111 public static final Class[] SERVLET_LISTENER_TYPES = new Class[] {ServletContextListener.class,
112 ServletContextAttributeListener.class,
113 ServletRequestListener.class,
114 ServletRequestAttributeListener.class};
116 public static final int DEFAULT_LISTENER_TYPE_INDEX = 1;
117 public static final int EXTENDED_LISTENER_TYPE_INDEX = 0;
120 final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler";
122 private static final Logger LOG = Log.getLogger(ContextHandler.class);
124 private static final ThreadLocal<Context> __context = new ThreadLocal<Context>();
127 * 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
128 * 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
129 * for the attribute value.
131 public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
133 /* ------------------------------------------------------------ */
135 * Get the current ServletContext implementation.
137 * @return ServletContext implementation
139 public static Context getCurrentContext()
141 return __context.get();
144 /* ------------------------------------------------------------ */
145 public static ContextHandler getContextHandler(ServletContext context)
147 if(context instanceof ContextHandler.Context)
148 return ((ContextHandler.Context)context).getContextHandler();
149 Context c= getCurrentContext();
151 return c.getContextHandler();
156 protected Context _scontext;
157 private final AttributesMap _attributes;
158 private final Map<String, String> _initParams;
159 private ClassLoader _classLoader;
160 private String _contextPath = "/";
162 private String _displayName;
164 private Resource _baseResource;
165 private MimeTypes _mimeTypes;
166 private Map<String, String> _localeEncodingMap;
167 private String[] _welcomeFiles;
168 private ErrorHandler _errorHandler;
169 private String[] _vhosts;
171 private Logger _logger;
172 private boolean _allowNullPathInfo;
173 private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",-1).intValue();
174 private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",-1).intValue();
175 private boolean _compactPath = false;
177 private final List<EventListener> _eventListeners=new CopyOnWriteArrayList<>();
178 private final List<EventListener> _programmaticListeners=new CopyOnWriteArrayList<>();
179 private final List<ServletContextListener> _contextListeners=new CopyOnWriteArrayList<>();
180 private final List<ServletContextAttributeListener> _contextAttributeListeners=new CopyOnWriteArrayList<>();
181 private final List<ServletRequestListener> _requestListeners=new CopyOnWriteArrayList<>();
182 private final List<ServletRequestAttributeListener> _requestAttributeListeners=new CopyOnWriteArrayList<>();
183 private final List<EventListener> _durableListeners = new CopyOnWriteArrayList<>();
184 private Map<String, Object> _managedAttributes;
185 private String[] _protectedTargets;
186 private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
188 public enum Availability { UNAVAILABLE,STARTING,AVAILABLE,SHUTDOWN,};
189 private volatile Availability _availability;
191 /* ------------------------------------------------------------ */
195 public ContextHandler()
198 _scontext = new Context();
199 _attributes = new AttributesMap();
200 _initParams = new HashMap<String, String>();
201 addAliasCheck(new ApproveNonExistentDirectoryAliases());
204 /* ------------------------------------------------------------ */
208 protected ContextHandler(Context context)
212 _attributes = new AttributesMap();
213 _initParams = new HashMap<String, String>();
214 addAliasCheck(new ApproveNonExistentDirectoryAliases());
217 /* ------------------------------------------------------------ */
221 public ContextHandler(String contextPath)
224 setContextPath(contextPath);
227 /* ------------------------------------------------------------ */
231 public ContextHandler(HandlerContainer parent, String contextPath)
234 setContextPath(contextPath);
235 if (parent instanceof HandlerWrapper)
236 ((HandlerWrapper)parent).setHandler(this);
237 else if (parent instanceof HandlerCollection)
238 ((HandlerCollection)parent).addHandler(this);
241 /* ------------------------------------------------------------ */
243 public void dump(Appendable out, String indent) throws IOException
245 dumpBeans(out,indent,
246 Collections.singletonList(new ClassLoaderDump(getClassLoader())),
247 _initParams.entrySet(),
248 _attributes.getAttributeEntrySet(),
249 _scontext.getAttributeEntrySet());
252 /* ------------------------------------------------------------ */
253 public Context getServletContext()
258 /* ------------------------------------------------------------ */
260 * @return the allowNullPathInfo true if /context is not redirected to /context/
262 @ManagedAttribute("Checks if the /context is not redirected to /context/")
263 public boolean getAllowNullPathInfo()
265 return _allowNullPathInfo;
268 /* ------------------------------------------------------------ */
270 * @param allowNullPathInfo
271 * true if /context is not redirected to /context/
273 public void setAllowNullPathInfo(boolean allowNullPathInfo)
275 _allowNullPathInfo = allowNullPathInfo;
278 /* ------------------------------------------------------------ */
280 public void setServer(Server server)
282 super.setServer(server);
283 if (_errorHandler != null)
284 _errorHandler.setServer(server);
287 /* ------------------------------------------------------------ */
289 * 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
290 * 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
291 * matching virtual host name.
294 * 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
295 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names. Hosts may start with '@', in which case they
296 * will match the {@link Connector#getName()} for the request.
298 public void setVirtualHosts(String[] vhosts)
306 _vhosts = new String[vhosts.length];
307 for (int i = 0; i < vhosts.length; i++)
308 _vhosts[i] = normalizeHostname(vhosts[i]);
312 /* ------------------------------------------------------------ */
313 /** Either set virtual hosts or add to an existing set of virtual hosts.
315 * @param virtualHosts
316 * 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
317 * 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
318 * will match the {@link Connector#getName()} for the request.
320 public void addVirtualHosts(String[] virtualHosts)
322 if (virtualHosts == null) // since this is add, we don't null the old ones
328 List<String> currentVirtualHosts = null;
331 currentVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
335 currentVirtualHosts = new ArrayList<String>();
338 for (int i = 0; i < virtualHosts.length; i++)
340 String normVhost = normalizeHostname(virtualHosts[i]);
341 if (!currentVirtualHosts.contains(normVhost))
343 currentVirtualHosts.add(normVhost);
346 _vhosts = currentVirtualHosts.toArray(new String[0]);
350 /* ------------------------------------------------------------ */
352 * Removes an array of virtual host entries, if this removes all entries the _vhosts will be set to null
354 * @param virtualHosts
355 * 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
356 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
358 public void removeVirtualHosts(String[] virtualHosts)
360 if (virtualHosts == null)
362 return; // do nothing
364 else if ( _vhosts == null || _vhosts.length == 0)
366 return; // do nothing
370 List<String> existingVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
372 for (int i = 0; i < virtualHosts.length; i++)
374 String toRemoveVirtualHost = normalizeHostname(virtualHosts[i]);
375 if (existingVirtualHosts.contains(toRemoveVirtualHost))
377 existingVirtualHosts.remove(toRemoveVirtualHost);
381 if (existingVirtualHosts.isEmpty())
383 _vhosts = null; // if we ended up removing them all, just null out _vhosts
387 _vhosts = existingVirtualHosts.toArray(new String[0]);
392 /* ------------------------------------------------------------ */
394 * 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
395 * 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
396 * matching virtual host name.
398 * @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
399 * representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
401 @ManagedAttribute(value="Virtual hosts accepted by the context", readonly=true)
402 public String[] getVirtualHosts()
407 /* ------------------------------------------------------------ */
409 * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
412 public Object getAttribute(String name)
414 return _attributes.getAttribute(name);
417 /* ------------------------------------------------------------ */
419 * @see javax.servlet.ServletContext#getAttributeNames()
422 public Enumeration<String> getAttributeNames()
424 return AttributesMap.getAttributeNamesCopy(_attributes);
427 /* ------------------------------------------------------------ */
429 * @return Returns the attributes.
431 public Attributes getAttributes()
436 /* ------------------------------------------------------------ */
438 * @return Returns the classLoader.
440 public ClassLoader getClassLoader()
445 /* ------------------------------------------------------------ */
447 * Make best effort to extract a file classpath from the context classloader
449 * @return Returns the classLoader.
451 @ManagedAttribute("The file classpath")
452 public String getClassPath()
454 if (_classLoader == null || !(_classLoader instanceof URLClassLoader))
456 URLClassLoader loader = (URLClassLoader)_classLoader;
457 URL[] urls = loader.getURLs();
458 StringBuilder classpath = new StringBuilder();
459 for (int i = 0; i < urls.length; i++)
463 Resource resource = newResource(urls[i]);
464 File file = resource.getFile();
465 if (file != null && file.exists())
467 if (classpath.length() > 0)
468 classpath.append(File.pathSeparatorChar);
469 classpath.append(file.getAbsolutePath());
472 catch (IOException e)
477 if (classpath.length() == 0)
479 return classpath.toString();
482 /* ------------------------------------------------------------ */
484 * @return Returns the _contextPath.
486 @ManagedAttribute("True if URLs are compacted to replace the multiple '/'s with a single '/'")
487 public String getContextPath()
492 /* ------------------------------------------------------------ */
494 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
496 public String getInitParameter(String name)
498 return _initParams.get(name);
501 /* ------------------------------------------------------------ */
504 public String setInitParameter(String name, String value)
506 return _initParams.put(name,value);
509 /* ------------------------------------------------------------ */
511 * @see javax.servlet.ServletContext#getInitParameterNames()
513 @SuppressWarnings("rawtypes")
514 public Enumeration getInitParameterNames()
516 return Collections.enumeration(_initParams.keySet());
519 /* ------------------------------------------------------------ */
521 * @return Returns the initParams.
523 @ManagedAttribute("Initial Parameter map for the context")
524 public Map<String, String> getInitParams()
529 /* ------------------------------------------------------------ */
531 * @see javax.servlet.ServletContext#getServletContextName()
533 @ManagedAttribute(value="Display name of the Context", readonly=true)
534 public String getDisplayName()
539 /* ------------------------------------------------------------ */
540 public EventListener[] getEventListeners()
542 return _eventListeners.toArray(new EventListener[_eventListeners.size()]);
545 /* ------------------------------------------------------------ */
547 * Set the context event listeners.
549 * @param eventListeners
550 * the event listeners
551 * @see ServletContextListener
552 * @see ServletContextAttributeListener
553 * @see ServletRequestListener
554 * @see ServletRequestAttributeListener
556 public void setEventListeners(EventListener[] eventListeners)
558 _contextListeners.clear();
559 _contextAttributeListeners.clear();
560 _requestListeners.clear();
561 _requestAttributeListeners.clear();
562 _eventListeners.clear();
564 if (eventListeners!=null)
565 for (EventListener listener : eventListeners)
566 addEventListener(listener);
569 /* ------------------------------------------------------------ */
571 * Add a context event listeners.
573 * @see ServletContextListener
574 * @see ServletContextAttributeListener
575 * @see ServletRequestListener
576 * @see ServletRequestAttributeListener
578 public void addEventListener(EventListener listener)
580 _eventListeners.add(listener);
582 if (!(isStarted() || isStarting()))
583 _durableListeners.add(listener);
585 if (listener instanceof ServletContextListener)
586 _contextListeners.add((ServletContextListener)listener);
588 if (listener instanceof ServletContextAttributeListener)
589 _contextAttributeListeners.add((ServletContextAttributeListener)listener);
591 if (listener instanceof ServletRequestListener)
592 _requestListeners.add((ServletRequestListener)listener);
594 if (listener instanceof ServletRequestAttributeListener)
595 _requestAttributeListeners.add((ServletRequestAttributeListener)listener);
598 /* ------------------------------------------------------------ */
600 * Remove a context event listeners.
602 * @see ServletContextListener
603 * @see ServletContextAttributeListener
604 * @see ServletRequestListener
605 * @see ServletRequestAttributeListener
607 public void removeEventListener(EventListener listener)
609 _eventListeners.remove(listener);
611 if (listener instanceof ServletContextListener)
612 _contextListeners.remove(listener);
614 if (listener instanceof ServletContextAttributeListener)
615 _contextAttributeListeners.remove(listener);
617 if (listener instanceof ServletRequestListener)
618 _requestListeners.remove(listener);
620 if (listener instanceof ServletRequestAttributeListener)
621 _requestAttributeListeners.remove(listener);
624 /* ------------------------------------------------------------ */
626 * Apply any necessary restrictions on a programmatic added listener.
630 protected void addProgrammaticListener (EventListener listener)
632 _programmaticListeners.add(listener);
635 /* ------------------------------------------------------------ */
636 protected boolean isProgrammaticListener(EventListener listener)
638 return _programmaticListeners.contains(listener);
643 /* ------------------------------------------------------------ */
645 * @return true if this context is accepting new requests
647 @ManagedAttribute("true for graceful shutdown, which allows existing requests to complete")
648 public boolean isShutdown()
650 switch(_availability)
659 /* ------------------------------------------------------------ */
661 * 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
662 * requests can complete, but no new requests are accepted.
666 public Future<Void> shutdown()
668 _availability = isRunning() ? Availability.SHUTDOWN : Availability.UNAVAILABLE;
669 return new FutureCallback(true);
672 /* ------------------------------------------------------------ */
674 * @return false if this context is unavailable (sends 503)
676 public boolean isAvailable()
678 return _availability==Availability.AVAILABLE;
681 /* ------------------------------------------------------------ */
683 * Set Available status.
685 public void setAvailable(boolean available)
689 if (available && isRunning())
690 _availability = Availability.AVAILABLE;
691 else if (!available || !isRunning())
692 _availability = Availability.UNAVAILABLE;
696 /* ------------------------------------------------------------ */
697 public Logger getLogger()
702 /* ------------------------------------------------------------ */
703 public void setLogger(Logger logger)
708 /* ------------------------------------------------------------ */
710 * @see org.eclipse.thread.AbstractLifeCycle#doStart()
713 protected void doStart() throws Exception
715 _availability = Availability.STARTING;
717 if (_contextPath == null)
718 throw new IllegalStateException("Null contextPath");
720 _logger = Log.getLogger(getDisplayName() == null?getContextPath():getDisplayName());
721 ClassLoader old_classloader = null;
722 Thread current_thread = null;
723 Context old_context = null;
725 _attributes.setAttribute("org.eclipse.jetty.server.Executor",getServer().getThreadPool());
729 // Set the classloader
730 if (_classLoader != null)
732 current_thread = Thread.currentThread();
733 old_classloader = current_thread.getContextClassLoader();
734 current_thread.setContextClassLoader(_classLoader);
737 if (_mimeTypes == null)
738 _mimeTypes = new MimeTypes();
740 old_context = __context.get();
741 __context.set(_scontext);
743 // defers the calling of super.doStart()
746 _availability = Availability.AVAILABLE;
747 LOG.info("Started {}", this);
751 __context.set(old_context);
753 // reset the classloader
754 if (_classLoader != null && current_thread!=null)
755 current_thread.setContextClassLoader(old_classloader);
759 /* ------------------------------------------------------------ */
761 * Extensible startContext. this method is called from {@link ContextHandler#doStart()} instead of a call to super.doStart(). This allows derived classes to
762 * insert additional handling (Eg configuration) before the call to super.doStart by this method will start contained handlers.
764 * @see org.eclipse.jetty.server.handler.ContextHandler.Context
766 protected void startContext() throws Exception
768 String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
769 if (managedAttributes != null)
771 _managedAttributes = new HashMap<String, Object>();
772 String[] attributes = managedAttributes.split(",");
773 for (String attribute : attributes)
774 _managedAttributes.put(attribute,null);
776 Enumeration<String> e = _scontext.getAttributeNames();
777 while (e.hasMoreElements())
779 String name = e.nextElement();
780 Object value = _scontext.getAttribute(name);
781 checkManagedAttribute(name,value);
787 // Call context listeners
788 if (!_contextListeners.isEmpty())
790 ServletContextEvent event = new ServletContextEvent(_scontext);
791 for (ServletContextListener listener:_contextListeners)
792 callContextInitialized(listener, event);
796 /* ------------------------------------------------------------ */
797 protected void callContextInitialized (ServletContextListener l, ServletContextEvent e)
799 LOG.debug("contextInitialized: {}->{}",e,l);
800 l.contextInitialized(e);
803 /* ------------------------------------------------------------ */
804 protected void callContextDestroyed (ServletContextListener l, ServletContextEvent e)
806 LOG.debug("contextDestroyed: {}->{}",e,l);
807 l.contextDestroyed(e);
810 /* ------------------------------------------------------------ */
812 * @see org.eclipse.thread.AbstractLifeCycle#doStop()
815 protected void doStop() throws Exception
817 _availability = Availability.UNAVAILABLE;
819 ClassLoader old_classloader = null;
820 Thread current_thread = null;
822 Context old_context = __context.get();
823 __context.set(_scontext);
826 // Set the classloader
827 if (_classLoader != null)
829 current_thread = Thread.currentThread();
830 old_classloader = current_thread.getContextClassLoader();
831 current_thread.setContextClassLoader(_classLoader);
837 if (!_contextListeners.isEmpty())
839 ServletContextEvent event = new ServletContextEvent(_scontext);
840 for (int i = _contextListeners.size(); i-->0;)
841 callContextDestroyed(_contextListeners.get(i),event);
844 //retain only durable listeners
845 setEventListeners(_durableListeners.toArray(new EventListener[_durableListeners.size()]));
846 _durableListeners.clear();
848 if (_errorHandler != null)
849 _errorHandler.stop();
851 Enumeration<String> e = _scontext.getAttributeNames();
852 while (e.hasMoreElements())
854 String name = e.nextElement();
855 checkManagedAttribute(name,null);
858 for (EventListener l : _programmaticListeners)
859 removeEventListener(l);
860 _programmaticListeners.clear();
864 LOG.info("Stopped {}", this);
865 __context.set(old_context);
866 // reset the classloader
867 if (_classLoader != null && current_thread!=null)
868 current_thread.setContextClassLoader(old_classloader);
871 _scontext.clearAttributes();
874 /* ------------------------------------------------------------ */
876 * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
878 public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException
880 DispatcherType dispatch = baseRequest.getDispatcherType();
882 switch (_availability)
886 baseRequest.setHandled(true);
887 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
890 if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
895 if (_vhosts != null && _vhosts.length > 0)
897 String vhost = normalizeHostname(baseRequest.getServerName());
899 boolean match = false;
900 boolean connectorName = false;
901 boolean connectorMatch = false;
903 for (String contextVhost:_vhosts)
905 if (contextVhost == null || contextVhost.length()==0)
907 char c=contextVhost.charAt(0);
911 if (contextVhost.startsWith("*."))
912 // wildcard only at the beginning, and only for one additional subdomain level
913 match = match || contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".") + 1,contextVhost.length() - 2);
917 String name=baseRequest.getHttpChannel().getConnector().getName();
918 boolean m=name!=null && contextVhost.length()==name.length()+1 && contextVhost.endsWith(name);
920 connectorMatch = connectorMatch || m;
923 match = match || contextVhost.equalsIgnoreCase(vhost);
927 if (!match || connectorName && !connectorMatch)
931 // Are we not the root context?
932 if (_contextPath.length() > 1)
934 // reject requests that are not for us
935 if (!target.startsWith(_contextPath))
937 if (target.length() > _contextPath.length() && target.charAt(_contextPath.length()) != '/')
940 // redirect null path infos
941 if (!_allowNullPathInfo && _contextPath.length() == target.length())
943 // context request must end with /
944 baseRequest.setHandled(true);
945 if (baseRequest.getQueryString() != null)
946 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
948 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
956 /* ------------------------------------------------------------ */
958 * @see org.eclipse.jetty.server.handler.ScopedHandler#doScope(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
959 * javax.servlet.http.HttpServletResponse)
962 public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
964 if (LOG.isDebugEnabled())
965 LOG.debug("scope {}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(),baseRequest.getPathInfo(),this);
967 Context old_context = null;
968 String old_context_path = null;
969 String old_servlet_path = null;
970 String old_path_info = null;
971 ClassLoader old_classloader = null;
972 Thread current_thread = null;
973 String pathInfo = target;
975 DispatcherType dispatch = baseRequest.getDispatcherType();
977 old_context = baseRequest.getContext();
979 // Are we already in this context?
980 if (old_context != _scontext)
983 if (DispatcherType.REQUEST.equals(dispatch) ||
984 DispatcherType.ASYNC.equals(dispatch) ||
985 DispatcherType.ERROR.equals(dispatch) && baseRequest.getHttpChannelState().isAsync())
988 target = URIUtil.compactPath(target);
989 if (!checkContext(target,baseRequest,response))
992 if (target.length() > _contextPath.length())
994 if (_contextPath.length() > 1)
995 target = target.substring(_contextPath.length());
998 else if (_contextPath.length() == 1)
1000 target = URIUtil.SLASH;
1001 pathInfo = URIUtil.SLASH;
1005 target = URIUtil.SLASH;
1010 // Set the classloader
1011 if (_classLoader != null)
1013 current_thread = Thread.currentThread();
1014 old_classloader = current_thread.getContextClassLoader();
1015 current_thread.setContextClassLoader(_classLoader);
1021 old_context_path = baseRequest.getContextPath();
1022 old_servlet_path = baseRequest.getServletPath();
1023 old_path_info = baseRequest.getPathInfo();
1026 baseRequest.setContext(_scontext);
1027 __context.set(_scontext);
1028 if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/"))
1030 if (_contextPath.length() == 1)
1031 baseRequest.setContextPath("");
1033 baseRequest.setContextPath(_contextPath);
1034 baseRequest.setServletPath(null);
1035 baseRequest.setPathInfo(pathInfo);
1038 if (LOG.isDebugEnabled())
1039 LOG.debug("context={}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(), baseRequest.getPathInfo(),this);
1041 // start manual inline of nextScope(target,baseRequest,request,response);
1043 nextScope(target,baseRequest,request,response);
1044 else if (_nextScope != null)
1045 _nextScope.doScope(target,baseRequest,request,response);
1046 else if (_outerScope != null)
1047 _outerScope.doHandle(target,baseRequest,request,response);
1049 doHandle(target,baseRequest,request,response);
1050 // end manual inline (pathentic attempt to reduce stack depth)
1054 if (old_context != _scontext)
1056 // reset the classloader
1057 if (_classLoader != null && current_thread!=null)
1059 current_thread.setContextClassLoader(old_classloader);
1062 // reset the context and servlet path.
1063 baseRequest.setContext(old_context);
1064 __context.set(old_context);
1065 baseRequest.setContextPath(old_context_path);
1066 baseRequest.setServletPath(old_servlet_path);
1067 baseRequest.setPathInfo(old_path_info);
1072 /* ------------------------------------------------------------ */
1074 * @see org.eclipse.jetty.server.handler.ScopedHandler#doHandle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
1075 * javax.servlet.http.HttpServletResponse)
1078 public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
1080 final DispatcherType dispatch = baseRequest.getDispatcherType();
1081 final boolean new_context = baseRequest.takeNewContext();
1086 // Handle the REALLY SILLY request events!
1087 if (!_requestAttributeListeners.isEmpty())
1088 for (ServletRequestAttributeListener l :_requestAttributeListeners)
1089 baseRequest.addEventListener(l);
1091 if (!_requestListeners.isEmpty())
1093 final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
1094 for (ServletRequestListener l : _requestListeners)
1095 l.requestInitialized(sre);
1099 if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target))
1101 response.sendError(HttpServletResponse.SC_NOT_FOUND);
1102 baseRequest.setHandled(true);
1106 // start manual inline of nextHandle(target,baseRequest,request,response);
1107 // noinspection ConstantIfStatement
1109 nextHandle(target,baseRequest,request,response);
1110 else if (_nextScope != null && _nextScope == _handler)
1111 _nextScope.doHandle(target,baseRequest,request,response);
1112 else if (_handler != null)
1113 _handler.handle(target,baseRequest,request,response);
1114 // end manual inline
1118 // Handle more REALLY SILLY request events!
1121 if (!_requestListeners.isEmpty())
1123 final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
1124 for (int i=_requestListeners.size();i-->0;)
1125 _requestListeners.get(i).requestDestroyed(sre);
1128 if (!_requestAttributeListeners.isEmpty())
1130 ListIterator<ServletRequestAttributeListener> iter = _requestAttributeListeners.listIterator(_requestAttributeListeners.size());
1131 for (int i=_requestAttributeListeners.size();i-->0;)
1132 baseRequest.removeEventListener(_requestAttributeListeners.get(i));
1138 /* ------------------------------------------------------------ */
1140 * Handle a runnable in this context
1142 public void handle(Runnable runnable)
1144 ClassLoader old_classloader = null;
1145 Thread current_thread = null;
1146 Context old_context = null;
1149 old_context = __context.get();
1150 __context.set(_scontext);
1152 // Set the classloader
1153 if (_classLoader != null)
1155 current_thread = Thread.currentThread();
1156 old_classloader = current_thread.getContextClassLoader();
1157 current_thread.setContextClassLoader(_classLoader);
1164 __context.set(old_context);
1165 if (old_classloader != null && current_thread!=null)
1167 current_thread.setContextClassLoader(old_classloader);
1172 /* ------------------------------------------------------------ */
1174 * Check the target. Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a target within a context is determined. If
1175 * the target is protected, 404 is returned.
1177 /* ------------------------------------------------------------ */
1178 public boolean isProtectedTarget(String target)
1180 if (target == null || _protectedTargets == null)
1183 while (target.startsWith("//"))
1184 target=URIUtil.compactPath(target);
1186 for (int i=0; i<_protectedTargets.length; i++)
1188 String t=_protectedTargets[i];
1189 if (StringUtil.startsWithIgnoreCase(target,t))
1191 if (target.length()==t.length())
1194 // Check that the target prefix really is a path segment, thus
1195 // it can end with /, a query, a target or a parameter
1196 char c=target.charAt(t.length());
1197 if (c=='/'||c=='?'||c=='#'||c==';')
1205 /* ------------------------------------------------------------ */
1207 * @param targets Array of URL prefix. Each prefix is in the form /path and will match
1208 * either /path exactly or /path/anything
1210 public void setProtectedTargets (String[] targets)
1212 if (targets == null)
1214 _protectedTargets = null;
1218 _protectedTargets = Arrays.copyOf(targets, targets.length);
1221 /* ------------------------------------------------------------ */
1222 public String[] getProtectedTargets()
1224 if (_protectedTargets == null)
1227 return Arrays.copyOf(_protectedTargets, _protectedTargets.length);
1231 /* ------------------------------------------------------------ */
1233 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1236 public void removeAttribute(String name)
1238 checkManagedAttribute(name,null);
1239 _attributes.removeAttribute(name);
1242 /* ------------------------------------------------------------ */
1244 * Set a context attribute. Attributes set via this API cannot be overriden by the ServletContext.setAttribute API. Their lifecycle spans the stop/start of
1245 * a context. No attribute listener events are triggered by this API.
1247 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1250 public void setAttribute( String name, Object value)
1252 checkManagedAttribute(name,value);
1253 _attributes.setAttribute(name,value);
1256 /* ------------------------------------------------------------ */
1259 * The attributes to set.
1261 public void setAttributes(Attributes attributes)
1263 _attributes.clearAttributes();
1264 _attributes.addAll(attributes);
1265 Enumeration<String> e = _attributes.getAttributeNames();
1266 while (e.hasMoreElements())
1268 String name = e.nextElement();
1269 checkManagedAttribute(name,attributes.getAttribute(name));
1273 /* ------------------------------------------------------------ */
1275 public void clearAttributes()
1277 Enumeration<String> e = _attributes.getAttributeNames();
1278 while (e.hasMoreElements())
1280 String name = e.nextElement();
1281 checkManagedAttribute(name,null);
1283 _attributes.clearAttributes();
1286 /* ------------------------------------------------------------ */
1287 public void checkManagedAttribute(String name, Object value)
1289 if (_managedAttributes != null && _managedAttributes.containsKey(name))
1291 setManagedAttribute(name,value);
1295 /* ------------------------------------------------------------ */
1296 public void setManagedAttribute(String name, Object value)
1298 Object old = _managedAttributes.put(name,value);
1299 updateBean(old,value);
1302 /* ------------------------------------------------------------ */
1304 * @param classLoader
1305 * The classLoader to set.
1307 public void setClassLoader(ClassLoader classLoader)
1309 _classLoader = classLoader;
1312 /* ------------------------------------------------------------ */
1314 * @param contextPath
1315 * The _contextPath to set.
1317 public void setContextPath(String contextPath)
1319 if (contextPath == null)
1320 throw new IllegalArgumentException("null contextPath");
1322 if (contextPath.endsWith("/*"))
1324 LOG.warn(this+" contextPath ends with /*");
1325 contextPath=contextPath.substring(0,contextPath.length()-2);
1327 else if (contextPath.length()>1 && contextPath.endsWith("/"))
1329 LOG.warn(this+" contextPath ends with /");
1330 contextPath=contextPath.substring(0,contextPath.length()-1);
1333 if (contextPath.length()==0)
1335 LOG.warn("Empty contextPath");
1339 _contextPath = contextPath;
1341 if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
1343 Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
1344 for (int h = 0; contextCollections != null && h < contextCollections.length; h++)
1345 ((ContextHandlerCollection)contextCollections[h]).mapContexts();
1349 /* ------------------------------------------------------------ */
1351 * @param servletContextName
1352 * The servletContextName to set.
1354 public void setDisplayName(String servletContextName)
1356 _displayName = servletContextName;
1359 /* ------------------------------------------------------------ */
1361 * @return Returns the resourceBase.
1363 public Resource getBaseResource()
1365 if (_baseResource == null)
1367 return _baseResource;
1370 /* ------------------------------------------------------------ */
1372 * @return Returns the base resource as a string.
1374 @ManagedAttribute("document root for context")
1375 public String getResourceBase()
1377 if (_baseResource == null)
1379 return _baseResource.toString();
1382 /* ------------------------------------------------------------ */
1384 * Set the base resource for this context.
1385 * @param base The resource used as the base for all static content of this context.
1386 * @see #setResourceBase(String)
1388 public void setBaseResource(Resource base)
1390 _baseResource = base;
1393 /* ------------------------------------------------------------ */
1395 * Set the base resource for this context.
1396 * @param resourceBase A string representing the base resource for the context. Any string accepted
1397 * by {@link Resource#newResource(String)} may be passed and the call is equivalent to
1398 * <code>setBaseResource(newResource(resourceBase));</code>
1400 public void setResourceBase(String resourceBase)
1404 setBaseResource(newResource(resourceBase));
1408 LOG.warn(e.toString());
1410 throw new IllegalArgumentException(resourceBase);
1414 /* ------------------------------------------------------------ */
1416 * @return Returns the mimeTypes.
1418 public MimeTypes getMimeTypes()
1420 if (_mimeTypes == null)
1421 _mimeTypes = new MimeTypes();
1425 /* ------------------------------------------------------------ */
1428 * The mimeTypes to set.
1430 public void setMimeTypes(MimeTypes mimeTypes)
1432 _mimeTypes = mimeTypes;
1435 /* ------------------------------------------------------------ */
1438 public void setWelcomeFiles(String[] files)
1440 _welcomeFiles = files;
1443 /* ------------------------------------------------------------ */
1445 * @return The names of the files which the server should consider to be welcome files in this context.
1446 * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
1447 * @see #setWelcomeFiles
1449 @ManagedAttribute(value="Partial URIs of directory welcome files", readonly=true)
1450 public String[] getWelcomeFiles()
1452 return _welcomeFiles;
1455 /* ------------------------------------------------------------ */
1457 * @return Returns the errorHandler.
1459 @ManagedAttribute("The error handler to use for the context")
1460 public ErrorHandler getErrorHandler()
1462 return _errorHandler;
1465 /* ------------------------------------------------------------ */
1467 * @param errorHandler
1468 * The errorHandler to set.
1470 public void setErrorHandler(ErrorHandler errorHandler)
1472 if (errorHandler != null)
1473 errorHandler.setServer(getServer());
1474 updateBean(_errorHandler,errorHandler);
1475 _errorHandler = errorHandler;
1478 /* ------------------------------------------------------------ */
1479 @ManagedAttribute("The maximum content size")
1480 public int getMaxFormContentSize()
1482 return _maxFormContentSize;
1485 /* ------------------------------------------------------------ */
1487 * Set the maximum size of a form post, to protect against DOS attacks from large forms.
1490 public void setMaxFormContentSize(int maxSize)
1492 _maxFormContentSize = maxSize;
1495 /* ------------------------------------------------------------ */
1496 public int getMaxFormKeys()
1498 return _maxFormKeys;
1501 /* ------------------------------------------------------------ */
1503 * Set the maximum number of form Keys to protect against DOS attack from crafted hash keys.
1506 public void setMaxFormKeys(int max)
1511 /* ------------------------------------------------------------ */
1513 * @return True if URLs are compacted to replace multiple '/'s with a single '/'
1515 public boolean isCompactPath()
1517 return _compactPath;
1520 /* ------------------------------------------------------------ */
1522 * @param compactPath
1523 * True if URLs are compacted to replace multiple '/'s with a single '/'
1525 public void setCompactPath(boolean compactPath)
1527 _compactPath = compactPath;
1530 /* ------------------------------------------------------------ */
1532 public String toString()
1534 String[] vhosts = getVirtualHosts();
1536 StringBuilder b = new StringBuilder();
1538 Package pkg = getClass().getPackage();
1541 String p = pkg.getName();
1542 if (p != null && p.length() > 0)
1544 String[] ss = p.split("\\.");
1546 b.append(s.charAt(0)).append('.');
1549 b.append(getClass().getSimpleName()).append('@').append(Integer.toString(hashCode(),16));
1550 b.append('{').append(getContextPath()).append(',').append(getBaseResource()).append(',').append(_availability);
1552 if (vhosts != null && vhosts.length > 0)
1553 b.append(',').append(vhosts[0]);
1556 return b.toString();
1559 /* ------------------------------------------------------------ */
1560 public synchronized Class<?> loadClass(String className) throws ClassNotFoundException
1562 if (className == null)
1565 if (_classLoader == null)
1566 return Loader.loadClass(this.getClass(),className);
1568 return _classLoader.loadClass(className);
1571 /* ------------------------------------------------------------ */
1572 public void addLocaleEncoding(String locale, String encoding)
1574 if (_localeEncodingMap == null)
1575 _localeEncodingMap = new HashMap<String, String>();
1576 _localeEncodingMap.put(locale,encoding);
1579 /* ------------------------------------------------------------ */
1580 public String getLocaleEncoding(String locale)
1582 if (_localeEncodingMap == null)
1584 String encoding = _localeEncodingMap.get(locale);
1588 /* ------------------------------------------------------------ */
1590 * 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
1591 * language is looked up.
1594 * a <code>Locale</code> value
1595 * @return a <code>String</code> representing the character encoding for the locale or null if none found.
1597 public String getLocaleEncoding(Locale locale)
1599 if (_localeEncodingMap == null)
1601 String encoding = _localeEncodingMap.get(locale.toString());
1602 if (encoding == null)
1603 encoding = _localeEncodingMap.get(locale.getLanguage());
1607 /* ------------------------------------------------------------ */
1609 * Get all of the locale encodings
1611 * @return a map of all the locale encodings: key is name of the locale and value is the char encoding
1613 public Map<String,String> getLocaleEncodings()
1615 if (_localeEncodingMap == null)
1617 return Collections.unmodifiableMap(_localeEncodingMap);
1620 /* ------------------------------------------------------------ */
1623 public Resource getResource(String path) throws MalformedURLException
1625 if (path == null || !path.startsWith(URIUtil.SLASH))
1626 throw new MalformedURLException(path);
1628 if (_baseResource == null)
1633 path = URIUtil.canonicalPath(path);
1634 Resource resource = _baseResource.addPath(path);
1636 if (checkAlias(path,resource))
1648 /* ------------------------------------------------------------ */
1649 public boolean checkAlias(String path, Resource resource)
1651 // Is the resource aliased?
1652 if (resource.getAlias() != null)
1654 if (LOG.isDebugEnabled())
1655 LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
1658 for (Iterator<AliasCheck> i=_aliasChecks.iterator();i.hasNext();)
1660 AliasCheck check = i.next();
1661 if (check.check(path,resource))
1663 if (LOG.isDebugEnabled())
1664 LOG.debug("Aliased resource: " + resource + " approved by " + check);
1673 /* ------------------------------------------------------------ */
1675 * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
1677 public Resource newResource(URL url) throws IOException
1679 return Resource.newResource(url);
1682 /* ------------------------------------------------------------ */
1684 * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
1686 public Resource newResource(URI uri) throws IOException
1688 return Resource.newResource(uri);
1691 /* ------------------------------------------------------------ */
1693 * Convert a URL or path to a Resource. The default implementation is a wrapper for {@link Resource#newResource(String)}.
1696 * The URL or path to convert
1697 * @return The Resource for the URL/path
1698 * @throws IOException
1699 * The Resource could not be created.
1701 public Resource newResource(String urlOrPath) throws IOException
1703 return Resource.newResource(urlOrPath);
1706 /* ------------------------------------------------------------ */
1709 public Set<String> getResourcePaths(String path)
1713 path = URIUtil.canonicalPath(path);
1714 Resource resource = getResource(path);
1716 if (resource != null && resource.exists())
1718 if (!path.endsWith(URIUtil.SLASH))
1719 path = path + URIUtil.SLASH;
1721 String[] l = resource.list();
1724 HashSet<String> set = new HashSet<String>();
1725 for (int i = 0; i < l.length; i++)
1726 set.add(path + l[i]);
1735 return Collections.emptySet();
1738 /* ------------------------------------------------------------ */
1739 private String normalizeHostname(String host)
1744 if (host.endsWith("."))
1745 return host.substring(0,host.length() - 1);
1750 /* ------------------------------------------------------------ */
1752 * Add an AliasCheck instance to possibly permit aliased resources
1753 * @param check The alias checker
1755 public void addAliasCheck(AliasCheck check)
1757 _aliasChecks.add(check);
1760 /* ------------------------------------------------------------ */
1762 * @return Mutable list of Alias checks
1764 public List<AliasCheck> getAliasChecks()
1766 return _aliasChecks;
1769 /* ------------------------------------------------------------ */
1771 * @param checks list of AliasCheck instances
1773 public void setAliasChecks(List<AliasCheck> checks)
1775 _aliasChecks.clear();
1776 _aliasChecks.addAll(checks);
1779 /* ------------------------------------------------------------ */
1783 * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}.
1788 public class Context extends NoContext
1790 protected boolean _enabled = true; //whether or not the dynamic API is enabled for callers
1791 protected boolean _extendedListenerTypes = false;
1794 /* ------------------------------------------------------------ */
1799 /* ------------------------------------------------------------ */
1800 public ContextHandler getContextHandler()
1802 return ContextHandler.this;
1805 /* ------------------------------------------------------------ */
1807 * @see javax.servlet.ServletContext#getContext(java.lang.String)
1810 public ServletContext getContext(String uripath)
1812 List<ContextHandler> contexts = new ArrayList<ContextHandler>();
1813 Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class);
1814 String matched_path = null;
1816 for (Handler handler : handlers)
1818 if (handler == null)
1820 ContextHandler ch = (ContextHandler)handler;
1821 String context_path = ch.getContextPath();
1823 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
1824 || "/".equals(context_path))
1826 // look first for vhost matching context only
1827 if (getVirtualHosts() != null && getVirtualHosts().length > 0)
1829 if (ch.getVirtualHosts() != null && ch.getVirtualHosts().length > 0)
1831 for (String h1 : getVirtualHosts())
1832 for (String h2 : ch.getVirtualHosts())
1835 if (matched_path == null || context_path.length() > matched_path.length())
1838 matched_path = context_path;
1841 if (matched_path.equals(context_path))
1848 if (matched_path == null || context_path.length() > matched_path.length())
1851 matched_path = context_path;
1854 if (matched_path.equals(context_path))
1860 if (contexts.size() > 0)
1861 return contexts.get(0)._scontext;
1863 // try again ignoring virtual hosts
1864 matched_path = null;
1865 for (Handler handler : handlers)
1867 if (handler == null)
1869 ContextHandler ch = (ContextHandler)handler;
1870 String context_path = ch.getContextPath();
1872 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
1873 || "/".equals(context_path))
1875 if (matched_path == null || context_path.length() > matched_path.length())
1878 matched_path = context_path;
1881 if (matched_path.equals(context_path))
1886 if (contexts.size() > 0)
1887 return contexts.get(0)._scontext;
1891 /* ------------------------------------------------------------ */
1893 * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
1896 public String getMimeType(String file)
1898 if (_mimeTypes == null)
1900 return _mimeTypes.getMimeByExtension(file);
1903 /* ------------------------------------------------------------ */
1905 * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
1908 public RequestDispatcher getRequestDispatcher(String uriInContext)
1910 if (uriInContext == null)
1913 if (!uriInContext.startsWith("/"))
1918 String query = null;
1920 if ((q = uriInContext.indexOf('?')) > 0)
1922 query = uriInContext.substring(q + 1);
1923 uriInContext = uriInContext.substring(0,q);
1926 String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
1927 if (pathInContext!=null)
1929 String uri = URIUtil.addPaths(getContextPath(),uriInContext);
1930 ContextHandler context = ContextHandler.this;
1931 return new Dispatcher(context,uri,pathInContext,query);
1941 /* ------------------------------------------------------------ */
1943 * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
1946 public String getRealPath(String path)
1950 if (path.length() == 0)
1951 path = URIUtil.SLASH;
1952 else if (path.charAt(0) != '/')
1953 path = URIUtil.SLASH + path;
1957 Resource resource = ContextHandler.this.getResource(path);
1958 if (resource != null)
1960 File file = resource.getFile();
1962 return file.getCanonicalPath();
1973 /* ------------------------------------------------------------ */
1975 public URL getResource(String path) throws MalformedURLException
1977 Resource resource = ContextHandler.this.getResource(path);
1978 if (resource != null && resource.exists())
1979 return resource.getURL();
1983 /* ------------------------------------------------------------ */
1985 * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
1988 public InputStream getResourceAsStream(String path)
1992 URL url = getResource(path);
1995 Resource r = Resource.newResource(url);
1996 return r.getInputStream();
2005 /* ------------------------------------------------------------ */
2007 * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
2010 public Set<String> getResourcePaths(String path)
2012 return ContextHandler.this.getResourcePaths(path);
2015 /* ------------------------------------------------------------ */
2017 * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String)
2020 public void log(Exception exception, String msg)
2022 _logger.warn(msg,exception);
2025 /* ------------------------------------------------------------ */
2027 * @see javax.servlet.ServletContext#log(java.lang.String)
2030 public void log(String msg)
2035 /* ------------------------------------------------------------ */
2037 * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable)
2040 public void log(String message, Throwable throwable)
2042 _logger.warn(message,throwable);
2045 /* ------------------------------------------------------------ */
2047 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
2050 public String getInitParameter(String name)
2052 return ContextHandler.this.getInitParameter(name);
2055 /* ------------------------------------------------------------ */
2057 * @see javax.servlet.ServletContext#getInitParameterNames()
2059 @SuppressWarnings("unchecked")
2061 public Enumeration<String> getInitParameterNames()
2063 return ContextHandler.this.getInitParameterNames();
2066 /* ------------------------------------------------------------ */
2068 * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
2071 public synchronized Object getAttribute(String name)
2073 Object o = ContextHandler.this.getAttribute(name);
2075 o = super.getAttribute(name);
2079 /* ------------------------------------------------------------ */
2081 * @see javax.servlet.ServletContext#getAttributeNames()
2084 public synchronized Enumeration<String> getAttributeNames()
2086 HashSet<String> set = new HashSet<String>();
2087 Enumeration<String> e = super.getAttributeNames();
2088 while (e.hasMoreElements())
2089 set.add(e.nextElement());
2090 e = _attributes.getAttributeNames();
2091 while (e.hasMoreElements())
2092 set.add(e.nextElement());
2094 return Collections.enumeration(set);
2097 /* ------------------------------------------------------------ */
2099 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
2102 public synchronized void setAttribute(String name, Object value)
2104 checkManagedAttribute(name,value);
2105 Object old_value = super.getAttribute(name);
2108 super.removeAttribute(name);
2110 super.setAttribute(name,value);
2112 if (!_contextAttributeListeners.isEmpty())
2114 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value == null?value:old_value);
2116 for (ServletContextAttributeListener l : _contextAttributeListeners)
2118 if (old_value == null)
2119 l.attributeAdded(event);
2120 else if (value == null)
2121 l.attributeRemoved(event);
2123 l.attributeReplaced(event);
2128 /* ------------------------------------------------------------ */
2130 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
2133 public synchronized void removeAttribute(String name)
2135 checkManagedAttribute(name,null);
2137 Object old_value = super.getAttribute(name);
2138 super.removeAttribute(name);
2139 if (old_value != null &&!_contextAttributeListeners.isEmpty())
2141 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value);
2143 for (ServletContextAttributeListener l : _contextAttributeListeners)
2144 l.attributeRemoved(event);
2148 /* ------------------------------------------------------------ */
2150 * @see javax.servlet.ServletContext#getServletContextName()
2153 public String getServletContextName()
2155 String name = ContextHandler.this.getDisplayName();
2157 name = ContextHandler.this.getContextPath();
2161 /* ------------------------------------------------------------ */
2163 public String getContextPath()
2165 if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH))
2168 return _contextPath;
2171 /* ------------------------------------------------------------ */
2173 public String toString()
2175 return "ServletContext@" + ContextHandler.this.toString();
2178 /* ------------------------------------------------------------ */
2180 public boolean setInitParameter(String name, String value)
2182 if (ContextHandler.this.getInitParameter(name) != null)
2184 ContextHandler.this.getInitParams().put(name,value);
2189 public void addListener(String className)
2192 throw new UnsupportedOperationException();
2196 Class<? extends EventListener> clazz = (Class<? extends EventListener>) (_classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className));
2199 catch (ClassNotFoundException e)
2201 throw new IllegalArgumentException(e);
2206 public <T extends EventListener> void addListener(T t)
2209 throw new UnsupportedOperationException();
2211 checkListener(t.getClass());
2213 ContextHandler.this.addEventListener(t);
2214 ContextHandler.this.addProgrammaticListener(t);
2218 public void addListener(Class<? extends EventListener> listenerClass)
2221 throw new UnsupportedOperationException();
2225 EventListener e = createListener(listenerClass);
2228 catch (ServletException e)
2230 throw new IllegalArgumentException(e);
2235 public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
2239 return createInstance(clazz);
2243 throw new ServletException(e);
2248 public void checkListener (Class<? extends EventListener> listener) throws IllegalStateException
2251 int startIndex = (isExtendedListenerTypes()?EXTENDED_LISTENER_TYPE_INDEX:DEFAULT_LISTENER_TYPE_INDEX);
2252 for (int i=startIndex;i<SERVLET_LISTENER_TYPES.length;i++)
2254 if (SERVLET_LISTENER_TYPES[i].isAssignableFrom(listener))
2261 throw new IllegalArgumentException("Inappropriate listener class "+listener.getName());
2264 public void setExtendedListenerTypes (boolean extended)
2266 _extendedListenerTypes = extended;
2269 public boolean isExtendedListenerTypes()
2271 return _extendedListenerTypes;
2276 public ClassLoader getClassLoader()
2279 throw new UnsupportedOperationException();
2281 //no security manager just return the classloader
2282 if (System.getSecurityManager() == null)
2283 return _classLoader;
2286 //check to see if the classloader of the caller is the same as the context
2287 //classloader, or a parent of it
2290 Class reflect = Loader.loadClass(getClass(), "sun.reflect.Reflection");
2291 Method getCallerClass = reflect.getMethod("getCallerClass", Integer.TYPE);
2292 Class caller = (Class)getCallerClass.invoke(null, 2);
2295 ClassLoader callerLoader = caller.getClassLoader();
2296 while (!ok && callerLoader != null)
2298 if (callerLoader == _classLoader)
2301 callerLoader = callerLoader.getParent();
2305 return _classLoader;
2309 LOG.warn("Unable to check classloader of caller",e);
2312 AccessController.checkPermission(new RuntimePermission("getClassLoader"));
2313 return _classLoader;
2318 public JspConfigDescriptor getJspConfigDescriptor()
2320 LOG.warn(__unimplmented);
2324 public void setJspConfigDescriptor(JspConfigDescriptor d)
2330 public void declareRoles(String... roleNames)
2333 throw new IllegalStateException ();
2335 throw new UnsupportedOperationException();
2338 public void setEnabled(boolean enabled)
2343 public boolean isEnabled()
2350 public <T> T createInstance (Class<T> clazz) throws Exception
2352 T o = clazz.newInstance();
2358 public static class NoContext extends AttributesMap implements ServletContext
2360 private int _effectiveMajorVersion = SERVLET_MAJOR_VERSION;
2361 private int _effectiveMinorVersion = SERVLET_MINOR_VERSION;
2363 /* ------------------------------------------------------------ */
2369 public ServletContext getContext(String uripath)
2375 public int getMajorVersion()
2377 return SERVLET_MAJOR_VERSION;
2381 public String getMimeType(String file)
2387 public int getMinorVersion()
2389 return SERVLET_MINOR_VERSION;
2393 public RequestDispatcher getNamedDispatcher(String name)
2399 public RequestDispatcher getRequestDispatcher(String uriInContext)
2405 public String getRealPath(String path)
2411 public URL getResource(String path) throws MalformedURLException
2417 public InputStream getResourceAsStream(String path)
2423 public Set<String> getResourcePaths(String path)
2429 public String getServerInfo()
2431 return "jetty/" + Server.getVersion();
2436 public Servlet getServlet(String name) throws ServletException
2441 @SuppressWarnings("unchecked")
2444 public Enumeration<String> getServletNames()
2446 return Collections.enumeration(Collections.EMPTY_LIST);
2449 @SuppressWarnings("unchecked")
2452 public Enumeration<Servlet> getServlets()
2454 return Collections.enumeration(Collections.EMPTY_LIST);
2458 public void log(Exception exception, String msg)
2460 LOG.warn(msg,exception);
2464 public void log(String msg)
2470 public void log(String message, Throwable throwable)
2472 LOG.warn(message,throwable);
2476 public String getInitParameter(String name)
2481 @SuppressWarnings("unchecked")
2483 public Enumeration<String> getInitParameterNames()
2485 return Collections.enumeration(Collections.EMPTY_LIST);
2490 public String getServletContextName()
2492 return "No Context";
2496 public String getContextPath()
2503 public boolean setInitParameter(String name, String value)
2509 public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
2511 LOG.warn(__unimplmented);
2516 public Dynamic addFilter(String filterName, Filter filter)
2518 LOG.warn(__unimplmented);
2523 public Dynamic addFilter(String filterName, String className)
2525 LOG.warn(__unimplmented);
2530 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
2532 LOG.warn(__unimplmented);
2537 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
2539 LOG.warn(__unimplmented);
2544 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className)
2546 LOG.warn(__unimplmented);
2551 public <T extends Filter> T createFilter(Class<T> c) throws ServletException
2553 LOG.warn(__unimplmented);
2558 public <T extends Servlet> T createServlet(Class<T> c) throws ServletException
2560 LOG.warn(__unimplmented);
2565 public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
2567 LOG.warn(__unimplmented);
2572 public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
2574 LOG.warn(__unimplmented);
2579 public FilterRegistration getFilterRegistration(String filterName)
2581 LOG.warn(__unimplmented);
2586 public Map<String, ? extends FilterRegistration> getFilterRegistrations()
2588 LOG.warn(__unimplmented);
2593 public ServletRegistration getServletRegistration(String servletName)
2595 LOG.warn(__unimplmented);
2600 public Map<String, ? extends ServletRegistration> getServletRegistrations()
2602 LOG.warn(__unimplmented);
2607 public SessionCookieConfig getSessionCookieConfig()
2609 LOG.warn(__unimplmented);
2614 public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
2616 LOG.warn(__unimplmented);
2620 public void addListener(String className)
2622 LOG.warn(__unimplmented);
2626 public <T extends EventListener> void addListener(T t)
2628 LOG.warn(__unimplmented);
2632 public void addListener(Class<? extends EventListener> listenerClass)
2634 LOG.warn(__unimplmented);
2638 public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
2642 return clazz.newInstance();
2644 catch (InstantiationException e)
2646 throw new ServletException(e);
2648 catch (IllegalAccessException e)
2650 throw new ServletException(e);
2655 public ClassLoader getClassLoader()
2657 AccessController.checkPermission(new RuntimePermission("getClassLoader"));
2658 return ContextHandler.class.getClassLoader();
2662 public int getEffectiveMajorVersion()
2664 return _effectiveMajorVersion;
2668 public int getEffectiveMinorVersion()
2670 return _effectiveMinorVersion;
2673 public void setEffectiveMajorVersion (int v)
2675 _effectiveMajorVersion = v;
2678 public void setEffectiveMinorVersion (int v)
2680 _effectiveMinorVersion = v;
2684 public JspConfigDescriptor getJspConfigDescriptor()
2686 LOG.warn(__unimplmented);
2691 public void declareRoles(String... roleNames)
2693 LOG.warn(__unimplmented);
2697 * @see javax.servlet.ServletContext#getVirtualServerName()
2700 public String getVirtualServerName()
2702 // TODO 3.1 Auto-generated method stub
2708 /* ------------------------------------------------------------ */
2709 /** Interface to check aliases
2711 public interface AliasCheck
2713 /* ------------------------------------------------------------ */
2715 * @param path The path the aliased resource was created for
2716 * @param resource The aliased resourced
2717 * @return True if the resource is OK to be served.
2719 boolean check(String path, Resource resource);
2723 /* ------------------------------------------------------------ */
2724 /** Approve all aliases.
2726 public static class ApproveAliases implements AliasCheck
2729 public boolean check(String path, Resource resource)
2735 /* ------------------------------------------------------------ */
2736 /** Approve Aliases with same suffix.
2737 * Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be
2738 * approved because both the resource and alias end with ".html".
2741 public static class ApproveSameSuffixAliases implements AliasCheck
2744 LOG.warn("ApproveSameSuffixAlias is not safe for production");
2748 public boolean check(String path, Resource resource)
2750 int dot = path.lastIndexOf('.');
2753 String suffix=path.substring(dot);
2754 return resource.toString().endsWith(suffix);
2759 /* ------------------------------------------------------------ */
2760 /** Approve Aliases with a path prefix.
2761 * Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be
2762 * approved because both the resource and alias end with "/foobar.html".
2765 public static class ApprovePathPrefixAliases implements AliasCheck
2768 LOG.warn("ApprovePathPrefixAliases is not safe for production");
2772 public boolean check(String path, Resource resource)
2774 int slash = path.lastIndexOf('/');
2775 if (slash<0 || slash==path.length()-1)
2777 String suffix=path.substring(slash);
2778 return resource.toString().endsWith(suffix);
2782 /* ------------------------------------------------------------ */
2783 /** Approve Aliases of a non existent directory.
2784 * If a directory "/foobar/" does not exist, then the resource is
2785 * aliased to "/foobar". Accept such aliases.
2787 public static class ApproveNonExistentDirectoryAliases implements AliasCheck
2790 public boolean check(String path, Resource resource)
2792 if (resource.exists())
2795 String a=resource.getAlias().toString();
2796 String r=resource.getURL().toString();
2798 if (a.length()>r.length())
2799 return a.startsWith(r) && a.length()==r.length()+1 && a.endsWith("/");
2800 if (a.length()<r.length())
2801 return r.startsWith(a) && r.length()==a.length()+1 && r.endsWith("/");