Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add the ability to configure the maximum form attribute size #16432

Merged
merged 1 commit into from
Apr 13, 2021

Conversation

geoand
Copy link
Contributor

@geoand geoand commented Apr 12, 2021

Vert.x defaults to 2K and prior to this PR we didn't have
a way to configure it.

Fixes: #16422

@cescoffier
Copy link
Member

Probably a good candidate for backport. WDYT @geoand ?

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

Yeah, I think so.

If this doesn't apply cleanly, I can certainly open a PR against the 1.13 branch

@gsmet
Copy link
Member

gsmet commented Apr 12, 2021

@geoand isn't there more to it? Shouldn't we have an exception thrown in the case the form is over the limit? AFAICS from the issue, we just put null in the value which sounds a bit weird to me.

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

That sounds reasonable, but I am not sure we can do that - it's something Vert.x handles. @cescoffier do you know how what @gsmet is asking for could be done?

@gsmet
Copy link
Member

gsmet commented Apr 12, 2021

/cc @vietj

@cescoffier
Copy link
Member

My understanding is that the request is going to be rejected with a PAYLOAD_TOO_LARGE response. @vietj / @pmlopes can you confirm?

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

My understanding is that the request is going to be rejected with a PAYLOAD_TOO_LARGE response. @vietj / @pmlopes can you confirm?

That is not what currently happens - currently the form param that exceeds the limit is simply never populated

@quarkus-bot
Copy link

quarkus-bot bot commented Apr 12, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 942efd3

Status Name Step Test failures Logs Raw logs
JVM Tests - JDK 11 Build Test failures Logs Raw logs
JVM Tests - JDK 11 Windows Build Test failures Logs Raw logs
JVM Tests - JDK 15 Build Test failures Logs Raw logs

Test Failures

⚙️ JVM Tests - JDK 11 #

📦 integration-tests/kafka

io.quarkus.it.kafka.SaslKafkaConsumerTest.testReception line 48 - Source on GitHub

io.quarkus.it.kafka.SslKafkaConsumerTest.testReception line 56 - Source on GitHub


⚙️ JVM Tests - JDK 11 Windows #

📦 extensions/mongodb-client/deployment

io.quarkus.mongodb.NamedReactiveMongoClientConfigTest. - Source on GitHub


⚙️ JVM Tests - JDK 15 #

📦 integration-tests/kafka

io.quarkus.it.kafka.SaslKafkaConsumerTest.testReception line 48 - Source on GitHub

io.quarkus.it.kafka.SslKafkaConsumerTest.testReception line 56 - Source on GitHub

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

My understanding is that the request is going to be rejected with a PAYLOAD_TOO_LARGE response. @vietj / @pmlopes can you confirm?

That is not what currently happens - currently the form param that exceeds the limit is simply never populated

It seems like Netty does throw an IOException in this case, which then Vert.x handles at: https://github.com/eclipse-vertx/vert.x/blob/4.0.3/src/main/java/io/vertx/core/http/impl/Http1xServerRequest.java#L524.
But that doesn't seem to result in response (perhaps we need to have some kind of exception handler somewhere?)

@gsmet
Copy link
Member

gsmet commented Apr 12, 2021

Maybe it's just me but I find this code a bit weird. I would at the very least have expected a return after the handleException(). My very wild guess is that there's something wrong around here.

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

Which code are you talking about? The Vert.x code I linked above?

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

In any case, I don't think there is anything we can in Quarkus, so I'll merge this once CI is done. If there is some way we can integrate with Vert.x to make it fail in the case, in question, we can do it in a follow up

@gsmet
Copy link
Member

gsmet commented Apr 12, 2021

Totally agree it doesn't block this PR but the behavior on the Vert.x side is definitely problematic.

@pmlopes
Copy link
Contributor

pmlopes commented Apr 12, 2021

@geoand @cescoffier @gsmet I don't see how this is related to vert.x, we don't enforce any limit by default, here's a test I've just created to check this issue:

  @Test
  public void testFormMultipartFormDataLarge() throws Exception {
    router.clear();
    router.route().handler(BodyHandler.create());
    router.route().handler(rc -> {
      MultiMap attrs = rc.request().formAttributes();
      assertNotNull(attrs);
      int size = 0;
      assertNotNull(attrs.get("attr1"));
      size += attrs.get("attr1").length();
      assertNotNull(attrs.get("attr2"));
      size += attrs.get("attr2").length();
      assertTrue(size > 2048);
      rc.response().end();
    });
    testRequest(HttpMethod.POST, "/?p1=foo", req -> {
      Buffer buffer = Buffer.buffer();
      String boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO";
      String header =
        "--" + boundary + "\r\n" +
          "Content-Disposition: form-data; name=\"attr1\"\r\n\r\n" + Base64.getUrlEncoder().encodeToString(TestUtils.randomBuffer(1024).getBytes()) + "\r\n" +
          "--" + boundary + "\r\n" +
          "Content-Disposition: form-data; name=\"attr2\"\r\n\r\n" + Base64.getUrlEncoder().encodeToString(TestUtils.randomBuffer(1024).getBytes()) + "\r\n" +
          "--" + boundary + "\r\n" +
          "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"file\"\r\n" +
          "Content-Type: application/octet-stream\r\n" +
          "Content-Transfer-Encoding: binary\r\n" +
          "\r\n";
      buffer.appendString(header);
      buffer.appendBuffer(TestUtils.randomBuffer(50));
      buffer.appendString("\r\n--" + boundary + "--\r\n");
      req.headers().set("content-length", String.valueOf(buffer.length()));
      req.headers().set("content-type", "multipart/form-data; boundary=" + boundary);
      req.write(buffer);
    }, 200, "OK", null);
  }

I'm sending a multipart larger than 2kb and there's no problem with that.

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

@pmlopes the problem in your test will likely surface if attr1 or attr2 (on its own) is larger than 2k.
We would expect Vert.x to return some error, but it seems like the attribute is just silently ignored

@geoand geoand added the triage/waiting-for-ci Ready to merge when CI successfully finishes label Apr 12, 2021
@pmlopes
Copy link
Contributor

pmlopes commented Apr 12, 2021

@geoand that doesn't seem to be the vert.x behavior:

  @Test
  public void testFormMultipartFormDataLarge() throws Exception {
    router.clear();
    router.route().handler(BodyHandler.create());
    router.route().handler(rc -> {
      MultiMap attrs = rc.request().formAttributes();
      assertNotNull(attrs);
      int size = 0;
      assertNotNull(attrs.get("attr1"));
      size += attrs.get("attr1").length();
      assertNotNull(attrs.get("attr2"));
      size += attrs.get("attr2").length();
      assertTrue(size > 4096);
      rc.response().end();
    }).failureHandler(ctx -> {
      assertNotNull(ctx.failure());
      assertTrue(ctx.failure() instanceof IOException);
      assertEquals("Size exceed allowed maximum capacity", ctx.failure().getMessage());
      ctx.next();
    });

    testRequest(HttpMethod.POST, "/?p1=foo", req -> {
      Buffer buffer = Buffer.buffer();
      String boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO";
      String header =
        "--" + boundary + "\r\n" +
          "Content-Disposition: form-data; name=\"attr1\"\r\n\r\n" + Base64.getUrlEncoder().encodeToString(TestUtils.randomBuffer(2048).getBytes()) + "\r\n" +
          "--" + boundary + "\r\n" +
          "Content-Disposition: form-data; name=\"attr2\"\r\n\r\n" + Base64.getUrlEncoder().encodeToString(TestUtils.randomBuffer(2048).getBytes()) + "\r\n" +
          "--" + boundary + "\r\n" +
          "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"file\"\r\n" +
          "Content-Type: application/octet-stream\r\n" +
          "Content-Transfer-Encoding: binary\r\n" +
          "\r\n";
      buffer.appendString(header);
      buffer.appendBuffer(TestUtils.randomBuffer(50));
      buffer.appendString("\r\n--" + boundary + "--\r\n");
      req.headers().set("content-length", String.valueOf(buffer.length()));
      req.headers().set("content-type", "multipart/form-data; boundary=" + boundary);
      req.write(buffer);
    }, 400, "Bad Request", null);
  }

When the attributes are larger than 2kb then indeed a DecodeException is catched in the BodyHandler that fails the request with a default 400 failure. The failure is indeed an IOException with the message mentioned in the issue.

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

@pmlopes OK, I see, thanks for the information

We aren't using the body handler in RESTEasy Reactive so I'll need to look into emulating its behavior

@geoand
Copy link
Contributor Author

geoand commented Apr 12, 2021

In light of the previous comments, I will actually push changes to this PR regarding the proper HTTP response code

@quarkus-bot
Copy link

quarkus-bot bot commented Apr 12, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 942efd3

Status Name Step Test failures Logs Raw logs
JVM Tests - JDK 11 Build Test failures Logs Raw logs
JVM Tests - JDK 11 Windows Build Test failures Logs Raw logs
Native Tests - Messaging Build ⚠️ Check → Logs Raw logs

Full information is available in the Build summary check run.

Test Failures

⚙️ JVM Tests - JDK 11 #

📦 integration-tests/kafka

io.quarkus.it.kafka.SaslKafkaConsumerTest.testReception line 48 - More details - Source on GitHub

io.quarkus.it.kafka.SslKafkaConsumerTest.testReception line 56 - More details - Source on GitHub


⚙️ JVM Tests - JDK 11 Windows #

📦 extensions/smallrye-reactive-messaging-amqp/deployment

io.quarkus.smallrye.reactivemessaging.amqp.devmode.nohttp.AmqpDevModeNoHttpTest.testProducerUpdate line 70 - More details - Source on GitHub

@quarkus-bot
Copy link

quarkus-bot bot commented Apr 12, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 8d1c330

Status Name Step Test failures Logs Raw logs
Initial JDK 11 Build Build ⚠️ Check → Logs Raw logs

@quarkus-bot
Copy link

quarkus-bot bot commented Apr 12, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 5e30eda

Status Name Step Test failures Logs Raw logs
Devtools Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
Devtools Tests - JDK 11 Windows ⚠️ Check →
Gradle Tests - JDK 11 ${{ matrix.os.family }} ⚠️ Check →
Initial JDK 11 Build Build ⚠️ Check → Logs Raw logs
JVM Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
JVM Tests - JDK 11 Windows ⚠️ Check →
Maven Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
Maven Tests - JDK 11 Windows ⚠️ Check →
MicroProfile TCKs Tests ⚠️ Check →
Native Tests - ${{ matrix.category }} ⚠️ Check →
Native Tests - Windows - ${{ matrix.category }} ⚠️ Check →

@quarkus-bot
Copy link

quarkus-bot bot commented Apr 12, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 5e30eda

Status Name Step Test failures Logs Raw logs
Devtools Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
Devtools Tests - JDK 11 Windows ⚠️ Check →
Gradle Tests - JDK 11 ${{ matrix.os.family }} ⚠️ Check →
Initial JDK 11 Build Build ⚠️ Check → Logs Raw logs
JVM Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
JVM Tests - JDK 11 Windows ⚠️ Check →
Maven Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
Maven Tests - JDK 11 Windows ⚠️ Check →
MicroProfile TCKs Tests ⚠️ Check →
Native Tests - ${{ matrix.category }} ⚠️ Check →
Native Tests - Windows - ${{ matrix.category }} ⚠️ Check →

@quarkus-bot
Copy link

quarkus-bot bot commented Apr 12, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 49e969c

Status Name Step Test failures Logs Raw logs
Devtools Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
Devtools Tests - JDK 11 Windows ⚠️ Check →
Gradle Tests - JDK 11 ${{ matrix.os.family }} ⚠️ Check →
Initial JDK 11 Build Build ⚠️ Check → Logs Raw logs
JVM Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
JVM Tests - JDK 11 Windows ⚠️ Check →
Maven Tests - JDK ${{ matrix.java.name }} ⚠️ Check →
Maven Tests - JDK 11 Windows ⚠️ Check →
MicroProfile TCKs Tests ⚠️ Check →
Native Tests - ${{ matrix.category }} ⚠️ Check →
Native Tests - Windows - ${{ matrix.category }} ⚠️ Check →

Vert.x defaults to 2K and prior to this PR we didn't have
a way to configure it.
When the a form attribute is too large in multipart request,
return HTTP 413.

Fixes: quarkusio#16422
@gsmet
Copy link
Member

gsmet commented Apr 12, 2021

Rebased to get the latest CI fixes.

@quarkus-bot
Copy link

quarkus-bot bot commented Apr 13, 2021

This workflow status is outdated as a new workflow run has been triggered.

Failing Jobs - Building 19eb163

Status Name Step Test failures Logs Raw logs
JVM Tests - JDK 11 Build Test failures Logs Raw logs
✔️ JVM Tests - JDK 11 Windows
JVM Tests - JDK 15 Build Test failures Logs Raw logs
✔️ JVM Tests - JDK 8

Full information is available in the Build summary check run.

Test Failures

⚙️ JVM Tests - JDK 11 #

📦 extensions/scheduler/deployment

io.quarkus.scheduler.test.PropertyDefaultValueSchedulerTest.testDefaultIdentity line 33 - More details - Source on GitHub

📦 integration-tests/kafka

io.quarkus.it.kafka.SaslKafkaConsumerTest.testReception line 48 - More details - Source on GitHub

io.quarkus.it.kafka.SslKafkaConsumerTest.testReception line 56 - More details - Source on GitHub


⚙️ JVM Tests - JDK 15 #

📦 integration-tests/kafka

io.quarkus.it.kafka.SaslKafkaConsumerTest.testReception line 48 - More details - Source on GitHub

io.quarkus.it.kafka.SslKafkaConsumerTest.testReception line 56 - More details - Source on GitHub

@geoand
Copy link
Contributor Author

geoand commented Apr 13, 2021

Thanks!

@gsmet gsmet merged commit f1e177f into quarkusio:main Apr 13, 2021
@quarkus-bot quarkus-bot bot added this to the 2.0 - main milestone Apr 13, 2021
@quarkus-bot quarkus-bot bot removed the triage/waiting-for-ci Ready to merge when CI successfully finishes label Apr 13, 2021
@geoand geoand deleted the #16422 branch April 13, 2021 07:21
@quarkus-bot
Copy link

quarkus-bot bot commented Apr 13, 2021

Failing Jobs - Building 19eb163

Status Name Step Test failures Logs Raw logs
JVM Tests - JDK 11 Build Test failures Logs Raw logs
✔️ JVM Tests - JDK 11 Windows
✔️ JVM Tests - JDK 15
JVM Tests - JDK 8 Build Test failures Logs Raw logs

Full information is available in the Build summary check run.

Test Failures

⚙️ JVM Tests - JDK 11 #

📦 integration-tests/kafka

io.quarkus.it.kafka.SaslKafkaConsumerTest.testReception line 48 - More details - Source on GitHub

io.quarkus.it.kafka.SslKafkaConsumerTest.testReception line 56 - More details - Source on GitHub


⚙️ JVM Tests - JDK 8 #

📦 integration-tests/kafka

io.quarkus.it.kafka.SaslKafkaConsumerTest.testReception line 48 - More details - Source on GitHub

io.quarkus.it.kafka.SslKafkaConsumerTest.testReception line 56 - More details - Source on GitHub

@gsmet
Copy link
Member

gsmet commented Apr 13, 2021

This is not easily backportable due to:

[ERROR] /data/home/gsmet/git/quarkus/extensions/resteasy-reactive/quarkus-resteasy-reactive/runtime/src/main/java/io/quarkus/resteasy/reactive/server/runtime/MultipartFormHandler.java:[162,32] cannot find symbol
[ERROR]   symbol:   method cancel()
[ERROR]   location: variable fileUpload of type io.vertx.ext.web.FileUpload

Should we just avoid calling this method?

@geoand
Copy link
Contributor Author

geoand commented Apr 13, 2021

Oh - yes, it's not entirely correct to not do this, but yeah, we can get away with it

@gsmet gsmet modified the milestones: 2.0 - main, 1.13.2.Final Apr 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Resteasy Reactive - Multipart does not accept text/plain bigger than 2048 bytes
4 participants