Skip to content

Commit

Permalink
Test case demonstrating how to bypass HTTP body size limit
Browse files Browse the repository at this point in the history
Also removes the duplicate addition of the body-size-limit enforcer.
  • Loading branch information
snazy authored and holly-cummins committed Feb 8, 2024
1 parent 7261d2d commit 762137f
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,6 @@ public void handle(RoutingContext event) {
}

HttpServerCommonHandlers.applyHeaders(managementConfiguration.getValue().header(), mr);
HttpServerCommonHandlers.enforceMaxBodySize(managementConfiguration.getValue().limits(), mr);
applyCompression(managementBuildTimeConfig.enableCompression(), mr);

Handler<HttpServerRequest> handler = HttpServerCommonHandlers.enforceDuplicatedContext(mr);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package io.quarkus.it.vertx;

import java.util.concurrent.atomic.AtomicLong;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.event.Observes;

import io.quarkus.runtime.StartupEvent;
import io.quarkus.vertx.http.runtime.ServerLimitsConfig;
import io.quarkus.vertx.http.runtime.options.HttpServerCommonHandlers;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.http.HttpServerRequest;
import io.vertx.core.http.HttpServerResponse;
import io.vertx.core.http.HttpVersion;
import io.vertx.ext.web.Router;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class UploadRoute {

/**
* Installs two POST-routes - one that bypasses the body-length limit using {@code order(-3)}
* ({@link HttpServerCommonHandlers#enforceMaxBodySize(ServerLimitsConfig, Router)} uses {@code order(-2)}) and one that
* does not bypass body-size enforcement.
*/
void installRoute(@Observes StartupEvent startupEvent, Router router) {
router.post("/unlimited-upload").order(-3).handler(UploadHandler::newRequest);
router.post("/limited-upload").handler(UploadHandler::newRequest);
}

static class UploadHandler {
final HttpServerResponse resp;

final AtomicLong total = new AtomicLong();

UploadHandler(HttpServerResponse resp) {
this.resp = resp;
}

void end(Void x) {
resp.setStatusCode(200)
.setStatusMessage("OK")
.putHeader("Content-Type", "text/plain")
.end("Got " + total);
}

void onData(Buffer buffer) {
total.addAndGet(buffer.length());
}

void onException(Throwable exception) {
resp.setStatusCode(500)
.setStatusMessage("Internal Server Error")
.end("Failed to process request.");
}

static void newRequest(RoutingContext routingContext) {
HttpServerRequest req = routingContext.request();
HttpServerResponse resp = routingContext.response();

String expectValue = req.getHeader(HttpHeaders.EXPECT);
if (expectValue != null) {
if (!"100-continue".equals(expectValue)) {
routingContext.fail(417);
}
if (req.version() != HttpVersion.HTTP_1_0) {
resp.writeContinue();
}
}

UploadHandler uploadHandler = new UploadHandler(resp);
req.handler(uploadHandler::onData)
.endHandler(uploadHandler::end)
.exceptionHandler(uploadHandler::onException);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package io.quarkus.it.vertx;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Map;

import org.junit.jupiter.api.Test;

import io.quarkus.test.common.http.TestHTTPResource;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.junit.QuarkusTestProfile;
import io.quarkus.test.junit.TestProfile;

@QuarkusTest
@TestProfile(UploadUnlimitedTestCase.UploadLimitProfile.class)
public class UploadUnlimitedTestCase {

/** See {@link io.quarkus.it.vertx.UploadRoute}. */
@TestHTTPResource(value = "/unlimited-upload")
URL unlimitedUrl;

/** See {@link io.quarkus.it.vertx.UploadRoute}. */
@TestHTTPResource(value = "/limited-upload")
URL limitedUrl;

/** No {@code quarkus.http.limits.max-body-size} via route-config. */
@Test
public void uploadBypassBodySizeLimit() throws Exception {
HttpURLConnection urlConn = (HttpURLConnection) unlimitedUrl.openConnection();
byte[] justData = new byte[8192];
urlConn.setRequestMethod("POST");
urlConn.setDoOutput(true);
urlConn.setRequestProperty("Content-Type", "multipart/form-data");
urlConn.setRequestProperty("Content-Length", String.valueOf(justData.length));
try (OutputStream output = urlConn.getOutputStream()) {
output.write(justData);
}
assertEquals(200, urlConn.getResponseCode(), urlConn.getResponseCode() + ": " + urlConn.getResponseMessage());
}

/** Respects {@code quarkus.http.limits.max-body-size}. */
@Test
public void uploadSizeLimitedByConfig() throws Exception {
HttpURLConnection urlConn = (HttpURLConnection) limitedUrl.openConnection();
byte[] justData = new byte[8192];
urlConn.setRequestMethod("POST");
urlConn.setDoOutput(true);
urlConn.setRequestProperty("Content-Length", String.valueOf(justData.length));
try (OutputStream output = urlConn.getOutputStream()) {
output.write(justData);
}
assertEquals(413, urlConn.getResponseCode(), urlConn.getResponseCode() + ": " + urlConn.getResponseMessage());
}

public static class UploadLimitProfile implements QuarkusTestProfile {

@Override
public Map<String, String> getConfigOverrides() {
return Map.of(
"quarkus.http.limits.max-body-size", "1K");
}
}
}

0 comments on commit 762137f

Please sign in to comment.