1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
19 package org.apache.catalina.core;
20
21
22 import java.io.IOException;
23 import java.security.Principal;
24 import java.security.PrivilegedActionException;
25
26 import javax.servlet.Filter;
27 import javax.servlet.FilterChain;
28 import javax.servlet.Servlet;
29 import javax.servlet.ServletException;
30 import javax.servlet.ServletRequest;
31 import javax.servlet.ServletResponse;
32 import javax.servlet.http.HttpServletRequest;
33 import javax.servlet.http.HttpServletResponse;
34
35 import org.apache.catalina.CometEvent;
36 import org.apache.catalina.CometFilter;
37 import org.apache.catalina.CometFilterChain;
38 import org.apache.catalina.CometProcessor;
39 import org.apache.catalina.Globals;
40 import org.apache.catalina.InstanceEvent;
41 import org.apache.catalina.security.SecurityUtil;
42 import org.apache.catalina.util.InstanceSupport;
43 import org.apache.catalina.util.StringManager;
44
45 /**
46 * Implementation of <code>javax.servlet.FilterChain</code> used to manage
47 * the execution of a set of filters for a particular request. When the
48 * set of defined filters has all been executed, the next call to
49 * <code>doFilter()</code> will execute the servlet's <code>service()</code>
50 * method itself.
51 *
52 * @author Craig R. McClanahan
53 * @version $Revision: 505593 $ $Date: 2007-02-10 01:54:56 +0100 (sam., 10 févr. 2007) $
54 */
55
56 final class ApplicationFilterChain implements FilterChain, CometFilterChain {
57
58 // Used to enforce requirements of SRV.8.2 / SRV.14.2.5.1
59 private final static ThreadLocal lastServicedRequest;
60 private final static ThreadLocal lastServicedResponse;
61
62 static {
63 if (Globals.STRICT_SERVLET_COMPLIANCE) {
64 lastServicedRequest = new ThreadLocal();
65 lastServicedResponse = new ThreadLocal();
66 } else {
67 lastServicedRequest = null;
68 lastServicedResponse = null;
69 }
70 }
71
72 // -------------------------------------------------------------- Constants
73
74
75 public static final int INCREMENT = 10;
76
77
78 // ----------------------------------------------------------- Constructors
79
80
81 /**
82 * Construct a new chain instance with no defined filters.
83 */
84 public ApplicationFilterChain() {
85
86 super();
87
88 }
89
90
91 // ----------------------------------------------------- Instance Variables
92
93
94 /**
95 * Filters.
96 */
97 private ApplicationFilterConfig[] filters =
98 new ApplicationFilterConfig[0];
99
100
101 /**
102 * The int which is used to maintain the current position
103 * in the filter chain.
104 */
105 private int pos = 0;
106
107
108 /**
109 * The int which gives the current number of filters in the chain.
110 */
111 private int n = 0;
112
113
114 /**
115 * The servlet instance to be executed by this chain.
116 */
117 private Servlet servlet = null;
118
119
120 /**
121 * The string manager for our package.
122 */
123 private static final StringManager sm =
124 StringManager.getManager(Constants.Package);
125
126
127 /**
128 * The InstanceSupport instance associated with our Wrapper (used to
129 * send "before filter" and "after filter" events.
130 */
131 private InstanceSupport support = null;
132
133
134 /**
135 * Static class array used when the SecurityManager is turned on and
136 * <code>doFilter</code> is invoked.
137 */
138 private static Class[] classType = new Class[]{ServletRequest.class,
139 ServletResponse.class,
140 FilterChain.class};
141
142 /**
143 * Static class array used when the SecurityManager is turned on and
144 * <code>service</code> is invoked.
145 */
146 private static Class[] classTypeUsedInService = new Class[]{
147 ServletRequest.class,
148 ServletResponse.class};
149
150 /**
151 * Static class array used when the SecurityManager is turned on and
152 * <code>doFilterEvent</code> is invoked.
153 */
154 private static Class[] cometClassType =
155 new Class[]{ CometEvent.class, CometFilterChain.class};
156
157 /**
158 * Static class array used when the SecurityManager is turned on and
159 * <code>event</code> is invoked.
160 */
161 private static Class[] classTypeUsedInEvent =
162 new Class[] { CometEvent.class };
163
164 // ---------------------------------------------------- FilterChain Methods
165
166
167 /**
168 * Invoke the next filter in this chain, passing the specified request
169 * and response. If there are no more filters in this chain, invoke
170 * the <code>service()</code> method of the servlet itself.
171 *
172 * @param request The servlet request we are processing
173 * @param response The servlet response we are creating
174 *
175 * @exception IOException if an input/output error occurs
176 * @exception ServletException if a servlet exception occurs
177 */
178 public void doFilter(ServletRequest request, ServletResponse response)
179 throws IOException, ServletException {
180
181 if( Globals.IS_SECURITY_ENABLED ) {
182 final ServletRequest req = request;
183 final ServletResponse res = response;
184 try {
185 java.security.AccessController.doPrivileged(
186 new java.security.PrivilegedExceptionAction() {
187 public Object run()
188 throws ServletException, IOException {
189 internalDoFilter(req,res);
190 return null;
191 }
192 }
193 );
194 } catch( PrivilegedActionException pe) {
195 Exception e = pe.getException();
196 if (e instanceof ServletException)
197 throw (ServletException) e;
198 else if (e instanceof IOException)
199 throw (IOException) e;
200 else if (e instanceof RuntimeException)
201 throw (RuntimeException) e;
202 else
203 throw new ServletException(e.getMessage(), e);
204 }
205 } else {
206 internalDoFilter(request,response);
207 }
208 }
209
210 private void internalDoFilter(ServletRequest request,
211 ServletResponse response)
212 throws IOException, ServletException {
213
214 // Call the next filter if there is one
215 if (pos < n) {
216 ApplicationFilterConfig filterConfig = filters[pos++];
217 Filter filter = null;
218 try {
219 filter = filterConfig.getFilter();
220 support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
221 filter, request, response);
222
223 if( Globals.IS_SECURITY_ENABLED ) {
224 final ServletRequest req = request;
225 final ServletResponse res = response;
226 Principal principal =
227 ((HttpServletRequest) req).getUserPrincipal();
228
229 Object[] args = new Object[]{req, res, this};
230 SecurityUtil.doAsPrivilege
231 ("doFilter", filter, classType, args);
232
233 args = null;
234 } else {
235 filter.doFilter(request, response, this);
236 }
237
238 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
239 filter, request, response);
240 } catch (IOException e) {
241 if (filter != null)
242 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
243 filter, request, response, e);
244 throw e;
245 } catch (ServletException e) {
246 if (filter != null)
247 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
248 filter, request, response, e);
249 throw e;
250 } catch (RuntimeException e) {
251 if (filter != null)
252 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
253 filter, request, response, e);
254 throw e;
255 } catch (Throwable e) {
256 if (filter != null)
257 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
258 filter, request, response, e);
259 throw new ServletException
260 (sm.getString("filterChain.filter"), e);
261 }
262 return;
263 }
264
265 // We fell off the end of the chain -- call the servlet instance
266 try {
267 if (Globals.STRICT_SERVLET_COMPLIANCE) {
268 lastServicedRequest.set(request);
269 lastServicedResponse.set(response);
270 }
271
272 support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
273 servlet, request, response);
274 if ((request instanceof HttpServletRequest) &&
275 (response instanceof HttpServletResponse)) {
276
277 if( Globals.IS_SECURITY_ENABLED ) {
278 final ServletRequest req = request;
279 final ServletResponse res = response;
280 Principal principal =
281 ((HttpServletRequest) req).getUserPrincipal();
282 Object[] args = new Object[]{req, res};
283 SecurityUtil.doAsPrivilege("service",
284 servlet,
285 classTypeUsedInService,
286 args,
287 principal);
288 args = null;
289 } else {
290 servlet.service((HttpServletRequest) request,
291 (HttpServletResponse) response);
292 }
293 } else {
294 servlet.service(request, response);
295 }
296 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
297 servlet, request, response);
298 } catch (IOException e) {
299 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
300 servlet, request, response, e);
301 throw e;
302 } catch (ServletException e) {
303 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
304 servlet, request, response, e);
305 throw e;
306 } catch (RuntimeException e) {
307 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
308 servlet, request, response, e);
309 throw e;
310 } catch (Throwable e) {
311 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
312 servlet, request, response, e);
313 throw new ServletException
314 (sm.getString("filterChain.servlet"), e);
315 } finally {
316 if (Globals.STRICT_SERVLET_COMPLIANCE) {
317 lastServicedRequest.set(null);
318 lastServicedResponse.set(null);
319 }
320 }
321
322 }
323
324
325 /**
326 * Invoke the next filter in this chain, passing the specified request
327 * and response. If there are no more filters in this chain, invoke
328 * the <code>service()</code> method of the servlet itself.
329 *
330 * @param request The servlet request we are processing
331 * @param response The servlet response we are creating
332 *
333 * @exception IOException if an input/output error occurs
334 * @exception ServletException if a servlet exception occurs
335 */
336 public void doFilterEvent(CometEvent event)
337 throws IOException, ServletException {
338
339 if( Globals.IS_SECURITY_ENABLED ) {
340 final CometEvent ev = event;
341 try {
342 java.security.AccessController.doPrivileged(
343 new java.security.PrivilegedExceptionAction() {
344 public Object run()
345 throws ServletException, IOException {
346 internalDoFilterEvent(ev);
347 return null;
348 }
349 }
350 );
351 } catch( PrivilegedActionException pe) {
352 Exception e = pe.getException();
353 if (e instanceof ServletException)
354 throw (ServletException) e;
355 else if (e instanceof IOException)
356 throw (IOException) e;
357 else if (e instanceof RuntimeException)
358 throw (RuntimeException) e;
359 else
360 throw new ServletException(e.getMessage(), e);
361 }
362 } else {
363 internalDoFilterEvent(event);
364 }
365 }
366
367
368 /**
369 * The last request passed to a servlet for servicing from the current
370 * thread.
371 *
372 * @return The last request to be serviced.
373 */
374 public static ServletRequest getLastServicedRequest() {
375 return (ServletRequest) lastServicedRequest.get();
376 }
377
378
379 /**
380 * The last response passed to a servlet for servicing from the current
381 * thread.
382 *
383 * @return The last response to be serviced.
384 */
385 public static ServletResponse getLastServicedResponse() {
386 return (ServletResponse) lastServicedResponse.get();
387 }
388
389
390 private void internalDoFilterEvent(CometEvent event)
391 throws IOException, ServletException {
392
393 // Call the next filter if there is one
394 if (pos < n) {
395 ApplicationFilterConfig filterConfig = filters[pos++];
396 CometFilter filter = null;
397 try {
398 filter = (CometFilter) filterConfig.getFilter();
399 // FIXME: No instance listener processing for events for now
400 /*
401 support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT,
402 filter, event);
403 */
404
405 if( Globals.IS_SECURITY_ENABLED ) {
406 final CometEvent ev = event;
407 Principal principal =
408 ev.getHttpServletRequest().getUserPrincipal();
409
410 Object[] args = new Object[]{ev, this};
411 SecurityUtil.doAsPrivilege
412 ("doFilterEvent", (Filter) filter, cometClassType, args);
413
414 args = null;
415 } else {
416 filter.doFilterEvent(event, this);
417 }
418
419 /*support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
420 filter, event);*/
421 } catch (IOException e) {
422 /*
423 if (filter != null)
424 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
425 filter, event, e);
426 */
427 throw e;
428 } catch (ServletException e) {
429 /*
430 if (filter != null)
431 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
432 filter, event, e);
433 */
434 throw e;
435 } catch (RuntimeException e) {
436 /*
437 if (filter != null)
438 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
439 filter, event, e);
440 */
441 throw e;
442 } catch (Throwable e) {
443 /*if (filter != null)
444 support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT,
445 filter, event, e);*/
446 throw new ServletException
447 (sm.getString("filterChain.filter"), e);
448 }
449 return;
450 }
451
452 // We fell off the end of the chain -- call the servlet instance
453 try {
454 /*
455 support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT,
456 servlet, request, response);
457 */
458 if( Globals.IS_SECURITY_ENABLED ) {
459 final CometEvent ev = event;
460 Principal principal =
461 ev.getHttpServletRequest().getUserPrincipal();
462 Object[] args = new Object[]{ ev };
463 SecurityUtil.doAsPrivilege("event",
464 servlet,
465 classTypeUsedInEvent,
466 args,
467 principal);
468 args = null;
469 } else {
470 ((CometProcessor) servlet).event(event);
471 }
472 /*
473 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
474 servlet, request, response);*/
475 } catch (IOException e) {
476 /*
477 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
478 servlet, request, response, e);
479 */
480 throw e;
481 } catch (ServletException e) {
482 /*
483 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
484 servlet, request, response, e);
485 */
486 throw e;
487 } catch (RuntimeException e) {
488 /*
489 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
490 servlet, request, response, e);
491 */
492 throw e;
493 } catch (Throwable e) {
494 /*
495 support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT,
496 servlet, request, response, e);
497 */
498 throw new ServletException
499 (sm.getString("filterChain.servlet"), e);
500 }
501
502 }
503
504
505 // -------------------------------------------------------- Package Methods
506
507
508
509 /**
510 * Add a filter to the set of filters that will be executed in this chain.
511 *
512 * @param filterConfig The FilterConfig for the servlet to be executed
513 */
514 void addFilter(ApplicationFilterConfig filterConfig) {
515
516 if (n == filters.length) {
517 ApplicationFilterConfig[] newFilters =
518 new ApplicationFilterConfig[n + INCREMENT];
519 System.arraycopy(filters, 0, newFilters, 0, n);
520 filters = newFilters;
521 }
522 filters[n++] = filterConfig;
523
524 }
525
526
527 /**
528 * Release references to the filters and wrapper executed by this chain.
529 */
530 void release() {
531
532 for (int i = 0; i < n; i++) {
533 filters[i] = null;
534 }
535 n = 0;
536 pos = 0;
537 servlet = null;
538 support = null;
539
540 }
541
542
543 /**
544 * Prepare for reuse of the filters and wrapper executed by this chain.
545 */
546 void reuse() {
547 pos = 0;
548 }
549
550
551 /**
552 * Set the servlet that will be executed at the end of this chain.
553 *
554 * @param servlet The Wrapper for the servlet to be executed
555 */
556 void setServlet(Servlet servlet) {
557
558 this.servlet = servlet;
559
560 }
561
562
563 /**
564 * Set the InstanceSupport object used for event notifications
565 * for this filter chain.
566 *
567 * @param support The InstanceSupport object for our Wrapper
568 */
569 void setSupport(InstanceSupport support) {
570
571 this.support = support;
572
573 }
574
575
576 }