1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.servlet;
20
21 import java.io.IOException;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.EnumSet;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.ListIterator;
30 import java.util.Map;
31 import java.util.Queue;
32 import java.util.Set;
33 import java.util.concurrent.ConcurrentHashMap;
34 import java.util.concurrent.ConcurrentLinkedQueue;
35 import java.util.concurrent.ConcurrentMap;
36
37 import javax.servlet.DispatcherType;
38 import javax.servlet.Filter;
39 import javax.servlet.FilterChain;
40 import javax.servlet.RequestDispatcher;
41 import javax.servlet.Servlet;
42 import javax.servlet.ServletContext;
43 import javax.servlet.ServletException;
44 import javax.servlet.ServletRegistration;
45 import javax.servlet.ServletRequest;
46 import javax.servlet.ServletResponse;
47 import javax.servlet.ServletSecurityElement;
48 import javax.servlet.UnavailableException;
49 import javax.servlet.http.HttpServlet;
50 import javax.servlet.http.HttpServletRequest;
51 import javax.servlet.http.HttpServletResponse;
52
53 import org.eclipse.jetty.http.HttpHeader;
54 import org.eclipse.jetty.http.HttpHeaderValue;
55 import org.eclipse.jetty.http.PathMap;
56 import org.eclipse.jetty.io.EofException;
57 import org.eclipse.jetty.io.RuntimeIOException;
58 import org.eclipse.jetty.security.IdentityService;
59 import org.eclipse.jetty.security.SecurityHandler;
60 import org.eclipse.jetty.server.HttpChannel;
61 import org.eclipse.jetty.server.QuietServletException;
62 import org.eclipse.jetty.server.Request;
63 import org.eclipse.jetty.server.ServletRequestHttpWrapper;
64 import org.eclipse.jetty.server.ServletResponseHttpWrapper;
65 import org.eclipse.jetty.server.UserIdentity;
66 import org.eclipse.jetty.server.handler.ContextHandler;
67 import org.eclipse.jetty.server.handler.ScopedHandler;
68 import org.eclipse.jetty.servlet.Holder.Source;
69 import org.eclipse.jetty.util.ArrayUtil;
70 import org.eclipse.jetty.util.LazyList;
71 import org.eclipse.jetty.util.MultiException;
72 import org.eclipse.jetty.util.MultiMap;
73 import org.eclipse.jetty.util.URIUtil;
74 import org.eclipse.jetty.util.annotation.ManagedAttribute;
75 import org.eclipse.jetty.util.annotation.ManagedObject;
76 import org.eclipse.jetty.util.component.LifeCycle;
77 import org.eclipse.jetty.util.log.Log;
78 import org.eclipse.jetty.util.log.Logger;
79
80
81
82
83
84
85
86
87
88
89
90
91
92 @ManagedObject("Servlet Handler")
93 public class ServletHandler extends ScopedHandler
94 {
95 private static final Logger LOG = Log.getLogger(ServletHandler.class);
96
97
98 public static final String __DEFAULT_SERVLET="default";
99
100
101 private ServletContextHandler _contextHandler;
102 private ServletContext _servletContext;
103 private FilterHolder[] _filters=new FilterHolder[0];
104 private FilterMapping[] _filterMappings;
105 private int _matchBeforeIndex = -1;
106 private int _matchAfterIndex = -1;
107 private boolean _filterChainsCached=true;
108 private int _maxFilterChainsCacheSize=512;
109 private boolean _startWithUnavailable=false;
110 private IdentityService _identityService;
111
112 private ServletHolder[] _servlets=new ServletHolder[0];
113 private ServletMapping[] _servletMappings;
114 private Map<String,ServletMapping> _servletPathMappings = new HashMap<String,ServletMapping>();
115
116 private final Map<String,FilterHolder> _filterNameMap= new HashMap<>();
117 private List<FilterMapping> _filterPathMappings;
118 private MultiMap<FilterMapping> _filterNameMappings;
119
120 private final Map<String,ServletHolder> _servletNameMap=new HashMap<>();
121 private PathMap<ServletHolder> _servletPathMap;
122
123 protected final ConcurrentMap<?, ?> _chainCache[] = new ConcurrentMap[FilterMapping.ALL];
124 protected final Queue<?>[] _chainLRU = new Queue[FilterMapping.ALL];
125
126
127
128
129
130 public ServletHandler()
131 {
132 }
133
134
135 @Override
136 protected synchronized void doStart()
137 throws Exception
138 {
139 ContextHandler.Context context=ContextHandler.getCurrentContext();
140 _servletContext=context==null?new ContextHandler.NoContext():context;
141 _contextHandler=(ServletContextHandler)(context==null?null:context.getContextHandler());
142
143 if (_contextHandler!=null)
144 {
145 SecurityHandler security_handler = _contextHandler.getChildHandlerByClass(SecurityHandler.class);
146 if (security_handler!=null)
147 _identityService=security_handler.getIdentityService();
148 }
149
150 updateNameMappings();
151 updateMappings();
152
153 if (getServletMapping("/")==null)
154 {
155 LOG.debug("Adding Default404Servlet to {}",this);
156 addServletWithMapping(Default404Servlet.class,"/");
157 updateMappings();
158 getServletMapping("/").setDefault(true);
159 }
160
161 if(_filterChainsCached)
162 {
163 _chainCache[FilterMapping.REQUEST]=new ConcurrentHashMap<String,FilterChain>();
164 _chainCache[FilterMapping.FORWARD]=new ConcurrentHashMap<String,FilterChain>();
165 _chainCache[FilterMapping.INCLUDE]=new ConcurrentHashMap<String,FilterChain>();
166 _chainCache[FilterMapping.ERROR]=new ConcurrentHashMap<String,FilterChain>();
167 _chainCache[FilterMapping.ASYNC]=new ConcurrentHashMap<String,FilterChain>();
168
169 _chainLRU[FilterMapping.REQUEST]=new ConcurrentLinkedQueue<String>();
170 _chainLRU[FilterMapping.FORWARD]=new ConcurrentLinkedQueue<String>();
171 _chainLRU[FilterMapping.INCLUDE]=new ConcurrentLinkedQueue<String>();
172 _chainLRU[FilterMapping.ERROR]=new ConcurrentLinkedQueue<String>();
173 _chainLRU[FilterMapping.ASYNC]=new ConcurrentLinkedQueue<String>();
174 }
175
176 if (_contextHandler==null)
177 initialize();
178
179 super.doStart();
180 }
181
182
183
184 @Override
185 protected void start(LifeCycle l) throws Exception
186 {
187
188
189
190
191 if (!(l instanceof Holder))
192 super.start(l);
193 }
194
195
196 @Override
197 protected synchronized void doStop()
198 throws Exception
199 {
200 super.doStop();
201
202
203 List<FilterHolder> filterHolders = new ArrayList<FilterHolder>();
204 List<FilterMapping> filterMappings = ArrayUtil.asMutableList(_filterMappings);
205 if (_filters!=null)
206 {
207 for (int i=_filters.length; i-->0;)
208 {
209 try
210 {
211 _filters[i].stop();
212 }
213 catch(Exception e)
214 {
215 LOG.warn(Log.EXCEPTION,e);
216 }
217 if (_filters[i].getSource() != Source.EMBEDDED)
218 {
219
220 _filterNameMap.remove(_filters[i].getName());
221
222 ListIterator<FilterMapping> fmitor = filterMappings.listIterator();
223 while (fmitor.hasNext())
224 {
225 FilterMapping fm = fmitor.next();
226 if (fm.getFilterName().equals(_filters[i].getName()))
227 fmitor.remove();
228 }
229 }
230 else
231 filterHolders.add(_filters[i]);
232 }
233 }
234
235
236 FilterHolder[] fhs = (FilterHolder[]) LazyList.toArray(filterHolders, FilterHolder.class);
237 updateBeans(_filters, fhs);
238 _filters = fhs;
239 FilterMapping[] fms = (FilterMapping[]) LazyList.toArray(filterMappings, FilterMapping.class);
240 updateBeans(_filterMappings, fms);
241 _filterMappings = fms;
242
243 _matchAfterIndex = (_filterMappings == null || _filterMappings.length == 0 ? -1 : _filterMappings.length-1);
244 _matchBeforeIndex = -1;
245
246
247 List<ServletHolder> servletHolders = new ArrayList<ServletHolder>();
248 List<ServletMapping> servletMappings = ArrayUtil.asMutableList(_servletMappings);
249 if (_servlets!=null)
250 {
251 for (int i=_servlets.length; i-->0;)
252 {
253 try
254 {
255 _servlets[i].stop();
256 }
257 catch(Exception e)
258 {
259 LOG.warn(Log.EXCEPTION,e);
260 }
261
262 if (_servlets[i].getSource() != Source.EMBEDDED)
263 {
264
265 _servletNameMap.remove(_servlets[i].getName());
266
267 ListIterator<ServletMapping> smitor = servletMappings.listIterator();
268 while (smitor.hasNext())
269 {
270 ServletMapping sm = smitor.next();
271 if (sm.getServletName().equals(_servlets[i].getName()))
272 smitor.remove();
273 }
274 }
275 else
276 servletHolders.add(_servlets[i]);
277 }
278 }
279
280
281 ServletHolder[] shs = (ServletHolder[]) LazyList.toArray(servletHolders, ServletHolder.class);
282 updateBeans(_servlets, shs);
283 _servlets = shs;
284 ServletMapping[] sms = (ServletMapping[])LazyList.toArray(servletMappings, ServletMapping.class);
285 updateBeans(_servletMappings, sms);
286 _servletMappings = sms;
287
288
289 _filterPathMappings=null;
290 _filterNameMappings=null;
291 _servletPathMap=null;
292 _servletPathMappings=null;
293 }
294
295
296 IdentityService getIdentityService()
297 {
298 return _identityService;
299 }
300
301
302
303
304
305 public Object getContextLog()
306 {
307 return null;
308 }
309
310
311
312
313
314 @ManagedAttribute(value="filters", readonly=true)
315 public FilterMapping[] getFilterMappings()
316 {
317 return _filterMappings;
318 }
319
320
321
322
323
324 @ManagedAttribute(value="filters", readonly=true)
325 public FilterHolder[] getFilters()
326 {
327 return _filters;
328 }
329
330
331
332
333
334
335 public PathMap.MappedEntry<ServletHolder> getHolderEntry(String pathInContext)
336 {
337 if (_servletPathMap==null)
338 return null;
339 return _servletPathMap.getMatch(pathInContext);
340 }
341
342
343 public ServletContext getServletContext()
344 {
345 return _servletContext;
346 }
347
348
349
350
351
352 @ManagedAttribute(value="mappings of servlets", readonly=true)
353 public ServletMapping[] getServletMappings()
354 {
355 return _servletMappings;
356 }
357
358
359
360
361
362
363
364
365
366
367 public ServletMapping getServletMapping(String pathSpec)
368 {
369 if (pathSpec == null || _servletPathMappings == null)
370 return null;
371
372 return _servletPathMappings.get(pathSpec);
373 }
374
375
376
377
378
379
380
381
382 @ManagedAttribute(value="servlets", readonly=true)
383 public ServletHolder[] getServlets()
384 {
385 return _servlets;
386 }
387
388
389 public ServletHolder getServlet(String name)
390 {
391 return _servletNameMap.get(name);
392 }
393
394
395 @Override
396 public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
397 {
398
399 final String old_servlet_path=baseRequest.getServletPath();
400 final String old_path_info=baseRequest.getPathInfo();
401
402 DispatcherType type = baseRequest.getDispatcherType();
403
404 ServletHolder servlet_holder=null;
405 UserIdentity.Scope old_scope=null;
406
407
408 if (target.startsWith("/"))
409 {
410
411 PathMap.MappedEntry<ServletHolder> entry=getHolderEntry(target);
412 if (entry!=null)
413 {
414 servlet_holder=entry.getValue();
415
416 String servlet_path_spec= entry.getKey();
417 String servlet_path=entry.getMapped()!=null?entry.getMapped():PathMap.pathMatch(servlet_path_spec,target);
418 String path_info=PathMap.pathInfo(servlet_path_spec,target);
419
420 if (DispatcherType.INCLUDE.equals(type))
421 {
422 baseRequest.setAttribute(RequestDispatcher.INCLUDE_SERVLET_PATH,servlet_path);
423 baseRequest.setAttribute(RequestDispatcher.INCLUDE_PATH_INFO, path_info);
424 }
425 else
426 {
427 baseRequest.setServletPath(servlet_path);
428 baseRequest.setPathInfo(path_info);
429 }
430 }
431 }
432 else
433 {
434
435 servlet_holder= _servletNameMap.get(target);
436 }
437
438 if (LOG.isDebugEnabled())
439 LOG.debug("servlet {}|{}|{} -> {}",baseRequest.getContextPath(),baseRequest.getServletPath(),baseRequest.getPathInfo(),servlet_holder);
440
441 try
442 {
443
444 old_scope=baseRequest.getUserIdentityScope();
445 baseRequest.setUserIdentityScope(servlet_holder);
446
447
448 if (never())
449 nextScope(target,baseRequest,request,response);
450 else if (_nextScope!=null)
451 _nextScope.doScope(target,baseRequest,request, response);
452 else if (_outerScope!=null)
453 _outerScope.doHandle(target,baseRequest,request, response);
454 else
455 doHandle(target,baseRequest,request, response);
456
457 }
458 finally
459 {
460 if (old_scope!=null)
461 baseRequest.setUserIdentityScope(old_scope);
462
463 if (!(DispatcherType.INCLUDE.equals(type)))
464 {
465 baseRequest.setServletPath(old_servlet_path);
466 baseRequest.setPathInfo(old_path_info);
467 }
468 }
469 }
470
471
472
473
474
475 @Override
476 public void doHandle(String target, Request baseRequest,HttpServletRequest request, HttpServletResponse response)
477 throws IOException, ServletException
478 {
479 DispatcherType type = baseRequest.getDispatcherType();
480
481 ServletHolder servlet_holder=(ServletHolder) baseRequest.getUserIdentityScope();
482 FilterChain chain=null;
483
484
485 if (target.startsWith("/"))
486 {
487 if (servlet_holder!=null && _filterMappings!=null && _filterMappings.length>0)
488 chain=getFilterChain(baseRequest, target, servlet_holder);
489 }
490 else
491 {
492 if (servlet_holder!=null)
493 {
494 if (_filterMappings!=null && _filterMappings.length>0)
495 {
496 chain=getFilterChain(baseRequest, null,servlet_holder);
497 }
498 }
499 }
500
501 LOG.debug("chain={}",chain);
502 Throwable th=null;
503 try
504 {
505 if (servlet_holder==null)
506 {
507 if (getHandler()==null)
508 notFound(request, response);
509 else
510 nextHandle(target,baseRequest,request,response);
511 }
512 else
513 {
514
515 ServletRequest req = request;
516 if (req instanceof ServletRequestHttpWrapper)
517 req = ((ServletRequestHttpWrapper)req).getRequest();
518 ServletResponse res = response;
519 if (res instanceof ServletResponseHttpWrapper)
520 res = ((ServletResponseHttpWrapper)res).getResponse();
521
522
523 if (chain!=null)
524 chain.doFilter(req, res);
525 else
526 servlet_holder.handle(baseRequest,req,res);
527 }
528 }
529 catch(EofException e)
530 {
531 throw e;
532 }
533 catch(RuntimeIOException e)
534 {
535 throw e;
536 }
537 catch(Exception e)
538 {
539 if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
540 {
541 if (e instanceof IOException)
542 throw (IOException)e;
543 if (e instanceof RuntimeException)
544 throw (RuntimeException)e;
545 if (e instanceof ServletException)
546 throw (ServletException)e;
547 }
548
549
550 th=e;
551 if (th instanceof ServletException)
552 {
553 if (th instanceof QuietServletException)
554 {
555 LOG.warn(th.toString());
556 LOG.debug(th);
557 }
558 else
559 LOG.warn(th);
560 }
561 else if (th instanceof EofException)
562 {
563 throw (EofException)th;
564 }
565 else
566 {
567 LOG.warn(request.getRequestURI(),th);
568 if (LOG.isDebugEnabled())
569 LOG.debug(request.toString());
570 }
571
572 request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,th.getClass());
573 request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,th);
574 if (!response.isCommitted())
575 {
576 baseRequest.getResponse().getHttpFields().put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
577 if (th instanceof UnavailableException)
578 {
579 UnavailableException ue = (UnavailableException)th;
580 if (ue.isPermanent())
581 response.sendError(HttpServletResponse.SC_NOT_FOUND);
582 else
583 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
584 }
585 else
586 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
587 }
588 else
589 LOG.debug("Response already committed",th);
590 }
591 catch(Error e)
592 {
593 if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
594 throw e;
595 th=e;
596 if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
597 throw e;
598 LOG.warn("Error for "+request.getRequestURI(),e);
599 if(LOG.isDebugEnabled())
600 LOG.debug(request.toString());
601
602 request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
603 request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
604 if (!response.isCommitted())
605 {
606 baseRequest.getResponse().getHttpFields().put(HttpHeader.CONNECTION,HttpHeaderValue.CLOSE);
607 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
608 }
609 else
610 LOG.debug("Response already committed for handling ",e);
611 }
612 finally
613 {
614
615 if (th!=null && request.isAsyncStarted())
616 request.getAsyncContext().complete();
617
618 if (servlet_holder!=null)
619 baseRequest.setHandled(true);
620 }
621 }
622
623
624 private FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder)
625 {
626 String key=pathInContext==null?servletHolder.getName():pathInContext;
627 int dispatch = FilterMapping.dispatch(baseRequest.getDispatcherType());
628
629 if (_filterChainsCached && _chainCache!=null)
630 {
631 FilterChain chain = (FilterChain)_chainCache[dispatch].get(key);
632 if (chain!=null)
633 return chain;
634 }
635
636
637 List<FilterHolder> filters = new ArrayList<>();
638
639
640 if (pathInContext!=null && _filterPathMappings!=null)
641 {
642 for (FilterMapping filterPathMapping : _filterPathMappings)
643 {
644 if (filterPathMapping.appliesTo(pathInContext, dispatch))
645 filters.add(filterPathMapping.getFilterHolder());
646 }
647 }
648
649
650 if (servletHolder != null && _filterNameMappings!=null && _filterNameMappings.size() > 0)
651 {
652
653 if (_filterNameMappings.size() > 0)
654 {
655 Object o= _filterNameMappings.get(servletHolder.getName());
656
657 for (int i=0; i<LazyList.size(o);i++)
658 {
659 FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
660 if (mapping.appliesTo(dispatch))
661 filters.add(mapping.getFilterHolder());
662 }
663
664 o= _filterNameMappings.get("*");
665 for (int i=0; i<LazyList.size(o);i++)
666 {
667 FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
668 if (mapping.appliesTo(dispatch))
669 filters.add(mapping.getFilterHolder());
670 }
671 }
672 }
673
674 if (filters.isEmpty())
675 return null;
676
677
678 FilterChain chain = null;
679 if (_filterChainsCached)
680 {
681 if (filters.size() > 0)
682 chain= new CachedChain(filters, servletHolder);
683
684 final Map<String,FilterChain> cache=(Map<String, FilterChain>)_chainCache[dispatch];
685 final Queue<String> lru=(Queue<String>)_chainLRU[dispatch];
686
687
688 while (_maxFilterChainsCacheSize>0 && cache.size()>=_maxFilterChainsCacheSize)
689 {
690
691
692
693 String k=lru.poll();
694 if (k==null)
695 {
696 cache.clear();
697 break;
698 }
699 cache.remove(k);
700 }
701
702 cache.put(key,chain);
703 lru.add(key);
704 }
705 else if (filters.size() > 0)
706 chain = new Chain(baseRequest,filters, servletHolder);
707
708 return chain;
709 }
710
711
712 private void invalidateChainsCache()
713 {
714 if (_chainLRU[FilterMapping.REQUEST]!=null)
715 {
716 _chainLRU[FilterMapping.REQUEST].clear();
717 _chainLRU[FilterMapping.FORWARD].clear();
718 _chainLRU[FilterMapping.INCLUDE].clear();
719 _chainLRU[FilterMapping.ERROR].clear();
720 _chainLRU[FilterMapping.ASYNC].clear();
721
722 _chainCache[FilterMapping.REQUEST].clear();
723 _chainCache[FilterMapping.FORWARD].clear();
724 _chainCache[FilterMapping.INCLUDE].clear();
725 _chainCache[FilterMapping.ERROR].clear();
726 _chainCache[FilterMapping.ASYNC].clear();
727 }
728 }
729
730
731
732
733
734 public boolean isAvailable()
735 {
736 if (!isStarted())
737 return false;
738 ServletHolder[] holders = getServlets();
739 for (ServletHolder holder : holders)
740 {
741 if (holder != null && !holder.isAvailable())
742 return false;
743 }
744 return true;
745 }
746
747
748
749
750
751 public void setStartWithUnavailable(boolean start)
752 {
753 _startWithUnavailable=start;
754 }
755
756
757
758
759
760 public boolean isStartWithUnavailable()
761 {
762 return _startWithUnavailable;
763 }
764
765
766
767
768
769
770
771 public void initialize()
772 throws Exception
773 {
774 MultiException mx = new MultiException();
775
776 if (_servlets!=null)
777 {
778
779 ServletHolder[] servlets = _servlets.clone();
780 Arrays.sort(servlets);
781 for (ServletHolder servlet : servlets)
782 {
783 try
784 {
785 if (servlet.getClassName() == null && servlet.getForcedPath() != null)
786 {
787 ServletHolder forced_holder = _servletPathMap.match(servlet.getForcedPath());
788 if (forced_holder == null || forced_holder.getClassName() == null)
789 {
790 mx.add(new IllegalStateException("No forced path servlet for " + servlet.getForcedPath()));
791 continue;
792 }
793 servlet.setClassName(forced_holder.getClassName());
794 }
795 }
796 catch (Throwable e)
797 {
798 LOG.debug(Log.EXCEPTION, e);
799 mx.add(e);
800 }
801 }
802 }
803
804
805 for (Holder<?> h: getBeans(Holder.class))
806 {
807 try
808 {
809 h.start();
810 h.initialize();
811 }
812 catch (Exception e)
813 {
814 mx.add(e);
815 }
816 }
817
818 mx.ifExceptionThrow();
819 }
820
821
822
823
824
825 public boolean isFilterChainsCached()
826 {
827 return _filterChainsCached;
828 }
829
830
831
832
833
834 public ServletHolder newServletHolder(Holder.Source source)
835 {
836 return new ServletHolder(source);
837 }
838
839
840
841
842
843
844
845
846
847
848
849
850 public ServletHolder addServletWithMapping (String className,String pathSpec)
851 {
852 ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
853 holder.setClassName(className);
854 addServletWithMapping(holder,pathSpec);
855 return holder;
856 }
857
858
859
860
861
862 public ServletHolder addServletWithMapping (Class<? extends Servlet> servlet,String pathSpec)
863 {
864 ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
865 holder.setHeldClass(servlet);
866 addServletWithMapping(holder,pathSpec);
867
868 return holder;
869 }
870
871
872
873
874
875
876 public void addServletWithMapping (ServletHolder servlet,String pathSpec)
877 {
878 ServletHolder[] holders=getServlets();
879 if (holders!=null)
880 holders = holders.clone();
881
882 try
883 {
884 setServlets(ArrayUtil.addToArray(holders, servlet, ServletHolder.class));
885
886 ServletMapping mapping = new ServletMapping();
887 mapping.setServletName(servlet.getName());
888 mapping.setPathSpec(pathSpec);
889 setServletMappings(ArrayUtil.addToArray(getServletMappings(), mapping, ServletMapping.class));
890 }
891 catch (Exception e)
892 {
893 setServlets(holders);
894 if (e instanceof RuntimeException)
895 throw (RuntimeException)e;
896 throw new RuntimeException(e);
897 }
898 }
899
900
901
902
903
904
905 public void addServlet(ServletHolder holder)
906 {
907 setServlets(ArrayUtil.addToArray(getServlets(), holder, ServletHolder.class));
908 }
909
910
911
912
913
914 public void addServletMapping (ServletMapping mapping)
915 {
916 setServletMappings(ArrayUtil.addToArray(getServletMappings(), mapping, ServletMapping.class));
917 }
918
919
920 public Set<String> setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement)
921 {
922 if (_contextHandler != null)
923 {
924 return _contextHandler.setServletSecurity(registration, servletSecurityElement);
925 }
926 return Collections.emptySet();
927 }
928
929
930 public FilterHolder newFilterHolder(Holder.Source source)
931 {
932 return new FilterHolder(source);
933 }
934
935
936 public FilterHolder getFilter(String name)
937 {
938 return _filterNameMap.get(name);
939 }
940
941
942
943
944
945
946
947
948
949 public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,EnumSet<DispatcherType> dispatches)
950 {
951 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
952 holder.setHeldClass(filter);
953 addFilterWithMapping(holder,pathSpec,dispatches);
954
955 return holder;
956 }
957
958
959
960
961
962
963
964
965 public FilterHolder addFilterWithMapping (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
966 {
967 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
968 holder.setClassName(className);
969
970 addFilterWithMapping(holder,pathSpec,dispatches);
971 return holder;
972 }
973
974
975
976
977
978
979
980 public void addFilterWithMapping (FilterHolder holder,String pathSpec,EnumSet<DispatcherType> dispatches)
981 {
982 FilterHolder[] holders = getFilters();
983 if (holders!=null)
984 holders = holders.clone();
985
986 try
987 {
988 setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
989
990 FilterMapping mapping = new FilterMapping();
991 mapping.setFilterName(holder.getName());
992 mapping.setPathSpec(pathSpec);
993 mapping.setDispatcherTypes(dispatches);
994 addFilterMapping(mapping);
995
996 }
997 catch (RuntimeException e)
998 {
999 setFilters(holders);
1000 throw e;
1001 }
1002 catch (Error e)
1003 {
1004 setFilters(holders);
1005 throw e;
1006 }
1007
1008 }
1009
1010
1011
1012
1013
1014
1015
1016
1017 public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,int dispatches)
1018 {
1019 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
1020 holder.setHeldClass(filter);
1021 addFilterWithMapping(holder,pathSpec,dispatches);
1022
1023 return holder;
1024 }
1025
1026
1027
1028
1029
1030
1031
1032
1033 public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches)
1034 {
1035 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
1036 holder.setClassName(className);
1037
1038 addFilterWithMapping(holder,pathSpec,dispatches);
1039 return holder;
1040 }
1041
1042
1043
1044
1045
1046
1047
1048 public void addFilterWithMapping (FilterHolder holder,String pathSpec,int dispatches)
1049 {
1050 FilterHolder[] holders = getFilters();
1051 if (holders!=null)
1052 holders = holders.clone();
1053
1054 try
1055 {
1056 setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
1057
1058 FilterMapping mapping = new FilterMapping();
1059 mapping.setFilterName(holder.getName());
1060 mapping.setPathSpec(pathSpec);
1061 mapping.setDispatches(dispatches);
1062 addFilterMapping(mapping);
1063 }
1064 catch (RuntimeException e)
1065 {
1066 setFilters(holders);
1067 throw e;
1068 }
1069 catch (Error e)
1070 {
1071 setFilters(holders);
1072 throw e;
1073 }
1074
1075 }
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085 public FilterHolder addFilter (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
1086 {
1087 return addFilterWithMapping(className, pathSpec, dispatches);
1088 }
1089
1090
1091
1092
1093
1094
1095
1096 public void addFilter (FilterHolder filter, FilterMapping filterMapping)
1097 {
1098 if (filter != null)
1099 setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
1100 if (filterMapping != null)
1101 addFilterMapping(filterMapping);
1102 }
1103
1104
1105
1106
1107
1108 public void addFilter (FilterHolder filter)
1109 {
1110 if (filter != null)
1111 setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
1112 }
1113
1114
1115
1116
1117
1118 public void addFilterMapping (FilterMapping mapping)
1119 {
1120 if (mapping != null)
1121 {
1122 Source source = (mapping.getFilterHolder()==null?null:mapping.getFilterHolder().getSource());
1123 FilterMapping[] mappings =getFilterMappings();
1124 if (mappings==null || mappings.length==0)
1125 {
1126 setFilterMappings(insertFilterMapping(mapping,0,false));
1127 if (source != null && source == Source.JAVAX_API)
1128 _matchAfterIndex = 0;
1129 }
1130 else
1131 {
1132
1133
1134
1135 if (source != null && Source.JAVAX_API == source)
1136 {
1137 setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
1138 if (_matchAfterIndex < 0)
1139 _matchAfterIndex = getFilterMappings().length-1;
1140 }
1141 else
1142 {
1143
1144 if (_matchAfterIndex < 0)
1145 setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
1146 else
1147 {
1148 FilterMapping[] new_mappings = insertFilterMapping(mapping, _matchAfterIndex, true);
1149 ++_matchAfterIndex;
1150 setFilterMappings(new_mappings);
1151 }
1152 }
1153 }
1154 }
1155 }
1156
1157
1158
1159
1160
1161
1162 public void prependFilterMapping (FilterMapping mapping)
1163 {
1164 if (mapping != null)
1165 {
1166 Source source = mapping.getFilterHolder().getSource();
1167
1168 FilterMapping[] mappings = getFilterMappings();
1169 if (mappings==null || mappings.length==0)
1170 {
1171 setFilterMappings(insertFilterMapping(mapping, 0, false));
1172 if (source != null && Source.JAVAX_API == source)
1173 _matchBeforeIndex = 0;
1174 }
1175 else
1176 {
1177 if (source != null && Source.JAVAX_API == source)
1178 {
1179
1180
1181
1182
1183 if (_matchBeforeIndex < 0)
1184 {
1185
1186 _matchBeforeIndex = 0;
1187 FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
1188 setFilterMappings(new_mappings);
1189 }
1190 else
1191 {
1192 FilterMapping[] new_mappings = insertFilterMapping(mapping,_matchBeforeIndex, false);
1193 ++_matchBeforeIndex;
1194 setFilterMappings(new_mappings);
1195 }
1196 }
1197 else
1198 {
1199
1200 FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
1201 setFilterMappings(new_mappings);
1202 }
1203
1204
1205 if (_matchAfterIndex >= 0)
1206 ++_matchAfterIndex;
1207 }
1208 }
1209 }
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220 protected FilterMapping[] insertFilterMapping (FilterMapping mapping, int pos, boolean before)
1221 {
1222 if (pos < 0)
1223 throw new IllegalArgumentException("FilterMapping insertion pos < 0");
1224 FilterMapping[] mappings = getFilterMappings();
1225
1226 if (mappings==null || mappings.length==0)
1227 {
1228 return new FilterMapping[] {mapping};
1229 }
1230 FilterMapping[] new_mappings = new FilterMapping[mappings.length+1];
1231
1232
1233 if (before)
1234 {
1235
1236 System.arraycopy(mappings,0,new_mappings,0,pos);
1237
1238
1239 new_mappings[pos] = mapping;
1240
1241
1242 System.arraycopy(mappings,pos,new_mappings,pos+1, mappings.length-pos);
1243
1244 }
1245 else
1246 {
1247
1248 System.arraycopy(mappings,0,new_mappings,0,pos+1);
1249
1250 new_mappings[pos+1] = mapping;
1251
1252
1253 if (mappings.length > pos+1)
1254 System.arraycopy(mappings,pos+1,new_mappings,pos+2, mappings.length-(pos+1));
1255 }
1256 return new_mappings;
1257 }
1258
1259
1260
1261 protected synchronized void updateNameMappings()
1262 {
1263
1264 _filterNameMap.clear();
1265 if (_filters!=null)
1266 {
1267 for (FilterHolder filter : _filters)
1268 {
1269 _filterNameMap.put(filter.getName(), filter);
1270 filter.setServletHandler(this);
1271 }
1272 }
1273
1274
1275 _servletNameMap.clear();
1276 if (_servlets!=null)
1277 {
1278
1279 for (ServletHolder servlet : _servlets)
1280 {
1281 _servletNameMap.put(servlet.getName(), servlet);
1282 servlet.setServletHandler(this);
1283 }
1284 }
1285 }
1286
1287
1288 protected synchronized void updateMappings()
1289 {
1290
1291 if (_filterMappings==null)
1292 {
1293 _filterPathMappings=null;
1294 _filterNameMappings=null;
1295 }
1296 else
1297 {
1298 _filterPathMappings=new ArrayList<>();
1299 _filterNameMappings=new MultiMap<FilterMapping>();
1300 for (FilterMapping filtermapping : _filterMappings)
1301 {
1302 FilterHolder filter_holder = _filterNameMap.get(filtermapping.getFilterName());
1303 if (filter_holder == null)
1304 throw new IllegalStateException("No filter named " + filtermapping.getFilterName());
1305 filtermapping.setFilterHolder(filter_holder);
1306 if (filtermapping.getPathSpecs() != null)
1307 _filterPathMappings.add(filtermapping);
1308
1309 if (filtermapping.getServletNames() != null)
1310 {
1311 String[] names = filtermapping.getServletNames();
1312 for (String name : names)
1313 {
1314 if (name != null)
1315 _filterNameMappings.add(name, filtermapping);
1316 }
1317 }
1318 }
1319 }
1320
1321
1322 if (_servletMappings==null || _servletNameMap==null)
1323 {
1324 _servletPathMap=null;
1325 }
1326 else
1327 {
1328 PathMap<ServletHolder> pm = new PathMap<>();
1329 Map<String,ServletMapping> servletPathMappings = new HashMap<String,ServletMapping>();
1330
1331
1332 HashMap<String, Set<ServletMapping>> sms = new HashMap<String, Set<ServletMapping>>();
1333 for (ServletMapping servletMapping : _servletMappings)
1334 {
1335 String[] pathSpecs = servletMapping.getPathSpecs();
1336 if (pathSpecs != null)
1337 {
1338 for (String pathSpec : pathSpecs)
1339 {
1340 Set<ServletMapping> mappings = sms.get(pathSpec);
1341 if (mappings == null)
1342 {
1343 mappings = new HashSet<ServletMapping>();
1344 sms.put(pathSpec, mappings);
1345 }
1346 mappings.add(servletMapping);
1347 }
1348 }
1349 }
1350
1351
1352 for (String pathSpec : sms.keySet())
1353 {
1354
1355
1356 Set<ServletMapping> mappings = sms.get(pathSpec);
1357
1358
1359
1360 ServletMapping finalMapping = null;
1361 for (ServletMapping mapping : mappings)
1362 {
1363
1364 ServletHolder servlet_holder = _servletNameMap.get(mapping.getServletName());
1365 if (servlet_holder == null)
1366 throw new IllegalStateException("No such servlet: " + mapping.getServletName());
1367
1368 if (!servlet_holder.isEnabled())
1369 continue;
1370
1371
1372 if (finalMapping == null)
1373 finalMapping = mapping;
1374 else
1375 {
1376
1377 if (finalMapping.isDefault())
1378 finalMapping = mapping;
1379 else
1380 {
1381
1382 if (!mapping.isDefault())
1383 throw new IllegalStateException("Multiple servlets map to path: "+pathSpec);
1384 }
1385 }
1386 }
1387 if (finalMapping == null)
1388 throw new IllegalStateException ("No acceptable servlet mappings for "+pathSpec);
1389
1390 if (LOG.isDebugEnabled()) LOG.debug("Chose path={} mapped to servlet={} from default={}", pathSpec, finalMapping.getServletName(), finalMapping.isDefault());
1391
1392 servletPathMappings.put(pathSpec, finalMapping);
1393 pm.put(pathSpec,_servletNameMap.get(finalMapping.getServletName()));
1394 }
1395
1396 _servletPathMap=pm;
1397 _servletPathMappings=servletPathMappings;
1398 }
1399
1400
1401 if (_chainCache!=null)
1402 {
1403 for (int i=_chainCache.length;i-->0;)
1404 {
1405 if (_chainCache[i]!=null)
1406 _chainCache[i].clear();
1407 }
1408 }
1409
1410 if (LOG.isDebugEnabled())
1411 {
1412 LOG.debug("filterNameMap="+_filterNameMap);
1413 LOG.debug("pathFilters="+_filterPathMappings);
1414 LOG.debug("servletFilterMap="+_filterNameMappings);
1415 LOG.debug("servletPathMap="+_servletPathMap);
1416 LOG.debug("servletNameMap="+_servletNameMap);
1417 }
1418
1419 try
1420 {
1421 if (_contextHandler!=null && _contextHandler.isStarted() || _contextHandler==null && isStarted())
1422 initialize();
1423 }
1424 catch (Exception e)
1425 {
1426 throw new RuntimeException(e);
1427 }
1428 }
1429
1430
1431 protected void notFound(HttpServletRequest request, HttpServletResponse response) throws IOException
1432 {
1433 if(LOG.isDebugEnabled())
1434 LOG.debug("Not Found "+request.getRequestURI());
1435
1436 }
1437
1438
1439
1440
1441
1442 public void setFilterChainsCached(boolean filterChainsCached)
1443 {
1444 _filterChainsCached = filterChainsCached;
1445 }
1446
1447
1448
1449
1450
1451 public void setFilterMappings(FilterMapping[] filterMappings)
1452 {
1453 updateBeans(_filterMappings,filterMappings);
1454 _filterMappings = filterMappings;
1455 updateMappings();
1456 invalidateChainsCache();
1457 }
1458
1459
1460 public synchronized void setFilters(FilterHolder[] holders)
1461 {
1462 if (holders!=null)
1463 for (FilterHolder holder:holders)
1464 holder.setServletHandler(this);
1465
1466 updateBeans(_filters,holders);
1467 _filters=holders;
1468 updateNameMappings();
1469 invalidateChainsCache();
1470 }
1471
1472
1473
1474
1475
1476 public void setServletMappings(ServletMapping[] servletMappings)
1477 {
1478 updateBeans(_servletMappings,servletMappings);
1479 _servletMappings = servletMappings;
1480 updateMappings();
1481 invalidateChainsCache();
1482 }
1483
1484
1485
1486
1487
1488 public synchronized void setServlets(ServletHolder[] holders)
1489 {
1490 if (holders!=null)
1491 for (ServletHolder holder:holders)
1492 holder.setServletHandler(this);
1493
1494 updateBeans(_servlets,holders);
1495 _servlets=holders;
1496 updateNameMappings();
1497 invalidateChainsCache();
1498 }
1499
1500
1501
1502 private class CachedChain implements FilterChain
1503 {
1504 FilterHolder _filterHolder;
1505 CachedChain _next;
1506 ServletHolder _servletHolder;
1507
1508
1509
1510
1511
1512
1513 CachedChain(List<FilterHolder> filters, ServletHolder servletHolder)
1514 {
1515 if (filters.size()>0)
1516 {
1517 _filterHolder=filters.get(0);
1518 filters.remove(0);
1519 _next=new CachedChain(filters,servletHolder);
1520 }
1521 else
1522 _servletHolder=servletHolder;
1523 }
1524
1525
1526 @Override
1527 public void doFilter(ServletRequest request, ServletResponse response)
1528 throws IOException, ServletException
1529 {
1530 final Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
1531
1532
1533 if (_filterHolder!=null)
1534 {
1535 if (LOG.isDebugEnabled())
1536 LOG.debug("call filter " + _filterHolder);
1537 Filter filter= _filterHolder.getFilter();
1538 if (_filterHolder.isAsyncSupported())
1539 filter.doFilter(request, response, _next);
1540 else
1541 {
1542 final boolean suspendable=baseRequest.isAsyncSupported();
1543 if (suspendable)
1544 {
1545 try
1546 {
1547 baseRequest.setAsyncSupported(false);
1548 filter.doFilter(request, response, _next);
1549 }
1550 finally
1551 {
1552 baseRequest.setAsyncSupported(true);
1553 }
1554 }
1555 else
1556 filter.doFilter(request, response, _next);
1557 }
1558 return;
1559 }
1560
1561
1562
1563 HttpServletRequest srequest = (HttpServletRequest)request;
1564 if (_servletHolder != null)
1565 {
1566 if (LOG.isDebugEnabled())
1567 LOG.debug("call servlet " + _servletHolder);
1568 _servletHolder.handle(baseRequest,request, response);
1569 }
1570 else if (getHandler()==null)
1571 notFound(srequest, (HttpServletResponse)response);
1572 else
1573 nextHandle(URIUtil.addPaths(srequest.getServletPath(),srequest.getPathInfo()),
1574 baseRequest,srequest,(HttpServletResponse)response);
1575
1576 }
1577
1578 @Override
1579 public String toString()
1580 {
1581 if (_filterHolder!=null)
1582 return _filterHolder+"->"+_next.toString();
1583 if (_servletHolder!=null)
1584 return _servletHolder.toString();
1585 return "null";
1586 }
1587 }
1588
1589
1590
1591 private class Chain implements FilterChain
1592 {
1593 final Request _baseRequest;
1594 final List<FilterHolder> _chain;
1595 final ServletHolder _servletHolder;
1596 int _filter= 0;
1597
1598
1599 Chain(Request baseRequest, List<FilterHolder> filters, ServletHolder servletHolder)
1600 {
1601 _baseRequest=baseRequest;
1602 _chain= filters;
1603 _servletHolder= servletHolder;
1604 }
1605
1606
1607 @Override
1608 public void doFilter(ServletRequest request, ServletResponse response)
1609 throws IOException, ServletException
1610 {
1611 if (LOG.isDebugEnabled())
1612 LOG.debug("doFilter " + _filter);
1613
1614
1615 if (_filter < _chain.size())
1616 {
1617 FilterHolder holder= _chain.get(_filter++);
1618 if (LOG.isDebugEnabled())
1619 LOG.debug("call filter " + holder);
1620 Filter filter= holder.getFilter();
1621
1622 if (holder.isAsyncSupported() || !_baseRequest.isAsyncSupported())
1623 {
1624 filter.doFilter(request, response, this);
1625 }
1626 else
1627 {
1628 try
1629 {
1630 _baseRequest.setAsyncSupported(false);
1631 filter.doFilter(request, response, this);
1632 }
1633 finally
1634 {
1635 _baseRequest.setAsyncSupported(true);
1636 }
1637 }
1638
1639 return;
1640 }
1641
1642
1643 HttpServletRequest srequest = (HttpServletRequest)request;
1644 if (_servletHolder != null)
1645 {
1646 if (LOG.isDebugEnabled())
1647 LOG.debug("call servlet " + _servletHolder);
1648 _servletHolder.handle(_baseRequest,request, response);
1649 }
1650 else if (getHandler()==null)
1651 notFound(srequest, (HttpServletResponse)response);
1652 else
1653 {
1654 Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
1655 nextHandle(URIUtil.addPaths(srequest.getServletPath(),srequest.getPathInfo()),
1656 baseRequest,srequest,(HttpServletResponse)response);
1657 }
1658 }
1659
1660
1661 @Override
1662 public String toString()
1663 {
1664 StringBuilder b = new StringBuilder();
1665 for(FilterHolder f: _chain)
1666 {
1667 b.append(f.toString());
1668 b.append("->");
1669 }
1670 b.append(_servletHolder);
1671 return b.toString();
1672 }
1673 }
1674
1675
1676
1677
1678
1679 public int getMaxFilterChainsCacheSize()
1680 {
1681 return _maxFilterChainsCacheSize;
1682 }
1683
1684
1685
1686
1687
1688
1689
1690
1691 public void setMaxFilterChainsCacheSize(int maxFilterChainsCacheSize)
1692 {
1693 _maxFilterChainsCacheSize = maxFilterChainsCacheSize;
1694 }
1695
1696
1697 void destroyServlet(Servlet servlet)
1698 {
1699 if (_contextHandler!=null)
1700 _contextHandler.destroyServlet(servlet);
1701 }
1702
1703
1704 void destroyFilter(Filter filter)
1705 {
1706 if (_contextHandler!=null)
1707 _contextHandler.destroyFilter(filter);
1708 }
1709
1710
1711
1712
1713 public static class Default404Servlet extends HttpServlet
1714 {
1715 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
1716 throws ServletException, IOException
1717 {
1718 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
1719 }
1720 }
1721 }