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