专栏名称: 预流
敲代码的
目录
相关文章推荐
极光新闻 东北网  ·  多家银行集体宣布:下调! ·  19 小时前  
极光新闻 东北网  ·  多家银行集体宣布:下调! ·  19 小时前  
中国人民银行  ·  李强对全国春季农业生产工作作出重要批示强调 ... ·  2 天前  
中国人民银行  ·  今日春分 ·  3 天前  
51好读  ›  专栏  ›  预流

Tomcat 7 的一次请求分析(三)请求与容器中具体组件的匹配

预流  · 掘金  ·  · 2018-02-03 14:49

正文

上文 分析到了 org.apache.coyote.http11.AbstractHttp11Processor 类 process 方法,以解析请求头的 getInputBuffer().parseRequestLine 方法调用为例,看到如何从 Socket 的 IO 流中取出字节流数据,根据 Http 协议将字节流组装到 Tomcat 内部的 org.apache.coyote.Request 对象的相关属性中。

接下来将会解释构造好的 Tomcat 的内部请求对象从 Connector 到 Engine 到 Host 到 Context 最后到 Servlet 的过程。 回到 org.apache.coyote.http11.AbstractHttp11Processor 类 process 方法的源码:


     1	    public SocketState process(SocketWrapper<S> socketWrapper)
     2	        throws IOException {
     3	        RequestInfo rp = request.getRequestProcessor();
     4	        rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
     5	
     6	        // Setting up the I/O
     7	        setSocketWrapper(socketWrapper);
     8	        getInputBuffer().init(socketWrapper, endpoint);
     9	        getOutputBuffer().init(socketWrapper, endpoint);
    10	
    11	        // Flags
    12	        error = false;
    13	        keepAlive = true;
    14	        comet = false;
    15	        openSocket = false;
    16	        sendfileInProgress = false;
    17	        readComplete = true;
    18	        if (endpoint.getUsePolling()) {
    19	            keptAlive = false;
    20	        } else {
    21	            keptAlive = socketWrapper.isKeptAlive();
    22	        }
    23	
    24	        if (disableKeepAlive()) {
    25	            socketWrapper.setKeepAliveLeft(0);
    26	        }
    27	
    28	        while (!error && keepAlive && !comet && !isAsync() &&
    29	                upgradeInbound == null && !endpoint.isPaused()) {
    30	
    31	            // Parsing the request header
    32	            try {
    33	                setRequestLineReadTimeout();
    34	
    35	                if (!getInputBuffer().parseRequestLine(keptAlive)) {
    36	                    if (handleIncompleteRequestLineRead()) {
    37	                        break;
    38	                    }
    39	                }
    40	
    41	                if (endpoint.isPaused()) {
    42	                    // 503 - Service unavailable
    43	                    response.setStatus(503);
    44	                    error = true;
    45	                } else {
    46	                    // Make sure that connectors that are non-blocking during
    47	                    // header processing (NIO) only set the start time the first
    48	                    // time a request is processed.
    49	                    if (request.getStartTime() < 0) {
    50	                        request.setStartTime(System.currentTimeMillis());
    51	                    }
    52	                    keptAlive = true;
    53	                    // Set this every time in case limit has been changed via JMX
    54	                    request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
    55	                    // Currently only NIO will ever return false here
    56	                    if (!getInputBuffer().parseHeaders()) {
    57	                        // We've read part of the request, don't recycle it
    58	                        // instead associate it with the socket
    59	                        openSocket = true;
    60	                        readComplete = false;
    61	                        break;
    62	                    }
    63	                    if (!disableUploadTimeout) {
    64	                        setSocketTimeout(connectionUploadTimeout);
    65	                    }
    66	                }
    67	            } catch (IOException e) {
    68	                if (getLog().isDebugEnabled()) {
    69	                    getLog().debug(
    70	                            sm.getString("http11processor.header.parse"), e);
    71	                }
    72	                error = true;
    73	                break;
    74	            } catch (Throwable t) {
    75	                ExceptionUtils.handleThrowable(t);
    76	                UserDataHelper.Mode logMode = userDataHelper.getNextMode();
    77	                if (logMode != null) {
    78	                    String message = sm.getString(
    79	                            "http11processor.header.parse");
    80	                    switch (logMode) {
    81	                        case INFO_THEN_DEBUG:
    82	                            message += sm.getString(
    83	                                    "http11processor.fallToDebug");
    84	                            //$FALL-THROUGH$
    85	                        case INFO:
    86	                            getLog().info(message);
    87	                            break;
    88	                        case DEBUG:
    89	                            getLog().debug(message);
    90	                    }
    91	                }
    92	                // 400 - Bad Request
    93	                response.setStatus(400);
    94	                adapter.log(request, response, 0);
    95	                error = true;
    96	            }
    97	
    98	            if (!error) {
    99	                // Setting up filters, and parse some request headers
   100	                rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
   101	                try {
   102	                    prepareRequest();
   103	                } catch (Throwable t) {
   104	                    ExceptionUtils.handleThrowable(t);
   105	                    if (getLog().isDebugEnabled()) {
   106	                        getLog().debug(sm.getString(
   107	                                "http11processor.request.prepare"), t);
   108	                    }
   109	                    // 400 - Internal Server Error
   110	                    response.setStatus(400);
   111	                    adapter.log(request, response, 0);
   112	                    error = true;
   113	                }
   114	            }
   115	
   116	            if (maxKeepAliveRequests == 1) {
   117	                keepAlive = false;
   118	            } else if (maxKeepAliveRequests > 0 &&
   119	                    socketWrapper.decrementKeepAlive() <= 0) {
   120	                keepAlive = false;
   121	            }
   122	
   123	            // Process the request in the adapter
   124	            if (!error) {
   125	                try {
   126	                    rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
   127	                    adapter.service(request, response);
   128	                    // Handle when the response was committed before a serious
   129	                    // error occurred.  Throwing a ServletException should both
   130	                    // set the status to 500 and set the errorException.
   131	                    // If we fail here, then the response is likely already
   132	                    // committed, so we can't try and set headers.
   133	                    if(keepAlive && !error) { // Avoid checking twice.
   134	                        error = response.getErrorException() != null ||
   135	                                (!isAsync() &&
   136	                                statusDropsConnection(response.getStatus()));
   137	                    }
   138	                    setCometTimeouts(socketWrapper);
   139	                } catch (InterruptedIOException e) {
   140	                    error = true;
   141	                } catch (HeadersTooLargeException e) {
   142	                    error = true;
   143	                    // The response should not have been committed but check it
   144	                    // anyway to be safe
   145	                    if (!response.isCommitted()) {
   146	                        response.reset();
   147	                        response.setStatus(500);
   148	                        response.setHeader("Connection", "close");
   149	                    }
   150	                } catch (Throwable t) {
   151	                    ExceptionUtils.handleThrowable(t);
   152	                    getLog().error(sm.getString(
   153	                            "http11processor.request.process"), t);
   154	                    // 500 - Internal Server Error
   155	                    response.setStatus(500);
   156	                    adapter.log(request, response, 0);
   157	                    error = true;
   158	                }
   159	            }
   160	
   161	            // Finish the handling of the request
   162	            rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
   163	
   164	            if (!isAsync() && !comet) {
   165	                if (error) {
   166	                    // If we know we are closing the connection, don't drain
   167	                    // input. This way uploading a 100GB file doesn't tie up the
   168	                    // thread if the servlet has rejected it.
   169	                    getInputBuffer().setSwallowInput(false);
   170	                }
   171	                endRequest();
   172	            }
   173	
   174	            rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
   175	
   176	            // If there was an error, make sure the request is counted as
   177	            // and error, and update the statistics counter
   178	            if (error) {
   179	                response.setStatus(500);
   180	            }
   181	            request.updateCounters();
   182	
   183	            if (!isAsync() && !comet || error) {
   184	                getInputBuffer().nextRequest();
   185	                getOutputBuffer().nextRequest();
   186	            }
   187	
   188	            if (!disableUploadTimeout) {
   189	                if(endpoint.getSoTimeout() > 0) {
   190	                    setSocketTimeout(endpoint.getSoTimeout());
   191	                } else {
   192	                    setSocketTimeout(0);
   193	                }
   194	            }
   195	
   196	            rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
   197	
   198	            if (breakKeepAliveLoop(socketWrapper)) {
   199	                break;
   200	            }
   201	        }
   202	
   203	        rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
   204	
   205	        if (error || endpoint.isPaused()) {
   206	            return SocketState.CLOSED;
   207	        } else if (isAsync() || comet) {
   208	            return SocketState.LONG;
   209	        } else if (isUpgrade()) {
   210	            return SocketState.UPGRADING;
   211	        } else {
   212	            if (sendfileInProgress) {
   213	                return SocketState.SENDFILE;
   214	            } else {
   215	                if (openSocket) {
   216	                    if (readComplete) {
   217	                        return SocketState.OPEN;
   218	                    } else {
   219	                        return SocketState.LONG;
   220	                    }
   221	                } else {
   222	                    return SocketState.CLOSED;
   223	                }
   224	            }
   225	        }
   226	    }

概述一下这个方法做的事情:第 3 到 26 行主要是在初始化变量。关注接下来一大段的 while 循环里面的代码,第 31 到 121 行在解析请求头,第 123 到 159 行将请求交由适配器( adapter )处理,第 161 到 200 行结束请求的处理(做一些收尾工作,比如废弃剩下的无意义字节流数据,设置相应状态码等)。

请求对象在容器中的流转在第 127 行:

adapter.service(request, response);

这里的 adapter 对象是在 Http11Processor 对象创建的时候设置的,见 org.apache.coyote.http11.Http11Protocol.Http11ConnectionHandler 类的 createProcessor 方法:

     1	        protected Http11Processor createProcessor() {
     2	            Http11Processor processor = new Http11Processor(
     3	                    proto.getMaxHttpHeaderSize(), (JIoEndpoint)proto.endpoint,
     4	                    proto.getMaxTrailerSize());
     5	            processor.setAdapter(proto.adapter);
     6	            processor.setMaxKeepAliveRequests(proto.getMaxKeepAliveRequests());
     7	            processor.setKeepAliveTimeout(proto.getKeepAliveTimeout());
     8	            processor.setConnectionUploadTimeout(
     9	                    proto.getConnectionUploadTimeout());
    10	            processor.setDisableUploadTimeout(proto.getDisableUploadTimeout());
    11	            processor.setCompressionMinSize(proto.getCompressionMinSize());
    12	            processor.setCompression(proto.getCompression());
    13	            processor.setNoCompressionUserAgents(proto.getNoCompressionUserAgents());
    14	            processor.setCompressableMimeTypes(proto.getCompressableMimeTypes());
    15	            processor.setRestrictedUserAgents(proto.getRestrictedUserAgents());
    16	            processor.setSocketBuffer(proto.getSocketBuffer());
    17	            processor.setMaxSavePostSize(proto.getMaxSavePostSize());
    18	            processor.setServer(proto.getServer());
    19	            processor.setDisableKeepAlivePercentage(
    20	                    proto.getDisableKeepAlivePercentage());
    21	            register(processor);
    22	            return processor;
    23	        }    }

可以看到 adapter 对象设置的是 org.apache.coyote.http11.Http11Protocol 的 adapter 变量,而该变量是在 Connector 类的 initInternal 方法中设值的:

     1	    protected void initInternal() throws LifecycleException {
     2	
     3	        super.initInternal();
     4	
     5	        // Initialize adapter
     6	        adapter = new CoyoteAdapter(this);
     7	        protocolHandler.setAdapter(adapter);
     8	
     9	        // Make sure parseBodyMethodsSet has a default
    10	        if( null == parseBodyMethodsSet ) {
    11	            setParseBodyMethods(getParseBodyMethods());
    12	        }
    13	
    14	        if (protocolHandler.isAprRequired() &&
    15	                !AprLifecycleListener.isAprAvailable()) {
    16	            throw new LifecycleException(
    17	                    sm.getString("coyoteConnector.protocolHandlerNoApr",
    18	                            getProtocolHandlerClassName()));
    19	        }
    20	
    21	        try {
    22	            protocolHandler.init();
    23	        } catch (Exception e) {
    24	            throw new LifecycleException
    25	                (sm.getString
    26	                 ("coyoteConnector.protocolHandlerInitializationFailed"), e);
    27	        }
    28	
    29	        // Initialize mapper listener
    30	        mapperListener.init();
    31	    }

第 6、7 行就是初始化 adapter 对象并设值到 Http11Protocol 对象中的。

所以上面看到的 adapter.service(request, response) 方法实际执行的是 org.apache.catalina.connector.CoyoteAdapter 类的 service 方法:

     1	    public void service(org.apache.coyote.Request req,
     2	                        org.apache.coyote.Response res)
     3	        throws Exception {
     4	
     5	        Request request = (Request) req.getNote(ADAPTER_NOTES);
     6	        Response response = (Response) res.getNote(ADAPTER_NOTES);
     7	
     8	        if (request == null) {
     9	
    10	            // Create objects
    11	            request = connector.createRequest();
    12	            request.setCoyoteRequest(req);
    13	            response = connector.createResponse();
    14	            response.setCoyoteResponse(res);
    15	
    16	            // Link objects
    17	            request.setResponse(response);
    18	            response.setRequest(request);
    19	
    20	            // Set as notes
    21	            req.setNote(ADAPTER_NOTES, request);
    22	            res.setNote(ADAPTER_NOTES, response);
    23	
    24	            // Set query string encoding
    25	            req.getParameters().setQueryStringEncoding
    26	                (connector.getURIEncoding());
    27	
    28	        }
    29	
    30	        if (connector.getXpoweredBy()) {
    31	            response.addHeader("X-Powered-By", POWERED_BY);
    32	        }
    33	
    34	        boolean comet = false;
    35	        boolean async = false;
    36	
    37	        try {
    38	
    39	            // Parse and set Catalina and configuration specific
    40	            // request parameters
    41	            req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
    42	            boolean postParseSuccess = postParseRequest(req, request, res, response);
    43	            if (postParseSuccess) {
    44	                //check valves if we support async
    45	                request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
    46	                // Calling the container
    47	                connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
    48	
    49	                if (request.isComet()) {
    50	                    if (!response.isClosed() && !response.isError()) {
    51	                        if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) {
    52	                            // Invoke a read event right away if there are available bytes
    53	                            if (event(req, res, SocketStatus.OPEN)) {
    54	                                comet = true;
    55	                                res.action(ActionCode.COMET_BEGIN, null);
    56	                            }
    57	                        } else {
    58	                            comet = true;
    59	                            res.action(ActionCode.COMET_BEGIN, null);
    60	                        }
    61	                    } else {
    62	                        // Clear the filter chain, as otherwise it will not be reset elsewhere
    63	                        // since this is a Comet request
    64	                        request.setFilterChain(null);
    65	                    }
    66	                }
    67	
    68	            }
    69	            AsyncContextImpl asyncConImpl = (AsyncContextImpl)request.getAsyncContext();
    70	            if (asyncConImpl != null) {
    71	                async = true;
    72	            } else if (!comet) {
    73	                request.finishRequest();
    74	                response.finishResponse();
    75	                if (postParseSuccess &&
    76	                        request.getMappingData().context != null) {
    77	                    // Log only if processing was invoked.
    78	                    // If postParseRequest() failed, it has already logged it.
    79	                    // If context is null this was the start of a comet request
    80	                    // that failed and has already been logged.
    81	                    ((Context) request.getMappingData().context).logAccess(
    82	                            request, response,
    83	                            System.currentTimeMillis() - req.getStartTime(),
    84	                            false);
    85	                }
    86	                req.action(ActionCode.POST_REQUEST , null);
    87	            }
    88	
    89	        } catch (IOException e) {
    90	            // Ignore
    91	        } finally {
    92	            req.getRequestProcessor().setWorkerThreadName(null);
    93	            // Recycle the wrapper request and response
    94	            if (!comet && !async) {
    95	                request.recycle();
    96	                response.recycle();
    97	            } else {
    98	                // Clear converters so that the minimum amount of memory
    99	                // is used by this processor
   100	                request.clearEncoders();
   101	                response.clearEncoders();
   102	            }
   103	        }
   104	
   105	    }

这段代码中可以看到入参 org.apache.coyote.Request 对象被转成了 org.apache.catalina.connector.Request 对象,后一类型的对象才是在 Tomcat 容器流转时真正传递的对象。重点关注第 42 行和第 47 行。

在第 42 行调用了 postParseRequest 方法:


     1	    /**
     2	     * Parse additional request parameters.
     3	     */
     4	    protected boolean postParseRequest(org.apache.coyote.Request req,
     5	                                       Request request,
     6	                                       org.apache.coyote.Response res,
     7	                                       Response response)
     8	            throws Exception {
     9	
    10	        // XXX the processor may have set a correct scheme and port prior to this point,
    11	        // in ajp13 protocols dont make sense to get the port from the connector...
    12	        // otherwise, use connector configuration
    13	        if (! req.scheme().isNull()) {
    14	            // use processor specified scheme to determine secure state
    15	            request.setSecure(req.scheme().equals("https"));
    16	        } else {
    17	            // use connector scheme and secure configuration, (defaults to
    18	            // "http" and false respectively)
    19	            req.scheme().setString(connector.getScheme());
    20	            request.setSecure(connector.getSecure());
    21	        }
    22	
    23	        // FIXME: the code below doesnt belongs to here,
    24	        // this is only have sense
    25	        // in Http11, not in ajp13..
    26	        // At this point the Host header has been processed.
    27	        // Override if the proxyPort/proxyHost are set
    28	        String proxyName = connector.getProxyName();
    29	        int proxyPort = connector.getProxyPort();
    30	        if (proxyPort != 0) {
    31	            req.setServerPort(proxyPort);
    32	        }
    33	        if (proxyName != null) {
    34	            req.serverName().setString(proxyName);
    35	        }
    36	
    37	        // Copy the raw URI to the decodedURI
    38	        MessageBytes decodedURI = req.decodedURI();
    39	        decodedURI.duplicate(req.requestURI());
    40	
    41	        // Parse the path parameters. This will:
    42	        //   - strip out the path parameters
    43	        //   - convert the decodedURI to bytes
    44	        parsePathParameters(req, request);
    45	
    46	        // URI decoding
    47	        // %xx decoding of the URL
    48	        try {
    49	            req.getURLDecoder().convert(decodedURI, false);
    50	        } catch (IOException ioe) {
    51	            res.setStatus(400);
    52	            res.setMessage("Invalid URI: " + ioe.getMessage());
    53	            connector.getService().getContainer().logAccess(
    54	                    request, response, 0, true);
    55	            return false;
    56	        }
    57	        // Normalization
    58	        if (!normalize(req.decodedURI())) {
    59	            res.setStatus(400);
    60	            res.setMessage("Invalid URI");
    61	            connector.getService().getContainer().logAccess(
    62	                    request, response, 0, true);
    63	            return false;
    64	        }
    65	        // Character decoding
    66	        convertURI(decodedURI, request);
    67	        // Check that the URI is still normalized
    68	        if (!checkNormalize(req.decodedURI())) {
    69	            res.setStatus(400);
    70	            res.setMessage("Invalid URI character encoding");
    71	            connector.getService().getContainer().logAccess(
    72	                    request, response, 0, true);
    73	            return false;
    74	        }
    75	
    76	        // Set the remote principal
    77	        String principal = req.getRemoteUser().toString();
    78	        if (principal != null) {
    79	            request.setUserPrincipal(new CoyotePrincipal(principal));
    80	        }
    81	
    82	        // Set the authorization type
    83	        String authtype = req.getAuthType().toString();
    84	        if (authtype != null) {
    85	            request.setAuthType(authtype);
    86	        }
    87	
    88	        // Request mapping.
    89	        MessageBytes serverName;
    90	        if (connector.getUseIPVHosts()) {
    91	            serverName = req.localName();
    92	            if (serverName.isNull()) {
    93	                // well, they did ask for it
    94	                res.action(ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, null);
    95	            }
    96	        } else {
    97	            serverName = req.serverName();
    98	        }
    99	        if (request.isAsyncStarted()) {
   100	            //TODO SERVLET3 - async
   101	            //reset mapping data, should prolly be done elsewhere
   102	            request.getMappingData().recycle();
   103	        }
   104	
   105	        boolean mapRequired = true;
   106	        String version = null;
   107	
   108	        while (mapRequired) {
   109	            if (version != null) {
   110	                // Once we have a version - that is it
   111	                mapRequired = false;
   112	            }
   113	            // This will map the the latest version by default
   114	            connector.getMapper().map(serverName, decodedURI, version,
   115	                                      request.getMappingData());
   116	            request.setContext((Context) request.getMappingData().context);
   117	            request.setWrapper((Wrapper) request.getMappingData().wrapper);
   118	
   119	            // Single contextVersion therefore no possibility of remap
   120	            if (request.getMappingData().contexts == null) {
   121	                mapRequired = false;
   122	            }
   123	
   124	            // If there is no context at this point, it is likely no ROOT context
   125	            // has been deployed
   126	            if (request.getContext() == null) {
   127	                res.setStatus(404);
   128	                res.setMessage("Not found");
   129	                // No context, so use host
   130	                Host host = request.getHost();
   131	                // Make sure there is a host (might not be during shutdown)
   132	                if (host != null) {
   133	                    host.logAccess(request, response, 0, true);
   134	                }
   135	                return false;
   136	            }
   137	
   138	            // Now we have the context, we can parse the session ID from the URL
   139	            // (if any). Need to do this before we redirect in case we need to
   140	            // include the session id in the redirect
   141	            String sessionID = null;
   142	            if (request.getServletContext().getEffectiveSessionTrackingModes()
   143	                    .contains(SessionTrackingMode.URL)) {
   144	
   145	                // Get the session ID if there was one
   146	                sessionID = request.getPathParameter(
   147	                        SessionConfig.getSessionUriParamName(
   148	                                request.getContext()));
   149	                if (sessionID != null) {
   150	                    request.setRequestedSessionId(sessionID);
   151	                    request.setRequestedSessionURL(true);
   152	                }
   153	            }
   154	
   155	            // Look for session ID in cookies and SSL session
   156	            parseSessionCookiesId(req, request);
   157	            parseSessionSslId(request);
   158	
   159	            sessionID = request.getRequestedSessionId();
   160	
   161	            if (mapRequired) {
   162	                if (sessionID == null) {
   163	                    // No session means no possibility of needing to remap
   164	                    mapRequired = false;
   165	                } else {
   166	                    // Find the context associated with the session
   167	                    Object[] objs = request.getMappingData().contexts;
   168	                    for (int i = (objs.length); i > 0; i--) {
   169	                        Context ctxt = (Context) objs[i - 1];
   170	                        if (ctxt.getManager().findSession(sessionID) != null) {
   171	                            // Was the correct context already mapped?
   172	                            if (ctxt.equals(request.getMappingData().context)) {
   173	                                mapRequired = false;
   174	                            } else {
   175	                                // Set version so second time through mapping the
   176	                                // correct context is found
   177	                                version = ctxt.getWebappVersion();
   178	                                // Reset mapping
   179	                                request.getMappingData().recycle();
   180	                                break;
   181	                            }
   182	                        }
   183	                    }
   184	                    if (version == null) {
   185	                        // No matching context found. No need to re-map
   186	                        mapRequired = false;
   187	                    }
   188	                }
   189	            }
   190	            if (!mapRequired && request.getContext().getPaused()) {
   191	                // Found a matching context but it is paused. Mapping data will
   192	                // be wrong since some Wrappers may not be registered at this
   193	                // point.
   194	                try {
   195	                    Thread.sleep(1000);
   196	                } catch (InterruptedException e) {
   197	                    // Should never happen
   198	                }
   199	                // Reset mapping
   200	                request.getMappingData().recycle();
   201	                mapRequired = true;
   202	            }
   203	        }
   204	
   205	        // Possible redirect
   206	        MessageBytes redirectPathMB = request.getMappingData().redirectPath;
   207	        if (!redirectPathMB.isNull()) {
   208	            String redirectPath = urlEncoder.encode(redirectPathMB.toString());
   209	            String query = request.getQueryString();
   210	            if (request.isRequestedSessionIdFromURL()) {
   211	                // This is not optimal, but as this is not very common, it
   212	                // shouldn't matter
   213	                redirectPath = redirectPath + ";" +
   214	                        SessionConfig.getSessionUriParamName(
   215	                            request.getContext()) +
   216	                    "=" + request.getRequestedSessionId();
   217	            }
   218	            if (query != null) {
   219	                // This is not optimal, but as this is not very common, it
   220	                // shouldn't matter
   221	                redirectPath = redirectPath + "?" + query;
   222	            }
   223	            response.sendRedirect(redirectPath);
   224	            request.getContext().logAccess(request, response, 0, true);
   225	            return false;
   226	        }
   227	
   228	        // Filter trace method
   229	        if (!connector.getAllowTrace()
   230	                && req.method().equalsIgnoreCase("TRACE")) {
   231	            Wrapper wrapper = request.getWrapper();
   232	            String header = null;
   233	            if (wrapper != null) {
   234	                String[] methods = wrapper.getServletMethods();
   235	                if (methods != null) {
   236	                    for (int i=0; i<methods.length; i++) {
   237	                        if ("TRACE".equals(methods[i])) {
   238	                            continue;
   239	                        }
   240	                        if (header == null) {
   241	                            header = methods[i];
   242	                        } else {
   243	                            header += ", " + methods[i];
   244	                        }
   245	                    }
   246	                }
   247	            }
   248	            res.setStatus(405);
   249	            res.addHeader("Allow", header);
   250	            res.setMessage("TRACE method is not allowed");
   251	            request.getContext().logAccess(request, response, 0, true);
   252	            return false;
   253	        }
   254	
   255	        return true;
   256	    }

这段代码的主要作用是给 org.apache.catalina.connector.Request 对象设值,其中第 113 到 117 行:







请到「今天看啥」查看全文