Skip to content

Commit

Permalink
[UNDERTOW-2277] Prevent writing more than content length at ServletOu…
Browse files Browse the repository at this point in the history
…tputStream/PrintWriter when contentlength is set

Signed-off-by: Flavia Rainone <frainone@redhat.com>
  • Loading branch information
fl4via committed Jun 6, 2023
1 parent 219e23a commit 22464f8
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -141,20 +141,21 @@ public void write(final byte[] b, final int off, final int len) throws IOExcepti
if (len < 1) {
return;
}
int finalLength = (int) Math.min(len, remainingContentLength());

if (listener == null) {
ByteBuffer buffer = buffer();
if (buffer.remaining() < len) {
writeTooLargeForBuffer(b, off, len, buffer);
if (buffer.remaining() < finalLength) {
writeTooLargeForBuffer(b, off, finalLength, buffer);
} else {
buffer.put(b, off, len);
buffer.put(b, off, finalLength);
if (buffer.remaining() == 0) {
writeBufferBlocking(false);
}
}
updateWritten(len);
updateWritten(finalLength);
} else {
writeAsync(b, off, len);
writeAsync(b, off, finalLength);
}
}

Expand Down Expand Up @@ -236,6 +237,7 @@ private void writeAsync(byte[] b, int off, int len) throws IOException {
if (anyAreClear(state, FLAG_READY)) {
throw UndertowServletMessages.MESSAGES.streamNotReady();
}
len = (int) Math.min(len, remainingContentLength());
//even though we are in async mode we are still buffering
try {
ByteBuffer buffer = buffer();
Expand Down Expand Up @@ -285,6 +287,7 @@ public void write(ByteBuffer[] buffers) throws IOException {
if (len < 1) {
return;
}
len = (int) Math.min(len, remainingContentLength());

if (listener == null) {
//if we have received the exact amount of content write it out in one go
Expand Down Expand Up @@ -374,7 +377,15 @@ void updateWritten(final long len) throws IOException {
}
}

void updateWrittenAsync(final long len) throws IOException {
long remainingContentLength() throws IOException {
final long contentLength = servletRequestContext.getOriginalResponse().getContentLength();
if (contentLength != -1) {
return contentLength - written;
}
return Long.MAX_VALUE;
}

void updateWrittenAsync(final long len) throws IOException {
this.written += len;
long contentLength = servletRequestContext.getOriginalResponse().getContentLength();
if (contentLength != -1 && this.written >= contentLength) {
Expand Down Expand Up @@ -534,6 +545,7 @@ public void transferFrom(FileChannel source) throws IOException {
if (anyAreSet(state, FLAG_CLOSED) || servletRequestContext.getOriginalResponse().isTreatAsCommitted()) {
throw UndertowServletMessages.MESSAGES.streamIsClosed();
}
final long remainingContentLength = remainingContentLength();
if (listener == null) {
if (buffer != null && buffer.position() != 0) {
writeBufferBlocking(false);
Expand All @@ -543,6 +555,9 @@ public void transferFrom(FileChannel source) throws IOException {
}
long position = source.position();
long count = source.size() - position;
if (count > remainingContentLength) {
count = remainingContentLength;
}
Channels.transferBlocking(channel, source, position, count);
updateWritten(count);
} else {
Expand All @@ -551,7 +566,7 @@ public void transferFrom(FileChannel source) throws IOException {

long pos = 0;
try {
long size = source.size();
long size = Math.min (source.size(), remainingContentLength);
pos = source.position();

while (size - pos > 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,17 @@ public void write(final CharBuffer input) {
underflow = null;
}
int last = -1;
while (cb.hasRemaining()) {
int remaining = buffer.remaining();
CoderResult result = charsetEncoder.encode(cb, buffer, false);
outputStream.updateWritten(remaining - buffer.remaining());
long remainingContentLength = outputStream.remainingContentLength();
while (remainingContentLength > 0 && cb.hasRemaining()) {
final int remaining = buffer.remaining();
final CoderResult result = charsetEncoder.encode(cb, buffer, false);
long writtenLength = remaining - buffer.remaining();
if (remainingContentLength < writtenLength) {
buffer.position(buffer.position() - (int) (writtenLength - remainingContentLength));
writtenLength = remainingContentLength;
}
remainingContentLength -= writtenLength;
outputStream.updateWritten(writtenLength);
if (result.isOverflow() || !buffer.hasRemaining()) {
outputStream.flushInternal();
if (!buffer.hasRemaining()) {
Expand Down Expand Up @@ -239,14 +246,19 @@ public void write(final char[] buf, final int off, final int len) {
private static int writeAndFlushAscii(ServletOutputStreamImpl outputStream, ByteBuffer buffer, char[] chars, int start, int end) throws IOException {
assert buffer.order() == ByteOrder.BIG_ENDIAN;
int i = start;
long remainingContentLength = outputStream.remainingContentLength();
while (i < end) {
final int bufferPos = buffer.position();
final int bufferRemaining = buffer.remaining();
final int sRemaining = end - i;
final int remaining = Math.min(sRemaining, bufferRemaining);
final int written = setAsciiBE(buffer, bufferPos, chars, i, remaining);
i += written;
buffer.position(bufferPos + written);
if ((remainingContentLength -= written) < 0) {
buffer.position(bufferPos + written + (int) remainingContentLength);
} else {
buffer.position(bufferPos + written);
}
if (!buffer.hasRemaining()) {
outputStream.flushInternal();
}
Expand Down Expand Up @@ -329,14 +341,19 @@ public void write(final String s, final int off, final int len) {
private static int writeAndFlushAscii(ServletOutputStreamImpl outputStream, ByteBuffer buffer, String s, int start, int end) throws IOException {
assert buffer.order() == ByteOrder.BIG_ENDIAN;
int i = start;
long remainingContentLength = outputStream.remainingContentLength();
while (i < end) {
final int bufferPos = buffer.position();
final int bufferRemaining = buffer.remaining();
final int sRemaining = end - i;
final int remaining = Math.min(sRemaining, bufferRemaining);
final int written = setAsciiBE(buffer, bufferPos, s, i, remaining);
i += written;
buffer.position(bufferPos + written);
if ((remainingContentLength -= written) < 0) {
buffer.position(bufferPos + written + (int) remainingContentLength);
} else {
buffer.position(bufferPos + written);
}
if (!buffer.hasRemaining()) {
outputStream.flushInternal();
}
Expand Down

0 comments on commit 22464f8

Please sign in to comment.