comparison src/org/eclipse/jetty/server/handler/ContextHandler.java @ 991:688c39c50ee3

simplify ContextHandler
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 18 Oct 2016 00:22:46 -0600
parents 900e5b8ccd19
children 0608a6664bee
comparison
equal deleted inserted replaced
990:83cc6e05a58f 991:688c39c50ee3
37 import java.util.Locale; 37 import java.util.Locale;
38 import java.util.Map; 38 import java.util.Map;
39 import java.util.Set; 39 import java.util.Set;
40 import java.util.concurrent.CopyOnWriteArrayList; 40 import java.util.concurrent.CopyOnWriteArrayList;
41 41
42 import javax.servlet.DispatcherType;
43 import javax.servlet.RequestDispatcher; 42 import javax.servlet.RequestDispatcher;
44 import javax.servlet.Servlet; 43 import javax.servlet.Servlet;
45 import javax.servlet.ServletContext; 44 import javax.servlet.ServletContext;
46 import javax.servlet.ServletContextAttributeEvent; 45 import javax.servlet.ServletContextAttributeEvent;
47 import javax.servlet.ServletContextAttributeListener; 46 import javax.servlet.ServletContextAttributeListener;
98 { 97 {
99 private static final Logger LOG = LoggerFactory.getLogger(ContextHandler.class); 98 private static final Logger LOG = LoggerFactory.getLogger(ContextHandler.class);
100 99
101 private static final ThreadLocal<Context> __context = new ThreadLocal<Context>(); 100 private static final ThreadLocal<Context> __context = new ThreadLocal<Context>();
102 101
103 /**
104 * 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
105 * 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
106 * for the attribute value.
107 */
108 public static final String MANAGED_ATTRIBUTES = "org.eclipse.jetty.server.context.ManagedAttributes";
109
110 /* ------------------------------------------------------------ */ 102 /* ------------------------------------------------------------ */
111 /** 103 /**
112 * Get the current ServletContext implementation. 104 * Get the current ServletContext implementation.
113 * 105 *
114 * @return ServletContext implementation 106 * @return ServletContext implementation
115 */ 107 */
116 public static Context getCurrentContext() 108 public static ContextHandler getCurrentContext()
117 { 109 {
118 return __context.get(); 110 Context context = __context.get();
119 } 111 return context==null ? null : context.getContextHandler();
120 112 }
121 protected Context _scontext; 113
114 private Context _scontext;
122 115
123 private final AttributesMap _contextAttributes; 116 private final AttributesMap _contextAttributes;
124 private final Map<String, String> _initParams;
125 private ClassLoader _classLoader;
126 private String _contextPath = "/"; 117 private String _contextPath = "/";
127 private String _displayName;
128 private Resource _baseResource; 118 private Resource _baseResource;
129 private MimeTypes _mimeTypes;
130 private Map<String, String> _localeEncodingMap;
131 private String[] _welcomeFiles;
132 private String[] _vhosts;
133 private Logger _logger; 119 private Logger _logger;
134 private boolean _allowNullPathInfo;
135 private int _maxFormKeys = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormKeys",-1).intValue();
136 private int _maxFormContentSize = Integer.getInteger("org.eclipse.jetty.server.Request.maxFormContentSize",-1).intValue();
137 private boolean _compactPath = false;
138 private boolean _aliasesAllowed = false;
139
140 private Map<String, Object> _managedAttributes;
141 private String[] _protectedTargets;
142 private final CopyOnWriteArrayList<AliasCheck> _aliasChecks = new CopyOnWriteArrayList<ContextHandler.AliasCheck>();
143 120
144 private boolean _shutdown = false; 121 private boolean _shutdown = false;
145 private boolean _available = true;
146 private volatile int _availability; // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE 122 private volatile int _availability; // 0=STOPPED, 1=AVAILABLE, 2=SHUTDOWN, 3=UNAVAILABLE
147 123
148 private final static int __STOPPED = 0, __AVAILABLE = 1, __SHUTDOWN = 2, __UNAVAILABLE = 3; 124 private final static int __STOPPED = 0, __AVAILABLE = 1, __SHUTDOWN = 2;
149 125
150 /* ------------------------------------------------------------ */
151 /**
152 *
153 */
154 public ContextHandler() 126 public ContextHandler()
155 { 127 {
156 super(); 128 super();
157 _scontext = new Context(); 129 _scontext = new Context();
158 _contextAttributes = new AttributesMap(); 130 _contextAttributes = new AttributesMap();
159 _initParams = new HashMap<String, String>(); 131 }
160 addAliasCheck(new ApproveNonExistentDirectoryAliases()); 132
161 }
162
163 /* ------------------------------------------------------------ */
164 /**
165 *
166 */
167 public ContextHandler(String contextPath) 133 public ContextHandler(String contextPath)
168 { 134 {
169 this(); 135 this();
170 setContextPath(contextPath); 136 setContextPath(contextPath);
171 } 137 }
172 138
173 /* ------------------------------------------------------------ */
174 /**
175 *
176 */
177 public ContextHandler(HandlerContainer parent, String contextPath) 139 public ContextHandler(HandlerContainer parent, String contextPath)
178 { 140 {
179 this(); 141 this();
180 setContextPath(contextPath); 142 setContextPath(contextPath);
181 if (parent instanceof HandlerWrapper) 143 if (parent instanceof HandlerWrapper)
182 ((HandlerWrapper)parent).setHandler(this); 144 ((HandlerWrapper)parent).setHandler(this);
183 else if (parent instanceof HandlerCollection) 145 else if (parent instanceof HandlerCollection)
184 ((HandlerCollection)parent).addHandler(this); 146 ((HandlerCollection)parent).addHandler(this);
185 } 147 }
186 148
187 /* ------------------------------------------------------------ */
188 @Override 149 @Override
189 public void dump(Appendable out, String indent) throws IOException 150 public void dump(Appendable out, String indent) throws IOException
190 { 151 {
191 dumpThis(out); 152 dumpThis(out);
192 dump(out,indent,Collections.singletonList(new CLDump(getClassLoader())),TypeUtil.asList(getHandlers()),getBeans(),_initParams.entrySet(), 153 dump(out,indent,TypeUtil.asList(getHandlers()),getBeans(),
193 _contextAttributes.getAttributeEntrySet()); 154 _contextAttributes.getAttributeEntrySet());
194 } 155 }
195 156
196 /* ------------------------------------------------------------ */
197 public Context getServletContext() 157 public Context getServletContext()
198 { 158 {
199 return _scontext; 159 return _scontext;
200 } 160 }
201 161
202 /* ------------------------------------------------------------ */
203 /**
204 * @return the allowNullPathInfo true if /context is not redirected to /context/
205 */
206 public boolean getAllowNullPathInfo()
207 {
208 return _allowNullPathInfo;
209 }
210
211 /* ------------------------------------------------------------ */
212 /**
213 * @param allowNullPathInfo
214 * true if /context is not redirected to /context/
215 */
216 public void setAllowNullPathInfo(boolean allowNullPathInfo)
217 {
218 _allowNullPathInfo = allowNullPathInfo;
219 }
220
221 /* ------------------------------------------------------------ */
222 /**
223 * 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
224 * 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
225 * matching virtual host name.
226 *
227 * @param vhosts
228 * 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
229 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
230 */
231 public void setVirtualHosts(String[] vhosts)
232 {
233 if (vhosts == null)
234 {
235 _vhosts = vhosts;
236 }
237 else
238 {
239 _vhosts = new String[vhosts.length];
240 for (int i = 0; i < vhosts.length; i++)
241 _vhosts[i] = normalizeHostname(vhosts[i]);
242 }
243 }
244
245 /* ------------------------------------------------------------ */
246 /** Either set virtual hosts or add to an existing set of virtual hosts.
247 *
248 * @param virtualHosts
249 * 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
250 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
251 */
252 public void addVirtualHosts(String[] virtualHosts)
253 {
254 if (virtualHosts == null) // since this is add, we don't null the old ones
255 {
256 return;
257 }
258 else
259 {
260 List<String> currentVirtualHosts = null;
261 if (_vhosts != null)
262 {
263 currentVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
264 }
265 else
266 {
267 currentVirtualHosts = new ArrayList<String>();
268 }
269
270 for (int i = 0; i < virtualHosts.length; i++)
271 {
272 String normVhost = normalizeHostname(virtualHosts[i]);
273 if (!currentVirtualHosts.contains(normVhost))
274 {
275 currentVirtualHosts.add(normVhost);
276 }
277 }
278 _vhosts = currentVirtualHosts.toArray(new String[0]);
279 }
280 }
281
282 /* ------------------------------------------------------------ */
283 /**
284 * Removes an array of virtual host entries, if this removes all entries the _vhosts will be set to null
285 *
286 * @param virtualHosts
287 * 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
288 * String representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
289 */
290 public void removeVirtualHosts(String[] virtualHosts)
291 {
292 if (virtualHosts == null)
293 {
294 return; // do nothing
295 }
296 else if ( _vhosts == null || _vhosts.length == 0)
297 {
298 return; // do nothing
299 }
300 else
301 {
302 List<String> existingVirtualHosts = new ArrayList<String>(Arrays.asList(_vhosts));
303
304 for (int i = 0; i < virtualHosts.length; i++)
305 {
306 String toRemoveVirtualHost = normalizeHostname(virtualHosts[i]);
307 if (existingVirtualHosts.contains(toRemoveVirtualHost))
308 {
309 existingVirtualHosts.remove(toRemoveVirtualHost);
310 }
311 }
312
313 if (existingVirtualHosts.isEmpty())
314 {
315 _vhosts = null; // if we ended up removing them all, just null out _vhosts
316 }
317 else
318 {
319 _vhosts = existingVirtualHosts.toArray(new String[0]);
320 }
321 }
322 }
323
324 /* ------------------------------------------------------------ */
325 /**
326 * 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
327 * 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
328 * matching virtual host name.
329 *
330 * @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
331 * representation of IP addresses. Host names may start with '*.' to wildcard one level of names.
332 */
333 public String[] getVirtualHosts()
334 {
335 return _vhosts;
336 }
337
338 /* ------------------------------------------------------------ */
339 /**
340 * @return Returns the classLoader.
341 */
342 public ClassLoader getClassLoader()
343 {
344 return _classLoader;
345 }
346
347 /* ------------------------------------------------------------ */
348 /**
349 * Make best effort to extract a file classpath from the context classloader
350 *
351 * @return Returns the classLoader.
352 */
353 public String getClassPath()
354 {
355 if (_classLoader == null || !(_classLoader instanceof URLClassLoader))
356 return null;
357 URLClassLoader loader = (URLClassLoader)_classLoader;
358 URL[] urls = loader.getURLs();
359 StringBuilder classpath = new StringBuilder();
360 for (int i = 0; i < urls.length; i++)
361 {
362 try
363 {
364 Resource resource = newResource(urls[i]);
365 File file = resource.getFile();
366 if (file != null && file.exists())
367 {
368 if (classpath.length() > 0)
369 classpath.append(File.pathSeparatorChar);
370 classpath.append(file.getAbsolutePath());
371 }
372 }
373 catch (IOException e)
374 {
375 LOG.debug("",e);
376 }
377 }
378 if (classpath.length() == 0)
379 return null;
380 return classpath.toString();
381 }
382
383 /* ------------------------------------------------------------ */
384 /**
385 * @return Returns the _contextPath.
386 */
387 public String getContextPath() 162 public String getContextPath()
388 { 163 {
389 return _contextPath; 164 return _contextPath;
390 }
391
392 /* ------------------------------------------------------------ */
393 /*
394 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
395 */
396 public String getInitParameter(String name)
397 {
398 return _initParams.get(name);
399 }
400
401 /* ------------------------------------------------------------ */
402 /*
403 */
404 public String setInitParameter(String name, String value)
405 {
406 return _initParams.put(name,value);
407 }
408
409 /* ------------------------------------------------------------ */
410 /*
411 * @see javax.servlet.ServletContext#getInitParameterNames()
412 */
413 @SuppressWarnings("rawtypes")
414 public Enumeration getInitParameterNames()
415 {
416 return Collections.enumeration(_initParams.keySet());
417 }
418
419 /* ------------------------------------------------------------ */
420 /**
421 * @return Returns the initParams.
422 */
423 public Map<String, String> getInitParams()
424 {
425 return _initParams;
426 }
427
428 /* ------------------------------------------------------------ */
429 /*
430 * @see javax.servlet.ServletContext#getServletContextName()
431 */
432 public String getDisplayName()
433 {
434 return _displayName;
435 }
436
437 /* ------------------------------------------------------------ */
438 /**
439 * @return true if this context is accepting new requests
440 */
441 public boolean isShutdown()
442 {
443 synchronized (this)
444 {
445 return !_shutdown;
446 }
447 } 165 }
448 166
449 /* ------------------------------------------------------------ */ 167 /* ------------------------------------------------------------ */
450 /** 168 /**
451 * 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 169 * 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
457 public void setShutdown(boolean shutdown) 175 public void setShutdown(boolean shutdown)
458 { 176 {
459 synchronized (this) 177 synchronized (this)
460 { 178 {
461 _shutdown = shutdown; 179 _shutdown = shutdown;
462 _availability = isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED; 180 _availability = isRunning()?(_shutdown?__SHUTDOWN:__AVAILABLE):__STOPPED;
463 }
464 }
465
466 /* ------------------------------------------------------------ */
467 /**
468 * @return false if this context is unavailable (sends 503)
469 */
470 public boolean isAvailable()
471 {
472 synchronized (this)
473 {
474 return _available;
475 }
476 }
477
478 /* ------------------------------------------------------------ */
479 /**
480 * Set Available status.
481 */
482 public void setAvailable(boolean available)
483 {
484 synchronized (this)
485 {
486 _available = available;
487 _availability = isRunning()?(_shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE):__STOPPED;
488 } 181 }
489 } 182 }
490 183
491 /* ------------------------------------------------------------ */ 184 /* ------------------------------------------------------------ */
492 public Logger getLogger() 185 public Logger getLogger()
510 _availability = __STOPPED; 203 _availability = __STOPPED;
511 204
512 if (_contextPath == null) 205 if (_contextPath == null)
513 throw new IllegalStateException("Null contextPath"); 206 throw new IllegalStateException("Null contextPath");
514 207
515 _logger = LoggerFactory.getLogger(getDisplayName() == null?getContextPath():getDisplayName()); 208 _logger = LoggerFactory.getLogger(getContextPath());
516 ClassLoader old_classloader = null; 209 ClassLoader old_classloader = null;
517 Thread current_thread = null; 210 Thread current_thread = null;
518 Context old_context = null; 211 Context old_context = null;
519 212
520 try 213 try
521 { 214 {
522 // Set the classloader
523 if (_classLoader != null)
524 {
525 current_thread = Thread.currentThread();
526 old_classloader = current_thread.getContextClassLoader();
527 current_thread.setContextClassLoader(_classLoader);
528 }
529
530 if (_mimeTypes == null)
531 _mimeTypes = new MimeTypes();
532
533 old_context = __context.get(); 215 old_context = __context.get();
534 __context.set(_scontext); 216 __context.set(_scontext);
535 217
536 // defers the calling of super.doStart() 218 // defers the calling of super.doStart()
537 startContext(); 219 startContext();
538 220
539 synchronized(this) 221 synchronized(this)
540 { 222 {
541 _availability = _shutdown?__SHUTDOWN:_available?__AVAILABLE:__UNAVAILABLE; 223 _availability = _shutdown?__SHUTDOWN:__AVAILABLE;
542 } 224 }
543 } 225 }
544 finally 226 finally
545 { 227 {
546 __context.set(old_context); 228 __context.set(old_context);
547
548 // reset the classloader
549 if (_classLoader != null)
550 {
551 current_thread.setContextClassLoader(old_classloader);
552 }
553
554 } 229 }
555 } 230 }
556 231
557 /* ------------------------------------------------------------ */ 232 /* ------------------------------------------------------------ */
558 /** 233 /**
561 * 236 *
562 * @see org.eclipse.jetty.server.handler.ContextHandler.Context 237 * @see org.eclipse.jetty.server.handler.ContextHandler.Context
563 */ 238 */
564 protected void startContext() throws Exception 239 protected void startContext() throws Exception
565 { 240 {
566 String managedAttributes = _initParams.get(MANAGED_ATTRIBUTES);
567 if (managedAttributes != null)
568 {
569 _managedAttributes = new HashMap<String, Object>();
570 String[] attributes = managedAttributes.split(",");
571 for (String attribute : attributes)
572 _managedAttributes.put(attribute,null);
573
574 Enumeration e = _scontext.getAttributeNames();
575 while (e.hasMoreElements())
576 {
577 String name = (String)e.nextElement();
578 Object value = _scontext.getAttribute(name);
579 checkManagedAttribute(name,value);
580 }
581 }
582
583 super.doStart(); 241 super.doStart();
584 } 242 }
585 243
586 /* ------------------------------------------------------------ */ 244 /* ------------------------------------------------------------ */
587 public void callContextInitialized (ServletContextListener l, ServletContextEvent e) 245 public void callContextInitialized (ServletContextListener l, ServletContextEvent e)
609 267
610 Context old_context = __context.get(); 268 Context old_context = __context.get();
611 __context.set(_scontext); 269 __context.set(_scontext);
612 try 270 try
613 { 271 {
614 // Set the classloader
615 if (_classLoader != null)
616 {
617 current_thread = Thread.currentThread();
618 old_classloader = current_thread.getContextClassLoader();
619 current_thread.setContextClassLoader(_classLoader);
620 }
621
622 super.doStop(); 272 super.doStop();
623
624 Enumeration e = _scontext.getAttributeNames();
625 while (e.hasMoreElements())
626 {
627 String name = (String)e.nextElement();
628 checkManagedAttribute(name,null);
629 }
630 } 273 }
631 finally 274 finally
632 { 275 {
633 LOG.info("stopped {}",this); 276 LOG.info("stopped {}",this);
634 __context.set(old_context); 277 __context.set(old_context);
635 // reset the classloader
636 if (_classLoader != null)
637 current_thread.setContextClassLoader(old_classloader);
638 } 278 }
639 279
640 _contextAttributes.clearAttributes(); 280 _contextAttributes.clearAttributes();
641 } 281 }
642 282
643 /* ------------------------------------------------------------ */ 283 /* ------------------------------------------------------------ */
644 /* 284 /*
645 * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) 285 * @see org.eclipse.jetty.server.Handler#handle(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
646 */ 286 */
647 public boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException, ServletException 287 private boolean checkContext(final String target, final Request baseRequest, final HttpServletResponse response) throws IOException, ServletException
648 { 288 {
649 DispatcherType dispatch = baseRequest.getDispatcherType();
650
651 switch (_availability) 289 switch (_availability)
652 { 290 {
653 case __STOPPED: 291 case __STOPPED:
654 case __SHUTDOWN: 292 case __SHUTDOWN:
655 return false; 293 return false;
656 case __UNAVAILABLE:
657 baseRequest.setHandled(true);
658 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
659 return false;
660 default: 294 default:
661 if ((DispatcherType.REQUEST.equals(dispatch) && baseRequest.isHandled())) 295 if (baseRequest.isHandled())
662 return false; 296 return false;
663 }
664
665 // Check the vhosts
666 if (_vhosts != null && _vhosts.length > 0)
667 {
668 String vhost = normalizeHostname(baseRequest.getServerName());
669
670 boolean match = false;
671
672 // TODO non-linear lookup
673 for (int i = 0; !match && i < _vhosts.length; i++)
674 {
675 String contextVhost = _vhosts[i];
676 if (contextVhost == null)
677 continue;
678 if (contextVhost.startsWith("*."))
679 {
680 // wildcard only at the beginning, and only for one additional subdomain level
681 match = contextVhost.regionMatches(true,2,vhost,vhost.indexOf(".") + 1,contextVhost.length() - 2);
682 }
683 else
684 match = contextVhost.equalsIgnoreCase(vhost);
685 }
686 if (!match)
687 return false;
688 } 297 }
689 298
690 // Are we not the root context? 299 // Are we not the root context?
691 if (_contextPath.length() > 1) 300 if (_contextPath.length() > 1)
692 { 301 {
695 return false; 304 return false;
696 if (target.length() > _contextPath.length() && target.charAt(_contextPath.length()) != '/') 305 if (target.length() > _contextPath.length() && target.charAt(_contextPath.length()) != '/')
697 return false; 306 return false;
698 307
699 // redirect null path infos 308 // redirect null path infos
700 if (!_allowNullPathInfo && _contextPath.length() == target.length()) 309 if (_contextPath.length() == target.length())
701 { 310 {
702 // context request must end with / 311 // context request must end with /
703 baseRequest.setHandled(true); 312 baseRequest.setHandled(true);
704 if (baseRequest.getQueryString() != null) 313 if (baseRequest.getQueryString() != null)
705 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString()); 314 response.sendRedirect(URIUtil.addPaths(baseRequest.getRequestURI(),URIUtil.SLASH) + "?" + baseRequest.getQueryString());
729 String old_path_info = null; 338 String old_path_info = null;
730 ClassLoader old_classloader = null; 339 ClassLoader old_classloader = null;
731 Thread current_thread = null; 340 Thread current_thread = null;
732 String pathInfo = target; 341 String pathInfo = target;
733 342
734 DispatcherType dispatch = baseRequest.getDispatcherType();
735
736 old_context = baseRequest.getContext(); 343 old_context = baseRequest.getContext();
737 344
738 // Are we already in this context? 345 // Are we already in this context?
739 if (old_context != _scontext) 346 if (old_context != _scontext)
740 { 347 {
741 // check the target. 348 if (!checkContext(target,baseRequest,response))
742 if (DispatcherType.REQUEST.equals(dispatch) || DispatcherType.ASYNC.equals(dispatch)) 349 return;
743 { 350
744 if (_compactPath) 351 if (target.length() > _contextPath.length())
745 target = URIUtil.compactPath(target); 352 {
746 if (!checkContext(target,baseRequest,response)) 353 if (_contextPath.length() > 1)
747 return; 354 target = target.substring(_contextPath.length());
748 355 pathInfo = target;
749 if (target.length() > _contextPath.length()) 356 }
750 { 357 else if (_contextPath.length() == 1)
751 if (_contextPath.length() > 1) 358 {
752 target = target.substring(_contextPath.length()); 359 target = URIUtil.SLASH;
753 pathInfo = target; 360 pathInfo = URIUtil.SLASH;
754 } 361 }
755 else if (_contextPath.length() == 1) 362 else
756 { 363 {
757 target = URIUtil.SLASH; 364 target = URIUtil.SLASH;
758 pathInfo = URIUtil.SLASH; 365 pathInfo = null;
759 }
760 else
761 {
762 target = URIUtil.SLASH;
763 pathInfo = null;
764 }
765 }
766
767 // Set the classloader
768 if (_classLoader != null)
769 {
770 current_thread = Thread.currentThread();
771 old_classloader = current_thread.getContextClassLoader();
772 current_thread.setContextClassLoader(_classLoader);
773 } 366 }
774 } 367 }
775 368
776 try 369 try
777 { 370 {
780 old_path_info = baseRequest.getPathInfo(); 373 old_path_info = baseRequest.getPathInfo();
781 374
782 // Update the paths 375 // Update the paths
783 baseRequest.setContext(_scontext); 376 baseRequest.setContext(_scontext);
784 __context.set(_scontext); 377 __context.set(_scontext);
785 if (!DispatcherType.INCLUDE.equals(dispatch) && target.startsWith("/")) 378 if (target.startsWith("/"))
786 { 379 {
787 if (_contextPath.length() == 1) 380 if (_contextPath.length() == 1)
788 baseRequest.setContextPath(""); 381 baseRequest.setContextPath("");
789 else 382 else
790 baseRequest.setContextPath(_contextPath); 383 baseRequest.setContextPath(_contextPath);
808 } 401 }
809 finally 402 finally
810 { 403 {
811 if (old_context != _scontext) 404 if (old_context != _scontext)
812 { 405 {
813 // reset the classloader
814 if (_classLoader != null)
815 {
816 current_thread.setContextClassLoader(old_classloader);
817 }
818
819 // reset the context and servlet path. 406 // reset the context and servlet path.
820 baseRequest.setContext(old_context); 407 baseRequest.setContext(old_context);
821 __context.set(old_context); 408 __context.set(old_context);
822 baseRequest.setContextPath(old_context_path); 409 baseRequest.setContextPath(old_context_path);
823 baseRequest.setServletPath(old_servlet_path); 410 baseRequest.setServletPath(old_servlet_path);
832 * javax.servlet.http.HttpServletResponse) 419 * javax.servlet.http.HttpServletResponse)
833 */ 420 */
834 @Override 421 @Override
835 public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException 422 public void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
836 { 423 {
837 final DispatcherType dispatch = baseRequest.getDispatcherType();
838 final boolean new_context = baseRequest.takeNewContext();
839 try 424 try
840 { 425 {
841 if (DispatcherType.REQUEST.equals(dispatch) && isProtectedTarget(target))
842 throw new HttpException(HttpServletResponse.SC_NOT_FOUND);
843
844 // start manual inline of nextHandle(target,baseRequest,request,response); 426 // start manual inline of nextHandle(target,baseRequest,request,response);
845 // noinspection ConstantIfStatement 427 // noinspection ConstantIfStatement
846 if (never()) 428 if (never())
847 nextHandle(target,baseRequest,request,response); 429 nextHandle(target,baseRequest,request,response);
848 else if (_nextScope != null && _nextScope == _handler) 430 else if (_nextScope != null && _nextScope == _handler)
857 baseRequest.setHandled(true); 439 baseRequest.setHandled(true);
858 response.sendError(e.getStatus(),e.getReason()); 440 response.sendError(e.getStatus(),e.getReason());
859 } 441 }
860 } 442 }
861 443
862 /* ------------------------------------------------------------ */
863 /*
864 * Handle a runnable in this context
865 */
866 public void handle(Runnable runnable)
867 {
868 ClassLoader old_classloader = null;
869 Thread current_thread = null;
870 Context old_context = null;
871 try
872 {
873 old_context = __context.get();
874 __context.set(_scontext);
875
876 // Set the classloader
877 if (_classLoader != null)
878 {
879 current_thread = Thread.currentThread();
880 old_classloader = current_thread.getContextClassLoader();
881 current_thread.setContextClassLoader(_classLoader);
882 }
883
884 runnable.run();
885 }
886 finally
887 {
888 __context.set(old_context);
889 if (old_classloader != null)
890 {
891 current_thread.setContextClassLoader(old_classloader);
892 }
893 }
894 }
895
896 /* ------------------------------------------------------------ */
897 /**
898 * Check the target. Called by {@link #handle(String, Request, HttpServletRequest, HttpServletResponse)} when a target within a context is determined. If
899 * the target is protected, 404 is returned.
900 */
901 /* ------------------------------------------------------------ */
902 public boolean isProtectedTarget(String target)
903 {
904 if (target == null || _protectedTargets == null)
905 return false;
906
907 while (target.startsWith("//"))
908 target=URIUtil.compactPath(target);
909
910 boolean isProtected = false;
911 int i=0;
912 while (!isProtected && i<_protectedTargets.length)
913 {
914 isProtected = StringUtil.startsWithIgnoreCase(target, _protectedTargets[i++]);
915 }
916 return isProtected;
917 }
918
919
920 public void setProtectedTargets (String[] targets)
921 {
922 if (targets == null)
923 {
924 _protectedTargets = null;
925 return;
926 }
927
928 _protectedTargets = new String[targets.length];
929 System.arraycopy(targets, 0, _protectedTargets, 0, targets.length);
930 }
931
932 public String[] getProtectedTargets ()
933 {
934 if (_protectedTargets == null)
935 return null;
936
937 String[] tmp = new String[_protectedTargets.length];
938 System.arraycopy(_protectedTargets, 0, tmp, 0, _protectedTargets.length);
939 return tmp;
940 }
941
942
943 /* ------------------------------------------------------------ */
944 public void checkManagedAttribute(String name, Object value)
945 {
946 if (_managedAttributes != null && _managedAttributes.containsKey(name))
947 {
948 setManagedAttribute(name,value);
949 }
950 }
951
952 /* ------------------------------------------------------------ */
953 public void setManagedAttribute(String name, Object value)
954 {
955 Object old = _managedAttributes.put(name,value);
956 }
957
958 /* ------------------------------------------------------------ */
959 /**
960 * @param classLoader
961 * The classLoader to set.
962 */
963 public void setClassLoader(ClassLoader classLoader)
964 {
965 _classLoader = classLoader;
966 }
967
968 /* ------------------------------------------------------------ */
969 /**
970 * @param contextPath
971 * The _contextPath to set.
972 */
973 public void setContextPath(String contextPath) 444 public void setContextPath(String contextPath)
974 { 445 {
975 if (contextPath != null && contextPath.length() > 1 && contextPath.endsWith("/")) 446 if (contextPath != null && contextPath.length() > 1 && contextPath.endsWith("/"))
976 throw new IllegalArgumentException("ends with /"); 447 throw new IllegalArgumentException("ends with /");
977 _contextPath = contextPath; 448 _contextPath = contextPath;
978 } 449 }
979 450
980 /* ------------------------------------------------------------ */ 451 /* ------------------------------------------------------------ */
981 /** 452 /**
982 * @param servletContextName
983 * The servletContextName to set.
984 */
985 public void setDisplayName(String servletContextName)
986 {
987 _displayName = servletContextName;
988 }
989
990 /* ------------------------------------------------------------ */
991 /**
992 * @return Returns the resourceBase. 453 * @return Returns the resourceBase.
993 */ 454 */
994 public Resource getBaseResource() 455 public Resource getBaseResource()
995 { 456 {
996 if (_baseResource == null)
997 return null;
998 return _baseResource; 457 return _baseResource;
999 } 458 }
1000 459
1001 /* ------------------------------------------------------------ */ 460 /* ------------------------------------------------------------ */
1002 /** 461 /**
1026 */ 485 */
1027 public void setResourceBase(String resourceBase) 486 public void setResourceBase(String resourceBase)
1028 { 487 {
1029 try 488 try
1030 { 489 {
1031 setBaseResource(newResource(resourceBase)); 490 setBaseResource(Resource.newResource(resourceBase));
1032 } 491 }
1033 catch (Exception e) 492 catch (Exception e)
1034 { 493 {
1035 LOG.warn(e.toString()); 494 LOG.warn(e.toString());
1036 LOG.debug("",e); 495 LOG.debug("",e);
1037 throw new IllegalArgumentException(resourceBase); 496 throw new IllegalArgumentException(resourceBase);
1038 } 497 }
1039 } 498 }
1040 499
1041 /* ------------------------------------------------------------ */
1042 /**
1043 * @return True if aliases are allowed
1044 */
1045 public boolean isAliases()
1046 {
1047 return _aliasesAllowed;
1048 }
1049
1050 /* ------------------------------------------------------------ */
1051 /**
1052 * @param aliases
1053 * aliases are allowed
1054 */
1055 public void setAliases(boolean aliases)
1056 {
1057 _aliasesAllowed = aliases;
1058 }
1059
1060 /* ------------------------------------------------------------ */
1061 /**
1062 * @return Returns the mimeTypes.
1063 */
1064 public MimeTypes getMimeTypes()
1065 {
1066 if (_mimeTypes == null)
1067 _mimeTypes = new MimeTypes();
1068 return _mimeTypes;
1069 }
1070
1071 /* ------------------------------------------------------------ */
1072 /**
1073 * @param mimeTypes
1074 * The mimeTypes to set.
1075 */
1076 public void setMimeTypes(MimeTypes mimeTypes)
1077 {
1078 _mimeTypes = mimeTypes;
1079 }
1080
1081 /* ------------------------------------------------------------ */
1082 /**
1083 */
1084 public void setWelcomeFiles(String[] files)
1085 {
1086 _welcomeFiles = files;
1087 }
1088
1089 /* ------------------------------------------------------------ */
1090 /**
1091 * @return The names of the files which the server should consider to be welcome files in this context.
1092 * @see <a href="http://jcp.org/aboutJava/communityprocess/final/jsr154/index.html">The Servlet Specification</a>
1093 * @see #setWelcomeFiles
1094 */
1095 public String[] getWelcomeFiles()
1096 {
1097 return _welcomeFiles;
1098 }
1099
1100 /* ------------------------------------------------------------ */
1101 public int getMaxFormContentSize()
1102 {
1103 return _maxFormContentSize;
1104 }
1105
1106 /* ------------------------------------------------------------ */
1107 /**
1108 * Set the maximum size of a form post, to protect against DOS attacks from large forms.
1109 * @param maxSize
1110 */
1111 public void setMaxFormContentSize(int maxSize)
1112 {
1113 _maxFormContentSize = maxSize;
1114 }
1115
1116 /* ------------------------------------------------------------ */
1117 public int getMaxFormKeys()
1118 {
1119 return _maxFormKeys;
1120 }
1121
1122 /* ------------------------------------------------------------ */
1123 /**
1124 * Set the maximum number of form Keys to protect against DOS attack from crafted hash keys.
1125 * @param max
1126 */
1127 public void setMaxFormKeys(int max)
1128 {
1129 _maxFormKeys = max;
1130 }
1131
1132 /* ------------------------------------------------------------ */
1133 /**
1134 * @return True if URLs are compacted to replace multiple '/'s with a single '/'
1135 */
1136 public boolean isCompactPath()
1137 {
1138 return _compactPath;
1139 }
1140
1141 /* ------------------------------------------------------------ */
1142 /**
1143 * @param compactPath
1144 * True if URLs are compacted to replace multiple '/'s with a single '/'
1145 */
1146 public void setCompactPath(boolean compactPath)
1147 {
1148 _compactPath = compactPath;
1149 }
1150
1151 /* ------------------------------------------------------------ */
1152 @Override 500 @Override
1153 public String toString() 501 public String toString()
1154 { 502 {
1155 String[] vhosts = getVirtualHosts();
1156
1157 StringBuilder b = new StringBuilder(); 503 StringBuilder b = new StringBuilder();
1158 504
1159 Package pkg = getClass().getPackage(); 505 Package pkg = getClass().getPackage();
1160 if (pkg != null) 506 if (pkg != null)
1161 { 507 {
1168 } 514 }
1169 } 515 }
1170 b.append(getClass().getSimpleName()); 516 b.append(getClass().getSimpleName());
1171 b.append('{').append(getContextPath()).append(',').append(getBaseResource()); 517 b.append('{').append(getContextPath()).append(',').append(getBaseResource());
1172 518
1173 if (vhosts != null && vhosts.length > 0)
1174 b.append(',').append(vhosts[0]);
1175 b.append('}'); 519 b.append('}');
1176 520
1177 return b.toString(); 521 return b.toString();
1178 }
1179
1180 /* ------------------------------------------------------------ */
1181 public void addLocaleEncoding(String locale, String encoding)
1182 {
1183 if (_localeEncodingMap == null)
1184 _localeEncodingMap = new HashMap<String, String>();
1185 _localeEncodingMap.put(locale,encoding);
1186 }
1187
1188 /* ------------------------------------------------------------ */
1189 public String getLocaleEncoding(String locale)
1190 {
1191 if (_localeEncodingMap == null)
1192 return null;
1193 String encoding = _localeEncodingMap.get(locale);
1194 return encoding;
1195 }
1196
1197 /* ------------------------------------------------------------ */
1198 /**
1199 * 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
1200 * language is looked up.
1201 *
1202 * @param locale
1203 * a <code>Locale</code> value
1204 * @return a <code>String</code> representing the character encoding for the locale or null if none found.
1205 */
1206 public String getLocaleEncoding(Locale locale)
1207 {
1208 if (_localeEncodingMap == null)
1209 return null;
1210 String encoding = _localeEncodingMap.get(locale.toString());
1211 if (encoding == null)
1212 encoding = _localeEncodingMap.get(locale.getLanguage());
1213 return encoding;
1214 } 522 }
1215 523
1216 /* ------------------------------------------------------------ */ 524 /* ------------------------------------------------------------ */
1217 /* 525 /*
1218 */ 526 */
1227 try 535 try
1228 { 536 {
1229 path = URIUtil.canonicalPath(path); 537 path = URIUtil.canonicalPath(path);
1230 Resource resource = _baseResource.addPath(path); 538 Resource resource = _baseResource.addPath(path);
1231 539
1232 if (checkAlias(path,resource)) 540 if (resource.getAlias() == null) // check not alias
1233 return resource; 541 return resource;
1234 return null; 542 return null;
1235 } 543 }
1236 catch (Exception e) 544 catch (Exception e)
1237 { 545 {
1238 LOG.trace("",e); 546 LOG.trace("",e);
1239 } 547 }
1240 548
1241 return null; 549 return null;
1242 } 550 }
1243
1244 /* ------------------------------------------------------------ */
1245 public boolean checkAlias(String path, Resource resource)
1246 {
1247 // Is the resource aliased?
1248 if (!_aliasesAllowed && resource.getAlias() != null)
1249 {
1250 if (LOG.isDebugEnabled())
1251 LOG.debug("Aliased resource: " + resource + "~=" + resource.getAlias());
1252
1253 // alias checks
1254 for (Iterator<AliasCheck> i=_aliasChecks.iterator();i.hasNext();)
1255 {
1256 AliasCheck check = i.next();
1257 if (check.check(path,resource))
1258 {
1259 if (LOG.isDebugEnabled())
1260 LOG.debug("Aliased resource: " + resource + " approved by " + check);
1261 return true;
1262 }
1263 }
1264 return false;
1265 }
1266 return true;
1267 }
1268 551
1269 /* ------------------------------------------------------------ */
1270 /**
1271 * Convert URL to Resource wrapper for {@link Resource#newResource(URL)} enables extensions to provide alternate resource implementations.
1272 */
1273 public Resource newResource(URL url) throws IOException
1274 {
1275 return Resource.newResource(url);
1276 }
1277
1278 /* ------------------------------------------------------------ */
1279 /**
1280 * Convert a URL or path to a Resource. The default implementation is a wrapper for {@link Resource#newResource(String)}.
1281 *
1282 * @param urlOrPath
1283 * The URL or path to convert
1284 * @return The Resource for the URL/path
1285 * @throws IOException
1286 * The Resource could not be created.
1287 */
1288 public Resource newResource(String urlOrPath) throws IOException
1289 {
1290 return Resource.newResource(urlOrPath);
1291 }
1292
1293 /* ------------------------------------------------------------ */
1294 /*
1295 */
1296 public Set<String> getResourcePaths(String path) 552 public Set<String> getResourcePaths(String path)
1297 { 553 {
1298 try 554 try
1299 { 555 {
1300 path = URIUtil.canonicalPath(path); 556 path = URIUtil.canonicalPath(path);
1321 } 577 }
1322 return Collections.emptySet(); 578 return Collections.emptySet();
1323 } 579 }
1324 580
1325 /* ------------------------------------------------------------ */ 581 /* ------------------------------------------------------------ */
1326 private String normalizeHostname(String host)
1327 {
1328 if (host == null)
1329 return null;
1330
1331 if (host.endsWith("."))
1332 return host.substring(0,host.length() - 1);
1333
1334 return host;
1335 }
1336
1337 /* ------------------------------------------------------------ */
1338 /**
1339 * Add an AliasCheck instance to possibly permit aliased resources
1340 * @param check The alias checker
1341 */
1342 public void addAliasCheck(AliasCheck check)
1343 {
1344 _aliasChecks.add(check);
1345 }
1346
1347 /* ------------------------------------------------------------ */
1348 /**
1349 * @return Mutable list of Alias checks
1350 */
1351 public List<AliasCheck> getAliasChecks()
1352 {
1353 return _aliasChecks;
1354 }
1355
1356 /* ------------------------------------------------------------ */
1357 /** 582 /**
1358 * Context. 583 * Context.
1359 * <p> 584 * <p>
1360 * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}. 585 * A partial implementation of {@link javax.servlet.ServletContext}. A complete implementation is provided by the derived {@link ContextHandler}.
1361 * </p> 586 * </p>
1388 { 613 {
1389 List<ContextHandler> contexts = new ArrayList<ContextHandler>(); 614 List<ContextHandler> contexts = new ArrayList<ContextHandler>();
1390 Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class); 615 Handler[] handlers = getServer().getChildHandlersByClass(ContextHandler.class);
1391 String matched_path = null; 616 String matched_path = null;
1392 617
1393 for (Handler handler : handlers)
1394 {
1395 if (handler == null)
1396 continue;
1397 ContextHandler ch = (ContextHandler)handler;
1398 String context_path = ch.getContextPath();
1399
1400 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
1401 || "/".equals(context_path))
1402 {
1403 // look first for vhost matching context only
1404 if (getVirtualHosts() != null && getVirtualHosts().length > 0)
1405 {
1406 if (ch.getVirtualHosts() != null && ch.getVirtualHosts().length > 0)
1407 {
1408 for (String h1 : getVirtualHosts())
1409 for (String h2 : ch.getVirtualHosts())
1410 if (h1.equals(h2))
1411 {
1412 if (matched_path == null || context_path.length() > matched_path.length())
1413 {
1414 contexts.clear();
1415 matched_path = context_path;
1416 }
1417
1418 if (matched_path.equals(context_path))
1419 contexts.add(ch);
1420 }
1421 }
1422 }
1423 else
1424 {
1425 if (matched_path == null || context_path.length() > matched_path.length())
1426 {
1427 contexts.clear();
1428 matched_path = context_path;
1429 }
1430
1431 if (matched_path.equals(context_path))
1432 contexts.add(ch);
1433 }
1434 }
1435 }
1436
1437 if (contexts.size() > 0)
1438 return contexts.get(0)._scontext;
1439
1440 // try again ignoring virtual hosts
1441 matched_path = null;
1442 for (Handler handler : handlers) 618 for (Handler handler : handlers)
1443 { 619 {
1444 if (handler == null) 620 if (handler == null)
1445 continue; 621 continue;
1446 ContextHandler ch = (ContextHandler)handler; 622 ContextHandler ch = (ContextHandler)handler;
1460 } 636 }
1461 } 637 }
1462 638
1463 if (contexts.size() > 0) 639 if (contexts.size() > 0)
1464 return contexts.get(0)._scontext; 640 return contexts.get(0)._scontext;
641
642 // try again ignoring virtual hosts
643 matched_path = null;
644 for (Handler handler : handlers)
645 {
646 if (handler == null)
647 continue;
648 ContextHandler ch = (ContextHandler)handler;
649 String context_path = ch.getContextPath();
650
651 if (uripath.equals(context_path) || (uripath.startsWith(context_path) && uripath.charAt(context_path.length()) == '/')
652 || "/".equals(context_path))
653 {
654 if (matched_path == null || context_path.length() > matched_path.length())
655 {
656 contexts.clear();
657 matched_path = context_path;
658 }
659
660 if (matched_path.equals(context_path))
661 contexts.add(ch);
662 }
663 }
664
665 if (contexts.size() > 0)
666 return contexts.get(0)._scontext;
1465 return null; 667 return null;
1466 } 668 }
1467 669
1468 /* ------------------------------------------------------------ */ 670 /* ------------------------------------------------------------ */
1469 /* 671 /*
1481 * @see javax.servlet.ServletContext#getMimeType(java.lang.String) 683 * @see javax.servlet.ServletContext#getMimeType(java.lang.String)
1482 */ 684 */
1483 @Override 685 @Override
1484 public String getMimeType(String file) 686 public String getMimeType(String file)
1485 { 687 {
1486 if (_mimeTypes == null)
1487 return null;
1488 Buffer mime = _mimeTypes.getMimeByExtension(file);
1489 if (mime != null)
1490 return mime.toString();
1491 return null; 688 return null;
1492 } 689 }
1493 690
1494 /* ------------------------------------------------------------ */ 691 /* ------------------------------------------------------------ */
1495 /* 692 /*
1675 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) 872 * @see javax.servlet.ServletContext#getInitParameter(java.lang.String)
1676 */ 873 */
1677 @Override 874 @Override
1678 public String getInitParameter(String name) 875 public String getInitParameter(String name)
1679 { 876 {
1680 return ContextHandler.this.getInitParameter(name); 877 return null;
1681 } 878 }
1682 879
1683 /* ------------------------------------------------------------ */ 880 /* ------------------------------------------------------------ */
1684 /* 881 /*
1685 * @see javax.servlet.ServletContext#getInitParameterNames() 882 * @see javax.servlet.ServletContext#getInitParameterNames()
1686 */ 883 */
1687 @SuppressWarnings("unchecked") 884 @SuppressWarnings("unchecked")
1688 @Override 885 @Override
1689 public Enumeration getInitParameterNames() 886 public Enumeration getInitParameterNames()
1690 { 887 {
1691 return ContextHandler.this.getInitParameterNames(); 888 return null;
1692 } 889 }
1693 890
1694 /* ------------------------------------------------------------ */ 891 /* ------------------------------------------------------------ */
1695 /* 892 /*
1696 * @see javax.servlet.ServletContext#getAttribute(java.lang.String) 893 * @see javax.servlet.ServletContext#getAttribute(java.lang.String)
1727 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object) 924 * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object)
1728 */ 925 */
1729 @Override 926 @Override
1730 public synchronized void setAttribute(String name, Object value) 927 public synchronized void setAttribute(String name, Object value)
1731 { 928 {
1732 checkManagedAttribute(name,value);
1733 Object old_value = _contextAttributes.getAttribute(name); 929 Object old_value = _contextAttributes.getAttribute(name);
1734 930
1735 if (value == null) 931 if (value == null)
1736 _contextAttributes.removeAttribute(name); 932 _contextAttributes.removeAttribute(name);
1737 else 933 else
1743 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) 939 * @see javax.servlet.ServletContext#removeAttribute(java.lang.String)
1744 */ 940 */
1745 @Override 941 @Override
1746 public synchronized void removeAttribute(String name) 942 public synchronized void removeAttribute(String name)
1747 { 943 {
1748 checkManagedAttribute(name,null);
1749
1750 if (_contextAttributes == null) 944 if (_contextAttributes == null)
1751 { 945 {
1752 // Set it on the handler 946 // Set it on the handler
1753 return; 947 return;
1754 } 948 }
1761 * @see javax.servlet.ServletContext#getServletContextName() 955 * @see javax.servlet.ServletContext#getServletContextName()
1762 */ 956 */
1763 @Override 957 @Override
1764 public String getServletContextName() 958 public String getServletContextName()
1765 { 959 {
1766 String name = ContextHandler.this.getDisplayName(); 960 return ContextHandler.this.getContextPath();
1767 if (name == null)
1768 name = ContextHandler.this.getContextPath();
1769 return name;
1770 } 961 }
1771 962
1772 /* ------------------------------------------------------------ */ 963 /* ------------------------------------------------------------ */
1773 @Override 964 @Override
1774 public String getContextPath() 965 public String getContextPath()
1788 979
1789 /* ------------------------------------------------------------ */ 980 /* ------------------------------------------------------------ */
1790 @Override 981 @Override
1791 public boolean setInitParameter(String name, String value) 982 public boolean setInitParameter(String name, String value)
1792 { 983 {
1793 if (ContextHandler.this.getInitParameter(name) != null) 984 return false;
1794 return false;
1795 ContextHandler.this.getInitParams().put(name,value);
1796 return true;
1797 } 985 }
1798 986
1799 /* ------------------------------------------------------------ */ 987 /* ------------------------------------------------------------ */
1800 final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler"; 988 final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler";
1801 989
1932 1120
1933 @Override 1121 @Override
1934 public ClassLoader getClassLoader() 1122 public ClassLoader getClassLoader()
1935 { 1123 {
1936 AccessController.checkPermission(new RuntimePermission("getClassLoader")); 1124 AccessController.checkPermission(new RuntimePermission("getClassLoader"));
1937 return _classLoader; 1125 return null;
1938 } 1126 }
1939 1127
1940 @Override 1128 @Override
1941 public int getEffectiveMajorVersion() 1129 public int getEffectiveMajorVersion()
1942 { 1130 {
1975 { 1163 {
1976 throw new UnsupportedOperationException(); 1164 throw new UnsupportedOperationException();
1977 } 1165 }
1978 } 1166 }
1979 1167
1980 private static class CLDump implements Dumpable
1981 {
1982 final ClassLoader _loader;
1983
1984 CLDump(ClassLoader loader)
1985 {
1986 _loader = loader;
1987 }
1988
1989 public String dump()
1990 {
1991 return AggregateLifeCycle.dump(this);
1992 }
1993
1994 public void dump(Appendable out, String indent) throws IOException
1995 {
1996 out.append(String.valueOf(_loader)).append("\n");
1997
1998 if (_loader != null)
1999 {
2000 Object parent = _loader.getParent();
2001 if (parent != null)
2002 {
2003 if (!(parent instanceof Dumpable))
2004 parent = new CLDump((ClassLoader)parent);
2005
2006 if (_loader instanceof URLClassLoader)
2007 AggregateLifeCycle.dump(out,indent,TypeUtil.asList(((URLClassLoader)_loader).getURLs()),Collections.singleton(parent));
2008 else
2009 AggregateLifeCycle.dump(out,indent,Collections.singleton(parent));
2010 }
2011 }
2012 }
2013 }
2014
2015
2016 /* ------------------------------------------------------------ */
2017 /** Interface to check aliases
2018 */
2019 public interface AliasCheck
2020 {
2021 /* ------------------------------------------------------------ */
2022 /** Check an alias
2023 * @param path The path the aliased resource was created for
2024 * @param resource The aliased resourced
2025 * @return True if the resource is OK to be served.
2026 */
2027 boolean check(String path, Resource resource);
2028 }
2029
2030
2031 /* ------------------------------------------------------------ */
2032 /** Approve Aliases with same suffix.
2033 * Eg. a symbolic link from /foobar.html to /somewhere/wibble.html would be
2034 * approved because both the resource and alias end with ".html".
2035 */
2036 @Deprecated
2037 public static class ApproveSameSuffixAliases implements AliasCheck
2038 {
2039 {
2040 LOG.warn("ApproveSameSuffixAlias is not safe for production");
2041 }
2042
2043 public boolean check(String path, Resource resource)
2044 {
2045 int dot = path.lastIndexOf('.');
2046 if (dot<0)
2047 return false;
2048 String suffix=path.substring(dot);
2049 return resource.toString().endsWith(suffix);
2050 }
2051 }
2052
2053
2054 /* ------------------------------------------------------------ */
2055 /** Approve Aliases with a path prefix.
2056 * Eg. a symbolic link from /dirA/foobar.html to /dirB/foobar.html would be
2057 * approved because both the resource and alias end with "/foobar.html".
2058 */
2059 @Deprecated
2060 public static class ApprovePathPrefixAliases implements AliasCheck
2061 {
2062 {
2063 LOG.warn("ApprovePathPrefixAliases is not safe for production");
2064 }
2065
2066 public boolean check(String path, Resource resource)
2067 {
2068 int slash = path.lastIndexOf('/');
2069 if (slash<0 || slash==path.length()-1)
2070 return false;
2071 String suffix=path.substring(slash);
2072 return resource.toString().endsWith(suffix);
2073 }
2074 }
2075
2076 /* ------------------------------------------------------------ */
2077 /** Approve Aliases of a non existent directory.
2078 * If a directory "/foobar/" does not exist, then the resource is
2079 * aliased to "/foobar". Accept such aliases.
2080 */
2081 public static class ApproveNonExistentDirectoryAliases implements AliasCheck
2082 {
2083 public boolean check(String path, Resource resource)
2084 {
2085 if (resource.exists())
2086 return false;
2087
2088 String a=resource.getAlias().toString();
2089 String r=resource.getURL().toString();
2090
2091 if (a.length()>r.length())
2092 return a.startsWith(r) && a.length()==r.length()+1 && a.endsWith("/");
2093 else
2094 return r.startsWith(a) && r.length()==a.length()+1 && r.endsWith("/");
2095 }
2096 }
2097
2098 } 1168 }