comparison src/org/eclipse/jetty/server/handler/ContextHandler.java @ 802:3428c60d7cfc

replace jetty jars with source
author Franklin Schmidt <fschmidt@gmail.com>
date Wed, 07 Sep 2016 21:15:48 -0600
parents
children 8e9db0bbf4f9
comparison
equal deleted inserted replaced
801:6a21393191c1 802:3428c60d7cfc
1 //
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.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.server.handler;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.MalformedURLException;
25 import java.net.URL;
26 import java.net.URLClassLoader;
27 import java.security.AccessController;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.Enumeration;
32 import java.util.EventListener;
33 import java.util.HashMap;
34 import java.util.HashSet;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.Map;
39 import java.util.Set;
40 import java.util.concurrent.CopyOnWriteArrayList;
41
42 import javax.servlet.DispatcherType;
43 import javax.servlet.RequestDispatcher;
44 import javax.servlet.Servlet;
45 import javax.servlet.ServletContext;
46 import javax.servlet.ServletContextAttributeEvent;
47 import javax.servlet.ServletContextAttributeListener;
48 import javax.servlet.ServletContextEvent;
49 import javax.servlet.ServletContextListener;
50 import javax.servlet.ServletException;
51 import javax.servlet.ServletRegistration;
52 import javax.servlet.ServletRequestAttributeListener;
53 import javax.servlet.ServletRequestEvent;
54 import javax.servlet.ServletRequestListener;
55 import javax.servlet.SessionCookieConfig;
56 import javax.servlet.SessionTrackingMode;
57 import javax.servlet.Filter;
58 import javax.servlet.FilterRegistration;
59 import javax.servlet.FilterRegistration.Dynamic;
60 import javax.servlet.descriptor.JspConfigDescriptor;
61 import javax.servlet.http.HttpServletRequest;
62 import javax.servlet.http.HttpServletResponse;
63
64 import org.eclipse.jetty.http.HttpException;
65 import org.eclipse.jetty.http.MimeTypes;
66 import org.eclipse.jetty.io.Buffer;
67 import org.eclipse.jetty.server.AbstractHttpConnection;
68 import org.eclipse.jetty.server.Dispatcher;
69 import org.eclipse.jetty.server.Handler;
70 import org.eclipse.jetty.server.HandlerContainer;
71 import org.eclipse.jetty.server.Request;
72 import org.eclipse.jetty.server.Server;
73 import org.eclipse.jetty.util.Attributes;
74 import org.eclipse.jetty.util.AttributesMap;
75 import org.eclipse.jetty.util.LazyList;
76 import org.eclipse.jetty.util.Loader;
77 import org.eclipse.jetty.util.StringUtil;
78 import org.eclipse.jetty.util.TypeUtil;
79 import org.eclipse.jetty.util.URIUtil;
80 import org.eclipse.jetty.util.component.AggregateLifeCycle;
81 import org.eclipse.jetty.util.component.Dumpable;
82 import org.eclipse.jetty.util.log.Log;
83 import org.eclipse.jetty.util.log.Logger;
84 import org.eclipse.jetty.util.resource.Resource;
85
86 /* ------------------------------------------------------------ */
87 /**
88 * ContextHandler.
89 *
90 * This handler wraps a call to handle by setting the context and servlet path, plus setting the context classloader.
91 *
92 * <p>
93 * 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
94 * context attribute names, which if set as attributes are passed to the servers Container so that they may be managed with JMX.
95 * <p>
96 * 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
97 * and org.eclipse.jetty.server.Request.maxFormContentSize. These can also be configured with {@link #setMaxFormContentSize(int)} and {@link #setMaxFormKeys(int)}
98 *
99 * @org.apache.xbean.XBean description="Creates a basic HTTP context"
100 */
101 public class ContextHandler extends ScopedHandler implements Attributes, Server.Graceful
102 {
103 private static final Logger LOG = Log.getLogger(ContextHandler.class);
104
105 private static final ThreadLocal<Context> __context = new ThreadLocal<Context>();
106
107 /**
108 * 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
109 * 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
110 * for the attribute value.
111 */
112 public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
113
114 /* ------------------------------------------------------------ */
115 /**
116 * Get the current ServletContext implementation.
117 *
118 * @return ServletContext implementation
119 */
120 public static Context getCurrentContext()
121 {
122 return __context.get();
123 }
124
125 protected Context _scontext;
126
127 private final AttributesMap _attributes;
128 private final AttributesMap _contextAttributes;
129 private final Map<String, String> _initParams;
130 private ClassLoader _classLoader;
131 private String _contextPath = "/";
132 private String _displayName;
133 private Resource _baseResource;
134 private MimeTypes _mimeTypes;
135 private Map<String, String> _localeEncodingMap;
136 private String[] _welcomeFiles;
137 private ErrorHandler _errorHandler;
138 private String[] _vhosts;
139 private Set<String> _connectors;
140 private EventListener[] _eventListeners;
141 private Logger _logger;
142 private boolean _allowNullPathInfo;
143 private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",-1).intValue();
144 private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",-1).intValue();
145 private boolean _compactPath = false;
146 private boolean _aliasesAllowed = false;
147
148 private Object _contextListeners;
149 private Object _contextAttributeListeners;
150 private Object _requestListeners;
151 private Object _requestAttributeListeners;
152 private Object _durableListeners;
153 private Map<String, Object> _managedAttributes;
154 private String[] _protectedTargets;
155 private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
156
157 private boolean _shutdown = false;
158 private boolean _available = true;
159 private volatile int _availability; // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE
160
161 private final static int __STOPPED = 0, __AVAILABLE = 1, __SHUTDOWN = 2, __UNAVAILABLE = 3;
162
163 /* ------------------------------------------------------------ */
164 /**
165 *
166 */
167 public ContextHandler()
168 {
169 super();
170 _scontext = new Context();
171 _attributes = new AttributesMap();
172 _contextAttributes = new AttributesMap();
173 _initParams = new HashMap<String, String>();
174 addAliasCheck(new ApproveNonExistentDirectoryAliases());
175 }
176
177 /* ------------------------------------------------------------ */
178 /**
179 *
180 */
181 protected ContextHandler(Context context)
182 {
183 super();
184 _scontext = context;
185 _attributes = new AttributesMap();
186 _contextAttributes = new AttributesMap();
187 _initParams = new HashMap<String, String>();
188 addAliasCheck(new ApproveNonExistentDirectoryAliases());
189 }
190
191 /* ------------------------------------------------------------ */
192 /**
193 *
194 */
195 public ContextHandler(String contextPath)
196 {
197 this();
198 setContextPath(contextPath);
199 }
200
201 /* ------------------------------------------------------------ */
202 /**
203 *
204 */
205 public ContextHandler(HandlerContainer parent, String contextPath)
206 {
207 this();
208 setContextPath(contextPath);
209 if (parent instanceof HandlerWrapper)
210 ((HandlerWrapper)parent).setHandler(this);
211 else if (parent instanceof HandlerCollection)
212 ((HandlerCollection)parent).addHandler(this);
213 }
214
215 /* ------------------------------------------------------------ */
216 @Override
217 public void dump(Appendable out, String indent) throws IOException
218 {
219 dumpThis(out);
220 dump(out,indent,Collections.singletonList(new CLDump(getClassLoader())),TypeUtil.asList(getHandlers()),getBeans(),_initParams.entrySet(),
221 _attributes.getAttributeEntrySet(),_contextAttributes.getAttributeEntrySet());
222 }
223
224 /* ------------------------------------------------------------ */
225 public Context getServletContext()
226 {
227 return _scontext;
228 }
229
230 /* ------------------------------------------------------------ */
231 /**
232 * @return the allowNullPathInfo true if /context is not redirected to /context/
233 */
234 public boolean getAllowNullPathInfo()
235 {
236 return _allowNullPathInfo;
237 }
238
239 /* ------------------------------------------------------------ */
240 /**
241 * @param allowNullPathInfo
242 * true if /context is not redirected to /context/
243 */
244 public void setAllowNullPathInfo(boolean allowNullPathInfo)
245 {
246 _allowNullPathInfo = allowNullPathInfo;
247 }
248
249 /* ------------------------------------------------------------ */
250 @Override
251 public void setServer(Server server)
252 {
253 if (_errorHandler != null)
254 {
255 Server old_server = getServer();
256 if (old_server != null && old_server != server)
257 old_server.getContainer().update(this,_errorHandler,null,"error",true);
258 super.setServer(server);
259 if (server != null && server != old_server)
260 server.getContainer().update(this,null,_errorHandler,"error",true);
261 _errorHandler.setServer(server);
262 }
263 else
264 super.setServer(server);
265 }
266
267 /* ------------------------------------------------------------ */
268 /**
269 * 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
270 * 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
271 * matching virtual host name.
272 *
273 * @param vhosts
274 * 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
275 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
276 */
277 public void setVirtualHosts(String[] vhosts)
278 {
279 if (vhosts == null)
280 {
281 _vhosts = vhosts;
282 }
283 else
284 {
285 _vhosts = new String[vhosts.length];
286 for (int i = 0; i < vhosts.length; i++)
287 _vhosts[i] = normalizeHostname(vhosts[i]);
288 }
289 }
290
291 /* ------------------------------------------------------------ */
292 /** Either set virtual hosts or add to an existing set of virtual hosts.
293 *
294 * @param virtualHosts
295 * 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
296 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
297 */
298 public void addVirtualHosts(String[] virtualHosts)
299 {
300 if (virtualHosts == null) // since this is add, we don't null the old ones
301 {
302 return;
303 }
304 else
305 {
306 List<String> currentVirtualHosts = null;
307 if (_vhosts != null)
308 {
309 currentVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
310 }
311 else
312 {
313 currentVirtualHosts = new ArrayList<String>();
314 }
315
316 for (int i = 0; i < virtualHosts.length; i++)
317 {
318 String normVhost = normalizeHostname(virtualHosts[i]);
319 if (!currentVirtualHosts.contains(normVhost))
320 {
321 currentVirtualHosts.add(normVhost);
322 }
323 }
324 _vhosts = currentVirtualHosts.toArray(new String[0]);
325 }
326 }
327
328 /* ------------------------------------------------------------ */
329 /**
330 * Removes an array of virtual host entries, if this removes all entries the _vhosts will be set to null
331 *
332 * @param virtualHosts
333 * 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
334 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
335 */
336 public void removeVirtualHosts(String[] virtualHosts)
337 {
338 if (virtualHosts == null)
339 {
340 return; // do nothing
341 }
342 else if ( _vhosts == null || _vhosts.length == 0)
343 {
344 return; // do nothing
345 }
346 else
347 {
348 List<String> existingVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
349
350 for (int i = 0; i < virtualHosts.length; i++)
351 {
352 String toRemoveVirtualHost = normalizeHostname(virtualHosts[i]);
353 if (existingVirtualHosts.contains(toRemoveVirtualHost))
354 {
355 existingVirtualHosts.remove(toRemoveVirtualHost);
356 }
357 }
358
359 if (existingVirtualHosts.isEmpty())
360 {
361 _vhosts = null; // if we ended up removing them all, just null out _vhosts
362 }
363 else
364 {
365 _vhosts = existingVirtualHosts.toArray(new String[0]);
366 }
367 }
368 }
369
370 /* ------------------------------------------------------------ */
371 /**
372 * 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
373 * 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
374 * matching virtual host name.
375 *
376 * @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
377 * representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
378 */
379 public String[] getVirtualHosts()
380 {
381 return _vhosts;
382 }
383
384 /* ------------------------------------------------------------ */
385 /**
386 * @return an array of connector names that this context will accept a request from.
387 */
388 public String[] getConnectorNames()
389 {
390 if (_connectors == null || _connectors.size() == 0)
391 return null;
392
393 return _connectors.toArray(new String[_connectors.size()]);
394 }
395
396 /* ------------------------------------------------------------ */
397 /**
398 * Set the names of accepted connectors.
399 *
400 * Names are either "host:port" or a specific configured name for a connector.
401 *
402 * @param connectors
403 * If non null, an array of connector names that this context will accept a request from.
404 */
405 public void setConnectorNames(String[] connectors)
406 {
407 if (connectors == null || connectors.length == 0)
408 _connectors = null;
409 else
410 _connectors = new HashSet<String>(Arrays.asList(connectors));
411 }
412
413 /* ------------------------------------------------------------ */
414 /*
415 * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
416 */
417 public Object getAttribute(String name)
418 {
419 return _attributes.getAttribute(name);
420 }
421
422 /* ------------------------------------------------------------ */
423 /*
424 * @see javax.servlet.ServletContext#getAttributeNames()
425 */
426 @SuppressWarnings("unchecked")
427 public Enumeration getAttributeNames()
428 {
429 return AttributesMap.getAttributeNamesCopy(_attributes);
430 }
431
432 /* ------------------------------------------------------------ */
433 /**
434 * @return Returns the attributes.
435 */
436 public Attributes getAttributes()
437 {
438 return _attributes;
439 }
440
441 /* ------------------------------------------------------------ */
442 /**
443 * @return Returns the classLoader.
444 */
445 public ClassLoader getClassLoader()
446 {
447 return _classLoader;
448 }
449
450 /* ------------------------------------------------------------ */
451 /**
452 * Make best effort to extract a file classpath from the context classloader
453 *
454 * @return Returns the classLoader.
455 */
456 public String getClassPath()
457 {
458 if (_classLoader == null || !(_classLoader instanceof URLClassLoader))
459 return null;
460 URLClassLoader loader = (URLClassLoader)_classLoader;
461 URL[] urls = loader.getURLs();
462 StringBuilder classpath = new StringBuilder();
463 for (int i = 0; i < urls.length; i++)
464 {
465 try
466 {
467 Resource resource = newResource(urls[i]);
468 File file = resource.getFile();
469 if (file != null && file.exists())
470 {
471 if (classpath.length() > 0)
472 classpath.append(File.pathSeparatorChar);
473 classpath.append(file.getAbsolutePath());
474 }
475 }
476 catch (IOException e)
477 {
478 LOG.debug(e);
479 }
480 }
481 if (classpath.length() == 0)
482 return null;
483 return classpath.toString();
484 }
485
486 /* ------------------------------------------------------------ */
487 /**
488 * @return Returns the _contextPath.
489 */
490 public String getContextPath()
491 {
492 return _contextPath;
493 }
494
495 /* ------------------------------------------------------------ */
496 /*
497 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
498 */
499 public String getInitParameter(String name)
500 {
501 return _initParams.get(name);
502 }
503
504 /* ------------------------------------------------------------ */
505 /*
506 */
507 public String setInitParameter(String name, String value)
508 {
509 return _initParams.put(name,value);
510 }
511
512 /* ------------------------------------------------------------ */
513 /*
514 * @see javax.servlet.ServletContext#getInitParameterNames()
515 */
516 @SuppressWarnings("rawtypes")
517 public Enumeration getInitParameterNames()
518 {
519 return Collections.enumeration(_initParams.keySet());
520 }
521
522 /* ------------------------------------------------------------ */
523 /**
524 * @return Returns the initParams.
525 */
526 public Map<String, String> getInitParams()
527 {
528 return _initParams;
529 }
530
531 /* ------------------------------------------------------------ */
532 /*
533 * @see javax.servlet.ServletContext#getServletContextName()
534 */
535 public String getDisplayName()
536 {
537 return _displayName;
538 }
539
540 /* ------------------------------------------------------------ */
541 public EventListener[] getEventListeners()
542 {
543 return _eventListeners;
544 }
545
546 /* ------------------------------------------------------------ */
547 /**
548 * Set the context event listeners.
549 *
550 * @param eventListeners
551 * the event listeners
552 * @see ServletContextListener
553 * @see ServletContextAttributeListener
554 * @see ServletRequestListener
555 * @see ServletRequestAttributeListener
556 */
557 public void setEventListeners(EventListener[] eventListeners)
558 {
559 _contextListeners = null;
560 _contextAttributeListeners = null;
561 _requestListeners = null;
562 _requestAttributeListeners = null;
563
564 _eventListeners = eventListeners;
565
566 for (int i = 0; eventListeners != null && i < eventListeners.length; i++)
567 {
568 EventListener listener = _eventListeners[i];
569
570 if (listener instanceof ServletContextListener)
571 _contextListeners = LazyList.add(_contextListeners,listener);
572
573 if (listener instanceof ServletContextAttributeListener)
574 _contextAttributeListeners = LazyList.add(_contextAttributeListeners,listener);
575
576 if (listener instanceof ServletRequestListener)
577 _requestListeners = LazyList.add(_requestListeners,listener);
578
579 if (listener instanceof ServletRequestAttributeListener)
580 _requestAttributeListeners = LazyList.add(_requestAttributeListeners,listener);
581 }
582 }
583
584 /* ------------------------------------------------------------ */
585 /**
586 * Add a context event listeners.
587 *
588 * @see ServletContextListener
589 * @see ServletContextAttributeListener
590 * @see ServletRequestListener
591 * @see ServletRequestAttributeListener
592 */
593 public void addEventListener(EventListener listener)
594 {
595 //Only listeners added before the context starts last through a stop/start cycle
596 if (!(isStarted() || isStarting()))
597 _durableListeners = LazyList.add(_durableListeners, listener);
598
599 setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(),listener,EventListener.class));
600 }
601
602
603 /**
604 * Apply any necessary restrictions on a programmatically added
605 * listener.
606 *
607 * Superclasses should implement.
608 *
609 * @param listener
610 */
611 public void restrictEventListener (EventListener listener)
612 {
613 }
614
615
616
617 /* ------------------------------------------------------------ */
618 /**
619 * @return true if this context is accepting new requests
620 */
621 public boolean isShutdown()
622 {
623 synchronized (this)
624 {
625 return !_shutdown;
626 }
627 }
628
629 /* ------------------------------------------------------------ */
630 /**
631 * 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
632 * requests can complete, but no new requests are accepted.
633 *
634 * @param shutdown
635 * true if this context is (not?) accepting new requests
636 */
637 public void setShutdown(boolean shutdown)
638 {
639 synchronized (this)
640 {
641 _shutdown = shutdown;
642 _availability = isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
643 }
644 }
645
646 /* ------------------------------------------------------------ */
647 /**
648 * @return false if this context is unavailable (sends 503)
649 */
650 public boolean isAvailable()
651 {
652 synchronized (this)
653 {
654 return _available;
655 }
656 }
657
658 /* ------------------------------------------------------------ */
659 /**
660 * Set Available status.
661 */
662 public void setAvailable(boolean available)
663 {
664 synchronized (this)
665 {
666 _available = available;
667 _availability = isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
668 }
669 }
670
671 /* ------------------------------------------------------------ */
672 public Logger getLogger()
673 {
674 return _logger;
675 }
676
677 /* ------------------------------------------------------------ */
678 public void setLogger(Logger logger)
679 {
680 _logger = logger;
681 }
682
683 /* ------------------------------------------------------------ */
684 /*
685 * @see org.eclipse.thread.AbstractLifeCycle#doStart()
686 */
687 @Override
688 protected void doStart() throws Exception
689 {
690 _availability = __STOPPED;
691
692 if (_contextPath == null)
693 throw new IllegalStateException("Null contextPath");
694
695 _logger = Log.getLogger(getDisplayName() == null?getContextPath():getDisplayName());
696 ClassLoader old_classloader = null;
697 Thread current_thread = null;
698 Context old_context = null;
699
700 try
701 {
702 // Set the classloader
703 if (_classLoader != null)
704 {
705 current_thread = Thread.currentThread();
706 old_classloader = current_thread.getContextClassLoader();
707 current_thread.setContextClassLoader(_classLoader);
708 }
709
710 if (_mimeTypes == null)
711 _mimeTypes = new MimeTypes();
712
713 old_context = __context.get();
714 __context.set(_scontext);
715
716 // defers the calling of super.doStart()
717 startContext();
718
719 synchronized(this)
720 {
721 _availability = _shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE;
722 }
723 }
724 finally
725 {
726 __context.set(old_context);
727
728 // reset the classloader
729 if (_classLoader != null)
730 {
731 current_thread.setContextClassLoader(old_classloader);
732 }
733
734 }
735 }
736
737 /* ------------------------------------------------------------ */
738 /**
739 * Extensible startContext. this method is called from {@link ContextHandler#doStart()} instead of a call to super.doStart(). This allows derived classes to
740 * insert additional handling (Eg configuration) before the call to super.doStart by this method will start contained handlers.
741 *
742 * @see org.eclipse.jetty.server.handler.ContextHandler.Context
743 */
744 protected void startContext() throws Exception
745 {
746 String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
747 if (managedAttributes != null)
748 {
749 _managedAttributes = new HashMap<String, Object>();
750 String[] attributes = managedAttributes.split(",");
751 for (String attribute : attributes)
752 _managedAttributes.put(attribute,null);
753
754 Enumeration e = _scontext.getAttributeNames();
755 while (e.hasMoreElements())
756 {
757 String name = (String)e.nextElement();
758 Object value = _scontext.getAttribute(name);
759 checkManagedAttribute(name,value);
760 }
761 }
762
763 super.doStart();
764
765 if (_errorHandler != null)
766 _errorHandler.start();
767
768 // Context listeners
769 if (_contextListeners != null)
770 {
771 ServletContextEvent event = new ServletContextEvent(_scontext);
772 for (int i = 0; i < LazyList.size(_contextListeners); i++)
773 {
774 callContextInitialized(((ServletContextListener)LazyList.get(_contextListeners, i)), event);
775 }
776 }
777 }
778
779 /* ------------------------------------------------------------ */
780 public void callContextInitialized (ServletContextListener l, ServletContextEvent e)
781 {
782 l.contextInitialized(e);
783 }
784
785 /* ------------------------------------------------------------ */
786 public void callContextDestroyed (ServletContextListener l, ServletContextEvent e)
787 {
788 l.contextDestroyed(e);
789 }
790
791 /* ------------------------------------------------------------ */
792 /*
793 * @see org.eclipse.thread.AbstractLifeCycle#doStop()
794 */
795 @Override
796 protected void doStop() throws Exception
797 {
798 _availability = __STOPPED;
799
800 ClassLoader old_classloader = null;
801 Thread current_thread = null;
802
803 Context old_context = __context.get();
804 __context.set(_scontext);
805 try
806 {
807 // Set the classloader
808 if (_classLoader != null)
809 {
810 current_thread = Thread.currentThread();
811 old_classloader = current_thread.getContextClassLoader();
812 current_thread.setContextClassLoader(_classLoader);
813 }
814
815 super.doStop();
816
817 // Context listeners
818 if (_contextListeners != null)
819 {
820 ServletContextEvent event = new ServletContextEvent(_scontext);
821 for (int i = LazyList.size(_contextListeners); i-- > 0;)
822 {
823 ((ServletContextListener)LazyList.get(_contextListeners,i)).contextDestroyed(event);
824 }
825 }
826
827 //remove all non-durable listeners
828 setEventListeners((EventListener[])LazyList.toArray(_durableListeners, EventListener.class));
829 _durableListeners = null;
830
831 if (_errorHandler != null)
832 _errorHandler.stop();
833
834 Enumeration e = _scontext.getAttributeNames();
835 while (e.hasMoreElements())
836 {
837 String name = (String)e.nextElement();
838 checkManagedAttribute(name,null);
839 }
840 }
841 finally
842 {
843 LOG.info("stopped {}",this);
844 __context.set(old_context);
845 // reset the classloader
846 if (_classLoader != null)
847 current_thread.setContextClassLoader(old_classloader);
848 }
849
850 _contextAttributes.clearAttributes();
851 }
852
853 /* ------------------------------------------------------------ */
854 /*
855 * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
856 */
857 public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException, ServletException
858 {
859 DispatcherType dispatch = baseRequest.getDispatcherType();
860
861 switch (_availability)
862 {
863 case __STOPPED:
864 case __SHUTDOWN:
865 return false;
866 case __UNAVAILABLE:
867 baseRequest.setHandled(true);
868 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
869 return false;
870 default:
871 if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled()))
872 return false;
873 }
874
875 // Check the vhosts
876 if (_vhosts != null && _vhosts.length > 0)
877 {
878 String vhost = normalizeHostname(baseRequest.getServerName());
879
880 boolean match = false;
881
882 // TODO non-linear lookup
883 for (int i = 0; !match && i < _vhosts.length; i++)
884 {
885 String contextVhost = _vhosts[i];
886 if (contextVhost == null)
887 continue;
888 if (contextVhost.startsWith("*."))
889 {
890 // wildcard only at the beginning, and only for one additional subdomain level
891 match = contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".") + 1,contextVhost.length() - 2);
892 }
893 else
894 match = contextVhost.equalsIgnoreCase(vhost);
895 }
896 if (!match)
897 return false;
898 }
899
900 // Check the connector
901 if (_connectors != null && _connectors.size() > 0)
902 {
903 String connector = AbstractHttpConnection.getCurrentConnection().getConnector().getName();
904 if (connector == null || !_connectors.contains(connector))
905 return false;
906 }
907
908 // Are we not the root context?
909 if (_contextPath.length() > 1)
910 {
911 // reject requests that are not for us
912 if (!target.startsWith(_contextPath))
913 return false;
914 if (target.length() > _contextPath.length() && target.charAt(_contextPath.length()) != '/')
915 return false;
916
917 // redirect null path infos
918 if (!_allowNullPathInfo && _contextPath.length() == target.length())
919 {
920 // context request must end with /
921 baseRequest.setHandled(true);
922 if (baseRequest.getQueryString() != null)
923 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
924 else
925 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH));
926 return false;
927 }
928 }
929
930 return true;
931 }
932
933 /* ------------------------------------------------------------ */
934 /**
935 * @see org.eclipse.jetty.server.handler.ScopedHandler#doScope(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
936 * javax.servlet.http.HttpServletResponse)
937 */
938 @Override
939 public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
940 {
941 if (LOG.isDebugEnabled())
942 LOG.debug("scope {}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(),baseRequest.getPathInfo(),this);
943
944 Context old_context = null;
945 String old_context_path = null;
946 String old_servlet_path = null;
947 String old_path_info = null;
948 ClassLoader old_classloader = null;
949 Thread current_thread = null;
950 String pathInfo = target;
951
952 DispatcherType dispatch = baseRequest.getDispatcherType();
953
954 old_context = baseRequest.getContext();
955
956 // Are we already in this context?
957 if (old_context != _scontext)
958 {
959 // check the target.
960 if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch) || (DispatcherType.ERROR.equals(dispatch) && baseRequest.getAsyncContinuation().isExpired()))
961 {
962 if (_compactPath)
963 target = URIUtil.compactPath(target);
964 if (!checkContext(target,baseRequest,response))
965 return;
966
967 if (target.length() > _contextPath.length())
968 {
969 if (_contextPath.length() > 1)
970 target = target.substring(_contextPath.length());
971 pathInfo = target;
972 }
973 else if (_contextPath.length() == 1)
974 {
975 target = URIUtil.SLASH;
976 pathInfo = URIUtil.SLASH;
977 }
978 else
979 {
980 target = URIUtil.SLASH;
981 pathInfo = null;
982 }
983 }
984
985 // Set the classloader
986 if (_classLoader != null)
987 {
988 current_thread = Thread.currentThread();
989 old_classloader = current_thread.getContextClassLoader();
990 current_thread.setContextClassLoader(_classLoader);
991 }
992 }
993
994 try
995 {
996 old_context_path = baseRequest.getContextPath();
997 old_servlet_path = baseRequest.getServletPath();
998 old_path_info = baseRequest.getPathInfo();
999
1000 // Update the paths
1001 baseRequest.setContext(_scontext);
1002 __context.set(_scontext);
1003 if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/"))
1004 {
1005 if (_contextPath.length() == 1)
1006 baseRequest.setContextPath("");
1007 else
1008 baseRequest.setContextPath(_contextPath);
1009 baseRequest.setServletPath(null);
1010 baseRequest.setPathInfo(pathInfo);
1011 }
1012
1013 if (LOG.isDebugEnabled())
1014 LOG.debug("context={}|{}|{} @ {}",baseRequest.getContextPath(),baseRequest.getServletPath(), baseRequest.getPathInfo(),this);
1015
1016 // start manual inline of nextScope(target,baseRequest,request,response);
1017 if (never())
1018 nextScope(target,baseRequest,request,response);
1019 else if (_nextScope != null)
1020 _nextScope.doScope(target,baseRequest,request,response);
1021 else if (_outerScope != null)
1022 _outerScope.doHandle(target,baseRequest,request,response);
1023 else
1024 doHandle(target,baseRequest,request,response);
1025 // end manual inline (pathentic attempt to reduce stack depth)
1026 }
1027 finally
1028 {
1029 if (old_context != _scontext)
1030 {
1031 // reset the classloader
1032 if (_classLoader != null)
1033 {
1034 current_thread.setContextClassLoader(old_classloader);
1035 }
1036
1037 // reset the context and servlet path.
1038 baseRequest.setContext(old_context);
1039 __context.set(old_context);
1040 baseRequest.setContextPath(old_context_path);
1041 baseRequest.setServletPath(old_servlet_path);
1042 baseRequest.setPathInfo(old_path_info);
1043 }
1044 }
1045 }
1046
1047 /* ------------------------------------------------------------ */
1048 /**
1049 * @see org.eclipse.jetty.server.handler.ScopedHandler#doHandle(java.lang.String, org.eclipse.jetty.server.Request, javax.servlet.http.HttpServletRequest,
1050 * javax.servlet.http.HttpServletResponse)
1051 */
1052 @Override
1053 public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
1054 {
1055 final DispatcherType dispatch = baseRequest.getDispatcherType();
1056 final boolean new_context = baseRequest.takeNewContext();
1057 try
1058 {
1059 if (new_context)
1060 {
1061 // Handle the REALLY SILLY request events!
1062 if (_requestAttributeListeners != null)
1063 {
1064 final int s = LazyList.size(_requestAttributeListeners);
1065 for (int i = 0; i < s; i++)
1066 baseRequest.addEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
1067 }
1068
1069 if (_requestListeners != null)
1070 {
1071 final int s = LazyList.size(_requestListeners);
1072 final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
1073 for (int i = 0; i < s; i++)
1074 ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestInitialized(sre);
1075 }
1076 }
1077
1078 if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target))
1079 throw new HttpException(HttpServletResponse.SC_NOT_FOUND);
1080
1081 // start manual inline of nextHandle(target,baseRequest,request,response);
1082 // noinspection ConstantIfStatement
1083 if (never())
1084 nextHandle(target,baseRequest,request,response);
1085 else if (_nextScope != null && _nextScope == _handler)
1086 _nextScope.doHandle(target,baseRequest,request,response);
1087 else if (_handler != null)
1088 _handler.handle(target,baseRequest,request,response);
1089 // end manual inline
1090 }
1091 catch (HttpException e)
1092 {
1093 LOG.debug(e);
1094 baseRequest.setHandled(true);
1095 response.sendError(e.getStatus(),e.getReason());
1096 }
1097 finally
1098 {
1099 // Handle more REALLY SILLY request events!
1100 if (new_context)
1101 {
1102 if (_requestListeners != null)
1103 {
1104 final ServletRequestEvent sre = new ServletRequestEvent(_scontext,request);
1105 for (int i = LazyList.size(_requestListeners); i-- > 0;)
1106 ((ServletRequestListener)LazyList.get(_requestListeners,i)).requestDestroyed(sre);
1107 }
1108
1109 if (_requestAttributeListeners != null)
1110 {
1111 for (int i = LazyList.size(_requestAttributeListeners); i-- > 0;)
1112 baseRequest.removeEventListener(((EventListener)LazyList.get(_requestAttributeListeners,i)));
1113 }
1114 }
1115 }
1116 }
1117
1118 /* ------------------------------------------------------------ */
1119 /*
1120 * Handle a runnable in this context
1121 */
1122 public void handle(Runnable runnable)
1123 {
1124 ClassLoader old_classloader = null;
1125 Thread current_thread = null;
1126 Context old_context = null;
1127 try
1128 {
1129 old_context = __context.get();
1130 __context.set(_scontext);
1131
1132 // Set the classloader
1133 if (_classLoader != null)
1134 {
1135 current_thread = Thread.currentThread();
1136 old_classloader = current_thread.getContextClassLoader();
1137 current_thread.setContextClassLoader(_classLoader);
1138 }
1139
1140 runnable.run();
1141 }
1142 finally
1143 {
1144 __context.set(old_context);
1145 if (old_classloader != null)
1146 {
1147 current_thread.setContextClassLoader(old_classloader);
1148 }
1149 }
1150 }
1151
1152 /* ------------------------------------------------------------ */
1153 /**
1154 * Check the target. Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a target within a context is determined. If
1155 * the target is protected, 404 is returned.
1156 */
1157 /* ------------------------------------------------------------ */
1158 public boolean isProtectedTarget(String target)
1159 {
1160 if (target == null || _protectedTargets == null)
1161 return false;
1162
1163 while (target.startsWith("//"))
1164 target=URIUtil.compactPath(target);
1165
1166 boolean isProtected = false;
1167 int i=0;
1168 while (!isProtected && i<_protectedTargets.length)
1169 {
1170 isProtected = StringUtil.startsWithIgnoreCase(target, _protectedTargets[i++]);
1171 }
1172 return isProtected;
1173 }
1174
1175
1176 public void setProtectedTargets (String[] targets)
1177 {
1178 if (targets == null)
1179 {
1180 _protectedTargets = null;
1181 return;
1182 }
1183
1184 _protectedTargets = new String[targets.length];
1185 System.arraycopy(targets, 0, _protectedTargets, 0, targets.length);
1186 }
1187
1188 public String[] getProtectedTargets ()
1189 {
1190 if (_protectedTargets == null)
1191 return null;
1192
1193 String[] tmp = new String[_protectedTargets.length];
1194 System.arraycopy(_protectedTargets, 0, tmp, 0, _protectedTargets.length);
1195 return tmp;
1196 }
1197
1198
1199 /* ------------------------------------------------------------ */
1200 /*
1201 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1202 */
1203 public void removeAttribute(String name)
1204 {
1205 checkManagedAttribute(name,null);
1206 _attributes.removeAttribute(name);
1207 }
1208
1209 /* ------------------------------------------------------------ */
1210 /*
1211 * Set a context attribute. Attributes set via this API cannot be overriden by the ServletContext.setAttribute API. Their lifecycle spans the stop/start of
1212 * a context. No attribute listener events are triggered by this API.
1213 *
1214 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1215 */
1216 public void setAttribute(String name, Object value)
1217 {
1218 checkManagedAttribute(name,value);
1219 _attributes.setAttribute(name,value);
1220 }
1221
1222 /* ------------------------------------------------------------ */
1223 /**
1224 * @param attributes
1225 * The attributes to set.
1226 */
1227 public void setAttributes(Attributes attributes)
1228 {
1229 _attributes.clearAttributes();
1230 _attributes.addAll(attributes);
1231 Enumeration e = _attributes.getAttributeNames();
1232 while (e.hasMoreElements())
1233 {
1234 String name = (String)e.nextElement();
1235 checkManagedAttribute(name,attributes.getAttribute(name));
1236 }
1237 }
1238
1239 /* ------------------------------------------------------------ */
1240 public void clearAttributes()
1241 {
1242 Enumeration e = _attributes.getAttributeNames();
1243 while (e.hasMoreElements())
1244 {
1245 String name = (String)e.nextElement();
1246 checkManagedAttribute(name,null);
1247 }
1248 _attributes.clearAttributes();
1249 }
1250
1251 /* ------------------------------------------------------------ */
1252 public void checkManagedAttribute(String name, Object value)
1253 {
1254 if (_managedAttributes != null && _managedAttributes.containsKey(name))
1255 {
1256 setManagedAttribute(name,value);
1257 }
1258 }
1259
1260 /* ------------------------------------------------------------ */
1261 public void setManagedAttribute(String name, Object value)
1262 {
1263 Object old = _managedAttributes.put(name,value);
1264 getServer().getContainer().update(this,old,value,name,true);
1265 }
1266
1267 /* ------------------------------------------------------------ */
1268 /**
1269 * @param classLoader
1270 * The classLoader to set.
1271 */
1272 public void setClassLoader(ClassLoader classLoader)
1273 {
1274 _classLoader = classLoader;
1275 }
1276
1277 /* ------------------------------------------------------------ */
1278 /**
1279 * @param contextPath
1280 * The _contextPath to set.
1281 */
1282 public void setContextPath(String contextPath)
1283 {
1284 if (contextPath != null && contextPath.length() > 1 && contextPath.endsWith("/"))
1285 throw new IllegalArgumentException("ends with /");
1286 _contextPath = contextPath;
1287
1288 if (getServer() != null && (getServer().isStarting() || getServer().isStarted()))
1289 {
1290 Handler[] contextCollections = getServer().getChildHandlersByClass(ContextHandlerCollection.class);
1291 for (int h = 0; contextCollections != null && h < contextCollections.length; h++)
1292 ((ContextHandlerCollection)contextCollections[h]).mapContexts();
1293 }
1294 }
1295
1296 /* ------------------------------------------------------------ */
1297 /**
1298 * @param servletContextName
1299 * The servletContextName to set.
1300 */
1301 public void setDisplayName(String servletContextName)
1302 {
1303 _displayName = servletContextName;
1304 }
1305
1306 /* ------------------------------------------------------------ */
1307 /**
1308 * @return Returns the resourceBase.
1309 */
1310 public Resource getBaseResource()
1311 {
1312 if (_baseResource == null)
1313 return null;
1314 return _baseResource;
1315 }
1316
1317 /* ------------------------------------------------------------ */
1318 /**
1319 * @return Returns the base resource as a string.
1320 */
1321 public String getResourceBase()
1322 {
1323 if (_baseResource == null)
1324 return null;
1325 return _baseResource.toString();
1326 }
1327
1328 /* ------------------------------------------------------------ */
1329 /**
1330 * @param base
1331 * The resourceBase to set.
1332 */
1333 public void setBaseResource(Resource base)
1334 {
1335 _baseResource = base;
1336 }
1337
1338 /* ------------------------------------------------------------ */
1339 /**
1340 * @param resourceBase
1341 * The base resource as a string.
1342 */
1343 public void setResourceBase(String resourceBase)
1344 {
1345 try
1346 {
1347 setBaseResource(newResource(resourceBase));
1348 }
1349 catch (Exception e)
1350 {
1351 LOG.warn(e.toString());
1352 LOG.debug(e);
1353 throw new IllegalArgumentException(resourceBase);
1354 }
1355 }
1356
1357 /* ------------------------------------------------------------ */
1358 /**
1359 * @return True if aliases are allowed
1360 */
1361 public boolean isAliases()
1362 {
1363 return _aliasesAllowed;
1364 }
1365
1366 /* ------------------------------------------------------------ */
1367 /**
1368 * @param aliases
1369 * aliases are allowed
1370 */
1371 public void setAliases(boolean aliases)
1372 {
1373 _aliasesAllowed = aliases;
1374 }
1375
1376 /* ------------------------------------------------------------ */
1377 /**
1378 * @return Returns the mimeTypes.
1379 */
1380 public MimeTypes getMimeTypes()
1381 {
1382 if (_mimeTypes == null)
1383 _mimeTypes = new MimeTypes();
1384 return _mimeTypes;
1385 }
1386
1387 /* ------------------------------------------------------------ */
1388 /**
1389 * @param mimeTypes
1390 * The mimeTypes to set.
1391 */
1392 public void setMimeTypes(MimeTypes mimeTypes)
1393 {
1394 _mimeTypes = mimeTypes;
1395 }
1396
1397 /* ------------------------------------------------------------ */
1398 /**
1399 */
1400 public void setWelcomeFiles(String[] files)
1401 {
1402 _welcomeFiles = files;
1403 }
1404
1405 /* ------------------------------------------------------------ */
1406 /**
1407 * @return The names of the files which the server should consider to be welcome files in this context.
1408 * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
1409 * @see #setWelcomeFiles
1410 */
1411 public String[] getWelcomeFiles()
1412 {
1413 return _welcomeFiles;
1414 }
1415
1416 /* ------------------------------------------------------------ */
1417 /**
1418 * @return Returns the errorHandler.
1419 */
1420 public ErrorHandler getErrorHandler()
1421 {
1422 return _errorHandler;
1423 }
1424
1425 /* ------------------------------------------------------------ */
1426 /**
1427 * @param errorHandler
1428 * The errorHandler to set.
1429 */
1430 public void setErrorHandler(ErrorHandler errorHandler)
1431 {
1432 if (errorHandler != null)
1433 errorHandler.setServer(getServer());
1434 if (getServer() != null)
1435 getServer().getContainer().update(this,_errorHandler,errorHandler,"errorHandler",true);
1436 _errorHandler = errorHandler;
1437 }
1438
1439 /* ------------------------------------------------------------ */
1440 public int getMaxFormContentSize()
1441 {
1442 return _maxFormContentSize;
1443 }
1444
1445 /* ------------------------------------------------------------ */
1446 /**
1447 * Set the maximum size of a form post, to protect against DOS attacks from large forms.
1448 * @param maxSize
1449 */
1450 public void setMaxFormContentSize(int maxSize)
1451 {
1452 _maxFormContentSize = maxSize;
1453 }
1454
1455 /* ------------------------------------------------------------ */
1456 public int getMaxFormKeys()
1457 {
1458 return _maxFormKeys;
1459 }
1460
1461 /* ------------------------------------------------------------ */
1462 /**
1463 * Set the maximum number of form Keys to protect against DOS attack from crafted hash keys.
1464 * @param max
1465 */
1466 public void setMaxFormKeys(int max)
1467 {
1468 _maxFormKeys = max;
1469 }
1470
1471 /* ------------------------------------------------------------ */
1472 /**
1473 * @return True if URLs are compacted to replace multiple '/'s with a single '/'
1474 */
1475 public boolean isCompactPath()
1476 {
1477 return _compactPath;
1478 }
1479
1480 /* ------------------------------------------------------------ */
1481 /**
1482 * @param compactPath
1483 * True if URLs are compacted to replace multiple '/'s with a single '/'
1484 */
1485 public void setCompactPath(boolean compactPath)
1486 {
1487 _compactPath = compactPath;
1488 }
1489
1490 /* ------------------------------------------------------------ */
1491 @Override
1492 public String toString()
1493 {
1494 String[] vhosts = getVirtualHosts();
1495
1496 StringBuilder b = new StringBuilder();
1497
1498 Package pkg = getClass().getPackage();
1499 if (pkg != null)
1500 {
1501 String p = pkg.getName();
1502 if (p != null && p.length() > 0)
1503 {
1504 String[] ss = p.split("\\.");
1505 for (String s : ss)
1506 b.append(s.charAt(0)).append('.');
1507 }
1508 }
1509 b.append(getClass().getSimpleName());
1510 b.append('{').append(getContextPath()).append(',').append(getBaseResource());
1511
1512 if (vhosts != null && vhosts.length > 0)
1513 b.append(',').append(vhosts[0]);
1514 b.append('}');
1515
1516 return b.toString();
1517 }
1518
1519 /* ------------------------------------------------------------ */
1520 public synchronized Class<?> loadClass(String className) throws ClassNotFoundException
1521 {
1522 if (className == null)
1523 return null;
1524
1525 if (_classLoader == null)
1526 return Loader.loadClass(this.getClass(),className);
1527
1528 return _classLoader.loadClass(className);
1529 }
1530
1531 /* ------------------------------------------------------------ */
1532 public void addLocaleEncoding(String locale, String encoding)
1533 {
1534 if (_localeEncodingMap == null)
1535 _localeEncodingMap = new HashMap<String, String>();
1536 _localeEncodingMap.put(locale,encoding);
1537 }
1538
1539 /* ------------------------------------------------------------ */
1540 public String getLocaleEncoding(String locale)
1541 {
1542 if (_localeEncodingMap == null)
1543 return null;
1544 String encoding = _localeEncodingMap.get(locale);
1545 return encoding;
1546 }
1547
1548 /* ------------------------------------------------------------ */
1549 /**
1550 * 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
1551 * language is looked up.
1552 *
1553 * @param locale
1554 * a <code>Locale</code> value
1555 * @return a <code>String</code> representing the character encoding for the locale or null if none found.
1556 */
1557 public String getLocaleEncoding(Locale locale)
1558 {
1559 if (_localeEncodingMap == null)
1560 return null;
1561 String encoding = _localeEncodingMap.get(locale.toString());
1562 if (encoding == null)
1563 encoding = _localeEncodingMap.get(locale.getLanguage());
1564 return encoding;
1565 }
1566
1567 /* ------------------------------------------------------------ */
1568 /*
1569 */
1570 public Resource getResource(String path) throws MalformedURLException
1571 {
1572 if (path == null || !path.startsWith(URIUtil.SLASH))
1573 throw new MalformedURLException(path);
1574
1575 if (_baseResource == null)
1576 return null;
1577
1578 try
1579 {
1580 path = URIUtil.canonicalPath(path);
1581 Resource resource = _baseResource.addPath(path);
1582
1583 if (checkAlias(path,resource))
1584 return resource;
1585 return null;
1586 }
1587 catch (Exception e)
1588 {
1589 LOG.ignore(e);
1590 }
1591
1592 return null;
1593 }
1594
1595 /* ------------------------------------------------------------ */
1596 public boolean checkAlias(String path, Resource resource)
1597 {
1598 // Is the resource aliased?
1599 if (!_aliasesAllowed && resource.getAlias() != null)
1600 {
1601 if (LOG.isDebugEnabled())
1602 LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
1603
1604 // alias checks
1605 for (Iterator<AliasCheck> i=_aliasChecks.iterator();i.hasNext();)
1606 {
1607 AliasCheck check = i.next();
1608 if (check.check(path,resource))
1609 {
1610 if (LOG.isDebugEnabled())
1611 LOG.debug("Aliased resource: " + resource + " approved by " + check);
1612 return true;
1613 }
1614 }
1615 return false;
1616 }
1617 return true;
1618 }
1619
1620 /* ------------------------------------------------------------ */
1621 /**
1622 * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
1623 */
1624 public Resource newResource(URL url) throws IOException
1625 {
1626 return Resource.newResource(url);
1627 }
1628
1629 /* ------------------------------------------------------------ */
1630 /**
1631 * Convert a URL or path to a Resource. The default implementation is a wrapper for {@link Resource#newResource(String)}.
1632 *
1633 * @param urlOrPath
1634 * The URL or path to convert
1635 * @return The Resource for the URL/path
1636 * @throws IOException
1637 * The Resource could not be created.
1638 */
1639 public Resource newResource(String urlOrPath) throws IOException
1640 {
1641 return Resource.newResource(urlOrPath);
1642 }
1643
1644 /* ------------------------------------------------------------ */
1645 /*
1646 */
1647 public Set<String> getResourcePaths(String path)
1648 {
1649 try
1650 {
1651 path = URIUtil.canonicalPath(path);
1652 Resource resource = getResource(path);
1653
1654 if (resource != null && resource.exists())
1655 {
1656 if (!path.endsWith(URIUtil.SLASH))
1657 path = path + URIUtil.SLASH;
1658
1659 String[] l = resource.list();
1660 if (l != null)
1661 {
1662 HashSet<String> set = new HashSet<String>();
1663 for (int i = 0; i < l.length; i++)
1664 set.add(path + l[i]);
1665 return set;
1666 }
1667 }
1668 }
1669 catch (Exception e)
1670 {
1671 LOG.ignore(e);
1672 }
1673 return Collections.emptySet();
1674 }
1675
1676 /* ------------------------------------------------------------ */
1677 private String normalizeHostname(String host)
1678 {
1679 if (host == null)
1680 return null;
1681
1682 if (host.endsWith("."))
1683 return host.substring(0,host.length() - 1);
1684
1685 return host;
1686 }
1687
1688 /* ------------------------------------------------------------ */
1689 /**
1690 * Add an AliasCheck instance to possibly permit aliased resources
1691 * @param check The alias checker
1692 */
1693 public void addAliasCheck(AliasCheck check)
1694 {
1695 _aliasChecks.add(check);
1696 }
1697
1698 /* ------------------------------------------------------------ */
1699 /**
1700 * @return Mutable list of Alias checks
1701 */
1702 public List<AliasCheck> getAliasChecks()
1703 {
1704 return _aliasChecks;
1705 }
1706
1707 /* ------------------------------------------------------------ */
1708 /**
1709 * Context.
1710 * <p>
1711 * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}.
1712 * </p>
1713 *
1714 *
1715 */
1716 public class Context implements ServletContext
1717 {
1718 protected int _majorVersion = 3;
1719 protected int _minorVersion = 0;
1720 protected boolean _enabled = true; //whether or not the dynamic API is enabled for callers
1721
1722 /* ------------------------------------------------------------ */
1723 protected Context()
1724 {
1725 }
1726
1727 /* ------------------------------------------------------------ */
1728 public ContextHandler getContextHandler()
1729 {
1730 // TODO reduce visibility of this method
1731 return ContextHandler.this;
1732 }
1733
1734 /* ------------------------------------------------------------ */
1735 /*
1736 * @see javax.servlet.ServletContext#getContext(java.lang.String)
1737 */
1738 @Override
1739 public ServletContext getContext(String uripath)
1740 {
1741 List<ContextHandler> contexts = new ArrayList<ContextHandler>();
1742 Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class);
1743 String matched_path = null;
1744
1745 for (Handler handler : handlers)
1746 {
1747 if (handler == null)
1748 continue;
1749 ContextHandler ch = (ContextHandler)handler;
1750 String context_path = ch.getContextPath();
1751
1752 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
1753 || "/".equals(context_path))
1754 {
1755 // look first for vhost matching context only
1756 if (getVirtualHosts() != null && getVirtualHosts().length > 0)
1757 {
1758 if (ch.getVirtualHosts() != null && ch.getVirtualHosts().length > 0)
1759 {
1760 for (String h1 : getVirtualHosts())
1761 for (String h2 : ch.getVirtualHosts())
1762 if (h1.equals(h2))
1763 {
1764 if (matched_path == null || context_path.length() > matched_path.length())
1765 {
1766 contexts.clear();
1767 matched_path = context_path;
1768 }
1769
1770 if (matched_path.equals(context_path))
1771 contexts.add(ch);
1772 }
1773 }
1774 }
1775 else
1776 {
1777 if (matched_path == null || context_path.length() > matched_path.length())
1778 {
1779 contexts.clear();
1780 matched_path = context_path;
1781 }
1782
1783 if (matched_path.equals(context_path))
1784 contexts.add(ch);
1785 }
1786 }
1787 }
1788
1789 if (contexts.size() > 0)
1790 return contexts.get(0)._scontext;
1791
1792 // try again ignoring virtual hosts
1793 matched_path = null;
1794 for (Handler handler : handlers)
1795 {
1796 if (handler == null)
1797 continue;
1798 ContextHandler ch = (ContextHandler)handler;
1799 String context_path = ch.getContextPath();
1800
1801 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
1802 || "/".equals(context_path))
1803 {
1804 if (matched_path == null || context_path.length() > matched_path.length())
1805 {
1806 contexts.clear();
1807 matched_path = context_path;
1808 }
1809
1810 if (matched_path.equals(context_path))
1811 contexts.add(ch);
1812 }
1813 }
1814
1815 if (contexts.size() > 0)
1816 return contexts.get(0)._scontext;
1817 return null;
1818 }
1819
1820 /* ------------------------------------------------------------ */
1821 /*
1822 * @see javax.servlet.ServletContext#getMajorVersion()
1823 */
1824 @Override
1825 public int getMajorVersion()
1826 {
1827 return 3;
1828 }
1829
1830
1831 /* ------------------------------------------------------------ */
1832 /*
1833 * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
1834 */
1835 @Override
1836 public String getMimeType(String file)
1837 {
1838 if (_mimeTypes == null)
1839 return null;
1840 Buffer mime = _mimeTypes.getMimeByExtension(file);
1841 if (mime != null)
1842 return mime.toString();
1843 return null;
1844 }
1845
1846 /* ------------------------------------------------------------ */
1847 /*
1848 * @see javax.servlet.ServletContext#getMinorVersion()
1849 */
1850 @Override
1851 public int getMinorVersion()
1852 {
1853 return 0;
1854 }
1855
1856 /* ------------------------------------------------------------ */
1857 /*
1858 * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String)
1859 */
1860 @Override
1861 public RequestDispatcher getNamedDispatcher(String name)
1862 {
1863 return null;
1864 }
1865
1866 /* ------------------------------------------------------------ */
1867 /*
1868 * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String)
1869 */
1870 @Override
1871 public RequestDispatcher getRequestDispatcher(String uriInContext)
1872 {
1873 if (uriInContext == null)
1874 return null;
1875
1876 if (!uriInContext.startsWith("/"))
1877 return null;
1878
1879 try
1880 {
1881 String query = null;
1882 int q = 0;
1883 if ((q = uriInContext.indexOf('?')) > 0)
1884 {
1885 query = uriInContext.substring(q + 1);
1886 uriInContext = uriInContext.substring(0,q);
1887 }
1888
1889 String pathInContext = URIUtil.canonicalPath(URIUtil.decodePath(uriInContext));
1890 if (pathInContext!=null)
1891 {
1892 String uri = URIUtil.addPaths(getContextPath(),uriInContext);
1893 ContextHandler context = ContextHandler.this;
1894 return new Dispatcher(context,uri,pathInContext,query);
1895 }
1896 }
1897 catch (Exception e)
1898 {
1899 LOG.ignore(e);
1900 }
1901 return null;
1902 }
1903
1904 /* ------------------------------------------------------------ */
1905 /*
1906 * @see javax.servlet.ServletContext#getRealPath(java.lang.String)
1907 */
1908 @Override
1909 public String getRealPath(String path)
1910 {
1911 if (path == null)
1912 return null;
1913 if (path.length() == 0)
1914 path = URIUtil.SLASH;
1915 else if (path.charAt(0) != '/')
1916 path = URIUtil.SLASH + path;
1917
1918 try
1919 {
1920 Resource resource = ContextHandler.this.getResource(path);
1921 if (resource != null)
1922 {
1923 File file = resource.getFile();
1924 if (file != null)
1925 return file.getCanonicalPath();
1926 }
1927 }
1928 catch (Exception e)
1929 {
1930 LOG.ignore(e);
1931 }
1932
1933 return null;
1934 }
1935
1936 /* ------------------------------------------------------------ */
1937 @Override
1938 public URL getResource(String path) throws MalformedURLException
1939 {
1940 Resource resource = ContextHandler.this.getResource(path);
1941 if (resource != null && resource.exists())
1942 return resource.getURL();
1943 return null;
1944 }
1945
1946 /* ------------------------------------------------------------ */
1947 /*
1948 * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String)
1949 */
1950 @Override
1951 public InputStream getResourceAsStream(String path)
1952 {
1953 try
1954 {
1955 URL url = getResource(path);
1956 if (url == null)
1957 return null;
1958 Resource r = Resource.newResource(url);
1959 return r.getInputStream();
1960 }
1961 catch (Exception e)
1962 {
1963 LOG.ignore(e);
1964 return null;
1965 }
1966 }
1967
1968 /* ------------------------------------------------------------ */
1969 /*
1970 * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String)
1971 */
1972 @Override
1973 public Set getResourcePaths(String path)
1974 {
1975 return ContextHandler.this.getResourcePaths(path);
1976 }
1977
1978 /* ------------------------------------------------------------ */
1979 /*
1980 * @see javax.servlet.ServletContext#getServerInfo()
1981 */
1982 @Override
1983 public String getServerInfo()
1984 {
1985 return "jetty/" + Server.getVersion();
1986 }
1987
1988 /* ------------------------------------------------------------ */
1989 /*
1990 * @see javax.servlet.ServletContext#getServlet(java.lang.String)
1991 */
1992 @Override
1993 @Deprecated
1994 public Servlet getServlet(String name) throws ServletException
1995 {
1996 return null;
1997 }
1998
1999 /* ------------------------------------------------------------ */
2000 /*
2001 * @see javax.servlet.ServletContext#getServletNames()
2002 */
2003 @SuppressWarnings("unchecked")
2004 @Override
2005 @Deprecated
2006 public Enumeration getServletNames()
2007 {
2008 return Collections.enumeration(Collections.EMPTY_LIST);
2009 }
2010
2011 /* ------------------------------------------------------------ */
2012 /*
2013 * @see javax.servlet.ServletContext#getServlets()
2014 */
2015 @SuppressWarnings("unchecked")
2016 @Override
2017 @Deprecated
2018 public Enumeration getServlets()
2019 {
2020 return Collections.enumeration(Collections.EMPTY_LIST);
2021 }
2022
2023 /* ------------------------------------------------------------ */
2024 /*
2025 * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String)
2026 */
2027 @Override
2028 public void log(Exception exception, String msg)
2029 {
2030 _logger.warn(msg,exception);
2031 }
2032
2033 /* ------------------------------------------------------------ */
2034 /*
2035 * @see javax.servlet.ServletContext#log(java.lang.String)
2036 */
2037 @Override
2038 public void log(String msg)
2039 {
2040 _logger.info(msg);
2041 }
2042
2043 /* ------------------------------------------------------------ */
2044 /*
2045 * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable)
2046 */
2047 @Override
2048 public void log(String message, Throwable throwable)
2049 {
2050 _logger.warn(message,throwable);
2051 }
2052
2053 /* ------------------------------------------------------------ */
2054 /*
2055 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
2056 */
2057 @Override
2058 public String getInitParameter(String name)
2059 {
2060 return ContextHandler.this.getInitParameter(name);
2061 }
2062
2063 /* ------------------------------------------------------------ */
2064 /*
2065 * @see javax.servlet.ServletContext#getInitParameterNames()
2066 */
2067 @SuppressWarnings("unchecked")
2068 @Override
2069 public Enumeration getInitParameterNames()
2070 {
2071 return ContextHandler.this.getInitParameterNames();
2072 }
2073
2074 /* ------------------------------------------------------------ */
2075 /*
2076 * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
2077 */
2078 @Override
2079 public synchronized Object getAttribute(String name)
2080 {
2081 Object o = ContextHandler.this.getAttribute(name);
2082 if (o == null && _contextAttributes != null)
2083 o = _contextAttributes.getAttribute(name);
2084 return o;
2085 }
2086
2087 /* ------------------------------------------------------------ */
2088 /*
2089 * @see javax.servlet.ServletContext#getAttributeNames()
2090 */
2091 @SuppressWarnings("unchecked")
2092 @Override
2093 public synchronized Enumeration getAttributeNames()
2094 {
2095 HashSet<String> set = new HashSet<String>();
2096 if (_contextAttributes != null)
2097 {
2098 Enumeration<String> e = _contextAttributes.getAttributeNames();
2099 while (e.hasMoreElements())
2100 set.add(e.nextElement());
2101 }
2102 Enumeration<String> e = _attributes.getAttributeNames();
2103 while (e.hasMoreElements())
2104 set.add(e.nextElement());
2105
2106 return Collections.enumeration(set);
2107 }
2108
2109 /* ------------------------------------------------------------ */
2110 /*
2111 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
2112 */
2113 @Override
2114 public synchronized void setAttribute(String name, Object value)
2115 {
2116 checkManagedAttribute(name,value);
2117 Object old_value = _contextAttributes.getAttribute(name);
2118
2119 if (value == null)
2120 _contextAttributes.removeAttribute(name);
2121 else
2122 _contextAttributes.setAttribute(name,value);
2123
2124 if (_contextAttributeListeners != null)
2125 {
2126 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value == null?value:old_value);
2127
2128 for (int i = 0; i < LazyList.size(_contextAttributeListeners); i++)
2129 {
2130 ServletContextAttributeListener l = (ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i);
2131
2132 if (old_value == null)
2133 l.attributeAdded(event);
2134 else if (value == null)
2135 l.attributeRemoved(event);
2136 else
2137 l.attributeReplaced(event);
2138 }
2139 }
2140 }
2141
2142 /* ------------------------------------------------------------ */
2143 /*
2144 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
2145 */
2146 @Override
2147 public synchronized void removeAttribute(String name)
2148 {
2149 checkManagedAttribute(name,null);
2150
2151 if (_contextAttributes == null)
2152 {
2153 // Set it on the handler
2154 _attributes.removeAttribute(name);
2155 return;
2156 }
2157
2158 Object old_value = _contextAttributes.getAttribute(name);
2159 _contextAttributes.removeAttribute(name);
2160 if (old_value != null)
2161 {
2162 if (_contextAttributeListeners != null)
2163 {
2164 ServletContextAttributeEvent event = new ServletContextAttributeEvent(_scontext,name,old_value);
2165
2166 for (int i = 0; i < LazyList.size(_contextAttributeListeners); i++)
2167 ((ServletContextAttributeListener)LazyList.get(_contextAttributeListeners,i)).attributeRemoved(event);
2168 }
2169 }
2170 }
2171
2172 /* ------------------------------------------------------------ */
2173 /*
2174 * @see javax.servlet.ServletContext#getServletContextName()
2175 */
2176 @Override
2177 public String getServletContextName()
2178 {
2179 String name = ContextHandler.this.getDisplayName();
2180 if (name == null)
2181 name = ContextHandler.this.getContextPath();
2182 return name;
2183 }
2184
2185 /* ------------------------------------------------------------ */
2186 @Override
2187 public String getContextPath()
2188 {
2189 if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH))
2190 return "";
2191
2192 return _contextPath;
2193 }
2194
2195 /* ------------------------------------------------------------ */
2196 @Override
2197 public String toString()
2198 {
2199 return "ServletContext@" + ContextHandler.this.toString();
2200 }
2201
2202 /* ------------------------------------------------------------ */
2203 @Override
2204 public boolean setInitParameter(String name, String value)
2205 {
2206 if (ContextHandler.this.getInitParameter(name) != null)
2207 return false;
2208 ContextHandler.this.getInitParams().put(name,value);
2209 return true;
2210 }
2211
2212 /* ------------------------------------------------------------ */
2213 final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler";
2214
2215 @Override
2216 public Dynamic addFilter(String filterName, Class<? extends Filter> filterClass)
2217 {
2218 LOG.warn(__unimplmented);
2219 return null;
2220 }
2221
2222 @Override
2223 public Dynamic addFilter(String filterName, Filter filter)
2224 {
2225 LOG.warn(__unimplmented);
2226 return null;
2227 }
2228
2229 @Override
2230 public Dynamic addFilter(String filterName, String className)
2231 {
2232 LOG.warn(__unimplmented);
2233 return null;
2234 }
2235
2236 @Override
2237 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class<? extends Servlet> servletClass)
2238 {
2239 LOG.warn(__unimplmented);
2240 return null;
2241 }
2242
2243 @Override
2244 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet)
2245 {
2246 LOG.warn(__unimplmented);
2247 return null;
2248 }
2249
2250 @Override
2251 public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className)
2252 {
2253 LOG.warn(__unimplmented);
2254 return null;
2255 }
2256
2257 @Override
2258 public <T extends Filter> T createFilter(Class<T> c) throws ServletException
2259 {
2260 LOG.warn(__unimplmented);
2261 return null;
2262 }
2263
2264 @Override
2265 public <T extends Servlet> T createServlet(Class<T> c) throws ServletException
2266 {
2267 LOG.warn(__unimplmented);
2268 return null;
2269 }
2270
2271 @Override
2272 public Set<SessionTrackingMode> getDefaultSessionTrackingModes()
2273 {
2274 LOG.warn(__unimplmented);
2275 return null;
2276 }
2277
2278 @Override
2279 public Set<SessionTrackingMode> getEffectiveSessionTrackingModes()
2280 {
2281 LOG.warn(__unimplmented);
2282 return null;
2283 }
2284
2285 @Override
2286 public FilterRegistration getFilterRegistration(String filterName)
2287 {
2288 LOG.warn(__unimplmented);
2289 return null;
2290 }
2291
2292 @Override
2293 public Map<String, ? extends FilterRegistration> getFilterRegistrations()
2294 {
2295 LOG.warn(__unimplmented);
2296 return null;
2297 }
2298
2299 @Override
2300 public ServletRegistration getServletRegistration(String servletName)
2301 {
2302 LOG.warn(__unimplmented);
2303 return null;
2304 }
2305
2306 @Override
2307 public Map<String, ? extends ServletRegistration> getServletRegistrations()
2308 {
2309 LOG.warn(__unimplmented);
2310 return null;
2311 }
2312
2313 @Override
2314 public SessionCookieConfig getSessionCookieConfig()
2315 {
2316 LOG.warn(__unimplmented);
2317 return null;
2318 }
2319
2320 @Override
2321 public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes)
2322 {
2323 LOG.warn(__unimplmented);
2324 }
2325
2326 @Override
2327 public void addListener(String className)
2328 {
2329 if (!_enabled)
2330 throw new UnsupportedOperationException();
2331
2332 try
2333 {
2334 // Class<? extends EventListener> clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className);
2335 Class clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className);
2336 addListener(clazz);
2337 }
2338 catch (ClassNotFoundException e)
2339 {
2340 throw new IllegalArgumentException(e);
2341 }
2342 }
2343
2344 @Override
2345 public <T extends EventListener> void addListener(T t)
2346 {
2347 if (!_enabled)
2348 throw new UnsupportedOperationException();
2349 ContextHandler.this.addEventListener(t);
2350 ContextHandler.this.restrictEventListener(t);
2351 }
2352
2353 @Override
2354 public void addListener(Class<? extends EventListener> listenerClass)
2355 {
2356 if (!_enabled)
2357 throw new UnsupportedOperationException();
2358
2359 try
2360 {
2361 EventListener e = createListener(listenerClass);
2362 ContextHandler.this.addEventListener(e);
2363 ContextHandler.this.restrictEventListener(e);
2364 }
2365 catch (ServletException e)
2366 {
2367 throw new IllegalArgumentException(e);
2368 }
2369 }
2370
2371 @Override
2372 public <T extends EventListener> T createListener(Class<T> clazz) throws ServletException
2373 {
2374 try
2375 {
2376 return clazz.newInstance();
2377 }
2378 catch (InstantiationException e)
2379 {
2380 throw new ServletException(e);
2381 }
2382 catch (IllegalAccessException e)
2383 {
2384 throw new ServletException(e);
2385 }
2386 }
2387
2388 @Override
2389 public ClassLoader getClassLoader()
2390 {
2391 AccessController.checkPermission(new RuntimePermission("getClassLoader"));
2392 return _classLoader;
2393 }
2394
2395 @Override
2396 public int getEffectiveMajorVersion()
2397 {
2398 return _majorVersion;
2399 }
2400
2401 @Override
2402 public int getEffectiveMinorVersion()
2403 {
2404 return _minorVersion;
2405 }
2406
2407 public void setEffectiveMajorVersion (int v)
2408 {
2409 _majorVersion = v;
2410 }
2411
2412 public void setEffectiveMinorVersion (int v)
2413 {
2414 _minorVersion = v;
2415 }
2416
2417 @Override
2418 public JspConfigDescriptor getJspConfigDescriptor()
2419 {
2420 LOG.warn(__unimplmented);
2421 return null;
2422 }
2423
2424 public void setJspConfigDescriptor(JspConfigDescriptor d)
2425 {
2426
2427 }
2428
2429 @Override
2430 public void declareRoles(String... roleNames)
2431 {
2432 if (!isStarting())
2433 throw new IllegalStateException ();
2434 if (!_enabled)
2435 throw new UnsupportedOperationException();
2436
2437 // TODO Auto-generated method stub
2438
2439 }
2440
2441 public void setEnabled(boolean enabled)
2442 {
2443 _enabled = enabled;
2444 }
2445
2446 public boolean isEnabled()
2447 {
2448 return _enabled;
2449 }
2450 }
2451
2452 private static class CLDump implements Dumpable
2453 {
2454 final ClassLoader _loader;
2455
2456 CLDump(ClassLoader loader)
2457 {
2458 _loader = loader;
2459 }
2460
2461 public String dump()
2462 {
2463 return AggregateLifeCycle.dump(this);
2464 }
2465
2466 public void dump(Appendable out, String indent) throws IOException
2467 {
2468 out.append(String.valueOf(_loader)).append("\n");
2469
2470 if (_loader != null)
2471 {
2472 Object parent = _loader.getParent();
2473 if (parent != null)
2474 {
2475 if (!(parent instanceof Dumpable))
2476 parent = new CLDump((ClassLoader)parent);
2477
2478 if (_loader instanceof URLClassLoader)
2479 AggregateLifeCycle.dump(out,indent,TypeUtil.asList(((URLClassLoader)_loader).getURLs()),Collections.singleton(parent));
2480 else
2481 AggregateLifeCycle.dump(out,indent,Collections.singleton(parent));
2482 }
2483 }
2484 }
2485 }
2486
2487
2488 /* ------------------------------------------------------------ */
2489 /** Interface to check aliases
2490 */
2491 public interface AliasCheck
2492 {
2493 /* ------------------------------------------------------------ */
2494 /** Check an alias
2495 * @param path The path the aliased resource was created for
2496 * @param resource The aliased resourced
2497 * @return True if the resource is OK to be served.
2498 */
2499 boolean check(String path, Resource resource);
2500 }
2501
2502
2503 /* ------------------------------------------------------------ */
2504 /** Approve Aliases with same suffix.
2505 * Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be
2506 * approved because both the resource and alias end with ".html".
2507 */
2508 @Deprecated
2509 public static class ApproveSameSuffixAliases implements AliasCheck
2510 {
2511 {
2512 LOG.warn("ApproveSameSuffixAlias is not safe for production");
2513 }
2514
2515 public boolean check(String path, Resource resource)
2516 {
2517 int dot = path.lastIndexOf('.');
2518 if (dot<0)
2519 return false;
2520 String suffix=path.substring(dot);
2521 return resource.toString().endsWith(suffix);
2522 }
2523 }
2524
2525
2526 /* ------------------------------------------------------------ */
2527 /** Approve Aliases with a path prefix.
2528 * Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be
2529 * approved because both the resource and alias end with "/foobar.html".
2530 */
2531 @Deprecated
2532 public static class ApprovePathPrefixAliases implements AliasCheck
2533 {
2534 {
2535 LOG.warn("ApprovePathPrefixAliases is not safe for production");
2536 }
2537
2538 public boolean check(String path, Resource resource)
2539 {
2540 int slash = path.lastIndexOf('/');
2541 if (slash<0 || slash==path.length()-1)
2542 return false;
2543 String suffix=path.substring(slash);
2544 return resource.toString().endsWith(suffix);
2545 }
2546 }
2547
2548 /* ------------------------------------------------------------ */
2549 /** Approve Aliases of a non existent directory.
2550 * If a directory "/foobar/" does not exist, then the resource is
2551 * aliased to "/foobar". Accept such aliases.
2552 */
2553 public static class ApproveNonExistentDirectoryAliases implements AliasCheck
2554 {
2555 public boolean check(String path, Resource resource)
2556 {
2557 if (resource.exists())
2558 return false;
2559
2560 String a=resource.getAlias().toString();
2561 String r=resource.getURL().toString();
2562
2563 if (a.length()>r.length())
2564 return a.startsWith(r) && a.length()==r.length()+1 && a.endsWith("/");
2565 else
2566 return r.startsWith(a) && r.length()==a.length()+1 && r.endsWith("/");
2567 }
2568 }
2569
2570 }