|
|
e41f6f |
--- java/org/apache/coyote/http11/filters/ChunkedInputFilter.java.orig 2015-03-24 16:32:02.657913000 -0400
|
|
|
e41f6f |
+++ java/org/apache/coyote/http11/filters/ChunkedInputFilter.java 2015-03-24 18:21:47.397617000 -0400
|
|
|
e41f6f |
@@ -14,7 +14,6 @@
|
|
|
e41f6f |
* See the License for the specific language governing permissions and
|
|
|
e41f6f |
* limitations under the License.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
-
|
|
|
e41f6f |
package org.apache.coyote.http11.filters;
|
|
|
e41f6f |
|
|
|
e41f6f |
import java.io.EOFException;
|
|
|
e41f6f |
@@ -29,6 +28,7 @@
|
|
|
e41f6f |
import org.apache.tomcat.util.buf.HexUtils;
|
|
|
e41f6f |
import org.apache.tomcat.util.buf.MessageBytes;
|
|
|
e41f6f |
import org.apache.tomcat.util.http.MimeHeaders;
|
|
|
e41f6f |
+import org.apache.tomcat.util.res.StringManager;
|
|
|
e41f6f |
|
|
|
e41f6f |
/**
|
|
|
e41f6f |
* Chunked input filter. Parses chunked data according to
|
|
|
e41f6f |
@@ -39,9 +39,11 @@
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
public class ChunkedInputFilter implements InputFilter {
|
|
|
e41f6f |
|
|
|
e41f6f |
+ private static final StringManager sm = StringManager.getManager(
|
|
|
e41f6f |
+ ChunkedInputFilter.class.getPackage().getName());
|
|
|
e41f6f |
|
|
|
e41f6f |
- // -------------------------------------------------------------- Constants
|
|
|
e41f6f |
|
|
|
e41f6f |
+ // -------------------------------------------------------------- Constants
|
|
|
e41f6f |
|
|
|
e41f6f |
protected static final String ENCODING_NAME = "chunked";
|
|
|
e41f6f |
protected static final ByteChunk ENCODING = new ByteChunk();
|
|
|
e41f6f |
@@ -49,7 +51,6 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// ----------------------------------------------------- Static Initializer
|
|
|
e41f6f |
|
|
|
e41f6f |
-
|
|
|
e41f6f |
static {
|
|
|
e41f6f |
ENCODING.setBytes(ENCODING_NAME.getBytes(Charset.defaultCharset()), 0,
|
|
|
e41f6f |
ENCODING_NAME.length());
|
|
|
e41f6f |
@@ -58,7 +59,6 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// ----------------------------------------------------- Instance Variables
|
|
|
e41f6f |
|
|
|
e41f6f |
-
|
|
|
e41f6f |
/**
|
|
|
e41f6f |
* Next buffer in the pipeline.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
@@ -106,6 +106,7 @@
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
protected ByteChunk trailingHeaders = new ByteChunk();
|
|
|
e41f6f |
|
|
|
e41f6f |
+
|
|
|
e41f6f |
/**
|
|
|
e41f6f |
* Flag set to true if the next call to doRead() must parse a CRLF pair
|
|
|
e41f6f |
* before doing anything else.
|
|
|
e41f6f |
@@ -130,21 +131,29 @@
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
private final int maxTrailerSize;
|
|
|
e41f6f |
|
|
|
e41f6f |
+
|
|
|
e41f6f |
/**
|
|
|
e41f6f |
* Size of extensions processed for this request.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
private long extensionSize;
|
|
|
e41f6f |
|
|
|
e41f6f |
|
|
|
e41f6f |
+ /**
|
|
|
e41f6f |
+ * Flag that indicates if an error has occurred.
|
|
|
e41f6f |
+ */
|
|
|
e41f6f |
+ private boolean error;
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+
|
|
|
e41f6f |
// ----------------------------------------------------------- Constructors
|
|
|
e41f6f |
+
|
|
|
e41f6f |
public ChunkedInputFilter(int maxTrailerSize, int maxExtensionSize) {
|
|
|
e41f6f |
this.trailingHeaders.setLimit(maxTrailerSize);
|
|
|
e41f6f |
this.maxExtensionSize = maxExtensionSize;
|
|
|
e41f6f |
this.maxTrailerSize = maxTrailerSize;
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
- // ---------------------------------------------------- InputBuffer Methods
|
|
|
e41f6f |
|
|
|
e41f6f |
+ // ---------------------------------------------------- InputBuffer Methods
|
|
|
e41f6f |
|
|
|
e41f6f |
/**
|
|
|
e41f6f |
* Read bytes.
|
|
|
e41f6f |
@@ -156,11 +165,12 @@
|
|
|
e41f6f |
* control, the returned value should be -1.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
@Override
|
|
|
e41f6f |
- public int doRead(ByteChunk chunk, Request req)
|
|
|
e41f6f |
- throws IOException {
|
|
|
e41f6f |
-
|
|
|
e41f6f |
- if (endChunk)
|
|
|
e41f6f |
+ public int doRead(ByteChunk chunk, Request req) throws IOException {
|
|
|
e41f6f |
+ if (endChunk) {
|
|
|
e41f6f |
return -1;
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+ checkError();
|
|
|
e41f6f |
|
|
|
e41f6f |
if(needCRLFParse) {
|
|
|
e41f6f |
needCRLFParse = false;
|
|
|
e41f6f |
@@ -169,7 +179,7 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
if (remaining <= 0) {
|
|
|
e41f6f |
if (!parseChunkHeader()) {
|
|
|
e41f6f |
- throw new IOException("Invalid chunk header");
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.invalidHeader"));
|
|
|
e41f6f |
}
|
|
|
e41f6f |
if (endChunk) {
|
|
|
e41f6f |
parseEndChunk();
|
|
|
e41f6f |
@@ -181,8 +191,7 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
if (pos >= lastValid) {
|
|
|
e41f6f |
if (readBytes() < 0) {
|
|
|
e41f6f |
- throw new IOException(
|
|
|
e41f6f |
- "Unexpected end of stream whilst reading request body");
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.eos"));
|
|
|
e41f6f |
}
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -207,13 +216,11 @@
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
return result;
|
|
|
e41f6f |
-
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
|
|
|
e41f6f |
// ---------------------------------------------------- InputFilter Methods
|
|
|
e41f6f |
|
|
|
e41f6f |
-
|
|
|
e41f6f |
/**
|
|
|
e41f6f |
* Read the content length from the request.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
@@ -227,17 +234,13 @@
|
|
|
e41f6f |
* End the current request.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
@Override
|
|
|
e41f6f |
- public long end()
|
|
|
e41f6f |
- throws IOException {
|
|
|
e41f6f |
-
|
|
|
e41f6f |
- // Consume extra bytes : parse the stream until the end chunk is found
|
|
|
e41f6f |
+ public long end() throws IOException {
|
|
|
e41f6f |
while (doRead(readChunk, null) >= 0) {
|
|
|
e41f6f |
- // NOOP: Just consume the input
|
|
|
e41f6f |
+ // NOOP: just consume the input
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
// Return the number of extra bytes which were consumed
|
|
|
e41f6f |
- return (lastValid - pos);
|
|
|
e41f6f |
-
|
|
|
e41f6f |
+ return lastValid - pos;
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -246,7 +249,7 @@
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
@Override
|
|
|
e41f6f |
public int available() {
|
|
|
e41f6f |
- return (lastValid - pos);
|
|
|
e41f6f |
+ return lastValid - pos;
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -272,6 +275,7 @@
|
|
|
e41f6f |
trailingHeaders.recycle();
|
|
|
e41f6f |
trailingHeaders.setLimit(maxTrailerSize);
|
|
|
e41f6f |
extensionSize = 0;
|
|
|
e41f6f |
+ error = false;
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -287,12 +291,10 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// ------------------------------------------------------ Protected Methods
|
|
|
e41f6f |
|
|
|
e41f6f |
-
|
|
|
e41f6f |
/**
|
|
|
e41f6f |
* Read bytes from the previous buffer.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
- protected int readBytes()
|
|
|
e41f6f |
- throws IOException {
|
|
|
e41f6f |
+ protected int readBytes() throws IOException {
|
|
|
e41f6f |
|
|
|
e41f6f |
int nRead = buffer.doRead(readChunk, null);
|
|
|
e41f6f |
pos = readChunk.getStart();
|
|
|
e41f6f |
@@ -300,7 +302,6 @@
|
|
|
e41f6f |
buf = readChunk.getBytes();
|
|
|
e41f6f |
|
|
|
e41f6f |
return nRead;
|
|
|
e41f6f |
-
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -315,8 +316,7 @@
|
|
|
e41f6f |
* digits. We should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid
|
|
|
e41f6f |
* header according to the spec.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
- protected boolean parseChunkHeader()
|
|
|
e41f6f |
- throws IOException {
|
|
|
e41f6f |
+ protected boolean parseChunkHeader() throws IOException {
|
|
|
e41f6f |
|
|
|
e41f6f |
int result = 0;
|
|
|
e41f6f |
boolean eol = false;
|
|
|
e41f6f |
@@ -356,7 +356,7 @@
|
|
|
e41f6f |
// validated. Currently it is simply ignored.
|
|
|
e41f6f |
extensionSize++;
|
|
|
e41f6f |
if (maxExtensionSize > -1 && extensionSize > maxExtensionSize) {
|
|
|
e41f6f |
- throw new IOException("maxExtensionSize exceeded");
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.maxExtension"));
|
|
|
e41f6f |
}
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -364,21 +364,22 @@
|
|
|
e41f6f |
if (!eol) {
|
|
|
e41f6f |
pos++;
|
|
|
e41f6f |
}
|
|
|
e41f6f |
-
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
- if (readDigit == 0 || result < 0)
|
|
|
e41f6f |
+ if (readDigit == 0 || result < 0) {
|
|
|
e41f6f |
return false;
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
|
|
|
e41f6f |
- if (result == 0)
|
|
|
e41f6f |
+ if (result == 0) {
|
|
|
e41f6f |
endChunk = true;
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
|
|
|
e41f6f |
remaining = result;
|
|
|
e41f6f |
- if (remaining < 0)
|
|
|
e41f6f |
+ if (remaining < 0) {
|
|
|
e41f6f |
return false;
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
|
|
|
e41f6f |
return true;
|
|
|
e41f6f |
-
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -405,26 +406,27 @@
|
|
|
e41f6f |
boolean crfound = false;
|
|
|
e41f6f |
|
|
|
e41f6f |
while (!eol) {
|
|
|
e41f6f |
-
|
|
|
e41f6f |
if (pos >= lastValid) {
|
|
|
e41f6f |
- if (readBytes() <= 0)
|
|
|
e41f6f |
- throw new IOException("Invalid CRLF");
|
|
|
e41f6f |
+ if (readBytes() <= 0) {
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoData"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
if (buf[pos] == Constants.CR) {
|
|
|
e41f6f |
- if (crfound) throw new IOException("Invalid CRLF, two CR characters encountered.");
|
|
|
e41f6f |
+ if (crfound) {
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.invalidCrlfCRCR"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
crfound = true;
|
|
|
e41f6f |
} else if (buf[pos] == Constants.LF) {
|
|
|
e41f6f |
if (!tolerant && !crfound) {
|
|
|
e41f6f |
- throw new IOException("Invalid CRLF, no CR character encountered.");
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.invalidCrlfNoCR"));
|
|
|
e41f6f |
}
|
|
|
e41f6f |
eol = true;
|
|
|
e41f6f |
} else {
|
|
|
e41f6f |
- throw new IOException("Invalid CRLF");
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.invalidCrlf"));
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
pos++;
|
|
|
e41f6f |
-
|
|
|
e41f6f |
}
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
@@ -433,7 +435,6 @@
|
|
|
e41f6f |
* Parse end chunk data.
|
|
|
e41f6f |
*/
|
|
|
e41f6f |
protected void parseEndChunk() throws IOException {
|
|
|
e41f6f |
-
|
|
|
e41f6f |
// Handle optional trailer headers
|
|
|
e41f6f |
while (parseHeader()) {
|
|
|
e41f6f |
// Loop until we run out of headers
|
|
|
e41f6f |
@@ -449,8 +450,9 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// Read new bytes if needed
|
|
|
e41f6f |
if (pos >= lastValid) {
|
|
|
e41f6f |
- if (readBytes() <0)
|
|
|
e41f6f |
- throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
|
|
|
e41f6f |
+ if (readBytes() <0) {
|
|
|
e41f6f |
+ throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
chr = buf[pos];
|
|
|
e41f6f |
@@ -474,8 +476,9 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// Read new bytes if needed
|
|
|
e41f6f |
if (pos >= lastValid) {
|
|
|
e41f6f |
- if (readBytes() <0)
|
|
|
e41f6f |
- throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
|
|
|
e41f6f |
+ if (readBytes() <0) {
|
|
|
e41f6f |
+ throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
chr = buf[pos];
|
|
|
e41f6f |
@@ -515,8 +518,9 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// Read new bytes if needed
|
|
|
e41f6f |
if (pos >= lastValid) {
|
|
|
e41f6f |
- if (readBytes() <0)
|
|
|
e41f6f |
- throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
|
|
|
e41f6f |
+ if (readBytes() <0) {
|
|
|
e41f6f |
+ throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
chr = buf[pos];
|
|
|
e41f6f |
@@ -526,7 +530,7 @@
|
|
|
e41f6f |
// limit placed on trailing header size
|
|
|
e41f6f |
int newlimit = trailingHeaders.getLimit() -1;
|
|
|
e41f6f |
if (trailingHeaders.getEnd() > newlimit) {
|
|
|
e41f6f |
- throw new IOException("Exceeded maxTrailerSize");
|
|
|
e41f6f |
+ throwIOException(sm.getString("chunkedInputFilter.maxTrailer"));
|
|
|
e41f6f |
}
|
|
|
e41f6f |
trailingHeaders.setLimit(newlimit);
|
|
|
e41f6f |
} else {
|
|
|
e41f6f |
@@ -540,8 +544,9 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// Read new bytes if needed
|
|
|
e41f6f |
if (pos >= lastValid) {
|
|
|
e41f6f |
- if (readBytes() <0)
|
|
|
e41f6f |
- throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
|
|
|
e41f6f |
+ if (readBytes() <0) {
|
|
|
e41f6f |
+ throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
chr = buf[pos];
|
|
|
e41f6f |
@@ -565,8 +570,9 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
// Read new bytes if needed
|
|
|
e41f6f |
if (pos >= lastValid) {
|
|
|
e41f6f |
- if (readBytes() <0)
|
|
|
e41f6f |
- throw new EOFException("Unexpected end of stream whilst reading trailer headers for chunked request");
|
|
|
e41f6f |
+ if (readBytes() <0) {
|
|
|
e41f6f |
+ throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
}
|
|
|
e41f6f |
|
|
|
e41f6f |
chr = buf[pos];
|
|
|
e41f6f |
@@ -587,4 +593,23 @@
|
|
|
e41f6f |
|
|
|
e41f6f |
return true;
|
|
|
e41f6f |
}
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+ private void throwIOException(String msg) throws IOException {
|
|
|
e41f6f |
+ error = true;
|
|
|
e41f6f |
+ throw new IOException(msg);
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+ private void throwEOFException(String msg) throws IOException {
|
|
|
e41f6f |
+ error = true;
|
|
|
e41f6f |
+ throw new EOFException(msg);
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+ private void checkError() throws IOException {
|
|
|
e41f6f |
+ if (error) {
|
|
|
e41f6f |
+ throw new IOException(sm.getString("chunkedInputFilter.error"));
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
+ }
|
|
|
e41f6f |
}
|
|
|
e41f6f |
--- java/org/apache/coyote/http11/filters/LocalStrings.properties.orig 2015-03-24 16:32:02.662909000 -0400
|
|
|
e41f6f |
+++ java/org/apache/coyote/http11/filters/LocalStrings.properties 2015-03-24 16:39:31.017419000 -0400
|
|
|
e41f6f |
@@ -0,0 +1,27 @@
|
|
|
e41f6f |
+# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
|
e41f6f |
+# contributor license agreements. See the NOTICE file distributed with
|
|
|
e41f6f |
+# this work for additional information regarding copyright ownership.
|
|
|
e41f6f |
+# The ASF licenses this file to You under the Apache License, Version 2.0
|
|
|
e41f6f |
+# (the "License"); you may not use this file except in compliance with
|
|
|
e41f6f |
+# the License. You may obtain a copy of the License at
|
|
|
e41f6f |
+#
|
|
|
e41f6f |
+# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
e41f6f |
+#
|
|
|
e41f6f |
+# Unless required by applicable law or agreed to in writing, software
|
|
|
e41f6f |
+# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
e41f6f |
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
e41f6f |
+# See the License for the specific language governing permissions and
|
|
|
e41f6f |
+# limitations under the License.
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+chunkedInputFilter.error=No data available due to previous error
|
|
|
e41f6f |
+chunkedInputFilter.eos=Unexpected end of stream while reading request body
|
|
|
e41f6f |
+chunkedInputFilter.eosTrailer=Unexpected end of stream while reading trailer headers
|
|
|
e41f6f |
+chunkedInputFilter.invalidCrlf=Invalid end of line sequence (character other than CR or LF found)
|
|
|
e41f6f |
+chunkedInputFilter.invalidCrlfCRCR=Invalid end of line sequence (CRCR)
|
|
|
e41f6f |
+chunkedInputFilter.invalidCrlfNoCR=Invalid end of line sequence (No CR before LF)
|
|
|
e41f6f |
+chunkedInputFilter.invalidCrlfNoData=Invalid end of line sequence (no data available to read)
|
|
|
e41f6f |
+chunkedInputFilter.invalidHeader=Invalid chunk header
|
|
|
e41f6f |
+chunkedInputFilter.maxExtension=maxExtensionSize exceeded
|
|
|
e41f6f |
+chunkedInputFilter.maxTrailer=maxTrailerSize exceeded
|
|
|
e41f6f |
+
|
|
|
e41f6f |
+inputFilter.maxSwallow=maxSwallowSize exceeded
|
|
|
e41f6f |
\ No newline at end of file
|