This is an automated email from the ASF dual-hosted git repository. markt pushed a commit to branch loom in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 6d4ee277815db06db6d9b5a8cfc028c14d2899ca Author: Mark Thomas <ma...@apache.org> AuthorDate: Wed Oct 12 16:51:29 2022 +0100 Refactor. Introduce AbstractHttp11Processor. This abstract class is introduced to allow for Loom and non-Loom Processors to use different Http11InputBuffers. --- ...Processor.java => AbstractHttp11Processor.java} | 58 +- java/org/apache/coyote/http11/Http11Processor.java | 1422 +------------------- .../apache/coyote/http11/Http11LoomProcessor.java | 13 +- 3 files changed, 38 insertions(+), 1455 deletions(-) diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/AbstractHttp11Processor.java similarity index 96% copy from java/org/apache/coyote/http11/Http11Processor.java copy to java/org/apache/coyote/http11/AbstractHttp11Processor.java index c27ff911f4..b63b824bc6 100644 --- a/java/org/apache/coyote/http11/Http11Processor.java +++ b/java/org/apache/coyote/http11/AbstractHttp11Processor.java @@ -48,8 +48,6 @@ import org.apache.coyote.http11.filters.VoidInputFilter; import org.apache.coyote.http11.filters.VoidOutputFilter; import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler; import org.apache.coyote.http11.upgrade.UpgradeApplicationBufferHandler; -import org.apache.juli.logging.Log; -import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.ExceptionUtils; import org.apache.tomcat.util.buf.ByteChunk; import org.apache.tomcat.util.buf.MessageBytes; @@ -67,9 +65,7 @@ import org.apache.tomcat.util.net.SendfileState; import org.apache.tomcat.util.net.SocketWrapperBase; import org.apache.tomcat.util.res.StringManager; -public class Http11Processor extends AbstractProcessor { - - private static final Log log = LogFactory.getLog(Http11Processor.class); +public abstract class AbstractHttp11Processor extends AbstractProcessor { /** * The string manager for this package. @@ -152,7 +148,7 @@ public class Http11Processor extends AbstractProcessor { private SendfileDataBase sendfileData = null; - public Http11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) { + public AbstractHttp11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) { super(adapter); this.protocol = protocol; @@ -218,8 +214,8 @@ public class Http11Processor extends AbstractProcessor { // 400 - Bad request response.setStatus(400); setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare") + + if (getLog().isDebugEnabled()) { + getLog().debug(sm.getString("http11processor.request.prepare") + " Transfer encoding lists chunked before [" + encodingName + "]"); } return; @@ -240,8 +236,8 @@ public class Http11Processor extends AbstractProcessor { // 501 - Unimplemented response.setStatus(501); setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare") + + if (getLog().isDebugEnabled()) { + getLog().debug(sm.getString("http11processor.request.prepare") + " Unsupported transfer encoding [" + encodingName + "]"); } } @@ -304,8 +300,8 @@ public class Http11Processor extends AbstractProcessor { } } } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.header.parse"), e); + if (getLog().isDebugEnabled()) { + getLog().debug(sm.getString("http11processor.header.parse"), e); } setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e); break; @@ -319,10 +315,10 @@ public class Http11Processor extends AbstractProcessor { message += sm.getString("http11processor.fallToDebug"); //$FALL-THROUGH$ case INFO: - log.info(message, t); + getLog().info(message, t); break; case DEBUG: - log.debug(message, t); + getLog().debug(message, t); } } // 400 - Bad Request @@ -376,8 +372,8 @@ public class Http11Processor extends AbstractProcessor { prepareRequest(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare"), t); + if (getLog().isDebugEnabled()) { + getLog().debug(sm.getString("http11processor.request.prepare"), t); } // 500 - Internal Server Error response.setStatus(500); @@ -410,7 +406,7 @@ public class Http11Processor extends AbstractProcessor { } catch (InterruptedIOException e) { setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e); } catch (HeadersTooLargeException e) { - log.error(sm.getString("http11processor.request.process"), e); + getLog().error(sm.getString("http11processor.request.process"), e); // The response should not have been committed but check it // anyway to be safe if (response.isCommitted()) { @@ -423,7 +419,7 @@ public class Http11Processor extends AbstractProcessor { } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); - log.error(sm.getString("http11processor.request.process"), t); + getLog().error(sm.getString("http11processor.request.process"), t); // 500 - Internal Server Error response.setStatus(500); setErrorState(ErrorState.CLOSE_CLEAN, t); @@ -621,8 +617,8 @@ public class Http11Processor extends AbstractProcessor { // Send 505; Unsupported HTTP version response.setStatus(505); setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare")+ + if (getLog().isDebugEnabled()) { + getLog().debug(sm.getString("http11processor.request.prepare")+ " Unsupported HTTP version \""+protocolMB+"\""); } } @@ -873,8 +869,8 @@ public class Http11Processor extends AbstractProcessor { private void badRequest(String errorKey) { response.setStatus(400); setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString(errorKey)); + if (getLog().isDebugEnabled()) { + getLog().debug(sm.getString(errorKey)); } } @@ -1066,7 +1062,7 @@ public class Http11Processor extends AbstractProcessor { outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); } catch (IllegalArgumentException iae) { // Log the problematic header - log.warn(sm.getString("http11processor.response.invalidHeader", + getLog().warn(sm.getString("http11processor.response.invalidHeader", headers.getName(i), headers.getValue(i)), iae); // Remove the problematic header headers.removeHeader(i); @@ -1175,12 +1171,6 @@ public class Http11Processor extends AbstractProcessor { } - @Override - protected Log getLog() { - return log; - } - - @Override protected ServletConnection getServletConnection() { return socketWrapper.getServletConnection("http/1.1", ""); @@ -1218,7 +1208,7 @@ public class Http11Processor extends AbstractProcessor { // written in the Adapter.service method. response.setStatus(500); setErrorState(ErrorState.CLOSE_NOW, t); - log.error(sm.getString("http11processor.request.finish"), t); + getLog().error(sm.getString("http11processor.request.finish"), t); } } if (getErrorState().isIoAllowed()) { @@ -1230,7 +1220,7 @@ public class Http11Processor extends AbstractProcessor { } catch (Throwable t) { ExceptionUtils.handleThrowable(t); setErrorState(ErrorState.CLOSE_NOW, t); - log.error(sm.getString("http11processor.response.finish"), t); + getLog().error(sm.getString("http11processor.response.finish"), t); } } } @@ -1320,7 +1310,7 @@ public class Http11Processor extends AbstractProcessor { request.setAttribute(SSLSupport.CERTIFICATE_KEY, sslO); } } catch (IOException ioe) { - log.warn(sm.getString("http11processor.socket.ssl"), ioe); + getLog().warn(sm.getString("http11processor.socket.ssl"), ioe); } } } @@ -1422,8 +1412,8 @@ public class Http11Processor extends AbstractProcessor { switch (result) { case ERROR: // Write failed - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.sendfile.error")); + if (getLog().isDebugEnabled()) { + getLog().debug(sm.getString("http11processor.sendfile.error")); } setErrorState(ErrorState.CLOSE_CONNECTION_NOW, null); //$FALL-THROUGH$ diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java index c27ff911f4..bfca3b93ba 100644 --- a/java/org/apache/coyote/http11/Http11Processor.java +++ b/java/org/apache/coyote/http11/Http11Processor.java @@ -16,1162 +16,17 @@ */ package org.apache.coyote.http11; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.nio.ByteBuffer; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Pattern; - -import jakarta.servlet.ServletConnection; -import jakarta.servlet.http.HttpServletResponse; - -import org.apache.coyote.AbstractProcessor; -import org.apache.coyote.ActionCode; import org.apache.coyote.Adapter; -import org.apache.coyote.ContinueResponseTiming; -import org.apache.coyote.ErrorState; -import org.apache.coyote.Request; -import org.apache.coyote.RequestInfo; -import org.apache.coyote.UpgradeProtocol; -import org.apache.coyote.UpgradeToken; -import org.apache.coyote.http11.filters.BufferedInputFilter; -import org.apache.coyote.http11.filters.ChunkedInputFilter; -import org.apache.coyote.http11.filters.ChunkedOutputFilter; -import org.apache.coyote.http11.filters.GzipOutputFilter; -import org.apache.coyote.http11.filters.IdentityInputFilter; -import org.apache.coyote.http11.filters.IdentityOutputFilter; -import org.apache.coyote.http11.filters.SavedRequestInputFilter; -import org.apache.coyote.http11.filters.VoidInputFilter; -import org.apache.coyote.http11.filters.VoidOutputFilter; -import org.apache.coyote.http11.upgrade.InternalHttpUpgradeHandler; -import org.apache.coyote.http11.upgrade.UpgradeApplicationBufferHandler; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; -import org.apache.tomcat.util.ExceptionUtils; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.FastHttpDateFormat; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.http.parser.HttpParser; -import org.apache.tomcat.util.http.parser.TokenList; -import org.apache.tomcat.util.log.UserDataHelper; -import org.apache.tomcat.util.net.AbstractEndpoint.Handler.SocketState; -import org.apache.tomcat.util.net.ApplicationBufferHandler; -import org.apache.tomcat.util.net.SSLSupport; -import org.apache.tomcat.util.net.SendfileDataBase; -import org.apache.tomcat.util.net.SendfileKeepAliveState; -import org.apache.tomcat.util.net.SendfileState; -import org.apache.tomcat.util.net.SocketWrapperBase; -import org.apache.tomcat.util.res.StringManager; -public class Http11Processor extends AbstractProcessor { +public class Http11Processor extends AbstractHttp11Processor { private static final Log log = LogFactory.getLog(Http11Processor.class); - /** - * The string manager for this package. - */ - private static final StringManager sm = StringManager.getManager(Http11Processor.class); - - - private final AbstractHttp11Protocol<?> protocol; - - - /** - * Input. - */ - private final Http11InputBuffer inputBuffer; - - - /** - * Output. - */ - private final Http11OutputBuffer outputBuffer; - - - private final HttpParser httpParser; - - - /** - * Tracks how many internal filters are in the filter library so they - * are skipped when looking for pluggable filters. - */ - private int pluggableFilterIndex = Integer.MAX_VALUE; - - - /** - * Keep-alive. - */ - private volatile boolean keepAlive = true; - - - /** - * Flag used to indicate that the socket should be kept open (e.g. for keep - * alive or send file). - */ - private volatile boolean openSocket = false; - - - /** - * Flag that indicates if the request headers have been completely read. - */ - private volatile boolean readComplete = true; - - /** - * HTTP/1.1 flag. - */ - private boolean http11 = true; - - - /** - * HTTP/0.9 flag. - */ - private boolean http09 = false; - - - /** - * Content delimiter for the request (if false, the connection will - * be closed at the end of the request). - */ - private boolean contentDelimitation = true; - - - /** - * Instance of the new protocol to use after the HTTP connection has been - * upgraded. - */ - private UpgradeToken upgradeToken = null; - - - /** - * Sendfile data. - */ - private SendfileDataBase sendfileData = null; - public Http11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) { - super(adapter); - this.protocol = protocol; - - httpParser = new HttpParser(protocol.getRelaxedPathChars(), - protocol.getRelaxedQueryChars()); - - inputBuffer = new Http11InputBuffer(request, protocol.getMaxHttpRequestHeaderSize(), - protocol.getRejectIllegalHeader(), httpParser); - request.setInputBuffer(inputBuffer); - - outputBuffer = new Http11OutputBuffer(response, protocol.getMaxHttpResponseHeaderSize()); - response.setOutputBuffer(outputBuffer); - - // Create and add the identity filters. - inputBuffer.addFilter(new IdentityInputFilter(protocol.getMaxSwallowSize())); - outputBuffer.addFilter(new IdentityOutputFilter()); - - // Create and add the chunked filters. - inputBuffer.addFilter(new ChunkedInputFilter(protocol.getMaxTrailerSize(), - protocol.getAllowedTrailerHeadersInternal(), protocol.getMaxExtensionSize(), - protocol.getMaxSwallowSize())); - outputBuffer.addFilter(new ChunkedOutputFilter()); - - // Create and add the void filters. - inputBuffer.addFilter(new VoidInputFilter()); - outputBuffer.addFilter(new VoidOutputFilter()); - - // Create and add buffered input filter - inputBuffer.addFilter(new BufferedInputFilter(protocol.getMaxSwallowSize())); - - // Create and add the gzip filters. - //inputBuffer.addFilter(new GzipInputFilter()); - outputBuffer.addFilter(new GzipOutputFilter()); - - pluggableFilterIndex = inputBuffer.getFilters().length; - } - - - /** - * Determine if we must drop the connection because of the HTTP status - * code. Use the same list of codes as Apache/httpd. - */ - private static boolean statusDropsConnection(int status) { - return status == 400 /* SC_BAD_REQUEST */ || - status == 408 /* SC_REQUEST_TIMEOUT */ || - status == 411 /* SC_LENGTH_REQUIRED */ || - status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || - status == 414 /* SC_REQUEST_URI_TOO_LONG */ || - status == 500 /* SC_INTERNAL_SERVER_ERROR */ || - status == 503 /* SC_SERVICE_UNAVAILABLE */ || - status == 501 /* SC_NOT_IMPLEMENTED */; - } - - - /** - * Add an input filter to the current request. If the encoding is not - * supported, a 501 response will be returned to the client. - */ - private void addInputFilter(InputFilter[] inputFilters, String encodingName) { - if (contentDelimitation) { - // Chunked has already been specified and it must be the final - // encoding. - // 400 - Bad request - response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare") + - " Transfer encoding lists chunked before [" + encodingName + "]"); - } - return; - } - - // Parsing trims and converts to lower case. - if (encodingName.equals("chunked")) { - inputBuffer.addActiveFilter(inputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - } else { - for (int i = pluggableFilterIndex; i < inputFilters.length; i++) { - if (inputFilters[i].getEncodingName().toString().equals(encodingName)) { - inputBuffer.addActiveFilter(inputFilters[i]); - return; - } - } - // Unsupported transfer encoding - // 501 - Unimplemented - response.setStatus(501); - setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare") + - " Unsupported transfer encoding [" + encodingName + "]"); - } - } - } - - - @Override - public SocketState service(SocketWrapperBase<?> socketWrapper) - throws IOException { - RequestInfo rp = request.getRequestProcessor(); - rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); - - // Setting up the I/O - setSocketWrapper(socketWrapper); - - // Flags - keepAlive = true; - openSocket = false; - readComplete = true; - boolean keptAlive = false; - SendfileState sendfileState = SendfileState.DONE; - - while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null && - sendfileState == SendfileState.DONE && !protocol.isPaused()) { - - // Parsing the request header - try { - if (!inputBuffer.parseRequestLine(keptAlive, protocol.getConnectionTimeout(), - protocol.getKeepAliveTimeout())) { - if (inputBuffer.getParsingRequestLinePhase() == -1) { - return SocketState.UPGRADING; - } else if (handleIncompleteRequestLineRead()) { - break; - } - } - - // Process the Protocol component of the request line - // Need to know if this is an HTTP 0.9 request before trying to - // parse headers. - prepareRequestProtocol(); - - if (protocol.isPaused()) { - // 503 - Service unavailable - response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN, null); - } else { - keptAlive = true; - // Set this every time in case limit has been changed via JMX - request.getMimeHeaders().setLimit(protocol.getMaxHeaderCount()); - // Don't parse headers for HTTP/0.9 - if (!http09 && !inputBuffer.parseHeaders()) { - // We've read part of the request, don't recycle it - // instead associate it with the socket - openSocket = true; - readComplete = false; - break; - } - if (!protocol.getDisableUploadTimeout()) { - socketWrapper.setReadTimeout(protocol.getConnectionUploadTimeout()); - } - } - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.header.parse"), e); - } - setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e); - break; - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - UserDataHelper.Mode logMode = userDataHelper.getNextMode(); - if (logMode != null) { - String message = sm.getString("http11processor.header.parse"); - switch (logMode) { - case INFO_THEN_DEBUG: - message += sm.getString("http11processor.fallToDebug"); - //$FALL-THROUGH$ - case INFO: - log.info(message, t); - break; - case DEBUG: - log.debug(message, t); - } - } - // 400 - Bad Request - response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN, t); - } - - // Has an upgrade been requested? - if (isConnectionToken(request.getMimeHeaders(), "upgrade")) { - // Check the protocol - String requestedProtocol = request.getHeader("Upgrade"); - - UpgradeProtocol upgradeProtocol = protocol.getUpgradeProtocol(requestedProtocol); - if (upgradeProtocol != null) { - if (upgradeProtocol.accept(request)) { - // Create clone of request for upgraded protocol - Request upgradeRequest = null; - try { - upgradeRequest = cloneRequest(request); - } catch (ByteChunk.BufferOverflowException ioe) { - response.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE); - setErrorState(ErrorState.CLOSE_CLEAN, null); - } catch (IOException ioe) { - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - setErrorState(ErrorState.CLOSE_CLEAN, ioe); - } - - if (upgradeRequest != null) { - // Complete the HTTP/1.1 upgrade process - response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS); - response.setHeader("Connection", "Upgrade"); - response.setHeader("Upgrade", requestedProtocol); - action(ActionCode.CLOSE, null); - getAdapter().log(request, response, 0); - - // Continue processing using new protocol - InternalHttpUpgradeHandler upgradeHandler = - upgradeProtocol.getInternalUpgradeHandler(socketWrapper, getAdapter(), upgradeRequest); - UpgradeToken upgradeToken = new UpgradeToken(upgradeHandler, null, null, requestedProtocol); - action(ActionCode.UPGRADE, upgradeToken); - return SocketState.UPGRADING; - } - } - } - } - - if (getErrorState().isIoAllowed()) { - // Setting up filters, and parse some request headers - rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); - try { - prepareRequest(); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare"), t); - } - // 500 - Internal Server Error - response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN, t); - } - } - - int maxKeepAliveRequests = protocol.getMaxKeepAliveRequests(); - if (maxKeepAliveRequests == 1) { - keepAlive = false; - } else if (maxKeepAliveRequests > 0 && - socketWrapper.decrementKeepAlive() <= 0) { - keepAlive = false; - } - - // Process the request in the adapter - if (getErrorState().isIoAllowed()) { - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - getAdapter().service(request, response); - // Handle when the response was committed before a serious - // error occurred. Throwing a ServletException should both - // set the status to 500 and set the errorException. - // If we fail here, then the response is likely already - // committed, so we can't try and set headers. - if(keepAlive && !getErrorState().isError() && !isAsync() && - statusDropsConnection(response.getStatus())) { - setErrorState(ErrorState.CLOSE_CLEAN, null); - } - } catch (InterruptedIOException e) { - setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e); - } catch (HeadersTooLargeException e) { - log.error(sm.getString("http11processor.request.process"), e); - // The response should not have been committed but check it - // anyway to be safe - if (response.isCommitted()) { - setErrorState(ErrorState.CLOSE_NOW, e); - } else { - response.reset(); - response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN, e); - response.setHeader("Connection", "close"); // TODO: Remove - } - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - log.error(sm.getString("http11processor.request.process"), t); - // 500 - Internal Server Error - response.setStatus(500); - setErrorState(ErrorState.CLOSE_CLEAN, t); - getAdapter().log(request, response, 0); - } - } - - // Finish the handling of the request - rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT); - if (!isAsync()) { - // If this is an async request then the request ends when it has - // been completed. The AsyncContext is responsible for calling - // endRequest() in that case. - endRequest(); - } - rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT); - - // If there was an error, make sure the request is counted as - // and error, and update the statistics counter - if (getErrorState().isError()) { - response.setStatus(500); - } - - if (!isAsync() || getErrorState().isError()) { - request.updateCounters(); - if (getErrorState().isIoAllowed()) { - inputBuffer.nextRequest(); - outputBuffer.nextRequest(); - } - } - - if (!protocol.getDisableUploadTimeout()) { - int connectionTimeout = protocol.getConnectionTimeout(); - if(connectionTimeout > 0) { - socketWrapper.setReadTimeout(connectionTimeout); - } else { - socketWrapper.setReadTimeout(0); - } - } - - rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); - - sendfileState = processSendfile(socketWrapper); - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - - if (getErrorState().isError() || (protocol.isPaused() && !isAsync())) { - return SocketState.CLOSED; - } else if (isAsync()) { - return SocketState.LONG; - } else if (isUpgrade()) { - return SocketState.UPGRADING; - } else { - if (sendfileState == SendfileState.PENDING) { - return SocketState.SENDFILE; - } else { - if (openSocket) { - if (readComplete) { - return SocketState.OPEN; - } else { - return SocketState.LONG; - } - } else { - return SocketState.CLOSED; - } - } - } - } - - - @Override - protected final void setSocketWrapper(SocketWrapperBase<?> socketWrapper) { - super.setSocketWrapper(socketWrapper); - inputBuffer.init(socketWrapper); - outputBuffer.init(socketWrapper); - } - - - private Request cloneRequest(Request source) throws IOException { - Request dest = new Request(); - - // Transfer the minimal information required for the copy of the Request - // that is passed to the HTTP upgrade process - dest.decodedURI().duplicate(source.decodedURI()); - dest.method().duplicate(source.method()); - dest.getMimeHeaders().duplicate(source.getMimeHeaders()); - dest.requestURI().duplicate(source.requestURI()); - dest.queryString().duplicate(source.queryString()); - - // Preparation for reading the request body - MimeHeaders headers = source.getMimeHeaders(); - prepareExpectation(headers); - prepareInputFilters(headers); - ack(ContinueResponseTiming.ALWAYS); - - // Need to read and buffer the request body, if any. RFC 7230 requires - // that the request is fully read before the upgrade takes place. - ByteChunk body = new ByteChunk(); - int maxSavePostSize = protocol.getMaxSavePostSize(); - if (maxSavePostSize != 0) { - body.setLimit(maxSavePostSize); - ApplicationBufferHandler buffer = new UpgradeApplicationBufferHandler(); - - while (source.getInputBuffer().doRead(buffer) >= 0) { - body.append(buffer.getByteBuffer()); - } - } - - // Make the buffered request body available to the upgraded protocol. - SavedRequestInputFilter srif = new SavedRequestInputFilter(body); - dest.setInputBuffer(srif); - - return dest; - } - - - private boolean handleIncompleteRequestLineRead() { - // Haven't finished reading the request so keep the socket - // open - openSocket = true; - // Check to see if we have read any of the request line yet - if (inputBuffer.getParsingRequestLinePhase() > 1) { - // Started to read request line. - if (protocol.isPaused()) { - // Partially processed the request so need to respond - response.setStatus(503); - setErrorState(ErrorState.CLOSE_CLEAN, null); - return false; - } else { - // Need to keep processor associated with socket - readComplete = false; - } - } - return true; - } - - - private void checkExpectationAndResponseStatus() { - if (request.hasExpectation() && !isRequestBodyFullyRead() && - (response.getStatus() < 200 || response.getStatus() > 299)) { - // Client sent Expect: 100-continue but received a - // non-2xx final response. Disable keep-alive (if enabled) - // to ensure that the connection is closed. Some clients may - // still send the body, some may send the next request. - // No way to differentiate, so close the connection to - // force the client to send the next request. - inputBuffer.setSwallowInput(false); - keepAlive = false; - } - } - - - private void checkMaxSwallowSize() { - // Parse content-length header - long contentLength = -1; - try { - contentLength = request.getContentLengthLong(); - } catch (Exception e) { - // Ignore, an error here is already processed in prepareRequest - // but is done again since the content length is still -1 - } - if (contentLength > 0 && protocol.getMaxSwallowSize() > -1 && - (contentLength - request.getBytesRead() > protocol.getMaxSwallowSize())) { - // There is more data to swallow than Tomcat will accept so the - // connection is going to be closed. Disable keep-alive which will - // trigger adding the "Connection: close" header if not already - // present. - keepAlive = false; - } - } - - - private void prepareRequestProtocol() { - - MessageBytes protocolMB = request.protocol(); - if (protocolMB.equals(Constants.HTTP_11)) { - http09 = false; - http11 = true; - protocolMB.setString(Constants.HTTP_11); - } else if (protocolMB.equals(Constants.HTTP_10)) { - http09 = false; - http11 = false; - keepAlive = false; - protocolMB.setString(Constants.HTTP_10); - } else if (protocolMB.equals("")) { - // HTTP/0.9 - http09 = true; - http11 = false; - keepAlive = false; - } else { - // Unsupported protocol - http09 = false; - http11 = false; - // Send 505; Unsupported HTTP version - response.setStatus(505); - setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare")+ - " Unsupported HTTP version \""+protocolMB+"\""); - } - } - } - - - /** - * After reading the request headers, we have to setup the request filters. - */ - private void prepareRequest() throws IOException { - - if (protocol.isSSLEnabled()) { - request.scheme().setString("https"); - } - - MimeHeaders headers = request.getMimeHeaders(); - - // Check connection header - MessageBytes connectionValueMB = headers.getValue(Constants.CONNECTION); - if (connectionValueMB != null && !connectionValueMB.isNull()) { - Set<String> tokens = new HashSet<>(); - TokenList.parseTokenList(headers.values(Constants.CONNECTION), tokens); - if (tokens.contains(Constants.CLOSE)) { - keepAlive = false; - } else if (tokens.contains(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN)) { - keepAlive = true; - } - } - - if (http11) { - prepareExpectation(headers); - } - - // Check user-agent header - Pattern restrictedUserAgents = protocol.getRestrictedUserAgentsPattern(); - if (restrictedUserAgents != null && (http11 || keepAlive)) { - MessageBytes userAgentValueMB = headers.getValue("user-agent"); - // Check in the restricted list, and adjust the http11 - // and keepAlive flags accordingly - if(userAgentValueMB != null && !userAgentValueMB.isNull()) { - String userAgentValue = userAgentValueMB.toString(); - if (restrictedUserAgents.matcher(userAgentValue).matches()) { - http11 = false; - keepAlive = false; - } - } - } - - - // Check host header - MessageBytes hostValueMB = null; - try { - hostValueMB = headers.getUniqueValue("host"); - } catch (IllegalArgumentException iae) { - // Multiple Host headers are not permitted - badRequest("http11processor.request.multipleHosts"); - } - if (http11 && hostValueMB == null) { - badRequest("http11processor.request.noHostHeader"); - } - - // Check for an absolute-URI less the query string which has already - // been removed during the parsing of the request line - ByteChunk uriBC = request.requestURI().getByteChunk(); - byte[] uriB = uriBC.getBytes(); - if (uriBC.startsWithIgnoreCase("http", 0)) { - int pos = 4; - // Check for https - if (uriBC.startsWithIgnoreCase("s", pos)) { - pos++; - } - // Next 3 characters must be "://" - if (uriBC.startsWith("://", pos)) { - pos += 3; - int uriBCStart = uriBC.getStart(); - - // '/' does not appear in the authority so use the first - // instance to split the authority and the path segments - int slashPos = uriBC.indexOf('/', pos); - // '@' in the authority delimits the userinfo - int atPos = uriBC.indexOf('@', pos); - if (slashPos > -1 && atPos > slashPos) { - // First '@' is in the path segments so no userinfo - atPos = -1; - } - - if (slashPos == -1) { - slashPos = uriBC.getLength(); - // Set URI as "/". Use 6 as it will always be a '/'. - // 01234567 - // http:// - // https:// - request.requestURI().setBytes(uriB, uriBCStart + 6, 1); - } else { - request.requestURI().setBytes(uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos); - } - - // Skip any user info - if (atPos != -1) { - // Validate the userinfo - for (; pos < atPos; pos++) { - byte c = uriB[uriBCStart + pos]; - if (!HttpParser.isUserInfo(c)) { - // Strictly there needs to be a check for valid %nn - // encoding here but skip it since it will never be - // decoded because the userinfo is ignored - badRequest("http11processor.request.invalidUserInfo"); - break; - } - } - // Skip the '@' - pos = atPos + 1; - } - - if (http11) { - // Missing host header is illegal but handled above - if (hostValueMB != null) { - // Any host in the request line must be consistent with - // the Host header - if (!hostValueMB.getByteChunk().equals( - uriB, uriBCStart + pos, slashPos - pos)) { - if (protocol.getAllowHostHeaderMismatch()) { - // The requirements of RFC 2616 are being - // applied. If the host header and the request - // line do not agree, the request line takes - // precedence - hostValueMB = headers.setValue("host"); - hostValueMB.setBytes(uriB, uriBCStart + pos, slashPos - pos); - } else { - // The requirements of RFC 7230 are being - // applied. If the host header and the request - // line do not agree, trigger a 400 response. - badRequest("http11processor.request.inconsistentHosts"); - } - } - } - } else { - // Not HTTP/1.1 - no Host header so generate one since - // Tomcat internals assume it is set - try { - hostValueMB = headers.setValue("host"); - hostValueMB.setBytes(uriB, uriBCStart + pos, slashPos - pos); - } catch (IllegalStateException e) { - // Edge case - // If the request has too many headers it won't be - // possible to create the host header. Ignore this as - // processing won't reach the point where the Tomcat - // internals expect there to be a host header. - } - } - } else { - badRequest("http11processor.request.invalidScheme"); - } - } - - // Validate the characters in the URI. %nn decoding will be checked at - // the point of decoding. - for (int i = uriBC.getStart(); i < uriBC.getEnd(); i++) { - if (!httpParser.isAbsolutePathRelaxed(uriB[i])) { - badRequest("http11processor.request.invalidUri"); - break; - } - } - - // Input filter setup - prepareInputFilters(headers); - - // Validate host name and extract port if present - parseHost(hostValueMB); - - if (!getErrorState().isIoAllowed()) { - getAdapter().log(request, response, 0); - } - } - - - private void prepareExpectation(MimeHeaders headers) { - MessageBytes expectMB = headers.getValue("expect"); - if (expectMB != null && !expectMB.isNull()) { - if (expectMB.toString().trim().equalsIgnoreCase("100-continue")) { - request.setExpectation(true); - } else { - response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED); - setErrorState(ErrorState.CLOSE_CLEAN, null); - } - } - } - - private void prepareInputFilters(MimeHeaders headers) throws IOException { - - contentDelimitation = false; - - InputFilter[] inputFilters = inputBuffer.getFilters(); - - // Parse transfer-encoding header - // HTTP specs say an HTTP 1.1 server should accept any recognised - // HTTP 1.x header from a 1.x client unless the specs says otherwise. - if (!http09) { - MessageBytes transferEncodingValueMB = headers.getValue("transfer-encoding"); - if (transferEncodingValueMB != null) { - List<String> encodingNames = new ArrayList<>(); - if (TokenList.parseTokenList(headers.values("transfer-encoding"), encodingNames)) { - for (String encodingName : encodingNames) { - addInputFilter(inputFilters, encodingName); - } - } else { - // Invalid transfer encoding - badRequest("http11processor.request.invalidTransferEncoding"); - } - } - } - - // Parse content-length header - long contentLength = -1; - try { - contentLength = request.getContentLengthLong(); - } catch (NumberFormatException e) { - badRequest("http11processor.request.nonNumericContentLength"); - } catch (IllegalArgumentException e) { - badRequest("http11processor.request.multipleContentLength"); - } - if (contentLength >= 0) { - if (contentDelimitation) { - // contentDelimitation being true at this point indicates that - // chunked encoding is being used but chunked encoding should - // not be used with a content length. RFC 2616, section 4.4, - // bullet 3 states Content-Length must be ignored in this case - - // so remove it. - headers.removeHeader("content-length"); - request.setContentLength(-1); - keepAlive = false; - } else { - inputBuffer.addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } - } - - if (!contentDelimitation) { - // If there's no content length - // (broken HTTP/1.0 or HTTP/1.1), assume - // the client is not broken and didn't send a body - inputBuffer.addActiveFilter(inputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - } - - - private void badRequest(String errorKey) { - response.setStatus(400); - setErrorState(ErrorState.CLOSE_CLEAN, null); - if (log.isDebugEnabled()) { - log.debug(sm.getString(errorKey)); - } - } - - - /** - * When committing the response, we have to validate the set of headers, as - * well as setup the response filters. - */ - @Override - protected final void prepareResponse() throws IOException { - - boolean entityBody = true; - contentDelimitation = false; - - OutputFilter[] outputFilters = outputBuffer.getFilters(); - - if (http09 == true) { - // HTTP/0.9 - outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]); - outputBuffer.commit(); - return; - } - - int statusCode = response.getStatus(); - if (statusCode < 200 || statusCode == 204 || statusCode == 205 || - statusCode == 304) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - entityBody = false; - contentDelimitation = true; - if (statusCode == 205) { - // RFC 7231 requires the server to explicitly signal an empty - // response in this case - response.setContentLength(0); - } else { - response.setContentLength(-1); - } - } - - MessageBytes methodMB = request.method(); - if (methodMB.equals("HEAD")) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - - // Sendfile support - if (protocol.getUseSendfile()) { - prepareSendfile(outputFilters); - } - - // Check for compression - boolean useCompression = false; - if (entityBody && sendfileData == null) { - useCompression = protocol.useCompression(request, response); - } - - MimeHeaders headers = response.getMimeHeaders(); - // A SC_NO_CONTENT response may include entity headers - if (entityBody || statusCode == HttpServletResponse.SC_NO_CONTENT) { - String contentType = response.getContentType(); - if (contentType != null) { - headers.setValue("Content-Type").setString(contentType); - } - String contentLanguage = response.getContentLanguage(); - if (contentLanguage != null) { - headers.setValue("Content-Language") - .setString(contentLanguage); - } - } - - long contentLength = response.getContentLengthLong(); - boolean connectionClosePresent = isConnectionToken(headers, Constants.CLOSE); - if (http11 && response.getTrailerFields() != null) { - // If trailer fields are set, always use chunking - outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); - } else if (contentLength != -1) { - headers.setValue("Content-Length").setLong(contentLength); - outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } else { - // If the response code supports an entity body and we're on - // HTTP 1.1 then we chunk unless we have a Connection: close header - if (http11 && entityBody && !connectionClosePresent) { - outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); - } else { - outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]); - } - } - - if (useCompression) { - outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); - } - - // Add date header unless application has already set one (e.g. in a - // Caching Filter) - if (headers.getValue("Date") == null) { - headers.addValue("Date").setString( - FastHttpDateFormat.getCurrentDate()); - } - - // FIXME: Add transfer encoding header - - if ((entityBody) && (!contentDelimitation) || connectionClosePresent) { - // Disable keep-alive if: - // - there is a response body but way for the client to determine - // the content length information; or - // - there is a "connection: close" header present - // This will cause the "connection: close" header to be added if it - // is not already present. - keepAlive = false; - } - - // This may disabled keep-alive to check before working out the - // Connection header. - checkExpectationAndResponseStatus(); - - // This may disable keep-alive if there is more body to swallow - // than the configuration allows - checkMaxSwallowSize(); - - // If we know that the request is bad this early, add the - // Connection: close header. - if (keepAlive && statusDropsConnection(statusCode)) { - keepAlive = false; - } - if (!keepAlive) { - // Avoid adding the close header twice - if (!connectionClosePresent) { - headers.addValue(Constants.CONNECTION).setString( - Constants.CLOSE); - } - } else if (!getErrorState().isError()) { - if (!http11) { - headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN); - } - - if (protocol.getUseKeepAliveResponseHeader()) { - boolean connectionKeepAlivePresent = - isConnectionToken(request.getMimeHeaders(), Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN); - - if (connectionKeepAlivePresent) { - int keepAliveTimeout = protocol.getKeepAliveTimeout(); - - if (keepAliveTimeout > 0) { - String value = "timeout=" + keepAliveTimeout / 1000L; - headers.setValue(Constants.KEEP_ALIVE_HEADER_NAME).setString(value); - - if (http11) { - // Append if there is already a Connection header, - // else create the header - MessageBytes connectionHeaderValue = headers.getValue(Constants.CONNECTION); - if (connectionHeaderValue == null) { - headers.addValue(Constants.CONNECTION).setString(Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN); - } else { - connectionHeaderValue.setString( - connectionHeaderValue.getString() + ", " + Constants.KEEP_ALIVE_HEADER_VALUE_TOKEN); - } - } - } - } - } - } - - // Add server header - String server = protocol.getServer(); - if (server == null) { - if (protocol.getServerRemoveAppProvidedValues()) { - headers.removeHeader("server"); - } - } else { - // server always overrides anything the app might set - headers.setValue("Server").setString(server); - } - - // Build the response header - try { - outputBuffer.sendStatus(); - - int size = headers.size(); - for (int i = 0; i < size; i++) { - try { - outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); - } catch (IllegalArgumentException iae) { - // Log the problematic header - log.warn(sm.getString("http11processor.response.invalidHeader", - headers.getName(i), headers.getValue(i)), iae); - // Remove the problematic header - headers.removeHeader(i); - size--; - // Header buffer is corrupted. Reset it and start again. - outputBuffer.resetHeaderBuffer(); - i = 0; - outputBuffer.sendStatus(); - } - } - outputBuffer.endHeaders(); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - // If something goes wrong, reset the header buffer so the error - // response can be written instead. - outputBuffer.resetHeaderBuffer(); - throw t; - } - - outputBuffer.commit(); - } - - private static boolean isConnectionToken(MimeHeaders headers, String token) throws IOException { - MessageBytes connection = headers.getValue(Constants.CONNECTION); - if (connection == null) { - return false; - } - - Set<String> tokens = new HashSet<>(); - TokenList.parseTokenList(headers.values(Constants.CONNECTION), tokens); - return tokens.contains(token); - } - - - private void prepareSendfile(OutputFilter[] outputFilters) { - String fileName = (String) request.getAttribute( - org.apache.coyote.Constants.SENDFILE_FILENAME_ATTR); - if (fileName == null) { - sendfileData = null; - } else { - // No entity body sent here - outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - long pos = ((Long) request.getAttribute( - org.apache.coyote.Constants.SENDFILE_FILE_START_ATTR)).longValue(); - long end = ((Long) request.getAttribute( - org.apache.coyote.Constants.SENDFILE_FILE_END_ATTR)).longValue(); - sendfileData = socketWrapper.createSendfileData(fileName, pos, end - pos); - } - } - - - /* - * Note: populateHost() is not over-ridden. - * request.serverName() will be set to return the default host name by - * the Mapper. - */ - - - /** - * {@inheritDoc} - * <p> - * This implementation provides the server port from the local port. - */ - @Override - protected void populatePort() { - // Ensure the local port field is populated before using it. - request.action(ActionCode.REQ_LOCALPORT_ATTRIBUTE, request); - request.setServerPort(request.getLocalPort()); - } - - - @Override - protected boolean flushBufferedWrite() throws IOException { - if (outputBuffer.hasDataToWrite()) { - if (outputBuffer.flushBuffer(false)) { - // The buffer wasn't fully flushed so re-register the - // socket for write. Note this does not go via the - // Response since the write registration state at - // that level should remain unchanged. Once the buffer - // has been emptied then the code below will call - // Adaptor.asyncDispatch() which will enable the - // Response to respond to this event. - outputBuffer.registerWriteInterest(); - return true; - } - } - return false; - } - - - @Override - protected SocketState dispatchEndRequest() { - if (!keepAlive || protocol.isPaused()) { - return SocketState.CLOSED; - } else { - endRequest(); - inputBuffer.nextRequest(); - outputBuffer.nextRequest(); - if (socketWrapper.isReadPending()) { - return SocketState.LONG; - } else { - return SocketState.OPEN; - } - } + super(protocol, adapter); } @@ -1179,277 +34,4 @@ public class Http11Processor extends AbstractProcessor { protected Log getLog() { return log; } - - - @Override - protected ServletConnection getServletConnection() { - return socketWrapper.getServletConnection("http/1.1", ""); - } - - - /* - * No more input will be passed to the application. Remaining input will be - * swallowed or the connection dropped depending on the error and - * expectation status. - */ - private void endRequest() { - if (getErrorState().isError()) { - // If we know we are closing the connection, don't drain - // input. This way uploading a 100GB file doesn't tie up the - // thread if the servlet has rejected it. - inputBuffer.setSwallowInput(false); - } else { - // Need to check this again here in case the response was - // committed before the error that requires the connection - // to be closed occurred. - checkExpectationAndResponseStatus(); - } - - // Finish the handling of the request - if (getErrorState().isIoAllowed()) { - try { - inputBuffer.endRequest(); - } catch (IOException e) { - setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - // 500 - Internal Server Error - // Can't add a 500 to the access log since that has already been - // written in the Adapter.service method. - response.setStatus(500); - setErrorState(ErrorState.CLOSE_NOW, t); - log.error(sm.getString("http11processor.request.finish"), t); - } - } - if (getErrorState().isIoAllowed()) { - try { - action(ActionCode.COMMIT, null); - outputBuffer.end(); - } catch (IOException e) { - setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e); - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - setErrorState(ErrorState.CLOSE_NOW, t); - log.error(sm.getString("http11processor.response.finish"), t); - } - } - } - - - @Override - protected final void finishResponse() throws IOException { - outputBuffer.end(); - } - - - @Override - protected final void ack(ContinueResponseTiming continueResponseTiming) { - // Only try and send the ACK for ALWAYS or if the timing of the request - // to send the ACK matches the current configuration. - if (continueResponseTiming == ContinueResponseTiming.ALWAYS || - continueResponseTiming == protocol.getContinueResponseTimingInternal()) { - // Acknowledge request - // Send a 100 status back if it makes sense (response not committed - // yet, and client specified an expectation for 100-continue) - if (!response.isCommitted() && request.hasExpectation()) { - try { - outputBuffer.sendAck(); - } catch (IOException e) { - setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e); - } - } - } - } - - - @Override - protected final void flush() throws IOException { - outputBuffer.flush(); - } - - - @Override - protected final int available(boolean doRead) { - return inputBuffer.available(doRead); - } - - - @Override - protected final void setRequestBody(ByteChunk body) { - InputFilter savedBody = new SavedRequestInputFilter(body); - Http11InputBuffer internalBuffer = (Http11InputBuffer) request.getInputBuffer(); - internalBuffer.addActiveFilter(savedBody); - } - - - @Override - protected final void setSwallowResponse() { - outputBuffer.responseFinished = true; - } - - - @Override - protected final void disableSwallowRequest() { - inputBuffer.setSwallowInput(false); - } - - - @Override - protected final void sslReHandShake() throws IOException { - if (sslSupport != null) { - // Consume and buffer the request body, so that it does not - // interfere with the client's handshake messages - InputFilter[] inputFilters = inputBuffer.getFilters(); - ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]).setLimit( - protocol.getMaxSavePostSize()); - inputBuffer.addActiveFilter(inputFilters[Constants.BUFFERED_FILTER]); - - /* - * Outside the try/catch because we want I/O errors during - * renegotiation to be thrown for the caller to handle since they - * will be fatal to the connection. - */ - socketWrapper.doClientAuth(sslSupport); - try { - /* - * Errors processing the cert chain do not affect the client - * connection so they can be logged and swallowed here. - */ - Object sslO = sslSupport.getPeerCertificateChain(); - if (sslO != null) { - request.setAttribute(SSLSupport.CERTIFICATE_KEY, sslO); - } - } catch (IOException ioe) { - log.warn(sm.getString("http11processor.socket.ssl"), ioe); - } - } - } - - - @Override - protected final boolean isRequestBodyFullyRead() { - return inputBuffer.isFinished(); - } - - - @Override - protected final void registerReadInterest() { - socketWrapper.registerReadInterest(); - } - - - @Override - protected final boolean isReadyForWrite() { - return outputBuffer.isReady(); - } - - - @Override - public UpgradeToken getUpgradeToken() { - return upgradeToken; - } - - - @Override - protected final void doHttpUpgrade(UpgradeToken upgradeToken) { - this.upgradeToken = upgradeToken; - // Stop further HTTP output - outputBuffer.responseFinished = true; - } - - - @Override - public ByteBuffer getLeftoverInput() { - return inputBuffer.getLeftover(); - } - - - @Override - public boolean isUpgrade() { - return upgradeToken != null; - } - - - @Override - protected boolean isTrailerFieldsReady() { - if (inputBuffer.isChunking()) { - return inputBuffer.isFinished(); - } else { - return true; - } - } - - - @Override - protected boolean isTrailerFieldsSupported() { - // Request must be HTTP/1.1 to support trailer fields - if (!http11) { - return false; - } - - // If the response is not yet committed, chunked encoding can be used - // and the trailer fields sent - if (!response.isCommitted()) { - return true; - } - - // Response has been committed - need to see if chunked is being used - return outputBuffer.isChunking(); - } - - - /** - * Trigger sendfile processing if required. - * - * @return The state of send file processing - */ - private SendfileState processSendfile(SocketWrapperBase<?> socketWrapper) { - openSocket = keepAlive; - // Done is equivalent to sendfile not being used - SendfileState result = SendfileState.DONE; - // Do sendfile as needed: add socket to sendfile and end - if (sendfileData != null && !getErrorState().isError()) { - if (keepAlive) { - if (available(false) == 0) { - sendfileData.keepAliveState = SendfileKeepAliveState.OPEN; - } else { - sendfileData.keepAliveState = SendfileKeepAliveState.PIPELINED; - } - } else { - sendfileData.keepAliveState = SendfileKeepAliveState.NONE; - } - result = socketWrapper.processSendfile(sendfileData); - switch (result) { - case ERROR: - // Write failed - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.sendfile.error")); - } - setErrorState(ErrorState.CLOSE_CONNECTION_NOW, null); - //$FALL-THROUGH$ - default: - sendfileData = null; - } - } - return result; - } - - - @Override - public final void recycle() { - getAdapter().checkRecycled(request, response); - super.recycle(); - inputBuffer.recycle(); - outputBuffer.recycle(); - upgradeToken = null; - socketWrapper = null; - sendfileData = null; - sslSupport = null; - } - - - @Override - public void pause() { - // NOOP for HTTP - } } diff --git a/modules/loom/src/main/java/org/apache/coyote/http11/Http11LoomProcessor.java b/modules/loom/src/main/java/org/apache/coyote/http11/Http11LoomProcessor.java index cc1e5de4d0..bfd16c7026 100644 --- a/modules/loom/src/main/java/org/apache/coyote/http11/Http11LoomProcessor.java +++ b/modules/loom/src/main/java/org/apache/coyote/http11/Http11LoomProcessor.java @@ -17,10 +17,21 @@ package org.apache.coyote.http11; import org.apache.coyote.Adapter; +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; + +public class Http11LoomProcessor extends AbstractHttp11Processor { + + private static final Log log = LogFactory.getLog(Http11LoomProcessor.class); -public class Http11LoomProcessor extends Http11Processor { public Http11LoomProcessor(AbstractHttp11Protocol<?> protocol, Adapter adapter) { super(protocol, adapter); } + + + @Override + protected Log getLog() { + return log; + } } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org