📄 requestdispatcherimpl.java
字号:
/* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * * [Additional notices, if required by prior licensing conditions] * */package org.apache.tomcat.facade;import org.apache.tomcat.core.*;import org.apache.tomcat.util.StringManager;import java.io.*;import java.util.*;import javax.servlet.*;import javax.servlet.http.*;/* This code needs a re-write, it's very ugly. The hardest problem is the requirement to pass the "same" request, but with small modifications. One solution is to use a facade ( was used in tomcat origianlly ). The current solution is to save the modified attributes and restore after the method returns. This saves one object creation - since the subRequest object still has to be created. The details are facade-specific, shouldn't affect the core.*//* We do a new sub-request for each include() or forward(). Even if today we take all decisions based only on path, that may change ( i.e. a request can take different paths based on authentication, headers, etc - other Interceptors may affect it), that means we need to call CM. I think this is the correct action - instead of doing a lookup when we construct the dispatcher. ( costin ) *//** * * * @author James Duncan Davidson [duncan@eng.sun.com] * @author Jason Hunter [jch@eng.sun.com] * @author James Todd [gonzo@eng.sun.com] * @author Alex Cruikshank [alex@epitonic.com] * @author costin@dnt.ro */final class RequestDispatcherImpl implements RequestDispatcher { // Use the strings from core private static StringManager sm = StringManager. getManager("org.apache.tomcat.core"); Context context; // path dispatchers String path; String queryString; // name dispatchers String name; /** Used for Context.getRD( path ) */ public RequestDispatcherImpl(Context context) { this.context = context; } public void setPath( String urlPath ) { // separate the query string int i = urlPath.indexOf("?"); if( i<0 ) this.path=urlPath; else { this.path=urlPath.substring( 0,i ); int len=urlPath.length(); if( i< len ) this.queryString =urlPath.substring(i + 1); } } public void setName( String name ) { this.name=name; } // -------------------- Public methods -------------------- public void forward(ServletRequest request, ServletResponse response) throws ServletException, IOException { /** We need to find the request/response. The servlet API * guarantees that we will receive the original request as parameter. */ Request realRequest = ((HttpServletRequestFacade)request). getRealRequest(); Response realResponse = realRequest.getResponse(); // according to specs (as of 2.2: started is OK, just not committed) if (realResponse.isBufferCommitted()) throw new IllegalStateException(sm.getString("rdi.forward.ise")); // reset the output buffer but not the headers and cookies realResponse.resetBuffer(); // the strange case in a separate method. if( name!=null) { forwardNamed( request, response ); return; } // from strange spec reasons, forward and include are very different in // the way they process the request - if you don't understand the code // try to understand the spec. // in forward case, the Path parametrs of the request are what you // expect, so we just do a new processRequest on the modified request // set the context - no need to fire context parsing again realRequest.setContext( context ); realRequest.setRequestURI( context.getPath() + path ); // merge query string as specified in specs - before, it may affect // the way the request is handled by special interceptors if( queryString != null ) addQueryString( realRequest, queryString ); // run the new request through the context manager // not that this is a very particular case of forwarding context.getContextManager().processRequest(realRequest); // unset "included" attribute if any - we may be in a servlet // included from another servlet, // in which case the attribute will create problems realRequest.removeAttribute( "javax.servlet.include.request_uri"); realRequest.removeAttribute( "javax.servlet.include.servlet_path"); // CM should have set the wrapper - call it ServletWrapper wr=realRequest.getWrapper(); Throwable t = null; if( wr != null ) { try { wr.service(realRequest, realResponse); } catch (Throwable t1) { t = t1; } } // Clean up the request and response as needed ; // No action required // Rethrow any exception thrown by the forwarded-to servlet if (t != null) { if (t instanceof IOException) throw (IOException) t; else if (t instanceof ServletException) throw (ServletException) t; else throw new ServletException (sm.getString("dispatcher.forwardException", t)); } // close the response - output after this point will be discarded. realResponse.finish(); } public void include(ServletRequest request, ServletResponse response) throws ServletException, IOException { Request realRequest = ((HttpServletRequestFacade)request). getRealRequest(); Response realResponse = realRequest.getResponse(); // the strange case in a separate method if( name!=null) { includeNamed( request, response ); return; } // Add an unspecified response.flushBuffer() call to work around // a fundamental problem in the way that the session interceptor // works. If we do not do this, the session cookie gets dropped (!) // if the first flush of the buffer happens inside an included // servlet. This occurs because the session interceptor uses the // normal response.addHeader() method to add the cookie -- but such // header changes are suppressed inside an included servlet. // (Reference: BugRat bug report #316) // // NOTE: This *must* be done before the include flag is set for // this request! response.flushBuffer(); // Implement the spec that "no changes in response, only write" // can also be done by setting the response to 0.9 mode // IncludedResponse iResponse = new IncludedResponse(realResponse); boolean old_included=realResponse.isIncluded(); if( ! old_included ) { realResponse.setIncluded( true ); } // Here the spec is very special, pay attention // We need to pass the original request, with all the paths - // and the new paths in special attributes. // We still need to find out where do we want to go ( today ) // That means we create a subRequest with the new paths ( since // the mapping and aliasing is done on Requests), and run it // through prepare. // That also means that some special cases ( like the invoker !! ) // will have to pay attention to the attributes, or we'll get a loop Request subRequest=context.getContextManager(). createRequest( context, path ); subRequest.setParent( realRequest ); subRequest.getTop(); // control inclusion depth // I hope no interceptor (or code) in processRequest use any // of the original request info ( like Auth headers ) // // XXX We need to clone the request, so that processRequest can // make an informed mapping ( Auth, Authorization, etc) // // This will never work corectly unless we do a full clone - but
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -