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