JDK-8211437 : java.net.http.HttpClient hangs on 204 reply without Content-length 0
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 11,12
  • Priority: P4
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2018-10-01
  • Updated: 2019-02-08
  • Resolved: 2018-10-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 11 JDK 12
11.0.2Fixed 12 b17Fixed
Related Reports
Relates :  
Relates :  
Relates :  
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
According to RFC 7230, a 204 reply should not have Content-length header:

"A server MUST NOT send a Content-Length header field in any response with a status code of 1xx (Informational) or 204 (No Content)."

However, if no such header is present on a 204 reply, an HTTP request made with java.net.http.HttpClient will hang waiting for more content.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1 - Create a webserver that replies with HTTP status code 204 and does not set the Content-length header to 0 (following the RFC).

2 - Use java.net.http.HttpClient to request a resource from such server.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Obtain a valid response.
ACTUAL -
Client hangs waiting for more content to read.

---------- BEGIN SOURCE ----------
I've used Spark Java (sparkjava.com) for the webserver as com.sun.net.httpserver.HttpServer does not conform with the RFC and always returns the Content-length (reported in another issue).

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse.BodyHandlers;

import static spark.Spark.*;

public class TestClient {

    public static void main(String[] args) throws IOException, InterruptedException {
        port(8000);
        get("/", (req, res) -> {
            res.status(204);
            return "";
        });

        awaitInitialization();

        var request = HttpRequest.newBuilder()
                .uri(URI.create("http://localhost:8000/"))
                .GET()
                .build();

        final var res = HttpClient.newHttpClient().send(request, BodyHandlers.ofString());
        System.out.println(res.statusCode());

        stop();
        awaitStop();
    }
}
---------- END SOURCE ----------

FREQUENCY : always



Comments
Fix Request. This fix is important as it resolves an issue where the HTTP Client does not correctly implement the semantics of the 204 response code. The fix avoids the issue where the client appears to hang waiting on response body data from the server ( which will never come ). A new automated test has been added, and the existing tests pass successfully. The backport patch applies cleanly.
19-10-2018

https://tools.ietf.org/html/rfc2616.html#section-10.2.5 10.2.5 204 No Content The server has fulfilled the request but does not need to return an entity-body, and might want to return updated metainformation. The response MAY include new or updated metainformation in the form of entity-headers, which if present SHOULD be associated with the requested variant. If the client is a user agent, it SHOULD NOT change its document view from that which caused the request to be sent. This response is primarily intended to allow input for actions to take place without causing a change to the user agent's active document view, although any new or updated metainformation SHOULD be applied to the document currently in the user agent's active view. The 204 response MUST NOT include a message-body, and thus is always terminated by the first empty line after the header fields.
03-10-2018

To reproduce the issue, run the attached test case. JDK 11+28 - Fail JDK 12-ea+10 - Fail The program hangs, no response is returned.
03-10-2018