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