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.Collection;
25 import java.util.Collections;
26 import java.util.EnumSet;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.ListIterator;
31 import java.util.Map;
32 import java.util.Queue;
33 import java.util.Set;
34 import java.util.concurrent.ConcurrentHashMap;
35 import java.util.concurrent.ConcurrentLinkedQueue;
36 import java.util.concurrent.ConcurrentMap;
37
38 import javax.servlet.DispatcherType;
39 import javax.servlet.Filter;
40 import javax.servlet.FilterChain;
41 import javax.servlet.RequestDispatcher;
42 import javax.servlet.Servlet;
43 import javax.servlet.ServletContext;
44 import javax.servlet.ServletException;
45 import javax.servlet.ServletRegistration;
46 import javax.servlet.ServletRequest;
47 import javax.servlet.ServletResponse;
48 import javax.servlet.ServletSecurityElement;
49 import javax.servlet.UnavailableException;
50 import javax.servlet.http.HttpServlet;
51 import javax.servlet.http.HttpServletRequest;
52 import javax.servlet.http.HttpServletResponse;
53
54 import org.eclipse.jetty.http.PathMap;
55 import org.eclipse.jetty.io.EofException;
56 import org.eclipse.jetty.io.RuntimeIOException;
57 import org.eclipse.jetty.security.IdentityService;
58 import org.eclipse.jetty.security.SecurityHandler;
59 import org.eclipse.jetty.server.Dispatcher;
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
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 Throwable 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 if (th instanceof UnavailableException)
577 {
578 UnavailableException ue = (UnavailableException)th;
579 if (ue.isPermanent())
580 response.sendError(HttpServletResponse.SC_NOT_FOUND);
581 else
582 response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
583 }
584 else
585 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
586 }
587 else
588 LOG.debug("Response already committed",th);
589
590
591 if (request.isAsyncStarted())
592 request.getAsyncContext().complete();
593 }
594 catch(Error e)
595 {
596 if ("ContinuationThrowable".equals(e.getClass().getSimpleName()))
597 throw e;
598 if (!(DispatcherType.REQUEST.equals(type) || DispatcherType.ASYNC.equals(type)))
599 throw e;
600 LOG.warn("Error for "+request.getRequestURI(),e);
601 if(LOG.isDebugEnabled())LOG.debug(request.toString());
602
603 request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE,e.getClass());
604 request.setAttribute(RequestDispatcher.ERROR_EXCEPTION,e);
605 if (!response.isCommitted())
606 response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
607 else
608 LOG.debug("Response already committed for handling ",e);
609
610
611 if (request.isAsyncStarted())
612 request.getAsyncContext().complete();
613 }
614 finally
615 {
616 if (servlet_holder!=null)
617 baseRequest.setHandled(true);
618 }
619 }
620
621
622 private FilterChain getFilterChain(Request baseRequest, String pathInContext, ServletHolder servletHolder)
623 {
624 String key=pathInContext==null?servletHolder.getName():pathInContext;
625 int dispatch = FilterMapping.dispatch(baseRequest.getDispatcherType());
626
627 if (_filterChainsCached && _chainCache!=null)
628 {
629 FilterChain chain = (FilterChain)_chainCache[dispatch].get(key);
630 if (chain!=null)
631 return chain;
632 }
633
634
635 List<FilterHolder> filters = new ArrayList<>();
636
637
638 if (pathInContext!=null && _filterPathMappings!=null)
639 {
640 for (FilterMapping filterPathMapping : _filterPathMappings)
641 {
642 if (filterPathMapping.appliesTo(pathInContext, dispatch))
643 filters.add(filterPathMapping.getFilterHolder());
644 }
645 }
646
647
648 if (servletHolder != null && _filterNameMappings!=null && _filterNameMappings.size() > 0)
649 {
650
651 if (_filterNameMappings.size() > 0)
652 {
653 Object o= _filterNameMappings.get(servletHolder.getName());
654
655 for (int i=0; i<LazyList.size(o);i++)
656 {
657 FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
658 if (mapping.appliesTo(dispatch))
659 filters.add(mapping.getFilterHolder());
660 }
661
662 o= _filterNameMappings.get("*");
663 for (int i=0; i<LazyList.size(o);i++)
664 {
665 FilterMapping mapping = (FilterMapping)LazyList.get(o,i);
666 if (mapping.appliesTo(dispatch))
667 filters.add(mapping.getFilterHolder());
668 }
669 }
670 }
671
672 if (filters.isEmpty())
673 return null;
674
675
676 FilterChain chain = null;
677 if (_filterChainsCached)
678 {
679 if (filters.size() > 0)
680 chain= new CachedChain(filters, servletHolder);
681
682 final Map<String,FilterChain> cache=(Map<String, FilterChain>)_chainCache[dispatch];
683 final Queue<String> lru=(Queue<String>)_chainLRU[dispatch];
684
685
686 while (_maxFilterChainsCacheSize>0 && cache.size()>=_maxFilterChainsCacheSize)
687 {
688
689
690
691 String k=lru.poll();
692 if (k==null)
693 {
694 cache.clear();
695 break;
696 }
697 cache.remove(k);
698 }
699
700 cache.put(key,chain);
701 lru.add(key);
702 }
703 else if (filters.size() > 0)
704 chain = new Chain(baseRequest,filters, servletHolder);
705
706 return chain;
707 }
708
709
710 private void invalidateChainsCache()
711 {
712 if (_chainLRU[FilterMapping.REQUEST]!=null)
713 {
714 _chainLRU[FilterMapping.REQUEST].clear();
715 _chainLRU[FilterMapping.FORWARD].clear();
716 _chainLRU[FilterMapping.INCLUDE].clear();
717 _chainLRU[FilterMapping.ERROR].clear();
718 _chainLRU[FilterMapping.ASYNC].clear();
719
720 _chainCache[FilterMapping.REQUEST].clear();
721 _chainCache[FilterMapping.FORWARD].clear();
722 _chainCache[FilterMapping.INCLUDE].clear();
723 _chainCache[FilterMapping.ERROR].clear();
724 _chainCache[FilterMapping.ASYNC].clear();
725 }
726 }
727
728
729
730
731
732 public boolean isAvailable()
733 {
734 if (!isStarted())
735 return false;
736 ServletHolder[] holders = getServlets();
737 for (ServletHolder holder : holders)
738 {
739 if (holder != null && !holder.isAvailable())
740 return false;
741 }
742 return true;
743 }
744
745
746
747
748
749 public void setStartWithUnavailable(boolean start)
750 {
751 _startWithUnavailable=start;
752 }
753
754
755
756
757
758 public boolean isStartWithUnavailable()
759 {
760 return _startWithUnavailable;
761 }
762
763
764
765
766
767
768
769 public void initialize()
770 throws Exception
771 {
772 MultiException mx = new MultiException();
773
774 if (_servlets!=null)
775 {
776
777 ServletHolder[] servlets = _servlets.clone();
778 Arrays.sort(servlets);
779 for (ServletHolder servlet : servlets)
780 {
781 try
782 {
783 if (servlet.getClassName() == null && servlet.getForcedPath() != null)
784 {
785 ServletHolder forced_holder = _servletPathMap.match(servlet.getForcedPath());
786 if (forced_holder == null || forced_holder.getClassName() == null)
787 {
788 mx.add(new IllegalStateException("No forced path servlet for " + servlet.getForcedPath()));
789 continue;
790 }
791 servlet.setClassName(forced_holder.getClassName());
792 }
793 }
794 catch (Throwable e)
795 {
796 LOG.debug(Log.EXCEPTION, e);
797 mx.add(e);
798 }
799 }
800 }
801
802
803 for (Holder<?> h: getBeans(Holder.class))
804 {
805 try
806 {
807 h.start();
808 h.initialize();
809 }
810 catch (Exception e)
811 {
812 mx.add(e);
813 }
814 }
815
816 mx.ifExceptionThrow();
817 }
818
819
820
821
822
823 public boolean isFilterChainsCached()
824 {
825 return _filterChainsCached;
826 }
827
828
829
830
831
832 public ServletHolder newServletHolder(Holder.Source source)
833 {
834 return new ServletHolder(source);
835 }
836
837
838
839
840
841
842
843
844
845
846
847
848 public ServletHolder addServletWithMapping (String className,String pathSpec)
849 {
850 ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
851 holder.setClassName(className);
852 addServletWithMapping(holder,pathSpec);
853 return holder;
854 }
855
856
857
858
859
860 public ServletHolder addServletWithMapping (Class<? extends Servlet> servlet,String pathSpec)
861 {
862 ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED);
863 holder.setHeldClass(servlet);
864 addServletWithMapping(holder,pathSpec);
865
866 return holder;
867 }
868
869
870
871
872
873
874 public void addServletWithMapping (ServletHolder servlet,String pathSpec)
875 {
876 ServletHolder[] holders=getServlets();
877 if (holders!=null)
878 holders = holders.clone();
879
880 try
881 {
882 setServlets(ArrayUtil.addToArray(holders, servlet, ServletHolder.class));
883
884 ServletMapping mapping = new ServletMapping();
885 mapping.setServletName(servlet.getName());
886 mapping.setPathSpec(pathSpec);
887 setServletMappings(ArrayUtil.addToArray(getServletMappings(), mapping, ServletMapping.class));
888 }
889 catch (Exception e)
890 {
891 setServlets(holders);
892 if (e instanceof RuntimeException)
893 throw (RuntimeException)e;
894 throw new RuntimeException(e);
895 }
896 }
897
898
899
900
901
902
903 public void addServlet(ServletHolder holder)
904 {
905 setServlets(ArrayUtil.addToArray(getServlets(), holder, ServletHolder.class));
906 }
907
908
909
910
911
912 public void addServletMapping (ServletMapping mapping)
913 {
914 setServletMappings(ArrayUtil.addToArray(getServletMappings(), mapping, ServletMapping.class));
915 }
916
917
918 public Set<String> setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement)
919 {
920 if (_contextHandler != null)
921 {
922 return _contextHandler.setServletSecurity(registration, servletSecurityElement);
923 }
924 return Collections.emptySet();
925 }
926
927
928 public FilterHolder newFilterHolder(Holder.Source source)
929 {
930 return new FilterHolder(source);
931 }
932
933
934 public FilterHolder getFilter(String name)
935 {
936 return _filterNameMap.get(name);
937 }
938
939
940
941
942
943
944
945
946
947 public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,EnumSet<DispatcherType> dispatches)
948 {
949 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
950 holder.setHeldClass(filter);
951 addFilterWithMapping(holder,pathSpec,dispatches);
952
953 return holder;
954 }
955
956
957
958
959
960
961
962
963 public FilterHolder addFilterWithMapping (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
964 {
965 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
966 holder.setClassName(className);
967
968 addFilterWithMapping(holder,pathSpec,dispatches);
969 return holder;
970 }
971
972
973
974
975
976
977
978 public void addFilterWithMapping (FilterHolder holder,String pathSpec,EnumSet<DispatcherType> dispatches)
979 {
980 FilterHolder[] holders = getFilters();
981 if (holders!=null)
982 holders = holders.clone();
983
984 try
985 {
986 setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
987
988 FilterMapping mapping = new FilterMapping();
989 mapping.setFilterName(holder.getName());
990 mapping.setPathSpec(pathSpec);
991 mapping.setDispatcherTypes(dispatches);
992 addFilterMapping(mapping);
993
994 }
995 catch (RuntimeException e)
996 {
997 setFilters(holders);
998 throw e;
999 }
1000 catch (Error e)
1001 {
1002 setFilters(holders);
1003 throw e;
1004 }
1005
1006 }
1007
1008
1009
1010
1011
1012
1013
1014
1015 public FilterHolder addFilterWithMapping (Class<? extends Filter> filter,String pathSpec,int dispatches)
1016 {
1017 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
1018 holder.setHeldClass(filter);
1019 addFilterWithMapping(holder,pathSpec,dispatches);
1020
1021 return holder;
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031 public FilterHolder addFilterWithMapping (String className,String pathSpec,int dispatches)
1032 {
1033 FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED);
1034 holder.setClassName(className);
1035
1036 addFilterWithMapping(holder,pathSpec,dispatches);
1037 return holder;
1038 }
1039
1040
1041
1042
1043
1044
1045
1046 public void addFilterWithMapping (FilterHolder holder,String pathSpec,int dispatches)
1047 {
1048 FilterHolder[] holders = getFilters();
1049 if (holders!=null)
1050 holders = holders.clone();
1051
1052 try
1053 {
1054 setFilters(ArrayUtil.addToArray(holders, holder, FilterHolder.class));
1055
1056 FilterMapping mapping = new FilterMapping();
1057 mapping.setFilterName(holder.getName());
1058 mapping.setPathSpec(pathSpec);
1059 mapping.setDispatches(dispatches);
1060 addFilterMapping(mapping);
1061 }
1062 catch (RuntimeException e)
1063 {
1064 setFilters(holders);
1065 throw e;
1066 }
1067 catch (Error e)
1068 {
1069 setFilters(holders);
1070 throw e;
1071 }
1072
1073 }
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083 public FilterHolder addFilter (String className,String pathSpec,EnumSet<DispatcherType> dispatches)
1084 {
1085 return addFilterWithMapping(className, pathSpec, dispatches);
1086 }
1087
1088
1089
1090
1091
1092
1093
1094 public void addFilter (FilterHolder filter, FilterMapping filterMapping)
1095 {
1096 if (filter != null)
1097 setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
1098 if (filterMapping != null)
1099 addFilterMapping(filterMapping);
1100 }
1101
1102
1103
1104
1105
1106 public void addFilter (FilterHolder filter)
1107 {
1108 if (filter != null)
1109 setFilters(ArrayUtil.addToArray(getFilters(), filter, FilterHolder.class));
1110 }
1111
1112
1113
1114
1115
1116 public void addFilterMapping (FilterMapping mapping)
1117 {
1118 if (mapping != null)
1119 {
1120 Source source = (mapping.getFilterHolder()==null?null:mapping.getFilterHolder().getSource());
1121 FilterMapping[] mappings =getFilterMappings();
1122 if (mappings==null || mappings.length==0)
1123 {
1124 setFilterMappings(insertFilterMapping(mapping,0,false));
1125 if (source != null && source == Source.JAVAX_API)
1126 _matchAfterIndex = 0;
1127 }
1128 else
1129 {
1130
1131
1132
1133 if (source != null && Source.JAVAX_API == source)
1134 {
1135 setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
1136 if (_matchAfterIndex < 0)
1137 _matchAfterIndex = getFilterMappings().length-1;
1138 }
1139 else
1140 {
1141
1142 if (_matchAfterIndex < 0)
1143 setFilterMappings(insertFilterMapping(mapping,mappings.length-1, false));
1144 else
1145 {
1146 FilterMapping[] new_mappings = insertFilterMapping(mapping, _matchAfterIndex, true);
1147 ++_matchAfterIndex;
1148 setFilterMappings(new_mappings);
1149 }
1150 }
1151 }
1152 }
1153 }
1154
1155
1156
1157
1158
1159
1160 public void prependFilterMapping (FilterMapping mapping)
1161 {
1162 if (mapping != null)
1163 {
1164 Source source = mapping.getFilterHolder().getSource();
1165
1166 FilterMapping[] mappings = getFilterMappings();
1167 if (mappings==null || mappings.length==0)
1168 {
1169 setFilterMappings(insertFilterMapping(mapping, 0, false));
1170 if (source != null && Source.JAVAX_API == source)
1171 _matchBeforeIndex = 0;
1172 }
1173 else
1174 {
1175 if (source != null && Source.JAVAX_API == source)
1176 {
1177
1178
1179
1180
1181 if (_matchBeforeIndex < 0)
1182 {
1183
1184 _matchBeforeIndex = 0;
1185 FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
1186 setFilterMappings(new_mappings);
1187 }
1188 else
1189 {
1190 FilterMapping[] new_mappings = insertFilterMapping(mapping,_matchBeforeIndex, false);
1191 ++_matchBeforeIndex;
1192 setFilterMappings(new_mappings);
1193 }
1194 }
1195 else
1196 {
1197
1198 FilterMapping[] new_mappings = insertFilterMapping(mapping, 0, true);
1199 setFilterMappings(new_mappings);
1200 }
1201
1202
1203 if (_matchAfterIndex >= 0)
1204 ++_matchAfterIndex;
1205 }
1206 }
1207 }
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218 protected FilterMapping[] insertFilterMapping (FilterMapping mapping, int pos, boolean before)
1219 {
1220 if (pos < 0)
1221 throw new IllegalArgumentException("FilterMapping insertion pos < 0");
1222 FilterMapping[] mappings = getFilterMappings();
1223
1224 if (mappings==null || mappings.length==0)
1225 {
1226 return new FilterMapping[] {mapping};
1227 }
1228 FilterMapping[] new_mappings = new FilterMapping[mappings.length+1];
1229
1230
1231 if (before)
1232 {
1233
1234 System.arraycopy(mappings,0,new_mappings,0,pos);
1235
1236
1237 new_mappings[pos] = mapping;
1238
1239
1240 System.arraycopy(mappings,pos,new_mappings,pos+1, mappings.length-pos);
1241
1242 }
1243 else
1244 {
1245
1246 System.arraycopy(mappings,0,new_mappings,0,pos+1);
1247
1248 new_mappings[pos+1] = mapping;
1249
1250
1251 if (mappings.length > pos+1)
1252 System.arraycopy(mappings,pos+1,new_mappings,pos+2, mappings.length-(pos+1));
1253 }
1254 return new_mappings;
1255 }
1256
1257
1258
1259 protected synchronized void updateNameMappings()
1260 {
1261
1262 _filterNameMap.clear();
1263 if (_filters!=null)
1264 {
1265 for (FilterHolder filter : _filters)
1266 {
1267 _filterNameMap.put(filter.getName(), filter);
1268 filter.setServletHandler(this);
1269 }
1270 }
1271
1272
1273 _servletNameMap.clear();
1274 if (_servlets!=null)
1275 {
1276
1277 for (ServletHolder servlet : _servlets)
1278 {
1279 _servletNameMap.put(servlet.getName(), servlet);
1280 servlet.setServletHandler(this);
1281 }
1282 }
1283 }
1284
1285
1286 protected synchronized void updateMappings()
1287 {
1288
1289 if (_filterMappings==null)
1290 {
1291 _filterPathMappings=null;
1292 _filterNameMappings=null;
1293 }
1294 else
1295 {
1296 _filterPathMappings=new ArrayList<>();
1297 _filterNameMappings=new MultiMap<FilterMapping>();
1298 for (FilterMapping filtermapping : _filterMappings)
1299 {
1300 FilterHolder filter_holder = _filterNameMap.get(filtermapping.getFilterName());
1301 if (filter_holder == null)
1302 throw new IllegalStateException("No filter named " + filtermapping.getFilterName());
1303 filtermapping.setFilterHolder(filter_holder);
1304 if (filtermapping.getPathSpecs() != null)
1305 _filterPathMappings.add(filtermapping);
1306
1307 if (filtermapping.getServletNames() != null)
1308 {
1309 String[] names = filtermapping.getServletNames();
1310 for (String name : names)
1311 {
1312 if (name != null)
1313 _filterNameMappings.add(name, filtermapping);
1314 }
1315 }
1316 }
1317 }
1318
1319
1320 if (_servletMappings==null || _servletNameMap==null)
1321 {
1322 _servletPathMap=null;
1323 }
1324 else
1325 {
1326 PathMap<ServletHolder> pm = new PathMap<>();
1327 Map<String,ServletMapping> servletPathMappings = new HashMap<String,ServletMapping>();
1328
1329
1330 HashMap<String, Set<ServletMapping>> sms = new HashMap<String, Set<ServletMapping>>();
1331 for (ServletMapping servletMapping : _servletMappings)
1332 {
1333 String[] pathSpecs = servletMapping.getPathSpecs();
1334 if (pathSpecs != null)
1335 {
1336 for (String pathSpec : pathSpecs)
1337 {
1338 Set<ServletMapping> mappings = sms.get(pathSpec);
1339 if (mappings == null)
1340 {
1341 mappings = new HashSet<ServletMapping>();
1342 sms.put(pathSpec, mappings);
1343 }
1344 mappings.add(servletMapping);
1345 }
1346 }
1347 }
1348
1349
1350 for (String pathSpec : sms.keySet())
1351 {
1352
1353
1354 Set<ServletMapping> mappings = sms.get(pathSpec);
1355
1356
1357
1358 ServletMapping finalMapping = null;
1359 for (ServletMapping mapping : mappings)
1360 {
1361
1362 ServletHolder servlet_holder = _servletNameMap.get(mapping.getServletName());
1363 if (servlet_holder == null)
1364 throw new IllegalStateException("No such servlet: " + mapping.getServletName());
1365
1366 if (!servlet_holder.isEnabled())
1367 continue;
1368
1369
1370 if (finalMapping == null)
1371 finalMapping = mapping;
1372 else
1373 {
1374
1375 if (finalMapping.isDefault())
1376 finalMapping = mapping;
1377 else
1378 {
1379
1380 if (!mapping.isDefault())
1381 throw new IllegalStateException("Multiple servlets map to path: "+pathSpec);
1382 }
1383 }
1384 }
1385 if (finalMapping == null)
1386 throw new IllegalStateException ("No acceptable servlet mappings for "+pathSpec);
1387
1388 if (LOG.isDebugEnabled()) LOG.debug("Chose path={} mapped to servlet={} from default={}", pathSpec, finalMapping.getServletName(), finalMapping.isDefault());
1389
1390 servletPathMappings.put(pathSpec, finalMapping);
1391 pm.put(pathSpec,_servletNameMap.get(finalMapping.getServletName()));
1392 }
1393
1394 _servletPathMap=pm;
1395 _servletPathMappings=servletPathMappings;
1396 }
1397
1398
1399 if (_chainCache!=null)
1400 {
1401 for (int i=_chainCache.length;i-->0;)
1402 {
1403 if (_chainCache[i]!=null)
1404 _chainCache[i].clear();
1405 }
1406 }
1407
1408 if (LOG.isDebugEnabled())
1409 {
1410 LOG.debug("filterNameMap="+_filterNameMap);
1411 LOG.debug("pathFilters="+_filterPathMappings);
1412 LOG.debug("servletFilterMap="+_filterNameMappings);
1413 LOG.debug("servletPathMap="+_servletPathMap);
1414 LOG.debug("servletNameMap="+_servletNameMap);
1415 }
1416
1417 try
1418 {
1419 if (_contextHandler!=null && _contextHandler.isStarted() || _contextHandler==null && isStarted())
1420 initialize();
1421 }
1422 catch (Exception e)
1423 {
1424 throw new RuntimeException(e);
1425 }
1426 }
1427
1428
1429 protected void notFound(HttpServletRequest request, HttpServletResponse response) throws IOException
1430 {
1431 if(LOG.isDebugEnabled())
1432 LOG.debug("Not Found "+request.getRequestURI());
1433
1434 }
1435
1436
1437
1438
1439
1440 public void setFilterChainsCached(boolean filterChainsCached)
1441 {
1442 _filterChainsCached = filterChainsCached;
1443 }
1444
1445
1446
1447
1448
1449 public void setFilterMappings(FilterMapping[] filterMappings)
1450 {
1451 updateBeans(_filterMappings,filterMappings);
1452 _filterMappings = filterMappings;
1453 updateMappings();
1454 invalidateChainsCache();
1455 }
1456
1457
1458 public synchronized void setFilters(FilterHolder[] holders)
1459 {
1460 if (holders!=null)
1461 for (FilterHolder holder:holders)
1462 holder.setServletHandler(this);
1463
1464 updateBeans(_filters,holders);
1465 _filters=holders;
1466 updateNameMappings();
1467 invalidateChainsCache();
1468 }
1469
1470
1471
1472
1473
1474 public void setServletMappings(ServletMapping[] servletMappings)
1475 {
1476 updateBeans(_servletMappings,servletMappings);
1477 _servletMappings = servletMappings;
1478 updateMappings();
1479 invalidateChainsCache();
1480 }
1481
1482
1483
1484
1485
1486 public synchronized void setServlets(ServletHolder[] holders)
1487 {
1488 if (holders!=null)
1489 for (ServletHolder holder:holders)
1490 holder.setServletHandler(this);
1491
1492 updateBeans(_servlets,holders);
1493 _servlets=holders;
1494 updateNameMappings();
1495 invalidateChainsCache();
1496 }
1497
1498
1499
1500 private class CachedChain implements FilterChain
1501 {
1502 FilterHolder _filterHolder;
1503 CachedChain _next;
1504 ServletHolder _servletHolder;
1505
1506
1507
1508
1509
1510
1511 CachedChain(List<FilterHolder> filters, ServletHolder servletHolder)
1512 {
1513 if (filters.size()>0)
1514 {
1515 _filterHolder=filters.get(0);
1516 filters.remove(0);
1517 _next=new CachedChain(filters,servletHolder);
1518 }
1519 else
1520 _servletHolder=servletHolder;
1521 }
1522
1523
1524 @Override
1525 public void doFilter(ServletRequest request, ServletResponse response)
1526 throws IOException, ServletException
1527 {
1528 final Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
1529
1530
1531 if (_filterHolder!=null)
1532 {
1533 if (LOG.isDebugEnabled())
1534 LOG.debug("call filter " + _filterHolder);
1535 Filter filter= _filterHolder.getFilter();
1536 if (_filterHolder.isAsyncSupported())
1537 filter.doFilter(request, response, _next);
1538 else
1539 {
1540 final boolean suspendable=baseRequest.isAsyncSupported();
1541 if (suspendable)
1542 {
1543 try
1544 {
1545 baseRequest.setAsyncSupported(false);
1546 filter.doFilter(request, response, _next);
1547 }
1548 finally
1549 {
1550 baseRequest.setAsyncSupported(true);
1551 }
1552 }
1553 else
1554 filter.doFilter(request, response, _next);
1555 }
1556 return;
1557 }
1558
1559
1560
1561 HttpServletRequest srequest = (HttpServletRequest)request;
1562 if (_servletHolder != null)
1563 {
1564 if (LOG.isDebugEnabled())
1565 LOG.debug("call servlet " + _servletHolder);
1566 _servletHolder.handle(baseRequest,request, response);
1567 }
1568 else if (getHandler()==null)
1569 notFound(srequest, (HttpServletResponse)response);
1570 else
1571 nextHandle(URIUtil.addPaths(srequest.getServletPath(),srequest.getPathInfo()),
1572 baseRequest,srequest,(HttpServletResponse)response);
1573
1574 }
1575
1576 @Override
1577 public String toString()
1578 {
1579 if (_filterHolder!=null)
1580 return _filterHolder+"->"+_next.toString();
1581 if (_servletHolder!=null)
1582 return _servletHolder.toString();
1583 return "null";
1584 }
1585 }
1586
1587
1588
1589 private class Chain implements FilterChain
1590 {
1591 final Request _baseRequest;
1592 final List<FilterHolder> _chain;
1593 final ServletHolder _servletHolder;
1594 int _filter= 0;
1595
1596
1597 Chain(Request baseRequest, List<FilterHolder> filters, ServletHolder servletHolder)
1598 {
1599 _baseRequest=baseRequest;
1600 _chain= filters;
1601 _servletHolder= servletHolder;
1602 }
1603
1604
1605 @Override
1606 public void doFilter(ServletRequest request, ServletResponse response)
1607 throws IOException, ServletException
1608 {
1609 if (LOG.isDebugEnabled())
1610 LOG.debug("doFilter " + _filter);
1611
1612
1613 if (_filter < _chain.size())
1614 {
1615 FilterHolder holder= _chain.get(_filter++);
1616 if (LOG.isDebugEnabled())
1617 LOG.debug("call filter " + holder);
1618 Filter filter= holder.getFilter();
1619
1620 if (holder.isAsyncSupported() || !_baseRequest.isAsyncSupported())
1621 {
1622 filter.doFilter(request, response, this);
1623 }
1624 else
1625 {
1626 try
1627 {
1628 _baseRequest.setAsyncSupported(false);
1629 filter.doFilter(request, response, this);
1630 }
1631 finally
1632 {
1633 _baseRequest.setAsyncSupported(true);
1634 }
1635 }
1636
1637 return;
1638 }
1639
1640
1641 HttpServletRequest srequest = (HttpServletRequest)request;
1642 if (_servletHolder != null)
1643 {
1644 if (LOG.isDebugEnabled())
1645 LOG.debug("call servlet " + _servletHolder);
1646 _servletHolder.handle(_baseRequest,request, response);
1647 }
1648 else if (getHandler()==null)
1649 notFound(srequest, (HttpServletResponse)response);
1650 else
1651 {
1652 Request baseRequest=(request instanceof Request)?((Request)request):HttpChannel.getCurrentHttpChannel().getRequest();
1653 nextHandle(URIUtil.addPaths(srequest.getServletPath(),srequest.getPathInfo()),
1654 baseRequest,srequest,(HttpServletResponse)response);
1655 }
1656 }
1657
1658
1659 @Override
1660 public String toString()
1661 {
1662 StringBuilder b = new StringBuilder();
1663 for(FilterHolder f: _chain)
1664 {
1665 b.append(f.toString());
1666 b.append("->");
1667 }
1668 b.append(_servletHolder);
1669 return b.toString();
1670 }
1671 }
1672
1673
1674
1675
1676
1677 public int getMaxFilterChainsCacheSize()
1678 {
1679 return _maxFilterChainsCacheSize;
1680 }
1681
1682
1683
1684
1685
1686
1687
1688
1689 public void setMaxFilterChainsCacheSize(int maxFilterChainsCacheSize)
1690 {
1691 _maxFilterChainsCacheSize = maxFilterChainsCacheSize;
1692 }
1693
1694
1695 void destroyServlet(Servlet servlet)
1696 {
1697 if (_contextHandler!=null)
1698 _contextHandler.destroyServlet(servlet);
1699 }
1700
1701
1702 void destroyFilter(Filter filter)
1703 {
1704 if (_contextHandler!=null)
1705 _contextHandler.destroyFilter(filter);
1706 }
1707
1708
1709
1710
1711 public static class Default404Servlet extends HttpServlet
1712 {
1713 protected void doGet(HttpServletRequest req, HttpServletResponse resp)
1714 throws ServletException, IOException
1715 {
1716 resp.sendError(HttpServletResponse.SC_NOT_FOUND);
1717 }
1718 }
1719 }