001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.webapp;
031:
032: import com.caucho.server.connection.AbstractHttpResponse;
033: import com.caucho.server.connection.AbstractResponseStream;
034: import com.caucho.server.connection.CauchoRequest;
035: import com.caucho.server.connection.CauchoResponse;
036: import com.caucho.server.dispatch.Invocation;
037: import com.caucho.util.L10N;
038:
039: import javax.servlet.RequestDispatcher;
040: import javax.servlet.ServletException;
041: import javax.servlet.ServletRequest;
042: import javax.servlet.ServletResponse;
043: import javax.servlet.http.HttpServletRequest;
044: import javax.servlet.http.HttpServletRequestWrapper;
045: import javax.servlet.http.HttpServletResponse;
046: import javax.servlet.http.HttpServletResponseWrapper;
047: import javax.servlet.http.HttpSession;
048: import java.io.IOException;
049: import java.io.OutputStream;
050: import java.io.PrintWriter;
051:
052: public class RequestDispatcherImpl implements RequestDispatcher {
053: private static final L10N L = new L10N(RequestDispatcherImpl.class);
054:
055: private static final String REQUEST_URI = "javax.servlet.include.request_uri";
056: private static final String CONTEXT_PATH = "javax.servlet.include.context_path";
057: private static final String SERVLET_PATH = "javax.servlet.include.servlet_path";
058: private static final String PATH_INFO = "javax.servlet.include.path_info";
059: private static final String QUERY_STRING = "javax.servlet.include.query_string";
060:
061: private static final String FWD_REQUEST_URI = "javax.servlet.forward.request_uri";
062: private static final String FWD_CONTEXT_PATH = "javax.servlet.forward.context_path";
063: private static final String FWD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
064: private static final String FWD_PATH_INFO = "javax.servlet.forward.path_info";
065: private static final String FWD_QUERY_STRING = "javax.servlet.forward.query_string";
066:
067: // WebApp the request dispatcher was called from
068: private WebApp _webApp;
069: private Invocation _includeInvocation;
070: private Invocation _forwardInvocation;
071: private Invocation _errorInvocation;
072: private boolean _isLogin;
073:
074: RequestDispatcherImpl(Invocation includeInvocation,
075: Invocation forwardInvocation, Invocation errorInvocation,
076: WebApp webApp) {
077: _includeInvocation = includeInvocation;
078: _forwardInvocation = forwardInvocation;
079: _errorInvocation = errorInvocation;
080: _webApp = webApp;
081: }
082:
083: public void setLogin(boolean isLogin) {
084: _isLogin = isLogin;
085: }
086:
087: public boolean isModified() {
088: return _includeInvocation.isModified();
089: }
090:
091: public void forward(ServletRequest request, ServletResponse response)
092: throws ServletException, IOException {
093: forward((HttpServletRequest) request,
094: (HttpServletResponse) response, null,
095: _forwardInvocation);
096: }
097:
098: public void error(ServletRequest request, ServletResponse response)
099: throws ServletException, IOException {
100: forward((HttpServletRequest) request,
101: (HttpServletResponse) response, "error",
102: _errorInvocation);
103: }
104:
105: /**
106: * Forwards the request to the servlet named by the request dispatcher.
107: *
108: * @param req the servlet request.
109: * @param res the servlet response.
110: * @param method special to tell if from error.
111: */
112: public void forward(HttpServletRequest req,
113: HttpServletResponse res, String method,
114: Invocation invocation) throws ServletException, IOException {
115: AbstractHttpResponse response = null;
116: DispatchRequest subRequest;
117: HttpSession session = null;
118:
119: CauchoResponse cauchoRes = null;
120:
121: if (res instanceof CauchoResponse)
122: cauchoRes = (CauchoResponse) res;
123:
124: if (res.isCommitted() && method == null) {
125: IllegalStateException exn;
126: exn = new IllegalStateException(
127: "forward() not allowed after buffer has committed.");
128:
129: if (cauchoRes == null || !cauchoRes.hasError()) {
130: if (cauchoRes != null)
131: cauchoRes.setHasError(true);
132: throw exn;
133: }
134:
135: _webApp.log(exn.getMessage(), exn);
136: }
137:
138: if (res instanceof AbstractHttpResponse)
139: response = (AbstractHttpResponse) res;
140:
141: ServletResponse resPtr = res;
142:
143: if (method == null || "error".equals(method))
144: method = req.getMethod();
145:
146: subRequest = DispatchRequest.createDispatch();
147:
148: HttpServletRequest parentRequest = req;
149: HttpServletRequestWrapper reqWrapper = null;
150: HttpServletRequest topRequest = subRequest;
151:
152: if (!(req instanceof CauchoRequest))
153: topRequest = req;
154:
155: while (parentRequest instanceof HttpServletRequestWrapper
156: && !(parentRequest instanceof CauchoRequest)) {
157: reqWrapper = (HttpServletRequestWrapper) parentRequest;
158: parentRequest = (HttpServletRequest) reqWrapper
159: .getRequest();
160: }
161:
162: String newQueryString = invocation.getQueryString();
163: String reqQueryString = req.getQueryString();
164:
165: String queryString;
166:
167: /* Changed to match tomcat */
168: // server/10y3
169: if (_isLogin)
170: queryString = newQueryString;
171: else if (reqQueryString == null)
172: queryString = newQueryString;
173: else if (newQueryString == null)
174: queryString = reqQueryString;
175: else if (reqQueryString.equals(newQueryString))
176: queryString = newQueryString;
177: /*
178: else
179: queryString = newQueryString + '&' + reqQueryString;
180: */
181: else
182: queryString = newQueryString;
183:
184: WebApp oldWebApp;
185:
186: if (req instanceof CauchoRequest)
187: oldWebApp = ((CauchoRequest) req).getWebApp();
188: else
189: oldWebApp = (WebApp) _webApp.getContext(req
190: .getContextPath());
191:
192: subRequest.init(invocation, invocation.getWebApp(), oldWebApp,
193: parentRequest, res, method, invocation.getURI(),
194: invocation.getServletPath(), invocation.getPathInfo(),
195: queryString, newQueryString);
196:
197: if (reqWrapper != null) {
198: reqWrapper.setRequest(subRequest);
199:
200: if (topRequest == parentRequest) // server/172o
201: topRequest = reqWrapper;
202: }
203:
204: Object oldUri = null;
205: Object oldContextPath = null;
206: Object oldServletPath = null;
207: Object oldPathInfo = null;
208: Object oldQueryString = null;
209: Object oldJSPFile = null;
210: Object oldForward = null;
211:
212: oldUri = req.getAttribute(REQUEST_URI);
213:
214: if (oldUri != null) {
215: oldContextPath = req.getAttribute(CONTEXT_PATH);
216: oldServletPath = req.getAttribute(SERVLET_PATH);
217: oldPathInfo = req.getAttribute(PATH_INFO);
218: oldQueryString = req.getAttribute(QUERY_STRING);
219:
220: req.removeAttribute(REQUEST_URI);
221: req.removeAttribute(CONTEXT_PATH);
222: req.removeAttribute(SERVLET_PATH);
223: req.removeAttribute(PATH_INFO);
224: req.removeAttribute(QUERY_STRING);
225: req.removeAttribute("caucho.jsp.jsp-file");
226: }
227:
228: if (req.getAttribute(FWD_REQUEST_URI) == null) {
229: subRequest.setAttribute(FWD_REQUEST_URI, req
230: .getRequestURI());
231: subRequest.setAttribute(FWD_CONTEXT_PATH, req
232: .getContextPath());
233: subRequest.setAttribute(FWD_SERVLET_PATH, req
234: .getServletPath());
235: subRequest.setAttribute(FWD_PATH_INFO, req.getPathInfo());
236: subRequest.setAttribute(FWD_QUERY_STRING, req
237: .getQueryString());
238: }
239:
240: oldForward = req.getAttribute("caucho.forward");
241: req.setAttribute("caucho.forward", "true");
242:
243: subRequest.setPageURI(subRequest.getRequestURI());
244: subRequest.setPageContextPath(subRequest.getContextPath());
245: subRequest.setPageServletPath(subRequest.getServletPath());
246: subRequest.setPagePathInfo(subRequest.getPathInfo());
247: subRequest.setPageQueryString(subRequest.getQueryString());
248:
249: CauchoRequest oldRequest = null;
250: AbstractResponseStream oldStream = null;
251: if (response != null) {
252: oldRequest = response.getRequest();
253: oldStream = response.getResponseStream();
254: }
255:
256: Thread thread = Thread.currentThread();
257: ClassLoader oldLoader = thread.getContextClassLoader();
258:
259: try {
260: if (response != null) {
261: response.setRequest(subRequest);
262: response
263: .setResponseStream(response.getOriginalStream());
264: }
265:
266: res.resetBuffer();
267: res.setContentLength(-1);
268:
269: invocation.service(topRequest, res);
270:
271: if (cauchoRes != null)
272: cauchoRes.close();
273: else {
274: // server/10ab
275: try {
276: PrintWriter out = res.getWriter();
277: if (out != null)
278: out.close();
279: } catch (IllegalStateException e1) {
280: }
281:
282: try {
283: OutputStream os = res.getOutputStream();
284: if (os != null)
285: os.close();
286: } catch (IllegalStateException e) {
287: }
288:
289: // server/1732 wants this commented out
290: /*
291: // TCK wants the code (test?)
292: ServletResponse ptr = res;
293: while (ptr instanceof HttpServletResponseWrapper) {
294: ptr = ((HttpServletResponseWrapper) ptr).getResponse();
295:
296: if (ptr instanceof AbstractHttpResponse) {
297: ((AbstractHttpResponse) ptr).finish();
298: break;
299: }
300: }
301: */
302: }
303: } finally {
304: subRequest.finish();
305:
306: thread.setContextClassLoader(oldLoader);
307:
308: if (response != null) {
309: response.setRequest(oldRequest);
310: response.setResponseStream(oldStream);
311: //response.setWriter(oldWriter);
312: }
313:
314: DispatchRequest.free(subRequest);
315:
316: if (reqWrapper != null)
317: reqWrapper.setRequest(parentRequest);
318:
319: // XXX: are these necessary?
320: if (oldUri != null)
321: req.setAttribute(REQUEST_URI, oldUri);
322:
323: if (oldContextPath != null)
324: req.setAttribute(CONTEXT_PATH, oldContextPath);
325:
326: if (oldServletPath != null)
327: req.setAttribute(SERVLET_PATH, oldServletPath);
328:
329: if (oldPathInfo != null)
330: req.setAttribute(PATH_INFO, oldPathInfo);
331:
332: if (oldQueryString != null)
333: req.setAttribute(QUERY_STRING, oldQueryString);
334:
335: if (oldForward == null)
336: req.removeAttribute("caucho.forward");
337: }
338: }
339:
340: public void include(ServletRequest request, ServletResponse response)
341: throws ServletException, IOException {
342: include(request, response, null);
343: }
344:
345: /**
346: * Include a request into the current page.
347: */
348: public void include(ServletRequest request,
349: ServletResponse response, String method)
350: throws ServletException, IOException {
351: HttpServletRequest req = (HttpServletRequest) request;
352: HttpServletResponse res = (HttpServletResponse) response;
353:
354: IncludeDispatchRequest subRequest;
355: DispatchResponse subResponse;
356:
357: Invocation invocation = _includeInvocation;
358: WebApp webApp = invocation.getWebApp();
359: String queryString = invocation.getQueryString();
360:
361: if (method == null)
362: method = req.getMethod();
363:
364: if (!"POST".equals(method))
365: method = "GET";
366:
367: HttpServletRequest parentRequest = req;
368: HttpServletRequestWrapper reqWrapper = null;
369:
370: HttpServletResponse parentResponse = res;
371: HttpServletResponseWrapper resWrapper = null;
372:
373: if (!_webApp.getDispatchWrapsFilters()) {
374: if (req instanceof HttpServletRequestWrapper
375: && !(req instanceof CauchoRequest)) {
376: reqWrapper = (HttpServletRequestWrapper) req;
377: parentRequest = (HttpServletRequest) reqWrapper
378: .getRequest();
379: }
380:
381: if (res instanceof HttpServletResponseWrapper
382: && !(res instanceof CauchoResponse)) {
383: resWrapper = (HttpServletResponseWrapper) res;
384: parentResponse = (HttpServletResponse) resWrapper
385: .getResponse();
386: }
387: }
388:
389: subRequest = IncludeDispatchRequest.createDispatch();
390:
391: WebApp oldWebApp;
392:
393: if (req instanceof CauchoRequest)
394: oldWebApp = ((CauchoRequest) req).getWebApp();
395: else
396: oldWebApp = (WebApp) webApp
397: .getContext(req.getContextPath());
398:
399: subRequest.init(invocation, webApp, oldWebApp, parentRequest,
400: parentResponse, method, req.getRequestURI(), req
401: .getServletPath(), req.getPathInfo(), req
402: .getQueryString(), queryString);
403:
404: HttpServletRequest topRequest = subRequest;
405:
406: if (reqWrapper != null) {
407: reqWrapper.setRequest(subRequest);
408: topRequest = reqWrapper;
409: }
410:
411: subResponse = DispatchResponse.createDispatch();
412: subResponse.setNextResponse(res);
413:
414: AbstractResponseStream s = null;
415: boolean oldDisableClose = false;
416:
417: subResponse.init(subRequest);
418: subResponse.setNextResponse(parentResponse);
419: subResponse.start();
420: subResponse.setCharacterEncoding(res.getCharacterEncoding());
421:
422: if (_webApp.getDispatchWrapsFilters())
423: subResponse.setCauchoResponseStream(true);
424:
425: CauchoResponse cauchoRes = null;
426: if (res instanceof CauchoResponse) {
427: cauchoRes = (CauchoResponse) res;
428: } else if (!_webApp.getDispatchWrapsFilters()) {
429: subResponse.killCache();
430: }
431:
432: HttpServletResponse topResponse = subResponse;
433:
434: if (resWrapper != null) {
435: resWrapper.setResponse(subResponse);
436: topResponse = res;
437: }
438:
439: Object oldUri = null;
440: Object oldContextPath = null;
441: Object oldServletPath = null;
442: Object oldPathInfo = null;
443: Object oldQueryString = null;
444:
445: oldUri = req.getAttribute(REQUEST_URI);
446: if (oldUri != null) {
447: oldContextPath = request.getAttribute(CONTEXT_PATH);
448: oldServletPath = req.getAttribute(SERVLET_PATH);
449: oldPathInfo = req.getAttribute(PATH_INFO);
450: oldQueryString = req.getAttribute(QUERY_STRING);
451: }
452:
453: subRequest.setPageURI(invocation.getURI());
454: subRequest.setAttribute(REQUEST_URI, invocation.getURI());
455: String contextPath;
456: if (webApp != null)
457: contextPath = webApp.getContextPath();
458: else
459: contextPath = null;
460:
461: subRequest.setPageContextPath(contextPath);
462: subRequest.setAttribute(CONTEXT_PATH, contextPath);
463: subRequest.setPageServletPath(invocation.getServletPath());
464: subRequest.setAttribute(SERVLET_PATH, invocation
465: .getServletPath());
466: subRequest.setPagePathInfo(invocation.getPathInfo());
467: subRequest.setAttribute(PATH_INFO, invocation.getPathInfo());
468: subRequest.setPageQueryString(queryString);
469: subRequest.setAttribute(QUERY_STRING, queryString);
470:
471: subRequest.removeAttribute("caucho.jsp.jsp-file");
472:
473: Thread thread = Thread.currentThread();
474: ClassLoader oldLoader = thread.getContextClassLoader();
475: boolean isOkay = false;
476: try {
477: invocation.service(topRequest, topResponse);
478: isOkay = true;
479: } finally {
480: thread.setContextClassLoader(oldLoader);
481: // XXX: In many cases, able to use clear()?
482:
483: subRequest.finish();
484:
485: /* XXX:
486: if (s != null)
487: s.setDisableClose(oldDisableClose);
488: */
489: if (oldUri != null)
490: req.setAttribute(REQUEST_URI, oldUri);
491: else
492: req.removeAttribute(REQUEST_URI);
493:
494: if (oldContextPath != null)
495: req.setAttribute(CONTEXT_PATH, oldContextPath);
496: else
497: req.removeAttribute(CONTEXT_PATH);
498:
499: if (oldServletPath != null)
500: req.setAttribute(SERVLET_PATH, oldServletPath);
501: else
502: req.removeAttribute(SERVLET_PATH);
503:
504: if (oldPathInfo != null)
505: req.setAttribute(PATH_INFO, oldPathInfo);
506: else
507: req.removeAttribute(PATH_INFO);
508:
509: if (oldQueryString != null)
510: req.setAttribute(QUERY_STRING, oldQueryString);
511: else
512: req.removeAttribute(QUERY_STRING);
513:
514: if (!isOkay)
515: subResponse.killCache();
516:
517: subResponse.close();
518:
519: /*
520: if (! (res instanceof CauchoResponse)) {
521: if (s != null)
522: s.close();
523: }
524: */
525:
526: IncludeDispatchRequest.free(subRequest);
527: DispatchResponse.free(subResponse);
528:
529: if (reqWrapper != null)
530: reqWrapper.setRequest(parentRequest);
531:
532: if (resWrapper != null)
533: resWrapper.setResponse(parentResponse);
534: }
535: }
536: }
|