You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2022/10/19 14:39:20 UTC
[tomcat] 02/03: Refactor to prepare for Loom specific Http11InputBuffer
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 38c63375b30fe283a205b17cb6016c95bd3cff35
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Wed Oct 12 18:00:40 2022 +0100
Refactor to prepare for Loom specific Http11InputBuffer
---
...tBuffer.java => AbstractHttp11InputBuffer.java} | 30 +-
.../coyote/http11/AbstractHttp11Processor.java | 9 +-
.../apache/coyote/http11/Http11InputBuffer.java | 1221 +-------------------
java/org/apache/coyote/http11/Http11Processor.java | 10 +
.../coyote/http11/Http11LoomInputBuffer.java | 12 +-
.../apache/coyote/http11/Http11LoomProcessor.java | 10 +
6 files changed, 54 insertions(+), 1238 deletions(-)
diff --git a/java/org/apache/coyote/http11/Http11InputBuffer.java b/java/org/apache/coyote/http11/AbstractHttp11InputBuffer.java
similarity index 98%
copy from java/org/apache/coyote/http11/Http11InputBuffer.java
copy to java/org/apache/coyote/http11/AbstractHttp11InputBuffer.java
index ddd7e2d1e2..8c9f53e162 100644
--- a/java/org/apache/coyote/http11/Http11InputBuffer.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11InputBuffer.java
@@ -26,7 +26,6 @@ import org.apache.coyote.CloseNowException;
import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.juli.logging.Log;
-import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.buf.MessageBytes;
import org.apache.tomcat.util.http.HeaderUtil;
import org.apache.tomcat.util.http.MimeHeaders;
@@ -36,15 +35,13 @@ import org.apache.tomcat.util.net.SocketWrapperBase;
import org.apache.tomcat.util.res.StringManager;
/**
- * InputBuffer for HTTP that provides request header parsing as well as transfer
- * encoding.
+ * Abstract base implementation of InputBuffer for HTTP that provides request
+ * header parsing as well as transfer encoding.
*/
-public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler {
+public abstract class AbstractHttp11InputBuffer implements InputBuffer, ApplicationBufferHandler {
// -------------------------------------------------------------- Constants
- private static final Log log = LogFactory.getLog(Http11InputBuffer.class);
-
/**
* The string manager for this package.
*/
@@ -153,7 +150,7 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
// ----------------------------------------------------------- Constructors
- public Http11InputBuffer(Request request, int headerBufferSize,
+ public AbstractHttp11InputBuffer(Request request, int headerBufferSize,
boolean rejectIllegalHeader, HttpParser httpParser) {
this.request = request;
@@ -696,8 +693,8 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
available = byteBuffer.remaining();
}
} catch (IOException ioe) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("iib.available.readFail"), ioe);
+ if (getLog().isDebugEnabled()) {
+ getLog().debug(sm.getString("iib.available.readFail"), ioe);
}
// Not ideal. This will indicate that data is available which should
// trigger a read which in turn will trigger another IOException and
@@ -771,8 +768,8 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
*/
private boolean fill(boolean block) throws IOException {
- if (log.isDebugEnabled()) {
- log.debug("Before fill(): parsingHeader: [" + parsingHeader +
+ if (getLog().isDebugEnabled()) {
+ getLog().debug("Before fill(): parsingHeader: [" + parsingHeader +
"], parsingRequestLine: [" + parsingRequestLine +
"], parsingRequestLinePhase: [" + parsingRequestLinePhase +
"], parsingRequestLineStart: [" + parsingRequestLineStart +
@@ -826,8 +823,8 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
}
}
- if (log.isDebugEnabled()) {
- log.debug("Received ["
+ if (getLog().isDebugEnabled()) {
+ getLog().debug("Received ["
+ new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining(), StandardCharsets.ISO_8859_1) + "]");
}
@@ -1085,14 +1082,14 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
headerData.lastSignificantChar = pos;
}
}
- if (rejectThisHeader || log.isDebugEnabled()) {
+ if (rejectThisHeader || getLog().isDebugEnabled()) {
String message = sm.getString("iib.invalidheader",
HeaderUtil.toPrintableString(byteBuffer.array(), headerData.lineStart,
headerData.lastSignificantChar - headerData.lineStart + 1));
if (rejectThisHeader) {
throw new IllegalArgumentException(message);
}
- log.debug(message);
+ getLog().debug(message);
}
headerParsePos = HeaderParsePosition.HEADER_START;
@@ -1100,6 +1097,9 @@ public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler
}
+ protected abstract Log getLog();
+
+
// ----------------------------------------------------------- Inner classes
private enum HeaderParseStatus {
diff --git a/java/org/apache/coyote/http11/AbstractHttp11Processor.java b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
index b63b824bc6..db1d743e8f 100644
--- a/java/org/apache/coyote/http11/AbstractHttp11Processor.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11Processor.java
@@ -79,7 +79,7 @@ public abstract class AbstractHttp11Processor extends AbstractProcessor {
/**
* Input.
*/
- private final Http11InputBuffer inputBuffer;
+ private final AbstractHttp11InputBuffer inputBuffer;
/**
@@ -155,8 +155,7 @@ public abstract class AbstractHttp11Processor extends AbstractProcessor {
httpParser = new HttpParser(protocol.getRelaxedPathChars(),
protocol.getRelaxedQueryChars());
- inputBuffer = new Http11InputBuffer(request, protocol.getMaxHttpRequestHeaderSize(),
- protocol.getRejectIllegalHeader(), httpParser);
+ inputBuffer = createInputBuffer(request, protocol, httpParser);
request.setInputBuffer(inputBuffer);
outputBuffer = new Http11OutputBuffer(response, protocol.getMaxHttpResponseHeaderSize());
@@ -187,6 +186,10 @@ public abstract class AbstractHttp11Processor extends AbstractProcessor {
}
+ protected abstract AbstractHttp11InputBuffer createInputBuffer(Request request,
+ AbstractHttp11Protocol<?> protocol, HttpParser httpParser);
+
+
/**
* Determine if we must drop the connection because of the HTTP status
* code. Use the same list of codes as Apache/httpd.
diff --git a/java/org/apache/coyote/http11/Http11InputBuffer.java b/java/org/apache/coyote/http11/Http11InputBuffer.java
index ddd7e2d1e2..56832039d9 100644
--- a/java/org/apache/coyote/http11/Http11InputBuffer.java
+++ b/java/org/apache/coyote/http11/Http11InputBuffer.java
@@ -16,1237 +16,28 @@
*/
package org.apache.coyote.http11;
-import java.io.EOFException;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-
-import org.apache.coyote.CloseNowException;
-import org.apache.coyote.InputBuffer;
import org.apache.coyote.Request;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
-import org.apache.tomcat.util.buf.MessageBytes;
-import org.apache.tomcat.util.http.HeaderUtil;
-import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.http.parser.HttpParser;
-import org.apache.tomcat.util.net.ApplicationBufferHandler;
-import org.apache.tomcat.util.net.SocketWrapperBase;
-import org.apache.tomcat.util.res.StringManager;
/**
* InputBuffer for HTTP that provides request header parsing as well as transfer
* encoding.
*/
-public class Http11InputBuffer implements InputBuffer, ApplicationBufferHandler {
-
- // -------------------------------------------------------------- Constants
+public class Http11InputBuffer extends AbstractHttp11InputBuffer {
private static final Log log = LogFactory.getLog(Http11InputBuffer.class);
- /**
- * The string manager for this package.
- */
- private static final StringManager sm = StringManager.getManager(Http11InputBuffer.class);
-
-
- private static final byte[] CLIENT_PREFACE_START =
- "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n".getBytes(StandardCharsets.ISO_8859_1);
-
- /**
- * Associated Coyote request.
- */
- private final Request request;
-
-
- /**
- * Headers of the associated request.
- */
- private final MimeHeaders headers;
-
-
- private final boolean rejectIllegalHeader;
-
- /**
- * State.
- */
- private volatile boolean parsingHeader;
-
-
- /**
- * Swallow input ? (in the case of an expectation)
- */
- private boolean swallowInput;
-
-
- /**
- * The read buffer.
- */
- private ByteBuffer byteBuffer;
-
-
- /**
- * Pos of the end of the header in the buffer, which is also the
- * start of the body.
- */
- private int end;
-
-
- /**
- * Wrapper that provides access to the underlying socket.
- */
- private SocketWrapperBase<?> wrapper;
-
-
- /**
- * Underlying input buffer.
- */
- private InputBuffer inputStreamInputBuffer;
-
-
- /**
- * Filter library.
- * Note: Filter[Constants.CHUNKED_FILTER] is always the "chunked" filter.
- */
- private InputFilter[] filterLibrary;
-
-
- /**
- * Active filters (in order).
- */
- private InputFilter[] activeFilters;
-
-
- /**
- * Index of the last active filter.
- */
- private int lastActiveFilter;
-
-
- /**
- * Parsing state - used for non blocking parsing so that
- * when more data arrives, we can pick up where we left off.
- */
- private byte prevChr = 0;
- private byte chr = 0;
- private volatile boolean parsingRequestLine;
- private int parsingRequestLinePhase = 0;
- private boolean parsingRequestLineEol = false;
- private int parsingRequestLineStart = 0;
- private int parsingRequestLineQPos = -1;
- private HeaderParsePosition headerParsePos;
- private final HeaderParseData headerData = new HeaderParseData();
- private final HttpParser httpParser;
-
- /**
- * Maximum allowed size of the HTTP request line plus headers plus any
- * leading blank lines.
- */
- private final int headerBufferSize;
-
- /**
- * Known size of the NioChannel read buffer.
- */
- private int socketReadBufferSize;
-
-
- // ----------------------------------------------------------- Constructors
-
- public Http11InputBuffer(Request request, int headerBufferSize,
- boolean rejectIllegalHeader, HttpParser httpParser) {
-
- this.request = request;
- headers = request.getMimeHeaders();
-
- this.headerBufferSize = headerBufferSize;
- this.rejectIllegalHeader = rejectIllegalHeader;
- this.httpParser = httpParser;
-
- filterLibrary = new InputFilter[0];
- activeFilters = new InputFilter[0];
- lastActiveFilter = -1;
-
- parsingHeader = true;
- parsingRequestLine = true;
- parsingRequestLinePhase = 0;
- parsingRequestLineEol = false;
- parsingRequestLineStart = 0;
- parsingRequestLineQPos = -1;
- headerParsePos = HeaderParsePosition.HEADER_START;
- swallowInput = true;
-
- inputStreamInputBuffer = new SocketInputBuffer();
- }
-
-
- // ------------------------------------------------------------- Properties
-
- /**
- * Add an input filter to the filter library.
- *
- * @throws NullPointerException if the supplied filter is null
- */
- void addFilter(InputFilter filter) {
-
- if (filter == null) {
- throw new NullPointerException(sm.getString("iib.filter.npe"));
- }
-
- InputFilter[] newFilterLibrary = Arrays.copyOf(filterLibrary, filterLibrary.length + 1);
- newFilterLibrary[filterLibrary.length] = filter;
- filterLibrary = newFilterLibrary;
-
- activeFilters = new InputFilter[filterLibrary.length];
- }
-
-
- /**
- * Get filters.
- */
- InputFilter[] getFilters() {
- return filterLibrary;
- }
-
-
- /**
- * Add an input filter to the filter library.
- */
- void addActiveFilter(InputFilter filter) {
-
- if (lastActiveFilter == -1) {
- filter.setBuffer(inputStreamInputBuffer);
- } else {
- for (int i = 0; i <= lastActiveFilter; i++) {
- if (activeFilters[i] == filter) {
- return;
- }
- }
- filter.setBuffer(activeFilters[lastActiveFilter]);
- }
-
- activeFilters[++lastActiveFilter] = filter;
-
- filter.setRequest(request);
- }
-
-
- /**
- * Set the swallow input flag.
- */
- void setSwallowInput(boolean swallowInput) {
- this.swallowInput = swallowInput;
- }
-
-
- // ---------------------------------------------------- InputBuffer Methods
-
- @Override
- public int doRead(ApplicationBufferHandler handler) throws IOException {
- if (lastActiveFilter == -1) {
- return inputStreamInputBuffer.doRead(handler);
- } else {
- return activeFilters[lastActiveFilter].doRead(handler);
- }
- }
-
-
- // ------------------------------------------------------- Protected Methods
-
- /**
- * Recycle the input buffer. This should be called when closing the
- * connection.
- */
- void recycle() {
- wrapper = null;
- request.recycle();
-
- for (int i = 0; i <= lastActiveFilter; i++) {
- activeFilters[i].recycle();
- }
-
- byteBuffer.limit(0).position(0);
- lastActiveFilter = -1;
- swallowInput = true;
-
- chr = 0;
- prevChr = 0;
- headerParsePos = HeaderParsePosition.HEADER_START;
- parsingRequestLinePhase = 0;
- parsingRequestLineEol = false;
- parsingRequestLineStart = 0;
- parsingRequestLineQPos = -1;
- headerData.recycle();
- // Recycled last because they are volatile
- // All variables visible to this thread are guaranteed to be visible to
- // any other thread once that thread reads the same volatile. The first
- // action when parsing input data is to read one of these volatiles.
- parsingRequestLine = true;
- parsingHeader = true;
- }
-
-
- /**
- * End processing of current HTTP request.
- * Note: All bytes of the current request should have been already
- * consumed. This method only resets all the pointers so that we are ready
- * to parse the next HTTP request.
- */
- void nextRequest() {
- request.recycle();
- if (byteBuffer.position() > 0) {
- if (byteBuffer.remaining() > 0) {
- // Copy leftover bytes to the beginning of the buffer
- byteBuffer.compact();
- byteBuffer.flip();
- } else {
- // Reset position and limit to 0
- byteBuffer.position(0).limit(0);
- }
- }
-
- // Recycle filters
- for (int i = 0; i <= lastActiveFilter; i++) {
- activeFilters[i].recycle();
- }
-
- // Reset pointers
- lastActiveFilter = -1;
- parsingHeader = true;
- swallowInput = true;
-
- headerParsePos = HeaderParsePosition.HEADER_START;
- parsingRequestLine = true;
- parsingRequestLinePhase = 0;
- parsingRequestLineEol = false;
- parsingRequestLineStart = 0;
- parsingRequestLineQPos = -1;
- headerData.recycle();
- }
-
-
- /**
- * Read the request line. This function is meant to be used during the
- * HTTP request header parsing. Do NOT attempt to read the request body
- * using it.
- *
- * @throws IOException If an exception occurs during the underlying socket
- * read operations, or if the given buffer is not big enough to accommodate
- * the whole line.
- *
- * @return true if data is properly fed; false if no data is available
- * immediately and thread should be freed
- */
- boolean parseRequestLine(boolean keptAlive, int connectionTimeout, int keepAliveTimeout)
- throws IOException {
-
- // check state
- if (!parsingRequestLine) {
- return true;
- }
- //
- // Skipping blank lines
- //
- if (parsingRequestLinePhase < 2) {
- do {
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (keptAlive) {
- // Haven't read any request data yet so use the keep-alive
- // timeout.
- wrapper.setReadTimeout(keepAliveTimeout);
- }
- if (!fill(false)) {
- // A read is pending, so no longer in initial state
- parsingRequestLinePhase = 1;
- return false;
- }
- // At least one byte of the request has been received.
- // Switch to the socket timeout.
- wrapper.setReadTimeout(connectionTimeout);
- }
- if (!keptAlive && byteBuffer.position() == 0 && byteBuffer.limit() >= CLIENT_PREFACE_START.length) {
- boolean prefaceMatch = true;
- for (int i = 0; i < CLIENT_PREFACE_START.length && prefaceMatch; i++) {
- if (CLIENT_PREFACE_START[i] != byteBuffer.get(i)) {
- prefaceMatch = false;
- }
- }
- if (prefaceMatch) {
- // HTTP/2 preface matched
- parsingRequestLinePhase = -1;
- return false;
- }
- }
- // Set the start time once we start reading data (even if it is
- // just skipping blank lines)
- if (request.getStartTimeNanos() < 0) {
- request.setStartTimeNanos(System.nanoTime());
- }
- chr = byteBuffer.get();
- } while ((chr == Constants.CR) || (chr == Constants.LF));
- byteBuffer.position(byteBuffer.position() - 1);
-
- parsingRequestLineStart = byteBuffer.position();
- parsingRequestLinePhase = 2;
- }
- if (parsingRequestLinePhase == 2) {
- //
- // Reading the method name
- // Method name is a token
- //
- boolean space = false;
- while (!space) {
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {
- return false;
- }
- }
- // Spec says method name is a token followed by a single SP but
- // also be tolerant of multiple SP and/or HT.
- int pos = byteBuffer.position();
- chr = byteBuffer.get();
- if (chr == Constants.SP || chr == Constants.HT) {
- space = true;
- request.method().setBytes(byteBuffer.array(), parsingRequestLineStart,
- pos - parsingRequestLineStart);
- } else if (!HttpParser.isToken(chr)) {
- // Avoid unknown protocol triggering an additional error
- request.protocol().setString(Constants.HTTP_11);
- String invalidMethodValue = parseInvalid(parsingRequestLineStart, byteBuffer);
- throw new IllegalArgumentException(sm.getString("iib.invalidmethod", invalidMethodValue));
- }
- }
- parsingRequestLinePhase = 3;
- }
- if (parsingRequestLinePhase == 3) {
- // Spec says single SP but also be tolerant of multiple SP and/or HT
- boolean space = true;
- while (space) {
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {
- return false;
- }
- }
- chr = byteBuffer.get();
- if (!(chr == Constants.SP || chr == Constants.HT)) {
- space = false;
- byteBuffer.position(byteBuffer.position() - 1);
- }
- }
- parsingRequestLineStart = byteBuffer.position();
- parsingRequestLinePhase = 4;
- }
- if (parsingRequestLinePhase == 4) {
- // Mark the current buffer position
-
- int end = 0;
- //
- // Reading the URI
- //
- boolean space = false;
- while (!space) {
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {
- return false;
- }
- }
- int pos = byteBuffer.position();
- prevChr = chr;
- chr = byteBuffer.get();
- if (prevChr == Constants.CR && chr != Constants.LF) {
- // CR not followed by LF so not an HTTP/0.9 request and
- // therefore invalid. Trigger error handling.
- // Avoid unknown protocol triggering an additional error
- request.protocol().setString(Constants.HTTP_11);
- String invalidRequestTarget = parseInvalid(parsingRequestLineStart, byteBuffer);
- throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget", invalidRequestTarget));
- }
- if (chr == Constants.SP || chr == Constants.HT) {
- space = true;
- end = pos;
- } else if (chr == Constants.CR) {
- // HTTP/0.9 style request. CR is optional. LF is not.
- } else if (chr == Constants.LF) {
- // HTTP/0.9 style request
- // Stop this processing loop
- space = true;
- // Set blank protocol (indicates HTTP/0.9)
- request.protocol().setString("");
- // Skip the protocol processing
- parsingRequestLinePhase = 7;
- if (prevChr == Constants.CR) {
- end = pos - 1;
- } else {
- end = pos;
- }
- } else if (chr == Constants.QUESTION && parsingRequestLineQPos == -1) {
- parsingRequestLineQPos = pos;
- } else if (parsingRequestLineQPos != -1 && !httpParser.isQueryRelaxed(chr)) {
- // Avoid unknown protocol triggering an additional error
- request.protocol().setString(Constants.HTTP_11);
- // %nn decoding will be checked at the point of decoding
- String invalidRequestTarget = parseInvalid(parsingRequestLineStart, byteBuffer);
- throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget", invalidRequestTarget));
- } else if (httpParser.isNotRequestTargetRelaxed(chr)) {
- // Avoid unknown protocol triggering an additional error
- request.protocol().setString(Constants.HTTP_11);
- // This is a general check that aims to catch problems early
- // Detailed checking of each part of the request target will
- // happen in Http11Processor#prepareRequest()
- String invalidRequestTarget = parseInvalid(parsingRequestLineStart, byteBuffer);
- throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget", invalidRequestTarget));
- }
- }
- if (parsingRequestLineQPos >= 0) {
- request.queryString().setBytes(byteBuffer.array(), parsingRequestLineQPos + 1,
- end - parsingRequestLineQPos - 1);
- request.requestURI().setBytes(byteBuffer.array(), parsingRequestLineStart,
- parsingRequestLineQPos - parsingRequestLineStart);
- } else {
- request.requestURI().setBytes(byteBuffer.array(), parsingRequestLineStart,
- end - parsingRequestLineStart);
- }
- // HTTP/0.9 processing jumps to stage 7.
- // Don't want to overwrite that here.
- if (parsingRequestLinePhase == 4) {
- parsingRequestLinePhase = 5;
- }
- }
- if (parsingRequestLinePhase == 5) {
- // Spec says single SP but also be tolerant of multiple and/or HT
- boolean space = true;
- while (space) {
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {
- return false;
- }
- }
- byte chr = byteBuffer.get();
- if (!(chr == Constants.SP || chr == Constants.HT)) {
- space = false;
- byteBuffer.position(byteBuffer.position() - 1);
- }
- }
- parsingRequestLineStart = byteBuffer.position();
- parsingRequestLinePhase = 6;
-
- // Mark the current buffer position
- end = 0;
- }
- if (parsingRequestLinePhase == 6) {
- //
- // Reading the protocol
- // Protocol is always "HTTP/" DIGIT "." DIGIT
- //
- while (!parsingRequestLineEol) {
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {
- return false;
- }
- }
-
- int pos = byteBuffer.position();
- prevChr = chr;
- chr = byteBuffer.get();
- if (chr == Constants.CR) {
- // Possible end of request line. Need LF next else invalid.
- } else if (prevChr == Constants.CR && chr == Constants.LF) {
- // CRLF is the standard line terminator
- end = pos - 1;
- parsingRequestLineEol = true;
- } else if (chr == Constants.LF) {
- // LF is an optional line terminator
- end = pos;
- parsingRequestLineEol = true;
- } else if (prevChr == Constants.CR || !HttpParser.isHttpProtocol(chr)) {
- String invalidProtocol = parseInvalid(parsingRequestLineStart, byteBuffer);
- throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol", invalidProtocol));
- }
- }
-
- if ((end - parsingRequestLineStart) > 0) {
- request.protocol().setBytes(byteBuffer.array(), parsingRequestLineStart,
- end - parsingRequestLineStart);
- parsingRequestLinePhase = 7;
- }
- // If no protocol is found, the ISE below will be triggered.
- }
- if (parsingRequestLinePhase == 7) {
- // Parsing is complete. Return and clean-up.
- parsingRequestLine = false;
- parsingRequestLinePhase = 0;
- parsingRequestLineEol = false;
- parsingRequestLineStart = 0;
- return true;
- }
- throw new IllegalStateException(sm.getString("iib.invalidPhase", Integer.valueOf(parsingRequestLinePhase)));
- }
-
-
- /**
- * Parse the HTTP headers.
- */
- boolean parseHeaders() throws IOException {
- if (!parsingHeader) {
- throw new IllegalStateException(sm.getString("iib.parseheaders.ise.error"));
- }
-
- HeaderParseStatus status = HeaderParseStatus.HAVE_MORE_HEADERS;
-
- do {
- status = parseHeader();
- // Checking that
- // (1) Headers plus request line size does not exceed its limit
- // (2) There are enough bytes to avoid expanding the buffer when
- // reading body
- // Technically, (2) is technical limitation, (1) is logical
- // limitation to enforce the meaning of headerBufferSize
- // From the way how buf is allocated and how blank lines are being
- // read, it should be enough to check (1) only.
- if (byteBuffer.position() > headerBufferSize || byteBuffer.capacity() - byteBuffer.position() < socketReadBufferSize) {
- throw new IllegalArgumentException(sm.getString("iib.requestheadertoolarge.error"));
- }
- } while (status == HeaderParseStatus.HAVE_MORE_HEADERS);
- if (status == HeaderParseStatus.DONE) {
- parsingHeader = false;
- end = byteBuffer.position();
- return true;
- } else {
- return false;
- }
- }
-
-
- int getParsingRequestLinePhase() {
- return parsingRequestLinePhase;
- }
-
-
- private String parseInvalid(int startPos, ByteBuffer buffer) {
- // Look for the next space
- byte b = 0;
- while (buffer.hasRemaining() && b != 0x20) {
- b = buffer.get();
- }
- String result = HeaderUtil.toPrintableString(buffer.array(), buffer.arrayOffset() + startPos, buffer.position() - startPos);
- if (b != 0x20) {
- // Ran out of buffer rather than found a space
- result = result + "...";
- }
- return result;
- }
-
-
- /**
- * End request (consumes leftover bytes).
- *
- * @throws IOException an underlying I/O error occurred
- */
- void endRequest() throws IOException {
-
- if (swallowInput && (lastActiveFilter != -1)) {
- int extraBytes = (int) activeFilters[lastActiveFilter].end();
- byteBuffer.position(byteBuffer.position() - extraBytes);
- }
- }
-
-
- @Override
- public int available() {
- return available(false);
- }
-
-
- /**
- * Available bytes in the buffers for the current request.
- *
- * Note that when requests are pipelined, the data in byteBuffer may relate
- * to the next request rather than this one.
- */
- int available(boolean read) {
- int available;
-
- if (lastActiveFilter == -1) {
- available = inputStreamInputBuffer.available();
- } else {
- available = activeFilters[lastActiveFilter].available();
- }
-
- // Only try a non-blocking read if:
- // - there is no data in the filters
- // - the caller requested a read
- // - there is no data in byteBuffer
- // - the socket wrapper indicates a read is allowed
- //
- // Notes: 1. When pipelined requests are being used available may be
- // zero even when byteBuffer has data. This is because the data
- // in byteBuffer is for the next request. We don't want to
- // attempt a read in this case.
- // 2. wrapper.hasDataToRead() is present to handle the NIO2 case
- try {
- if (available == 0 && read && !byteBuffer.hasRemaining() && wrapper.hasDataToRead()) {
- fill(false);
- available = byteBuffer.remaining();
- }
- } catch (IOException ioe) {
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("iib.available.readFail"), ioe);
- }
- // Not ideal. This will indicate that data is available which should
- // trigger a read which in turn will trigger another IOException and
- // that one can be thrown.
- available = 1;
- }
- return available;
- }
-
-
- /**
- * Has all of the request body been read? There are subtle differences
- * between this and available() > 0 primarily because of having to handle
- * faking non-blocking reads with the blocking IO connector.
- */
- boolean isFinished() {
- // The active filters have the definitive information on whether or not
- // the current request body has been read. Note that byteBuffer may
- // contain pipelined data so is not a good indicator.
- if (lastActiveFilter >= 0) {
- return activeFilters[lastActiveFilter].isFinished();
- } else {
- // No filters. Assume request is not finished. EOF will signal end of
- // request.
- return false;
- }
- }
-
- ByteBuffer getLeftover() {
- int available = byteBuffer.remaining();
- if (available > 0) {
- return ByteBuffer.wrap(byteBuffer.array(), byteBuffer.position(), available);
- } else {
- return null;
- }
- }
-
-
- boolean isChunking() {
- for (int i = 0; i < lastActiveFilter; i++) {
- if (activeFilters[i] == filterLibrary[Constants.CHUNKED_FILTER]) {
- return true;
- }
- }
- return false;
- }
-
-
- void init(SocketWrapperBase<?> socketWrapper) {
-
- wrapper = socketWrapper;
- wrapper.setAppReadBufHandler(this);
-
- int bufLength = headerBufferSize +
- wrapper.getSocketBufferHandler().getReadBuffer().capacity();
- if (byteBuffer == null || byteBuffer.capacity() < bufLength) {
- byteBuffer = ByteBuffer.allocate(bufLength);
- byteBuffer.position(0).limit(0);
- }
- }
-
-
-
- // --------------------------------------------------------- Private Methods
-
- /**
- * Attempts to read some data into the input buffer.
- *
- * @return <code>true</code> if more data was added to the input buffer
- * otherwise <code>false</code>
- */
- private boolean fill(boolean block) throws IOException {
-
- if (log.isDebugEnabled()) {
- log.debug("Before fill(): parsingHeader: [" + parsingHeader +
- "], parsingRequestLine: [" + parsingRequestLine +
- "], parsingRequestLinePhase: [" + parsingRequestLinePhase +
- "], parsingRequestLineStart: [" + parsingRequestLineStart +
- "], byteBuffer.position(): [" + byteBuffer.position() +
- "], byteBuffer.limit(): [" + byteBuffer.limit() +
- "], end: [" + end + "]");
- }
-
- if (parsingHeader) {
- if (byteBuffer.limit() >= headerBufferSize) {
- if (parsingRequestLine) {
- // Avoid unknown protocol triggering an additional error
- request.protocol().setString(Constants.HTTP_11);
- }
- throw new IllegalArgumentException(sm.getString("iib.requestheadertoolarge.error"));
- }
- } else {
- byteBuffer.limit(end).position(end);
- }
-
- int nRead = -1;
- int mark = byteBuffer.position();
- try {
- if (byteBuffer.position() < byteBuffer.limit()) {
- byteBuffer.position(byteBuffer.limit());
- }
- byteBuffer.limit(byteBuffer.capacity());
- SocketWrapperBase<?> socketWrapper = this.wrapper;
- if (socketWrapper != null) {
- nRead = socketWrapper.read(block, byteBuffer);
- } else {
- throw new CloseNowException(sm.getString("iib.eof.error"));
- }
- } finally {
- // Ensure that the buffer limit and position are returned to a
- // consistent "ready for read" state if an error occurs during in
- // the above code block.
- // Some error conditions can result in the position being reset to
- // zero which also invalidates the mark.
- // https://bz.apache.org/bugzilla/show_bug.cgi?id=65677
- if (byteBuffer.position() >= mark) {
- // // Position and mark are consistent. Assume a read (possibly
- // of zero bytes) has occurred.
- byteBuffer.limit(byteBuffer.position());
- byteBuffer.position(mark);
- } else {
- // Position and mark are inconsistent. Set position and limit to
- // zero so effectively no data is reported as read.
- byteBuffer.position(0);
- byteBuffer.limit(0);
- }
- }
-
- if (log.isDebugEnabled()) {
- log.debug("Received ["
- + new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.remaining(), StandardCharsets.ISO_8859_1) + "]");
- }
-
- if (nRead > 0) {
- return true;
- } else if (nRead == -1) {
- throw new EOFException(sm.getString("iib.eof.error"));
- } else {
- return false;
- }
-
- }
-
-
- /**
- * Parse an HTTP header.
- *
- * @return One of {@link HeaderParseStatus#NEED_MORE_DATA},
- * {@link HeaderParseStatus#HAVE_MORE_HEADERS} or
- * {@link HeaderParseStatus#DONE}.
- */
- private HeaderParseStatus parseHeader() throws IOException {
-
- while (headerParsePos == HeaderParsePosition.HEADER_START) {
-
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {
- return HeaderParseStatus.NEED_MORE_DATA;
- }
- }
-
- prevChr = chr;
- chr = byteBuffer.get();
-
- if (chr == Constants.CR && prevChr != Constants.CR) {
- // Possible start of CRLF - process the next byte.
- } else if (chr == Constants.LF) {
- // CRLF or LF is an acceptable line terminator
- return HeaderParseStatus.DONE;
- } else {
- if (prevChr == Constants.CR) {
- // Must have read two bytes (first was CR, second was not LF)
- byteBuffer.position(byteBuffer.position() - 2);
- } else {
- // Must have only read one byte
- byteBuffer.position(byteBuffer.position() - 1);
- }
- break;
- }
- }
-
- if (headerParsePos == HeaderParsePosition.HEADER_START) {
- // Mark the current buffer position
- headerData.start = byteBuffer.position();
- headerData.lineStart = headerData.start;
- headerParsePos = HeaderParsePosition.HEADER_NAME;
- }
-
- //
- // Reading the header name
- // Header name is always US-ASCII
- //
-
- while (headerParsePos == HeaderParsePosition.HEADER_NAME) {
-
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) { // parse header
- return HeaderParseStatus.NEED_MORE_DATA;
- }
- }
-
- int pos = byteBuffer.position();
- chr = byteBuffer.get();
- if (chr == Constants.COLON) {
- headerParsePos = HeaderParsePosition.HEADER_VALUE_START;
- headerData.headerValue = headers.addValue(byteBuffer.array(), headerData.start,
- pos - headerData.start);
- pos = byteBuffer.position();
- // Mark the current buffer position
- headerData.start = pos;
- headerData.realPos = pos;
- headerData.lastSignificantChar = pos;
- break;
- } else if (!HttpParser.isToken(chr)) {
- // Non-token characters are illegal in header names
- // Parsing continues so the error can be reported in context
- headerData.lastSignificantChar = pos;
- byteBuffer.position(byteBuffer.position() - 1);
- // skipLine() will handle the error
- return skipLine(false);
- }
-
- // chr is next byte of header name. Convert to lowercase.
- if ((chr >= Constants.A) && (chr <= Constants.Z)) {
- byteBuffer.put(pos, (byte) (chr - Constants.LC_OFFSET));
- }
- }
-
- // Skip the line and ignore the header
- if (headerParsePos == HeaderParsePosition.HEADER_SKIPLINE) {
- return skipLine(false);
- }
-
- //
- // Reading the header value (which can be spanned over multiple lines)
- //
-
- while (headerParsePos == HeaderParsePosition.HEADER_VALUE_START ||
- headerParsePos == HeaderParsePosition.HEADER_VALUE ||
- headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE) {
-
- if (headerParsePos == HeaderParsePosition.HEADER_VALUE_START) {
- // Skipping spaces
- while (true) {
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {// parse header
- // HEADER_VALUE_START
- return HeaderParseStatus.NEED_MORE_DATA;
- }
- }
-
- chr = byteBuffer.get();
- if (!(chr == Constants.SP || chr == Constants.HT)) {
- headerParsePos = HeaderParsePosition.HEADER_VALUE;
- byteBuffer.position(byteBuffer.position() - 1);
- // Avoids prevChr = chr at start of header value
- // parsing which causes problems when chr is CR
- // (in the case of an empty header value)
- chr = 0;
- break;
- }
- }
- }
- if (headerParsePos == HeaderParsePosition.HEADER_VALUE) {
-
- // Reading bytes until the end of the line
- boolean eol = false;
- while (!eol) {
-
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {// parse header
- // HEADER_VALUE
- return HeaderParseStatus.NEED_MORE_DATA;
- }
- }
-
- prevChr = chr;
- chr = byteBuffer.get();
- if (chr == Constants.CR && prevChr != Constants.CR) {
- // CR is only permitted at the start of a CRLF sequence.
- // Possible start of CRLF - process the next byte.
- } else if (chr == Constants.LF) {
- // CRLF or LF is an acceptable line terminator
- eol = true;
- } else if (prevChr == Constants.CR) {
- // Invalid value - also need to delete header
- return skipLine(true);
- } else if (chr != Constants.HT && HttpParser.isControl(chr)) {
- // Invalid value - also need to delete header
- return skipLine(true);
- } else if (chr == Constants.SP || chr == Constants.HT) {
- byteBuffer.put(headerData.realPos, chr);
- headerData.realPos++;
- } else {
- byteBuffer.put(headerData.realPos, chr);
- headerData.realPos++;
- headerData.lastSignificantChar = headerData.realPos;
- }
- }
-
- // Ignore whitespaces at the end of the line
- headerData.realPos = headerData.lastSignificantChar;
-
- // Checking the first character of the new line. If the character
- // is a LWS, then it's a multiline header
- headerParsePos = HeaderParsePosition.HEADER_MULTI_LINE;
- }
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {// parse header
- // HEADER_MULTI_LINE
- return HeaderParseStatus.NEED_MORE_DATA;
- }
- }
-
- byte peek = byteBuffer.get(byteBuffer.position());
- if (headerParsePos == HeaderParsePosition.HEADER_MULTI_LINE) {
- if ((peek != Constants.SP) && (peek != Constants.HT)) {
- headerParsePos = HeaderParsePosition.HEADER_START;
- break;
- } else {
- // Copying one extra space in the buffer (since there must
- // be at least one space inserted between the lines)
- byteBuffer.put(headerData.realPos, peek);
- headerData.realPos++;
- headerParsePos = HeaderParsePosition.HEADER_VALUE_START;
- }
- }
- }
- // Set the header value
- headerData.headerValue.setBytes(byteBuffer.array(), headerData.start,
- headerData.lastSignificantChar - headerData.start);
- headerData.recycle();
- return HeaderParseStatus.HAVE_MORE_HEADERS;
- }
-
-
- private HeaderParseStatus skipLine(boolean deleteHeader) throws IOException {
- boolean rejectThisHeader = rejectIllegalHeader;
- // Check if rejectIllegalHeader is disabled and needs to be overridden
- // for this header. The header name is required to determine if this
- // override is required. The header name is only available once the
- // header has been created. If the header has been created then
- // deleteHeader will be true.
- if (!rejectThisHeader && deleteHeader) {
- if (headers.getName(headers.size() - 1).equalsIgnoreCase("content-length")) {
- // Malformed content-length headers must always be rejected
- // RFC 9112, section 6.3, bullet 5.
- rejectThisHeader = true;
- } else {
- // Only need to delete the header if the request isn't going to
- // be rejected (it will be the most recent one)
- headers.removeHeader(headers.size() - 1);
- }
- }
-
- // Parse the rest of the invalid header so we can construct a useful
- // exception and/or debug message.
- headerParsePos = HeaderParsePosition.HEADER_SKIPLINE;
- boolean eol = false;
-
- // Reading bytes until the end of the line
- while (!eol) {
-
- // Read new bytes if needed
- if (byteBuffer.position() >= byteBuffer.limit()) {
- if (!fill(false)) {
- return HeaderParseStatus.NEED_MORE_DATA;
- }
- }
-
- int pos = byteBuffer.position();
- prevChr = chr;
- chr = byteBuffer.get();
- if (chr == Constants.CR) {
- // Skip
- } else if (chr == Constants.LF) {
- // CRLF or LF is an acceptable line terminator
- eol = true;
- } else {
- headerData.lastSignificantChar = pos;
- }
- }
- if (rejectThisHeader || log.isDebugEnabled()) {
- String message = sm.getString("iib.invalidheader",
- HeaderUtil.toPrintableString(byteBuffer.array(), headerData.lineStart,
- headerData.lastSignificantChar - headerData.lineStart + 1));
- if (rejectThisHeader) {
- throw new IllegalArgumentException(message);
- }
- log.debug(message);
- }
-
- headerParsePos = HeaderParsePosition.HEADER_START;
- return HeaderParseStatus.HAVE_MORE_HEADERS;
- }
-
-
- // ----------------------------------------------------------- Inner classes
-
- private enum HeaderParseStatus {
- DONE, HAVE_MORE_HEADERS, NEED_MORE_DATA
- }
-
-
- private enum HeaderParsePosition {
- /**
- * Start of a new header. A CRLF here means that there are no more
- * headers. Any other character starts a header name.
- */
- HEADER_START,
- /**
- * Reading a header name. All characters of header are HTTP_TOKEN_CHAR.
- * Header name is followed by ':'. No whitespace is allowed.<br>
- * Any non-HTTP_TOKEN_CHAR (this includes any whitespace) encountered
- * before ':' will result in the whole line being ignored.
- */
- HEADER_NAME,
- /**
- * Skipping whitespace before text of header value starts, either on the
- * first line of header value (just after ':') or on subsequent lines
- * when it is known that subsequent line starts with SP or HT.
- */
- HEADER_VALUE_START,
- /**
- * Reading the header value. We are inside the value. Either on the
- * first line or on any subsequent line. We come into this state from
- * HEADER_VALUE_START after the first non-SP/non-HT byte is encountered
- * on the line.
- */
- HEADER_VALUE,
- /**
- * Before reading a new line of a header. Once the next byte is peeked,
- * the state changes without advancing our position. The state becomes
- * either HEADER_VALUE_START (if that first byte is SP or HT), or
- * HEADER_START (otherwise).
- */
- HEADER_MULTI_LINE,
- /**
- * Reading all bytes until the next CRLF. The line is being ignored.
- */
- HEADER_SKIPLINE
- }
-
-
- private static class HeaderParseData {
- /**
- * The first character of the header line.
- */
- int lineStart = 0;
- /**
- * When parsing header name: first character of the header.<br>
- * When skipping broken header line: first character of the header.<br>
- * When parsing header value: first character after ':'.
- */
- int start = 0;
- /**
- * When parsing header name: not used (stays as 0).<br>
- * When skipping broken header line: not used (stays as 0).<br>
- * When parsing header value: starts as the first character after ':'.
- * Then is increased as far as more bytes of the header are harvested.
- * Bytes from buf[pos] are copied to buf[realPos]. Thus the string from
- * [start] to [realPos-1] is the prepared value of the header, with
- * whitespaces removed as needed.<br>
- */
- int realPos = 0;
- /**
- * When parsing header name: not used (stays as 0).<br>
- * When skipping broken header line: last non-CR/non-LF character.<br>
- * When parsing header value: position after the last not-LWS character.<br>
- */
- int lastSignificantChar = 0;
- /**
- * MB that will store the value of the header. It is null while parsing
- * header name and is created after the name has been parsed.
- */
- MessageBytes headerValue = null;
- public void recycle() {
- lineStart = 0;
- start = 0;
- realPos = 0;
- lastSignificantChar = 0;
- headerValue = null;
- }
- }
-
-
- // ------------------------------------- InputStreamInputBuffer Inner Class
-
- /**
- * This class is an input buffer which will read its data from an input
- * stream.
- */
- private class SocketInputBuffer implements InputBuffer {
-
- @Override
- public int doRead(ApplicationBufferHandler handler) throws IOException {
-
- if (byteBuffer.position() >= byteBuffer.limit()) {
- // The application is reading the HTTP request body
- boolean block = (request.getReadListener() == null);
- if (!fill(block)) {
- if (block) {
- return -1;
- } else {
- return 0;
- }
- }
- }
-
- int length = byteBuffer.remaining();
- handler.setByteBuffer(byteBuffer.duplicate());
- byteBuffer.position(byteBuffer.limit());
-
- return length;
- }
-
- @Override
- public int available() {
- return byteBuffer.remaining();
- }
- }
-
-
- @Override
- public void setByteBuffer(ByteBuffer buffer) {
- byteBuffer = buffer;
- }
-
-
- @Override
- public ByteBuffer getByteBuffer() {
- return byteBuffer;
+ public Http11InputBuffer(Request request, int headerBufferSize, boolean rejectIllegalHeader,
+ HttpParser httpParser) {
+ super(request, headerBufferSize, rejectIllegalHeader, httpParser);
}
@Override
- public void expand(int size) {
- if (byteBuffer.capacity() >= size) {
- byteBuffer.limit(size);
- }
- ByteBuffer temp = ByteBuffer.allocate(size);
- temp.put(byteBuffer);
- byteBuffer = temp;
- byteBuffer.mark();
- temp = null;
+ protected Log getLog() {
+ return log;
}
}
diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java
index bfca3b93ba..f607755525 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/java/org/apache/coyote/http11/Http11Processor.java
@@ -17,8 +17,10 @@
package org.apache.coyote.http11;
import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.parser.HttpParser;
public class Http11Processor extends AbstractHttp11Processor {
@@ -30,6 +32,14 @@ public class Http11Processor extends AbstractHttp11Processor {
}
+ @Override
+ protected AbstractHttp11InputBuffer createInputBuffer(Request request, AbstractHttp11Protocol<?> protocol,
+ HttpParser httpParser) {
+ return new Http11InputBuffer(request, protocol.getMaxHttpRequestHeaderSize(),
+ protocol.getRejectIllegalHeader(), httpParser);
+ }
+
+
@Override
protected Log getLog() {
return log;
diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/modules/loom/src/main/java/org/apache/coyote/http11/Http11LoomInputBuffer.java
similarity index 68%
copy from java/org/apache/coyote/http11/Http11Processor.java
copy to modules/loom/src/main/java/org/apache/coyote/http11/Http11LoomInputBuffer.java
index bfca3b93ba..08e43eb5c0 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/modules/loom/src/main/java/org/apache/coyote/http11/Http11LoomInputBuffer.java
@@ -16,17 +16,19 @@
*/
package org.apache.coyote.http11;
-import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.parser.HttpParser;
-public class Http11Processor extends AbstractHttp11Processor {
+public class Http11LoomInputBuffer extends AbstractHttp11InputBuffer {
- private static final Log log = LogFactory.getLog(Http11Processor.class);
+ private static final Log log = LogFactory.getLog(Http11LoomInputBuffer.class);
- public Http11Processor(AbstractHttp11Protocol<?> protocol, Adapter adapter) {
- super(protocol, adapter);
+ public Http11LoomInputBuffer(Request request, int headerBufferSize, boolean rejectIllegalHeader,
+ HttpParser httpParser) {
+ super(request, headerBufferSize, rejectIllegalHeader, httpParser);
}
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 bfd16c7026..ef838ac580 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,8 +17,10 @@
package org.apache.coyote.http11;
import org.apache.coyote.Adapter;
+import org.apache.coyote.Request;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.http.parser.HttpParser;
public class Http11LoomProcessor extends AbstractHttp11Processor {
@@ -30,6 +32,14 @@ public class Http11LoomProcessor extends AbstractHttp11Processor {
}
+ @Override
+ protected AbstractHttp11InputBuffer createInputBuffer(Request request, AbstractHttp11Protocol<?> protocol,
+ HttpParser httpParser) {
+ return new Http11LoomInputBuffer(request, protocol.getMaxHttpRequestHeaderSize(),
+ protocol.getRejectIllegalHeader(), httpParser);
+ }
+
+
@Override
protected Log getLog() {
return log;
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org