Skip to content

Commit 6ec7fef

Browse files
committed
cleanup, testing.
1 parent bf41b95 commit 6ec7fef

File tree

1 file changed

+15
-31
lines changed

1 file changed

+15
-31
lines changed

src/main/java/io/fusionauth/http/server/io/HTTPInputStream.java

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
import io.fusionauth.http.server.Instrumenter;
3232

3333
/**
34-
* An InputStream that handles the HTTP body, including body bytes that were read while the preamble was processed. This class also handles
35-
* chunked bodies by using a delegate InputStream that wraps the original source of the body bytes. The {@link ChunkedInputStream} is the
36-
* delegate that this class leverages for chunking.
34+
* An InputStream intended to be read the HTTP request body.
35+
* <p>
36+
* This will handle fixed length requests, chunked requests as well as decompression if necessary.
3737
*
3838
* @author Brian Pontarelli
3939
*/
@@ -140,17 +140,14 @@ public int read(byte[] b, int off, int len) throws IOException {
140140
initialize();
141141
}
142142

143-
// When we have a fixed length request, read beyond the remainingBytes if possible.
144-
// - If we have read past the end of the current request, push those bytes back onto the InputStream.
145-
// - When a maximum content length has been specified, read at most one byte past the maximum.
143+
// When a maximum content length has been specified, read at most one byte past the maximum.
146144
int maxReadLen = maximumContentLength == -1 ? len : Math.min(len, maximumContentLength - bytesRead + 1);
147145
int read = delegate.read(b, off, maxReadLen);
148146
if (read > 0) {
149147
bytesRead += read;
150148
}
151149

152-
// Note that when the request is fixed length, we will have failed early during commit().
153-
// - This will handle all requests that are not fixed length.
150+
// Throw an exception once we have read past the maximum configured content length,
154151
if (maximumContentLength != -1 && bytesRead > maximumContentLength) {
155152
String detailedMessage = "The maximum request size has been exceeded. The maximum request size is [" + maximumContentLength + "] bytes.";
156153
throw new ContentTooLargeException(maximumContentLength, detailedMessage);
@@ -167,9 +164,6 @@ private void initialize() throws IOException {
167164
// In practice, we will remove the Content-Length header when sent in addition to Transfer-Encoding. See HTTPWorker.validatePreamble.
168165
Long contentLength = request.getContentLength();
169166
boolean hasBody = (contentLength != null && contentLength > 0) || request.isChunked();
170-
171-
// Note that isChunked() should take precedence over the fact that we have a Content-Length.
172-
// - The client should not send both, but in the case they are both present we ignore Content-Length
173167
if (!hasBody) {
174168
delegate = InputStream.nullInputStream();
175169
} else if (request.isChunked()) {
@@ -185,26 +179,7 @@ private void initialize() throws IOException {
185179
logger.trace("Client indicated it was NOT sending an entity-body in the request");
186180
}
187181

188-
// If we have a maximumContentLength, and this is a fixed content length request, before we read any bytes, fail early.
189-
// For good measure do this last so if anyone downstream wants to read from the InputStream they could in theory because
190-
// we will have set up the InputStream.
191-
// TODO : Compression : we may have to delete this code, or only enforce it when compression was not used.
192-
// Content-Length represents the compressed size, not the uncompressed bytes.
193-
if (contentLength != null && maximumContentLength != -1 && contentLength > maximumContentLength) {
194-
String detailedMessage = "The maximum request size has been exceeded. The reported Content-Length is [" + contentLength + "] and the maximum request size is [" + maximumContentLength + "] bytes.";
195-
throw new ContentTooLargeException(maximumContentLength, detailedMessage);
196-
}
197-
198-
// Current state
199-
// Chunked HTTPInputStream (this) > Chunked > Pushback > Throughput > Socket
200-
// Fixed length HTTPInputStream (this) > Fixed > Pushback > Throughput > Socket
201-
202-
// When decompressing, the result will be something like this:
203-
// Chunked HTTPInputStream (this) > Decompress > Chunked > Pushback > Throughput > Socket
204-
// Fixed length HTTPInputStream (this) > Decompress> Fixed > Pushback > Throughput > Socket
205-
//
206-
// You may have one or more Decompress InputStreams in the above diagram.
207-
182+
// Now that we have the InputStream set up to read the body, handle decompression.
208183
if (hasBody) {
209184
// The request may contain more than one value, apply in reverse order.
210185
// - These are both using the default 512 buffer size.
@@ -216,5 +191,14 @@ private void initialize() throws IOException {
216191
}
217192
}
218193
}
194+
195+
// If we have a fixed length request that is reporting a contentLength larger than the configured maximum, fail earl.
196+
// - Do this last so if anyone downstream wants to read from the InputStream it would work.
197+
// - Note that it is possible that the body is compressed which would mean the contentLength represents the compressed value.
198+
// But when we decompress the bytes the result will be larger than the reported contentLength, so we can safely throw this exception.
199+
if (contentLength != null && maximumContentLength != -1 && contentLength > maximumContentLength) {
200+
String detailedMessage = "The maximum request size has been exceeded. The reported Content-Length is [" + contentLength + "] and the maximum request size is [" + maximumContentLength + "] bytes.";
201+
throw new ContentTooLargeException(maximumContentLength, detailedMessage);
202+
}
219203
}
220204
}

0 commit comments

Comments
 (0)