View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses.
12  // ========================================================================
13  
14  package org.eclipse.jetty.server.handler;
15  
16  import java.io.File;
17  import java.io.IOException;
18  import java.io.InputStream;
19  import java.net.MalformedURLException;
20  import java.net.URL;
21  import java.net.URLClassLoader;
22  import java.util.Arrays;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.EventListener;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.Locale;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import javax.servlet.RequestDispatcher;
33  import javax.servlet.Servlet;
34  import javax.servlet.ServletContext;
35  import javax.servlet.ServletContextAttributeEvent;
36  import javax.servlet.ServletContextAttributeListener;
37  import javax.servlet.ServletContextEvent;
38  import javax.servlet.ServletContextListener;
39  import javax.servlet.ServletException;
40  import javax.servlet.ServletRequestAttributeListener;
41  import javax.servlet.ServletRequestEvent;
42  import javax.servlet.ServletRequestListener;
43  import javax.servlet.http.HttpServletRequest;
44  import javax.servlet.http.HttpServletResponse;
45  
46  import org.eclipse.jetty.http.HttpException;
47  import org.eclipse.jetty.http.MimeTypes;
48  import org.eclipse.jetty.io.Buffer;
49  import org.eclipse.jetty.server.Dispatcher;
50  import org.eclipse.jetty.server.DispatcherType;
51  import org.eclipse.jetty.server.Handler;
52  import org.eclipse.jetty.server.HandlerContainer;
53  import org.eclipse.jetty.server.HttpConnection;
54  import org.eclipse.jetty.server.Request;
55  import org.eclipse.jetty.server.Server;
56  import org.eclipse.jetty.util.Attributes;
57  import org.eclipse.jetty.util.AttributesMap;
58  import org.eclipse.jetty.util.LazyList;
59  import org.eclipse.jetty.util.Loader;
60  import org.eclipse.jetty.util.URIUtil;
61  import org.eclipse.jetty.util.log.Log;
62  import org.eclipse.jetty.util.log.Logger;
63  import org.eclipse.jetty.util.resource.Resource;
64  
65  /* ------------------------------------------------------------ */
66  /** ContextHandler.
67   *
68   * This handler wraps a call to handle by setting the context and
69   * servlet path, plus setting the context classloader.
70   *
71   * <p>
72   * If the context init parameter "org.eclipse.jetty.server.context.ManagedAttributes"
73   * is set to a comma separated list of names, then they are treated as context
74   * attribute names, which if set as attributes are passed to the servers Container
75   * so that they may be managed with JMX.
76   *
77   * @org.apache.xbean.XBean description="Creates a basic HTTP context"
78   */
79  public class ContextHandler extends ScopedHandler implements Attributes, Server.Graceful
80  {
81      private static final ThreadLocal<Context> __context=new ThreadLocal<Context>();
82      public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
83  
84      /* ------------------------------------------------------------ */
85      /** Get the current ServletContext implementation.
86       * This call is only valid during a call to doStart and is available to
87       * nested handlers to access the context.
88       *
89       * @return ServletContext implementation
90       */
91      public static Context getCurrentContext()
92      {
93          return __context.get();
94      }
95  
96      protected Context _scontext;
97  
98      private AttributesMap _attributes;
99      private AttributesMap _contextAttributes;
100     private ClassLoader _classLoader;
101     private String _contextPath="/";
102     private Map<String,String> _initParams;
103     private String _displayName;
104     private Resource _baseResource;
105     private MimeTypes _mimeTypes;
106     private Map<String,String> _localeEncodingMap;
107     private String[] _welcomeFiles;
108     private ErrorHandler _errorHandler;
109     private String[] _vhosts;
110     private Set<String> _connectors;
111     private EventListener[] _eventListeners;
112     private Logger _logger;
113     private boolean _allowNullPathInfo;
114     private int _maxFormContentSize=Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",200000).intValue();
115     private boolean _compactPath=false;
116     private boolean _aliases=false;
117 
118     private Object _contextListeners;
119     private Object _contextAttributeListeners;
120     private Object _requestListeners;
121     private Object _requestAttributeListeners;
122     private Map<String,Object> _managedAttributes;
123 
124     private boolean _shutdown=false;
125     private boolean _available=true;
126     private volatile int _availability;  // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE
127 
128     private final static int __STOPPED=0,__AVAILABLE=1,__SHUTDOWN=2,__UNAVAILABLE=3;
129 
130 
131     /* ------------------------------------------------------------ */
132     /**
133      *
134      */
135     public ContextHandler()
136     {
137         super();
138         _scontext=new Context();
139         _attributes=new AttributesMap();
140         _initParams=new HashMap<String,String>();
141     }
142 
143     /* ------------------------------------------------------------ */
144     /**
145      *
146      */
147     protected ContextHandler(Context context)
148     {
149         super();
150         _scontext=context;
151         _attributes=new AttributesMap();
152         _initParams=new HashMap<String,String>();
153     }
154 
155     /* ------------------------------------------------------------ */
156     /**
157      *
158      */
159     public ContextHandler(String contextPath)
160     {
161         this();
162         setContextPath(contextPath);
163     }
164 
165     /* ------------------------------------------------------------ */
166     /**
167      *
168      */
169     public ContextHandler(HandlerContainer parent, String contextPath)
170     {
171         this();
172         setContextPath(contextPath);
173         if (parent instanceof HandlerWrapper)
174             ((HandlerWrapper)parent).setHandler(this);
175         else if (parent instanceof HandlerCollection)
176             ((HandlerCollection)parent).addHandler(this);
177     }
178 
179     /* ------------------------------------------------------------ */
180     public Context getServletContext()
181     {
182         return _scontext;
183     }
184 
185     /* ------------------------------------------------------------ */
186     /**
187      * @return the allowNullPathInfo true if /context is not redirected to /context/
188      */
189     public boolean getAllowNullPathInfo()
190     {
191         return _allowNullPathInfo;
192     }
193 
194     /* ------------------------------------------------------------ */
195     /**
196      * @param allowNullPathInfo  true if /context is not redirected to /context/
197      */
198     public void setAllowNullPathInfo(boolean allowNullPathInfo)
199     {
200         _allowNullPathInfo=allowNullPathInfo;
201     }
202 
203     /* ------------------------------------------------------------ */
204     @Override
205     public void setServer(Server server)
206     {
207         if (_errorHandler!=null)
208         {
209             Server old_server=getServer();
210             if (old_server!=null && old_server!=server)
211                 old_server.getContainer().update(this, _errorHandler, null, "error",true);
212             super.setServer(server);
213             if (server!=null && server!=old_server)
214                 server.getContainer().update(this, null, _errorHandler, "error",true);
215             _errorHandler.setServer(server);
216         }
217         else
218             super.setServer(server);
219     }
220 
221     /* ------------------------------------------------------------ */
222     /** Set the virtual hosts for the context.
223      * Only requests that have a matching host header or fully qualified
224      * URL will be passed to that context with a virtual host name.
225      * A context with no virtual host names or a null virtual host name is
226      * available to all requests that are not served by a context with a
227      * matching virtual host name.
228      * @param vhosts Array of virtual hosts that this context responds to. A
229      * null host name or null/empty array means any hostname is acceptable.
230      * Host names may be String representation of IP addresses. Host names may
231      * start with '*.' to wildcard one level of names.
232      */
233     public void setVirtualHosts( String[] vhosts )
234     {
235         if ( vhosts == null )
236         {
237             _vhosts = vhosts;
238         }
239         else
240         {
241             _vhosts = new String[vhosts.length];
242             for ( int i = 0; i < vhosts.length; i++ )
243                 _vhosts[i] = normalizeHostname( vhosts[i]);
244         }
245     }
246 
247     /* ------------------------------------------------------------ */
248     /** Get the virtual hosts for the context.
249      * Only requests that have a matching host header or fully qualified
250      * URL will be passed to that context with a virtual host name.
251      * A context with no virtual host names or a null virtual host name is
252      * available to all requests that are not served by a context with a
253      * matching virtual host name.
254      * @return Array of virtual hosts that this context responds to. A
255      * null host name or empty array means any hostname is acceptable.
256      * Host names may be String representation of IP addresses.
257      * Host names may start with '*.' to wildcard one level of names.
258      */
259     public String[] getVirtualHosts()
260     {
261         return _vhosts;
262     }
263 
264     /* ------------------------------------------------------------ */
265     /**
266      * @deprecated use {@link #setConnectorNames(String[])}
267      */
268     @Deprecated
269     public void setHosts(String[] hosts)
270     {
271         setConnectorNames(hosts);
272     }
273 
274     /* ------------------------------------------------------------ */
275     /** Get the hosts for the context.
276      * @deprecated
277      */
278     @Deprecated
279     public String[] getHosts()
280     {
281         return getConnectorNames();
282     }
283 
284     /* ------------------------------------------------------------ */
285     /**
286      * @return an array of connector names that this context
287      * will accept a request from.
288      */
289     public String[] getConnectorNames()
290     {
291         if (_connectors==null || _connectors.size()==0)
292             return null;
293 
294         return _connectors.toArray(new String[_connectors.size()]);
295     }
296 
297     /* ------------------------------------------------------------ */
298     /** Set the names of accepted connectors.
299      *
300      * Names are either "host:port" or a specific configured name for a connector.
301      *
302      * @param connectors If non null, an array of connector names that this context
303      * will accept a request from.
304      */
305     public void setConnectorNames(String[] connectors)
306     {
307         if (connectors==null || connectors.length==0)
308             _connectors=null;
309         else
310             _connectors= new HashSet<String>(Arrays.asList(connectors));
311     }
312 
313     /* ------------------------------------------------------------ */
314     /*
315      * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
316      */
317     public Object getAttribute(String name)
318     {
319         return _attributes.getAttribute(name);
320     }
321 
322     /* ------------------------------------------------------------ */
323     /*
324      * @see javax.servlet.ServletContext#getAttributeNames()
325      */
326     @SuppressWarnings("unchecked")
327     public Enumeration getAttributeNames()
328     {
329         return AttributesMap.getAttributeNamesCopy(_attributes);
330     }
331 
332     /* ------------------------------------------------------------ */
333     /**
334      * @return Returns the attributes.
335      */
336     public Attributes getAttributes()
337     {
338         return _attributes;
339     }
340 
341     /* ------------------------------------------------------------ */
342     /**
343      * @return Returns the classLoader.
344      */
345     public ClassLoader getClassLoader()
346     {
347         return _classLoader;
348     }
349 
350     /* ------------------------------------------------------------ */
351     /**
352      * Make best effort to extract a file classpath from the context classloader
353      * @return Returns the classLoader.
354      */
355     public String getClassPath()
356     {
357         if ( _classLoader==null || !(_classLoader instanceof URLClassLoader))
358             return null;
359         URLClassLoader loader = (URLClassLoader)_classLoader;
360         URL[] urls =loader.getURLs();
361         StringBuilder classpath=new StringBuilder();
362         for (int i=0;i<urls.length;i++)
363         {
364             try
365             {
366                 Resource resource = newResource(urls[i]);
367                 File file=resource.getFile();
368                 if (file!=null && file.exists())
369                 {
370                     if (classpath.length()>0)
371                         classpath.append(File.pathSeparatorChar);
372                     classpath.append(file.getAbsolutePath());
373                 }
374             }
375             catch (IOException e)
376             {
377                 Log.debug(e);
378             }
379         }
380         if (classpath.length()==0)
381             return null;
382         return classpath.toString();
383     }
384 
385     /* ------------------------------------------------------------ */
386     /**
387      * @return Returns the _contextPath.
388      */
389     public String getContextPath()
390     {
391         return _contextPath;
392     }
393 
394     /* ------------------------------------------------------------ */
395     /*
396      * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
397      */
398     public String getInitParameter(String name)
399     {
400         return _initParams.get(name);
401     }
402 
403     /* ------------------------------------------------------------ */
404     /*
405      * @see javax.servlet.ServletContext#getInitParameterNames()
406      */
407     @SuppressWarnings("unchecked")
408     public Enumeration getInitParameterNames()
409     {
410         return Collections.enumeration(_initParams.keySet());
411     }
412 
413     /* ------------------------------------------------------------ */
414     /**
415      * @return Returns the initParams.
416      */
417     public Map<String,String> getInitParams()
418     {
419         return _initParams;
420     }
421 
422     /* ------------------------------------------------------------ */
423     /*
424      * @see javax.servlet.ServletContext#getServletContextName()
425      */
426     public String getDisplayName()
427     {
428         return _displayName;
429     }
430 
431     /* ------------------------------------------------------------ */
432     public EventListener[] getEventListeners()
433     {
434         return _eventListeners;
435     }
436 
437     /* ------------------------------------------------------------ */
438     /**
439      * Set the context event listeners.
440      * @see ServletContextListener
441      * @see ServletContextAttributeListener
442      * @see ServletRequestListener
443      * @see ServletRequestAttributeListener
444      */
445     public void setEventListeners(EventListener[] eventListeners)
446     {
447         _contextListeners=null;
448         _contextAttributeListeners=null;
449         _requestListeners=null;
450         _requestAttributeListeners=null;
451 
452         _eventListeners=eventListeners;
453 
454         for (int i=0; eventListeners!=null && i<eventListeners.length;i ++)
455         {
456             EventListener listener = _eventListeners[i];
457 
458             if (listener instanceof ServletContextListener)
459                 _contextListeners= LazyList.add(_contextListeners, listener);
460 
461             if (listener instanceof ServletContextAttributeListener)
462                 _contextAttributeListeners= LazyList.add(_contextAttributeListeners, listener);
463 
464             if (listener instanceof ServletRequestListener)
465                 _requestListeners= LazyList.add(_requestListeners, listener);
466 
467             if (listener instanceof ServletRequestAttributeListener)
468                 _requestAttributeListeners= LazyList.add(_requestAttributeListeners, listener);
469         }
470     }
471 
472     /* ------------------------------------------------------------ */
473     /**
474     * Add a context event listeners.
475     * @see ServletContextListener
476     * @see ServletContextAttributeListener
477     * @see ServletRequestListener
478     * @see ServletRequestAttributeListener
479     */
480     public void addEventListener(EventListener listener)
481     {
482         setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(), listener, EventListener.class));
483     }
484 
485     /* ------------------------------------------------------------ */
486     /**
487      * @return true if this context is accepting new requests
488      */
489     public boolean isShutdown()
490     {
491         return !_shutdown;
492     }
493 
494     /* ------------------------------------------------------------ */
495     /** Set shutdown status.
496      * This field allows for graceful shutdown of a context. A started context may be put into non accepting state so
497      * that existing requests can complete, but no new requests are accepted.
498      * @param shutdown true if this context is (not?) accepting new requests
499      */
500     public void setShutdown(boolean shutdown)
501     {
502         synchronized(this)
503         {
504             _shutdown = shutdown;
505             _availability=isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
506         }
507     }
508 
509     /* ------------------------------------------------------------ */
510     /**
511      * @return false if this context is unavailable (sends 503)
512      */
513     public boolean isAvailable()
514     {
515         return _available;
516     }
517 
518     /* ------------------------------------------------------------ */
519     /** Set Available status.
520      */
521     public void setAvailable(boolean available)
522     {
523         synchronized(this)
524         {
525             _available = available;
526             _availability=isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
527         }
528     }
529 
530     /* ------------------------------------------------------------ */
531     public Logger getLogger()
532     {
533         return _logger;
534     }
535 
536     /* ------------------------------------------------------------ */
537     public void setLogger(Logger logger)
538     {
539         _logger=logger;
540     }
541 
542     /* ------------------------------------------------------------ */
543     /*
544      * @see org.eclipse.thread.AbstractLifeCycle#doStart()
545      */
546     @Override
547     protected void doStart() throws Exception
548     {
549         _availability=__STOPPED;
550 
551         if (_contextPath==null)
552             throw new IllegalStateException("Null contextPath");
553 
554         _logger=Log.getLogger(getDisplayName()==null?getContextPath():getDisplayName());
555         ClassLoader old_classloader=null;
556         Thread current_thread=null;
557         Context old_context=null;
558 
559         _contextAttributes=new AttributesMap();
560         try
561         {
562 
563             // Set the classloader
564             if (_classLoader!=null)
565             {
566                 current_thread=Thread.currentThread();
567                 old_classloader=current_thread.getContextClassLoader();
568                 current_thread.setContextClassLoader(_classLoader);
569             }
570 
571 
572             if (_mimeTypes==null)
573                 _mimeTypes=new MimeTypes();
574 
575             old_context=__context.get();
576             __context.set(_scontext);
577 
578             // defers the calling of super.doStart()
579             startContext();
580 
581             _availability=_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE;
582         }
583         finally
584         {
585             __context.set(old_context);
586 
587             // reset the classloader
588             if (_classLoader!=null)
589             {
590                 current_thread.setContextClassLoader(old_classloader);
591             }
592 
593         }
594     }
595 
596     /* ------------------------------------------------------------ */
597     /**
598      * Extensible startContext.
599      * this method is called from {@link ContextHandler#doStart()} instead of a
600      * call to super.doStart().   This allows derived classes to insert additional
601      * handling (Eg configuration) before the call to super.doStart by this method
602      * will start contained handlers.
603      * @see org.eclipse.jetty.server.handler.ContextHandler.Context
604      */
605     protected void startContext()
606     	throws Exception
607     {
608         String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
609         if (managedAttributes!=null)
610         {
611             _managedAttributes=new HashMap<String,Object>();
612             String[] attributes = managedAttributes.split(",");
613             for (String attribute : attributes)
614                 _managedAttributes.put(attribute,null);
615 
616             Enumeration e = _scontext.getAttributeNames();
617             while(e.hasMoreElements())
618             {
619                 String name = (String)e.nextElement();
620                 Object value = _scontext.getAttribute(name);
621                 setManagedAttribute(name,value);
622             }
623         }
624 
625         super.doStart();
626 
627         if (_errorHandler!=null)
628             _errorHandler.start();
629 
630         // Context listeners
631         if (_contextListeners != null )
632         {
633             ServletContextEvent event= new ServletContextEvent(_scontext);
634             for (int i= 0; i < LazyList.size(_contextListeners); i++)
635             {
636                 ((ServletContextListener)LazyList.get(_contextListeners, i)).contextInitialized(event);
637             }
638         }
639 
640     }
641 
642     /* ------------------------------------------------------------ */
643     /*
644      * @see org.eclipse.thread.AbstractLifeCycle#doStop()
645      */
646     @Override
647     protected void doStop() throws Exception
648     {
649         _availability=__STOPPED;
650 
651         ClassLoader old_classloader=null;
652         Thread current_thread=null;
653 
654         Context old_context=__context.get();
655         __context.set(_scontext);
656         try
657         {
658             // Set the classloader
659             if (_classLoader!=null)
660             {
661                 current_thread=Thread.currentThread();
662                 old_classloader=current_thread.getContextClassLoader();
663                 current_thread.setContextClassLoader(_classLoader);
664             }
665 
666             super.doStop();
667 
668             // Context listeners
669             if (_contextListeners != null )
670             {
671                 ServletContextEvent event= new ServletContextEvent(_scontext);
672                 for (int i=LazyList.size(_contextListeners); i-->0;)
673                 {
674                     ((ServletContextListener)LazyList.get(_contextListeners, i)).contextDestroyed(event);
675                 }
676             }
677 
678             if (_errorHandler!=null)
679                 _errorHandler.stop();
680 
681             Enumeration e = _scontext.getAttributeNames();
682             while(e.hasMoreElements())
683             {
684                 String name = (String)e.nextElement();
685                 setManagedAttribute(name,null);
686             }
687         }
688         finally
689         {
690             __context.set(old_context);
691             // reset the classloader
692             if (_classLoader!=null)
693                 current_thread.setContextClassLoader(old_classloader);
694         }
695 
696         if (_contextAttributes!=null)
697             _contextAttributes.clearAttributes();
698         _contextAttributes=null;
699     }
700 
701     /* ------------------------------------------------------------ */
702     /*
703      * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
704      */
705     public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response)
706             throws IOException, ServletException
707     {
708         DispatcherType dispatch=baseRequest.getDispatcherType();
709 
710         switch(_availability)
711         {
712             case __STOPPED:
713             case __SHUTDOWN:
714                 return false;
715             case __UNAVAILABLE:
716                 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
717                 return false;
718             default:
719                 if((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
720                     return false;
721         }
722 
723         // Check the vhosts
724         if (_vhosts!=null && _vhosts.length>0)
725         {
726             String vhost = normalizeHostname( baseRequest.getServerName());
727 
728             boolean match=false;
729 
730             // TODO non-linear lookup
731             for (int i=0;!match && i<_vhosts.length;i++)
732             {
733                 String contextVhost = _vhosts[i];
734                 if(contextVhost==null) continue;
735                 if(contextVhost.startsWith("*.")) {
736                     // wildcard only at the beginning, and only for one additional subdomain level
737                     match=contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".")+1,contextVhost.length()-2);
738                 } else
739                     match=contextVhost.equalsIgnoreCase(vhost);
740             }
741             if (!match)
742                 return false;
743         }
744 
745         // Check the connector
746         if (_connectors!=null && _connectors.size()>0)
747         {
748             String connector=HttpConnection.getCurrentConnection().getConnector().getName();
749             if (connector==null || !_connectors.contains(connector))
750                 return false;
751         }
752                 
753         // Are we not the root context?
754         if (_contextPath.length()>1)
755         {
756             // reject requests that are not for us
757             if (!target.startsWith(_contextPath))
758                 return false;
759             if (target.length()>_contextPath.length() && target.charAt(_contextPath.length())!='/')
760                 return false;
761             
762             // redirect null path infos
763             if (!_allowNullPathInfo && _contextPath.length()==target.length())
764             {
765                 // context request must end with /
766                 baseRequest.setHandled(true);
767                 if (baseRequest.getQueryString()!=null)
768                     response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH)+"?"+baseRequest.getQueryString());
769                 else
770                     response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
771                 return false;
772             }
773         }
774 
775         return true;
776     }
777 
778 
779 
780     /* ------------------------------------------------------------ */
781     /**
782      * @see org.eclipse.jetty.server.handler.ScopedHandler#doScope(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
783      */
784     @Override
785     public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
786     {
787         Context old_context=null;
788         String old_context_path=null;
789         String old_servlet_path=null;
790         String old_path_info=null;
791         ClassLoader old_classloader=null;
792         Thread current_thread=null;
793         String pathInfo=null;
794 
795         DispatcherType dispatch=baseRequest.getDispatcherType();
796 
797         old_context=baseRequest.getContext();
798 
799         // Are we already in this context?
800         if (old_context!=_scontext)
801         {
802             // check the target.
803             if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch))
804             {
805                 if (_compactPath)
806                     target=URIUtil.compactPath(target);
807                 if (!checkContext(target,baseRequest,response))
808                     return;
809 
810                 if (target.length()>_contextPath.length())
811                 {
812                     if (_contextPath.length()>1)
813                         target=target.substring(_contextPath.length());
814                     pathInfo=target;
815                 }
816                 else if (_contextPath.length()==1)
817                 {
818                     target=URIUtil.SLASH;
819                     pathInfo=URIUtil.SLASH;
820                 }
821                 else
822                 {
823                     target=URIUtil.SLASH;
824                     pathInfo=null;
825                 }
826             }
827 
828             // Set the classloader
829             if (_classLoader!=null)
830             {
831                 current_thread=Thread.currentThread();
832                 old_classloader=current_thread.getContextClassLoader();
833                 current_thread.setContextClassLoader(_classLoader);
834             }
835         }
836 
837         try
838         {
839             old_context_path=baseRequest.getContextPath();
840             old_servlet_path=baseRequest.getServletPath();
841             old_path_info=baseRequest.getPathInfo();
842 
843             // Update the paths
844             baseRequest.setContext(_scontext);
845             if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/"))
846             {
847                 if (_contextPath.length()==1)
848                     baseRequest.setContextPath("");
849                 else
850                     baseRequest.setContextPath(_contextPath);
851                 baseRequest.setServletPath(null);
852                 baseRequest.setPathInfo(pathInfo);
853             }
854 
855             // start manual inline of nextScope(target,baseRequest,request,response);
856             //noinspection ConstantIfStatement
857             if (false)
858                 nextScope(target,baseRequest,request,response);
859             else if (_nextScope!=null)
860                 _nextScope.doScope(target,baseRequest,request, response);
861             else if (_outerScope!=null)
862                 _outerScope.doHandle(target,baseRequest,request, response);
863             else
864                 doHandle(target,baseRequest,request, response);
865             // end manual inline (pathentic attempt to reduce stack depth)
866         }
867         finally
868         {
869             if (old_context!=_scontext)
870             {
871                 // reset the classloader
872                 if (_classLoader!=null)
873                 {
874                     current_thread.setContextClassLoader(old_classloader);
875                 }
876 
877                 // reset the context and servlet path.
878                 baseRequest.setContext(old_context);
879                 baseRequest.setContextPath(old_context_path);
880                 baseRequest.setServletPath(old_servlet_path);
881                 baseRequest.setPathInfo(old_path_info);
882             }
883         }
884     }
885 
886     /* ------------------------------------------------------------ */
887     /**
888      * @see org.eclipse.jetty.server.handler.ScopedHandler#doHandle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
889      */
890     @Override
891     public void doHandle(String target,Request baseRequest,HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException
892     {
893         final DispatcherType dispatch=baseRequest.getDispatcherType();
894         final boolean new_context=baseRequest.takeNewContext();
895         try
896         {
897             if (new_context)
898             {
899                 // Handle the REALLY SILLY request events!
900                 if (_requestAttributeListeners!=null)
901                 {
902                     final int s=LazyList.size(_requestAttributeListeners);
903                     for(int i=0;i<s;i++)
904                         baseRequest.addEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
905                 }
906 
907                 if (_requestListeners!=null)
908                 {
909                     final int s=LazyList.size(_requestListeners);
910                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
911                     for(int i=0;i<s;i++)
912                         ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(sre);
913                 }
914             }
915 
916             if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target))
917                 throw new HttpException(HttpServletResponse.SC_NOT_FOUND);
918 
919             // start manual inline of nextHandle(target,baseRequest,request,response);
920             //noinspection ConstantIfStatement
921             if (false)
922                 nextHandle(target,baseRequest,request,response);
923             else if (_nextScope!=null && _nextScope==_handler)
924                 _nextScope.doHandle(target,baseRequest,request, response);
925             else if (_handler!=null)
926                 _handler.handle(target,baseRequest, request, response);
927             // end manual inline
928         }
929         catch(HttpException e)
930         {
931             Log.debug(e);
932             response.sendError(e.getStatus(), e.getReason());
933         }
934         finally
935         {
936             // Handle more REALLY SILLY request events!
937             if (new_context)
938             {
939                 if (_requestListeners!=null)
940                 {
941                     final int s=LazyList.size(_requestListeners);
942                     final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
943                     for(int i=0;i<s;i++)
944                         ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestDestroyed(sre);
945                 }
946 
947                 if (_requestAttributeListeners!=null)
948                 {
949                     for(int i=LazyList.size(_requestAttributeListeners);i-->0;)
950                         baseRequest.removeEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
951                 }
952             }
953         }
954     }
955 
956     /* ------------------------------------------------------------ */
957     /* Handle a runnable in this context
958      */
959     public void handle(Runnable runnable)
960     {
961         ClassLoader old_classloader=null;
962         Thread current_thread=null;
963         try
964         {
965             // Set the classloader
966             if (_classLoader!=null)
967             {
968                 current_thread=Thread.currentThread();
969                 old_classloader=current_thread.getContextClassLoader();
970                 current_thread.setContextClassLoader(_classLoader);
971             }
972 
973             runnable.run();
974         }
975         finally
976         {
977             if (old_classloader!=null)
978             {
979                 current_thread.setContextClassLoader(old_classloader);
980             }
981         }
982     }
983 
984     /* ------------------------------------------------------------ */
985     /** Check the target.
986      * Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a
987      * target within a context is determined.  If the target is protected, 404 is returned.
988      * The default implementation always returns false.
989      */
990     /* ------------------------------------------------------------ */
991     protected boolean isProtectedTarget(String target)
992     {
993         return false;
994     }
995 
996     /* ------------------------------------------------------------ */
997     /*
998      * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
999      */
1000     public void removeAttribute(String name)
1001     {
1002         setManagedAttribute(name,null);
1003         _attributes.removeAttribute(name);
1004     }
1005 
1006     /* ------------------------------------------------------------ */
1007     /* Set a context attribute.
1008      * Attributes set via this API cannot be overriden by the ServletContext.setAttribute API.
1009      * Their lifecycle spans the stop/start of a context.  No attribute listener events are
1010      * triggered by this API.
1011      * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1012      */
1013     public void setAttribute(String name, Object value)
1014     {
1015         setManagedAttribute(name,value);
1016         _attributes.setAttribute(name,value);
1017     }
1018 
1019     /* ------------------------------------------------------------ */
1020     /**
1021      * @param attributes The attributes to set.
1022      */
1023     public void setAttributes(Attributes attributes)
1024     {
1025         if (attributes instanceof AttributesMap)
1026         {
1027             _attributes = (AttributesMap)attributes;
1028             Enumeration e = _attributes.getAttributeNames();
1029             while (e.hasMoreElements())
1030             {
1031                 String name = (String)e.nextElement();
1032                 setManagedAttribute(name,attributes.getAttribute(name));
1033             }
1034         }
1035         else
1036         {
1037             _attributes=new AttributesMap();
1038             Enumeration e = attributes.getAttributeNames();
1039             while (e.hasMoreElements())
1040             {
1041                 String name = (String)e.nextElement();
1042                 Object value=attributes.getAttribute(name);
1043                 setManagedAttribute(name,value);
1044                 _attributes.setAttribute(name,value);
1045             }
1046         }
1047     }
1048 
1049     /* ------------------------------------------------------------ */
1050     public void clearAttributes()
1051     {
1052         Enumeration e = _attributes.getAttributeNames();
1053         while (e.hasMoreElements())
1054         {
1055             String name = (String)e.nextElement();
1056             setManagedAttribute(name,null);
1057         }
1058         _attributes.clearAttributes();
1059     }
1060 
1061     /* ------------------------------------------------------------ */
1062     private void setManagedAttribute(String name, Object value)
1063     {
1064         if (_managedAttributes!=null && _managedAttributes.containsKey(name))
1065         {
1066             Object old =_managedAttributes.put(name,value);
1067             if (old!=null)
1068                 getServer().getContainer().removeBean(old);
1069             if (value!=null)
1070             {
1071                 if (_logger.isDebugEnabled()) _logger.debug("Managing "+name);
1072                 getServer().getContainer().addBean(value);
1073             }
1074         }
1075     }
1076 
1077     /* ------------------------------------------------------------ */
1078     /**
1079      * @param classLoader The classLoader to set.
1080      */
1081     public void setClassLoader(ClassLoader classLoader)
1082     {
1083         _classLoader = classLoader;
1084     }
1085 
1086     /* ------------------------------------------------------------ */
1087     /**
1088      * @param contextPath The _contextPath to set.
1089      */
1090     public void setContextPath(String contextPath)
1091     {
1092         if (contextPath!=null && contextPath.length()>1 && contextPath.endsWith("/"))
1093             throw new IllegalArgumentException("ends with /");
1094         _contextPath = contextPath;
1095 
1096         if (getServer()!=null && (getServer().isStarting() || getServer().isStarted()))
1097         {
1098             Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
1099             for (int h=0;contextCollections!=null&& h<contextCollections.length;h++)
1100                 ((ContextHandlerCollection)contextCollections[h]).mapContexts();
1101         }
1102     }
1103 
1104     /* ------------------------------------------------------------ */
1105     /**
1106      * @param initParams The initParams to set.
1107      */
1108     public void setInitParams(Map<String,String> initParams)
1109     {
1110         if (initParams == null)
1111             return;
1112         _initParams = new HashMap<String,String>(initParams);
1113     }
1114 
1115     /* ------------------------------------------------------------ */
1116     /**
1117      * @param servletContextName The servletContextName to set.
1118      */
1119     public void setDisplayName(String servletContextName)
1120     {
1121         _displayName = servletContextName;
1122     }
1123 
1124     /* ------------------------------------------------------------ */
1125     /**
1126      * @return Returns the resourceBase.
1127      */
1128     public Resource getBaseResource()
1129     {
1130         if (_baseResource==null)
1131             return null;
1132         return _baseResource;
1133     }
1134 
1135     /* ------------------------------------------------------------ */
1136     /**
1137      * @return Returns the base resource as a string.
1138      */
1139     public String getResourceBase()
1140     {
1141         if (_baseResource==null)
1142             return null;
1143         return _baseResource.toString();
1144     }
1145 
1146     /* ------------------------------------------------------------ */
1147     /**
1148      * @param base The resourceBase to set.
1149      */
1150     public void setBaseResource(Resource base)
1151     {
1152         _baseResource=base;
1153     }
1154 
1155     /* ------------------------------------------------------------ */
1156     /**
1157      * @param resourceBase The base resource as a string.
1158      */
1159     public void setResourceBase(String resourceBase)
1160     {
1161         try
1162         {
1163             setBaseResource(newResource(resourceBase));
1164         }
1165         catch (Exception e)
1166         {
1167             Log.warn(e.toString());
1168             Log.debug(e);
1169             throw new IllegalArgumentException(resourceBase);
1170         }
1171     }
1172     /* ------------------------------------------------------------ */
1173     /**
1174      * @return True if aliases are allowed
1175      */
1176     public boolean isAliases()
1177     {
1178         return _aliases;
1179     }
1180 
1181     /* ------------------------------------------------------------ */
1182     /**
1183      * @param aliases  aliases are allowed
1184      */
1185     public void setAliases(boolean aliases)
1186     {
1187         _aliases = aliases;
1188     }
1189 
1190     /* ------------------------------------------------------------ */
1191     /**
1192      * @return Returns the mimeTypes.
1193      */
1194     public MimeTypes getMimeTypes()
1195     {
1196         return _mimeTypes;
1197     }
1198 
1199     /* ------------------------------------------------------------ */
1200     /**
1201      * @param mimeTypes The mimeTypes to set.
1202      */
1203     public void setMimeTypes(MimeTypes mimeTypes)
1204     {
1205         _mimeTypes = mimeTypes;
1206     }
1207 
1208     /* ------------------------------------------------------------ */
1209     /**
1210      */
1211     public void setWelcomeFiles(String[] files)
1212     {
1213         _welcomeFiles=files;
1214     }
1215 
1216     /* ------------------------------------------------------------ */
1217     /**
1218      * @return The names of the files which the server should consider to be welcome files in this context.
1219      * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
1220      * @see #setWelcomeFiles
1221      */
1222     public String[] getWelcomeFiles()
1223     {
1224         return _welcomeFiles;
1225     }
1226 
1227     /* ------------------------------------------------------------ */
1228     /**
1229      * @return Returns the errorHandler.
1230      */
1231     public ErrorHandler getErrorHandler()
1232     {
1233         return _errorHandler;
1234     }
1235 
1236     /* ------------------------------------------------------------ */
1237     /**
1238      * @param errorHandler The errorHandler to set.
1239      */
1240     public void setErrorHandler(ErrorHandler errorHandler)
1241     {
1242         if (errorHandler!=null)
1243             errorHandler.setServer(getServer());
1244         if (getServer()!=null)
1245             getServer().getContainer().update(this, _errorHandler, errorHandler, "errorHandler",true);
1246         _errorHandler = errorHandler;
1247     }
1248 
1249     /* ------------------------------------------------------------ */
1250     public int getMaxFormContentSize()
1251     {
1252         return _maxFormContentSize;
1253     }
1254 
1255     /* ------------------------------------------------------------ */
1256     public void setMaxFormContentSize(int maxSize)
1257     {
1258         _maxFormContentSize=maxSize;
1259     }
1260 
1261 
1262     /* ------------------------------------------------------------ */
1263     /**
1264      * @return True if URLs are compacted to replace multiple '/'s with a single '/'
1265      */
1266     public boolean isCompactPath()
1267     {
1268         return _compactPath;
1269     }
1270 
1271     /* ------------------------------------------------------------ */
1272     /**
1273      * @param compactPath True if URLs are compacted to replace multiple '/'s with a single '/'
1274      */
1275     public void setCompactPath(boolean compactPath)
1276     {
1277         _compactPath=compactPath;
1278     }
1279 
1280     /* ------------------------------------------------------------ */
1281     @Override
1282     public String toString()
1283     {
1284 
1285         return super.toString()+"@"+Integer.toHexString(hashCode())+getContextPath()+","+getBaseResource();
1286     }
1287 
1288     /* ------------------------------------------------------------ */
1289     public synchronized Class<?> loadClass(String className)
1290         throws ClassNotFoundException
1291     {
1292         if (className==null)
1293             return null;
1294 
1295         if (_classLoader==null)
1296             return Loader.loadClass(this.getClass(), className);
1297 
1298         return _classLoader.loadClass(className);
1299     }
1300 
1301 
1302     /* ------------------------------------------------------------ */
1303     public void addLocaleEncoding(String locale,String encoding)
1304     {
1305         if (_localeEncodingMap==null)
1306             _localeEncodingMap=new HashMap<String,String>();
1307         _localeEncodingMap.put(locale, encoding);
1308     }
1309 
1310     /* ------------------------------------------------------------ */
1311     /**
1312      * Get the character encoding for a locale. The full locale name is first
1313      * looked up in the map of encodings. If no encoding is found, then the
1314      * locale language is looked up.
1315      *
1316      * @param locale a <code>Locale</code> value
1317      * @return a <code>String</code> representing the character encoding for
1318      * the locale or null if none found.
1319      */
1320     public String getLocaleEncoding(Locale locale)
1321     {
1322         if (_localeEncodingMap==null)
1323             return null;
1324         String encoding = _localeEncodingMap.get(locale.toString());
1325         if (encoding==null)
1326             encoding = _localeEncodingMap.get(locale.getLanguage());
1327         return encoding;
1328     }
1329 
1330     /* ------------------------------------------------------------ */
1331     /*
1332      */
1333     public Resource getResource(String path) throws MalformedURLException
1334     {
1335         if (path==null || !path.startsWith(URIUtil.SLASH))
1336             throw new MalformedURLException(path);
1337 
1338         if (_baseResource==null)
1339             return null;
1340 
1341         try
1342         {
1343             path=URIUtil.canonicalPath(path);
1344             Resource resource=_baseResource.addPath(path);
1345 
1346             if (!_aliases && resource.getAlias()!=null)
1347             {
1348                 if (resource.exists())
1349                     Log.warn("Aliased resource: "+resource+"~="+resource.getAlias());
1350                 else if (Log.isDebugEnabled())
1351                     Log.debug("Aliased resource: "+resource+"~="+resource.getAlias());
1352                 return null;
1353             }
1354 
1355             return resource;
1356         }
1357         catch(Exception e)
1358         {
1359             Log.ignore(e);
1360         }
1361 
1362         return null;
1363     }
1364 
1365     /* ------------------------------------------------------------ */
1366     /** Convert URL to Resource
1367      * wrapper for {@link Resource#newResource(URL)} enables extensions to
1368      * provide alternate resource implementations.
1369      */
1370     public Resource newResource(URL url) throws IOException
1371     {
1372         return Resource.newResource(url);
1373     }
1374 
1375     /* ------------------------------------------------------------ */
1376     /** Convert URL to Resource
1377      * wrapper for {@link Resource#newResource(String)} enables extensions to
1378      * provide alternate resource implementations.
1379      */
1380     public Resource newResource(String url) throws IOException
1381     {
1382         return Resource.newResource(url);
1383     }
1384 
1385     /* ------------------------------------------------------------ */
1386     /*
1387      */
1388     public Set<String> getResourcePaths(String path)
1389     {
1390         try
1391         {
1392             path=URIUtil.canonicalPath(path);
1393             Resource resource=getResource(path);
1394 
1395             if (resource!=null && resource.exists())
1396             {
1397                 if (!path.endsWith(URIUtil.SLASH))
1398                     path=path+URIUtil.SLASH;
1399 
1400                 String[] l=resource.list();
1401                 if (l!=null)
1402                 {
1403                     HashSet<String> set = new HashSet<String>();
1404                     for(int i=0;i<l.length;i++)
1405                         set.add(path+l[i]);
1406                     return set;
1407                 }
1408             }
1409         }
1410         catch(Exception e)
1411         {
1412             Log.ignore(e);
1413         }
1414         return Collections.emptySet();
1415     }
1416 
1417 
1418 
1419     /* ------------------------------------------------------------ */
1420     private String normalizeHostname( String host )
1421     {
1422         if ( host == null )
1423             return null;
1424 
1425         if ( host.endsWith( "." ) )
1426             return host.substring( 0, host.length() -1);
1427 
1428             return host;
1429     }
1430 
1431     /* ------------------------------------------------------------ */
1432     /** Context.
1433      * <p>
1434      * A partial implementation of  {@link javax.servlet.ServletContext}.
1435      * A complete implementation is provided by the derived {@link ContextHandler}.
1436      * </p>
1437      *
1438      *
1439      */
1440     public class Context implements ServletContext
1441     {
1442         /* ------------------------------------------------------------ */
1443         protected Context()
1444         {
1445         }
1446 
1447         /* ------------------------------------------------------------ */
1448         public ContextHandler getContextHandler()
1449         {
1450             // TODO reduce visibility of this method
1451             return ContextHandler.this;
1452         }
1453 
1454         /* ------------------------------------------------------------ */
1455         /*
1456          * @see javax.servlet.ServletContext#getContext(java.lang.String)
1457          */
1458         public ServletContext getContext(String uripath)
1459         {
1460             ContextHandler context=null;
1461             Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class);
1462             for (int i=0;i<handlers.length;i++)
1463             {
1464                 if (handlers[i]==null || !handlers[i].isStarted())
1465                     continue;
1466                 ContextHandler ch = (ContextHandler)handlers[i];
1467                 String context_path=ch.getContextPath();
1468                 
1469                 if (uripath.equals(context_path) || (uripath.startsWith(context_path)&&uripath.charAt(context_path.length())=='/') || "/".equals(context_path))
1470                 {
1471                     if (context==null || context_path.length()>context.getContextPath().length())
1472                         context=ch;
1473                 }
1474             }
1475 
1476             if (context!=null)
1477                 return context._scontext;
1478             return null;
1479         }
1480 
1481         /* ------------------------------------------------------------ */
1482         /*
1483          * @see javax.servlet.ServletContext#getMajorVersion()
1484          */
1485         public int getMajorVersion()
1486         {
1487             return 2;
1488         }
1489 
1490         /* ------------------------------------------------------------ */
1491         /*
1492          * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
1493          */
1494         public String getMimeType(String file)
1495         {
1496             if (_mimeTypes==null)
1497                 return null;
1498             Buffer mime = _mimeTypes.getMimeByExtension(file);
1499             if (mime!=null)
1500                 return mime.toString();
1501             return null;
1502         }
1503 
1504         /* ------------------------------------------------------------ */
1505         /*
1506          * @see javax.servlet.ServletContext#getMinorVersion()
1507          */
1508         public int getMinorVersion()
1509         {
1510             return 5;
1511         }
1512 
1513         /* ------------------------------------------------------------ */
1514         /*
1515          * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String)
1516          */
1517         public RequestDispatcher getNamedDispatcher(String name)
1518         {
1519             return null;
1520         }
1521         /* ------------------------------------------------------------ */
1522         /*
1523          * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
1524          */
1525         public RequestDispatcher getRequestDispatcher(String uriInContext)
1526         {
1527             if (uriInContext == null)
1528                 return null;
1529 
1530             if (!uriInContext.startsWith("/"))
1531                 return null;
1532 
1533             try
1534             {
1535                 String query=null;
1536                 int q=0;
1537                 if ((q=uriInContext.indexOf('?'))>0)
1538                 {
1539                     query=uriInContext.substring(q+1);
1540                     uriInContext=uriInContext.substring(0,q);
1541                 }
1542                 if ((q=uriInContext.indexOf(';'))>0)
1543                     uriInContext=uriInContext.substring(0,q);
1544 
1545                 String pathInContext=URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
1546                 String uri=URIUtil.addPaths(getContextPath(), uriInContext);
1547                 ContextHandler context=ContextHandler.this;
1548                 return new Dispatcher(context,uri, pathInContext, query);
1549             }
1550             catch(Exception e)
1551             {
1552                 Log.ignore(e);
1553             }
1554             return null;
1555         }
1556         /* ------------------------------------------------------------ */
1557         /*
1558          * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
1559          */
1560         public String getRealPath(String path)
1561         {
1562             if(path==null)
1563                 return null;
1564             if(path.length()==0)
1565                 path = URIUtil.SLASH;
1566             else if(path.charAt(0)!='/')
1567                 path = URIUtil.SLASH + path;
1568 
1569             try
1570             {
1571                 Resource resource=ContextHandler.this.getResource(path);
1572                 if(resource!=null)
1573                 {
1574                     File file = resource.getFile();
1575                     if (file!=null)
1576                         return file.getCanonicalPath();
1577                 }
1578             }
1579             catch (Exception e)
1580             {
1581                 Log.ignore(e);
1582             }
1583 
1584             return null;
1585         }
1586 
1587         /* ------------------------------------------------------------ */
1588         public URL getResource(String path) throws MalformedURLException
1589         {
1590             Resource resource=ContextHandler.this.getResource(path);
1591             if (resource!=null && resource.exists())
1592                 return resource.getURL();
1593             return null;
1594         }
1595 
1596         /* ------------------------------------------------------------ */
1597         /*
1598          * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
1599          */
1600         public InputStream getResourceAsStream(String path)
1601         {
1602             try
1603             {
1604                 URL url=getResource(path);
1605                 if (url==null)
1606                     return null;
1607                 return url.openStream();
1608             }
1609             catch(Exception e)
1610             {
1611                 Log.ignore(e);
1612                 return null;
1613             }
1614         }
1615 
1616         /* ------------------------------------------------------------ */
1617         /*
1618          * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
1619          */
1620         public Set getResourcePaths(String path)
1621         {
1622             return ContextHandler.this.getResourcePaths(path);
1623         }
1624 
1625         /* ------------------------------------------------------------ */
1626         /*
1627          * @see javax.servlet.ServletContext#getServerInfo()
1628          */
1629         public String getServerInfo()
1630         {
1631             return "jetty/"+Server.getVersion();
1632         }
1633 
1634         /* ------------------------------------------------------------ */
1635         /*
1636          * @see javax.servlet.ServletContext#getServlet(java.lang.String)
1637          */
1638         public Servlet getServlet(String name) throws ServletException
1639         {
1640             return null;
1641         }
1642 
1643         /* ------------------------------------------------------------ */
1644         /*
1645          * @see javax.servlet.ServletContext#getServletNames()
1646          */
1647         @SuppressWarnings("unchecked")
1648         public Enumeration getServletNames()
1649         {
1650             return Collections.enumeration(Collections.EMPTY_LIST);
1651         }
1652 
1653         /* ------------------------------------------------------------ */
1654         /*
1655          * @see javax.servlet.ServletContext#getServlets()
1656          */
1657         @SuppressWarnings("unchecked")
1658         public Enumeration getServlets()
1659         {
1660             return Collections.enumeration(Collections.EMPTY_LIST);
1661         }
1662 
1663         /* ------------------------------------------------------------ */
1664         /*
1665          * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String)
1666          */
1667         public void log(Exception exception, String msg)
1668         {
1669             _logger.warn(msg,exception);
1670         }
1671 
1672         /* ------------------------------------------------------------ */
1673         /*
1674          * @see javax.servlet.ServletContext#log(java.lang.String)
1675          */
1676         public void log(String msg)
1677         {
1678             _logger.info(msg, null, null);
1679         }
1680 
1681         /* ------------------------------------------------------------ */
1682         /*
1683          * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable)
1684          */
1685         public void log(String message, Throwable throwable)
1686         {
1687             _logger.warn(message,throwable);
1688         }
1689 
1690         /* ------------------------------------------------------------ */
1691         /*
1692          * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
1693          */
1694         public String getInitParameter(String name)
1695         {
1696             return ContextHandler.this.getInitParameter(name);
1697         }
1698 
1699         /* ------------------------------------------------------------ */
1700         /*
1701          * @see javax.servlet.ServletContext#getInitParameterNames()
1702          */
1703         @SuppressWarnings("unchecked")
1704         public Enumeration getInitParameterNames()
1705         {
1706             return ContextHandler.this.getInitParameterNames();
1707         }
1708 
1709         /* ------------------------------------------------------------ */
1710         /*
1711          * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
1712          */
1713         public synchronized Object getAttribute(String name)
1714         {
1715             Object o = ContextHandler.this.getAttribute(name);
1716             if (o==null && _contextAttributes!=null)
1717                 o=_contextAttributes.getAttribute(name);
1718             return o;
1719         }
1720 
1721         /* ------------------------------------------------------------ */
1722         /*
1723          * @see javax.servlet.ServletContext#getAttributeNames()
1724          */
1725         @SuppressWarnings("unchecked")
1726         public synchronized Enumeration getAttributeNames()
1727         {
1728             HashSet<String> set = new HashSet<String>();
1729             if (_contextAttributes!=null)
1730             {
1731             	Enumeration<String> e = _contextAttributes.getAttributeNames();
1732             	while(e.hasMoreElements())
1733             		set.add(e.nextElement());
1734             }
1735             Enumeration<String> e = _attributes.getAttributeNames();
1736             while(e.hasMoreElements())
1737                 set.add(e.nextElement());
1738 
1739             return Collections.enumeration(set);
1740         }
1741 
1742         /* ------------------------------------------------------------ */
1743         /*
1744          * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1745          */
1746         public synchronized void setAttribute(String name, Object value)
1747         {
1748 
1749             if (_contextAttributes==null)
1750             {
1751             	// Set it on the handler
1752             	ContextHandler.this.setAttribute(name, value);
1753                 return;
1754             }
1755 
1756             setManagedAttribute(name,value);
1757             Object old_value=_contextAttributes.getAttribute(name);
1758 
1759             if (value==null)
1760                 _contextAttributes.removeAttribute(name);
1761             else
1762                 _contextAttributes.setAttribute(name,value);
1763 
1764             if (_contextAttributeListeners!=null)
1765             {
1766                 ServletContextAttributeEvent event =
1767                     new ServletContextAttributeEvent(_scontext,name, old_value==null?value:old_value);
1768 
1769                 for(int i=0;i<LazyList.size(_contextAttributeListeners);i++)
1770                 {
1771                     ServletContextAttributeListener l = (ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i);
1772 
1773                     if (old_value==null)
1774                         l.attributeAdded(event);
1775                     else if (value==null)
1776                         l.attributeRemoved(event);
1777                     else
1778                         l.attributeReplaced(event);
1779                 }
1780             }
1781         }
1782 
1783         /* ------------------------------------------------------------ */
1784         /*
1785          * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1786          */
1787         public synchronized void removeAttribute(String name)
1788         {
1789             setManagedAttribute(name,null);
1790 
1791             if (_contextAttributes==null)
1792             {
1793             	// Set it on the handler
1794             	_attributes.removeAttribute(name);
1795                 return;
1796             }
1797 
1798             Object old_value=_contextAttributes.getAttribute(name);
1799             _contextAttributes.removeAttribute(name);
1800             if (old_value!=null)
1801             {
1802                 if (_contextAttributeListeners!=null)
1803                 {
1804                     ServletContextAttributeEvent event =
1805                         new ServletContextAttributeEvent(_scontext,name, old_value);
1806 
1807                     for(int i=0;i<LazyList.size(_contextAttributeListeners);i++)
1808                         ((ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i)).attributeRemoved(event);
1809                 }
1810             }
1811         }
1812 
1813         /* ------------------------------------------------------------ */
1814         /*
1815          * @see javax.servlet.ServletContext#getServletContextName()
1816          */
1817         public String getServletContextName()
1818         {
1819             String name = ContextHandler.this.getDisplayName();
1820             if (name==null)
1821                 name=ContextHandler.this.getContextPath();
1822             return name;
1823         }
1824 
1825         /* ------------------------------------------------------------ */
1826         public String getContextPath()
1827         {
1828             if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH))
1829                 return "";
1830 
1831             return _contextPath;
1832         }
1833 
1834         /* ------------------------------------------------------------ */
1835         @Override
1836         public String toString()
1837         {
1838             return "ServletContext@"+Integer.toHexString(hashCode())+"{"+(getContextPath().equals("")?URIUtil.SLASH:getContextPath())+","+getBaseResource()+"}";
1839         }
1840 
1841         /* ------------------------------------------------------------ */
1842         public boolean setInitParameter(String name, String value)
1843         {
1844             if (ContextHandler.this.getInitParameter(name)!=null)
1845                 return false;
1846             ContextHandler.this.getInitParams().put(name,value);
1847             return true;
1848         }
1849 
1850     }
1851 
1852 }