Skip to content

Commit

Permalink
[UNDERTOW-2340] Remove Content-Length header when request is deflated.
Browse files Browse the repository at this point in the history
  • Loading branch information
baranowb committed Jul 30, 2024
1 parent 3b486c4 commit 81daf51
Show file tree
Hide file tree
Showing 8 changed files with 540 additions and 22 deletions.
38 changes: 34 additions & 4 deletions core/src/main/java/io/undertow/io/AsyncReceiverImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import io.undertow.server.Connectors;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HeaderMap;
import io.undertow.util.Headers;
import io.undertow.util.StatusCodes;
import org.xnio.ChannelListener;
Expand Down Expand Up @@ -108,6 +109,9 @@ public void receiveFullString(final FullStringCallback callback, final ErrorCall
return;
}
String contentLengthString = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(contentLengthString == null) {
contentLengthString = exchange.getRequestHeaders().getFirst(Headers.X_CONTENT_LENGTH);
}
long contentLength;
final ByteArrayOutputStream sb;
if (contentLengthString != null) {
Expand Down Expand Up @@ -137,7 +141,12 @@ public void receiveFullString(final FullStringCallback callback, final ErrorCall
res = channel.read(buffer);
if (res == -1) {
done = true;
callback.handle(exchange, sb.toString(charset.name()));
final String message = sb.toString(charset.name());
final HeaderMap requestHeaders = exchange.getRequestHeaders();
if(requestHeaders.contains(Headers.X_CONTENT_LENGTH) && !requestHeaders.contains(Headers.CONTENT_LENGTH)) {
requestHeaders.put(Headers.CONTENT_LENGTH, message.length());
}
callback.handle(exchange, message);
return;
} else if (res == 0) {
channel.getReadSetter().set(new ChannelListener<StreamSourceChannel>() {
Expand All @@ -159,7 +168,12 @@ public void handleEvent(StreamSourceChannel channel) {
Connectors.executeRootHandler(new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
callback.handle(exchange, sb.toString(charset.name()));
final String message = sb.toString(charset.name());
final HeaderMap requestHeaders = exchange.getRequestHeaders();
if(requestHeaders.contains(Headers.X_CONTENT_LENGTH) && !requestHeaders.contains(Headers.CONTENT_LENGTH)) {
requestHeaders.put(Headers.CONTENT_LENGTH, message.length());
}
callback.handle(exchange, message);
}
}, exchange);
return;
Expand Down Expand Up @@ -238,6 +252,9 @@ public void receivePartialString(final PartialStringCallback callback, final Err
return;
}
String contentLengthString = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(contentLengthString == null) {
contentLengthString = exchange.getRequestHeaders().getFirst(Headers.X_CONTENT_LENGTH);
}
long contentLength;
if (contentLengthString != null) {
contentLength = Long.parseLong(contentLengthString);
Expand Down Expand Up @@ -396,7 +413,12 @@ public void receiveFullBytes(final FullBytesCallback callback, final ErrorCallba
res = channel.read(buffer);
if (res == -1) {
done = true;
callback.handle(exchange, sb.toByteArray());
final byte[] message = sb.toByteArray();
final HeaderMap requestHeaders = exchange.getRequestHeaders();
if(requestHeaders.contains(Headers.X_CONTENT_LENGTH) && !requestHeaders.contains(Headers.CONTENT_LENGTH)) {
requestHeaders.put(Headers.CONTENT_LENGTH, message.length);
}
callback.handle(exchange, message);
return;
} else if (res == 0) {
channel.getReadSetter().set(new ChannelListener<StreamSourceChannel>() {
Expand All @@ -418,7 +440,12 @@ public void handleEvent(StreamSourceChannel channel) {
Connectors.executeRootHandler(new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
callback.handle(exchange, sb.toByteArray());
final byte[] message = sb.toByteArray();
final HeaderMap requestHeaders = exchange.getRequestHeaders();
if(requestHeaders.contains(Headers.X_CONTENT_LENGTH) && !requestHeaders.contains(Headers.CONTENT_LENGTH)) {
requestHeaders.put(Headers.CONTENT_LENGTH, message.length);
}
callback.handle(exchange, message);
}
}, exchange);
return;
Expand Down Expand Up @@ -495,6 +522,9 @@ public void receivePartialBytes(final PartialBytesCallback callback, final Error
return;
}
String contentLengthString = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(contentLengthString == null) {
contentLengthString = exchange.getRequestHeaders().getFirst(Headers.X_CONTENT_LENGTH);
}
long contentLength;
if (contentLengthString != null) {
contentLength = Long.parseLong(contentLengthString);
Expand Down
27 changes: 25 additions & 2 deletions core/src/main/java/io/undertow/io/BlockingReceiverImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import io.undertow.UndertowMessages;
import io.undertow.connector.PooledByteBuffer;
import io.undertow.server.HttpServerExchange;
import io.undertow.util.HeaderMap;
import io.undertow.util.Headers;
import io.undertow.util.StatusCodes;

Expand Down Expand Up @@ -100,6 +101,9 @@ public void receiveFullString(final FullStringCallback callback, final ErrorCall
return;
}
String contentLengthString = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(contentLengthString == null) {
contentLengthString = exchange.getRequestHeaders().getFirst(Headers.X_CONTENT_LENGTH);
}
long contentLength;
final ByteArrayOutputStream sb;
if (contentLengthString != null) {
Expand All @@ -125,7 +129,12 @@ public void receiveFullString(final FullStringCallback callback, final ErrorCall
while ((s = inputStream.read(pooled.getBuffer().array(), pooled.getBuffer().arrayOffset(), pooled.getBuffer().remaining())) > 0) {
sb.write(pooled.getBuffer().array(), pooled.getBuffer().arrayOffset(), s);
}
callback.handle(exchange, sb.toString(charset.name()));
final String message = sb.toString(charset.name());
final HeaderMap requestHeaders = exchange.getRequestHeaders();
if(requestHeaders.contains(Headers.X_CONTENT_LENGTH) && !requestHeaders.contains(Headers.CONTENT_LENGTH)) {
requestHeaders.put(Headers.CONTENT_LENGTH, message.length());
}
callback.handle(exchange, message);
} else {
throw UndertowMessages.MESSAGES.failedToAllocateResource();
}
Expand Down Expand Up @@ -154,6 +163,9 @@ public void receivePartialString(final PartialStringCallback callback, final Err
return;
}
String contentLengthString = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(contentLengthString == null) {
contentLengthString = exchange.getRequestHeaders().getFirst(Headers.X_CONTENT_LENGTH);
}
long contentLength;
if (contentLengthString != null) {
contentLength = Long.parseLong(contentLengthString);
Expand Down Expand Up @@ -209,6 +221,9 @@ public void receiveFullBytes(final FullBytesCallback callback, final ErrorCallba
return;
}
String contentLengthString = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(contentLengthString == null) {
contentLengthString = exchange.getRequestHeaders().getFirst(Headers.X_CONTENT_LENGTH);
}
long contentLength;
final ByteArrayOutputStream sb;
if (contentLengthString != null) {
Expand All @@ -234,7 +249,12 @@ public void receiveFullBytes(final FullBytesCallback callback, final ErrorCallba
while ((s = inputStream.read(pooled.getBuffer().array(), pooled.getBuffer().arrayOffset(), pooled.getBuffer().remaining())) > 0) {
sb.write(pooled.getBuffer().array(), pooled.getBuffer().arrayOffset(), s);
}
callback.handle(exchange, sb.toByteArray());
final byte[] message = sb.toByteArray();
final HeaderMap requestHeaders = exchange.getRequestHeaders();
if(requestHeaders.contains(Headers.X_CONTENT_LENGTH) && !requestHeaders.contains(Headers.CONTENT_LENGTH)) {
requestHeaders.put(Headers.CONTENT_LENGTH, message.length);
}
callback.handle(exchange, message);
} else {
throw UndertowMessages.MESSAGES.failedToAllocateResource();
}
Expand Down Expand Up @@ -263,6 +283,9 @@ public void receivePartialBytes(final PartialBytesCallback callback, final Error
return;
}
String contentLengthString = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(contentLengthString == null) {
contentLengthString = exchange.getRequestHeaders().getFirst(Headers.X_CONTENT_LENGTH);
}
long contentLength;
if (contentLengthString != null) {
contentLength = Long.parseLong(contentLengthString);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
// Nested handlers or even servlet filters may implement logic to decode encoded request data.
// Since the data is no longer encoded, we remove the encoding header.
exchange.getRequestHeaders().remove(Headers.CONTENT_ENCODING);
final String encodedContentLength = exchange.getRequestHeaders().getFirst(Headers.CONTENT_LENGTH);
if(encodedContentLength != null) {
exchange.getRequestHeaders().remove(Headers.CONTENT_LENGTH);
exchange.getRequestHeaders().put(Headers.X_CONTENT_LENGTH, encodedContentLength);
}
}
next.handleRequest(exchange);
}
Expand Down
21 changes: 11 additions & 10 deletions core/src/main/java/io/undertow/util/Headers.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ private Headers() {
public static final String VIA_STRING = "Via";
public static final String WARNING_STRING = "Warning";
public static final String WWW_AUTHENTICATE_STRING = "WWW-Authenticate";
public static final String X_CONTENT_LENGTH_STRING = "X-Content-Length";
public static final String X_CONTENT_TYPE_OPTIONS_STRING = "X-Content-Type-Options";
public static final String X_DISABLE_PUSH_STRING = "X-Disable-Push";
public static final String X_FORWARDED_FOR_STRING = "X-Forwarded-For";
Expand All @@ -123,7 +124,6 @@ private Headers() {
public static final String X_FORWARDED_SERVER_STRING = "X-Forwarded-Server";
public static final String X_FRAME_OPTIONS_STRING = "X-Frame-Options";
public static final String X_XSS_PROTECTION_STRING = "X-Xss-Protection";

// Header names

public static final HttpString ACCEPT = new HttpString(ACCEPT_STRING, 1);
Expand Down Expand Up @@ -200,15 +200,16 @@ private Headers() {
public static final HttpString VIA = new HttpString(VIA_STRING, 72);
public static final HttpString WARNING = new HttpString(WARNING_STRING, 73);
public static final HttpString WWW_AUTHENTICATE = new HttpString(WWW_AUTHENTICATE_STRING, 74);
public static final HttpString X_CONTENT_TYPE_OPTIONS = new HttpString(X_CONTENT_TYPE_OPTIONS_STRING, 75);
public static final HttpString X_DISABLE_PUSH = new HttpString(X_DISABLE_PUSH_STRING, 76);
public static final HttpString X_FORWARDED_FOR = new HttpString(X_FORWARDED_FOR_STRING, 77);
public static final HttpString X_FORWARDED_HOST = new HttpString(X_FORWARDED_HOST_STRING, 78);
public static final HttpString X_FORWARDED_PORT = new HttpString(X_FORWARDED_PORT_STRING, 79);
public static final HttpString X_FORWARDED_PROTO = new HttpString(X_FORWARDED_PROTO_STRING, 80);
public static final HttpString X_FORWARDED_SERVER = new HttpString(X_FORWARDED_SERVER_STRING, 81);
public static final HttpString X_FRAME_OPTIONS = new HttpString(X_FRAME_OPTIONS_STRING, 82);
public static final HttpString X_XSS_PROTECTION = new HttpString(X_XSS_PROTECTION_STRING, 83);
public static final HttpString X_CONTENT_LENGTH = new HttpString(X_CONTENT_LENGTH_STRING, 75);
public static final HttpString X_CONTENT_TYPE_OPTIONS = new HttpString(X_CONTENT_TYPE_OPTIONS_STRING, 76);
public static final HttpString X_DISABLE_PUSH = new HttpString(X_DISABLE_PUSH_STRING, 77);
public static final HttpString X_FORWARDED_FOR = new HttpString(X_FORWARDED_FOR_STRING, 78);
public static final HttpString X_FORWARDED_HOST = new HttpString(X_FORWARDED_HOST_STRING, 79);
public static final HttpString X_FORWARDED_PORT = new HttpString(X_FORWARDED_PORT_STRING, 80);
public static final HttpString X_FORWARDED_PROTO = new HttpString(X_FORWARDED_PROTO_STRING, 81);
public static final HttpString X_FORWARDED_SERVER = new HttpString(X_FORWARDED_SERVER_STRING, 82);
public static final HttpString X_FRAME_OPTIONS = new HttpString(X_FRAME_OPTIONS_STRING, 83);
public static final HttpString X_XSS_PROTECTION = new HttpString(X_XSS_PROTECTION_STRING, 84);
// Content codings

public static final HttpString COMPRESS = new HttpString("compress");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,26 +67,24 @@ public void handleRequest(final HttpServerExchange exchange) throws Exception {
exchange.getResponseSender().send(message, IoCallback.END_EXCHANGE);
}
});
final EncodingHandler wrappedEncode = new EncodingHandler(contentEncodingRepository).setNext(encode);

final HttpHandler decode = new RequestEncodingHandler(new HttpHandler() {
@Override
public void handleRequest(HttpServerExchange exchange) throws Exception {
exchange.getRequestReceiver().receiveFullBytes(new Receiver.FullBytesCallback() {
@Override
public void handle(HttpServerExchange exchange, byte[] message) {
Assert.assertTrue(exchange.getRequestContentLength()>0);
exchange.getResponseSender().send(ByteBuffer.wrap(message));
}
});
}
}).addEncoding("deflate", InflatingStreamSourceConduit.WRAPPER)
.addEncoding("gzip", GzipStreamSourceConduit.WRAPPER);
final HttpHandler wrappedDecode = new RequestEncodingHandler(decode)
.addEncoding("deflate", InflatingStreamSourceConduit.WRAPPER)
.addEncoding("gzip", GzipStreamSourceConduit.WRAPPER);

PathHandler pathHandler = new PathHandler();
pathHandler.addPrefixPath("/encode", wrappedEncode);
pathHandler.addPrefixPath("/decode", wrappedDecode);
pathHandler.addPrefixPath("/encode", encode);
pathHandler.addPrefixPath("/decode", decode);

DefaultServer.setRootHandler(pathHandler);
}
Expand Down
Loading

0 comments on commit 81daf51

Please sign in to comment.