Mercurial Hosting > luan
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 } |