quarkus: Incoming HTTP request not being fully read or closed when a constraint validator rejects the request

Describe the bug

Machine: Apple M1 Pro JVM: openjdk 11.0.2 Quarkus: 2.7.4.Final, 2.13.3.Final

There seems to be a race condition between reading a request from a TCP socket and constraint validators.

When a request gets rejected by a constraint validator (such as @Consume) before Quarkus had a chance to fully ACK the incoming request, Quarkus answers back with the appropriate status code and stops reading the request from the TCP socket but doesn’t close the connection.

This behavior, keeping the connection open but not reading data from the socket, leaves clients in a hanging state after they fully filled the TCP transmission window, waiting for it to be ACK’ed.

The client hang may not be observed if the requests are smaller in size, given that in those cases it’s likely that the request has been completely received and ACK’ed by Quarkus before the constraint validator had the chance to fire. In these cases, no hanging is observed.

Expected behavior

Quarkus should either read the incoming request fully or close the connection, so as to signal to the client that the request transmission should be over.

Actual behavior

Described in the previous section. Follow the steps below to reproduce.

How to Reproduce?

  1. Create a sample Quarkus application using quarkus create && cd code-with-quarkus
  2. Add the following endpoint:
@Path("/hello")
public class GreetingResource {

    @POST
    @Consumes({"image/jpeg", "image/png"})
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(byte[] imageFile) {
        throw new NotAuthorizedException("");
    }
}
  1. Make a request with a large payload (3MB is enough on my machine, Apple M1 Pro) which breaks the @Consumes filter by sending a different Content-Type header. For your convenience, here’s a python snippet that’ll do it:
import requests
import os

url = "http://localhost:8080/hello"

payload=b"\x00"+os.urandom(1024 * 1024 * 3)+b"\x00"
headers = {
  'Content-Type': 'image/gif'
}

response = requests.request("POST", url, headers=headers, data=payload)

print(response.text)

At this point, the Python code should hang because the request stream is neither being fully read nor closed by Quarkus.

Output of uname -a or ver

(macOS M1 Pro) Darwin <REDACTED>.local 21.6.0 Darwin Kernel Version 21.6.0: Mon Aug 22 20:19:52 PDT 2022; root:xnu-8020.140.49~2/RELEASE_ARM64_T6000 arm64

Output of java -version

openjdk version “11.0.2” 2019-01-15 OpenJDK Runtime Environment 18.9 (build 11.0.2+9) OpenJDK 64-Bit Server VM 18.9 (build 11.0.2+9, mixed mode)

GraalVM version (if different from Java)

No response

Quarkus version or git rev

Reproduced in 2.7.4.Final and 2.13.3.Final

Build tool (ie. output of mvnw --version or gradlew --version)

Apache Maven 3.8.6 Maven home: /Users/<REDACTED>/.m2/wrapper/dists/apache-maven-3.8.6-bin/67568434/apache-maven-3.8.6 Java version: 11.0.2, vendor: Oracle Corporation, runtime: /Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home Default locale: en_PT, platform encoding: UTF-8 OS name: “mac os x”, version: “10.16”, arch: “x86_64”, family: “mac”

Additional information

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 5
  • Comments: 19 (10 by maintainers)

Commits related to this issue

Most upvoted comments

I could reproduce this issue and this is a tentative fix for it: https://github.com/quarkusio/quarkus/pull/29119

If you have a sample that shows this, I’d love to test it out.

@geoand Here’s a quick project that’ll help you repro it in 5 minutes. The README has a 3 step guide on what you should do to trigger the issue.

https://github.com/davidreis97/QuarkusRepro28818