eclipse-ee4j / grizzly

Grizzly
https://eclipse-ee4j.github.io/grizzly
Other
147 stars 68 forks source link

Grizzly 2.4.4/4.0.0 missing Content-Type in response #2192

Closed rabbit20210221 closed 10 months ago

rabbit20210221 commented 10 months ago

Response from Grizzly http server does not contain Content-Type header when client includes HTTP 2 upgrade headers.

I am not interested in HTTP 2 support, but expect Grizzly to give HTTP 1.1 response with Content-Type header.

Test program:

public static void main(String[] args) throws IOException, InterruptedException {
        HttpServer server = HttpServer.createSimpleServer();
        server.getServerConfiguration().addHttpHandler(new HttpHandler() {
            public void service(Request request, Response response)
                    throws Exception {
                for (String header: request.getHeaderNames()) {
                    String value = String.join("," , request.getHeaders(header));
                    System.out.println("<< " + header + "=" + value);
                }
                final String date = "{ "
                        + "\"name\": \"" + server.getServerConfiguration().getHttpServerName() + ","
                        + "\"version\": \"" + server.getServerConfiguration().getHttpServerVersion() + ","
                        + "\"time\": \"" + Instant.now().toString() 
                    + "\" }";
                response.setContentType("application/json");
                response.setContentLength(date.length());
                response.setCharacterEncoding("UTF-8");
                response.getWriter().write(date);
            }
        }, "/time");
        server.start();
        NetworkListener listener = server.getListener("grizzly");

        HttpRequest request = HttpRequest.newBuilder()
                .GET()
                .uri(URI.create("http://127.0.0.1:" + listener.getPort() + "/time"))
                .setHeader("Accept", "application/json")
                .build();

        System.out.println("\n\nDefault HttpClient with Upgrade h2c");
        HttpClient httpClient1 = HttpClient.newBuilder()
                .connectTimeout(Duration.ofSeconds(30))
                .build();
        HttpResponse<String> response1 = httpClient1.send(request, HttpResponse.BodyHandlers.ofString());
        HttpHeaders headers1 = response1.headers();
        headers1.map().forEach((k, v) -> System.out.println(">> " + k + ":" + v));
        System.out.println(response1.statusCode());
        System.out.println(response1.body());

        System.out.println("\n\nHttpClient 1.1");
        HttpClient httpClient2 = HttpClient.newBuilder()
                .version(HttpClient.Version.HTTP_1_1)
                .connectTimeout(Duration.ofSeconds(30))
                .build();
        HttpResponse<String> response2 = httpClient2.send(request, HttpResponse.BodyHandlers.ofString());
        HttpHeaders headers2 = response2.headers();
        headers2.map().forEach((k, v) -> System.out.println(">>" + k + ":" + v));
        System.out.println(response2.statusCode());
        System.out.println(response2.body());
    }

Output:

Default HttpClient with Upgrade h2c
<< connection=Upgrade, HTTP2-Settings
<< content-length=0
<< host=127.0.0.1:8080
<< http2-settings=AAEAAEAAAAIAAAABAAMAAABkAAQBAAAAAAUAAEAA
<< upgrade=h2c
<< user-agent=Java-http-client/11.0.20
<< accept=application/json
>> content-length:[44]
200
{ "name": "Grizzly,"version": "4.0.0,"time": "2023-10-07T00:37:10.670102600Z" }

HttpClient 1.1
<< content-length=0
<< host=127.0.0.1:8080
<< user-agent=Java-http-client/11.0.20
<< accept=application/json
>>content-length:[41]
>>content-type:[application/json;charset=UTF-8]
200
{ "name": "Grizzly,"version": "4.0.0,"time": "2023-10-07T00:40:06.860429100Z" }

Note missing "content-type" in the first response.

mnriem commented 10 months ago
  1. Can you reproduce this on the latest Grizzly version?
  2. Can you reproduce this with another HttpClient library?
rabbit20210221 commented 10 months ago
  1. Grizzly 2.4.4 is already the latest of the 2.x.x series. I cannot upgrade to Grizzly 4.x.x as my code base is not migrated to Jakarta EE yet.
  2. This is reproducible with any HTTP client library -- even with "curl" command line. All you need to trigger the bug is the presence of "Upgrade: h2c" in client request.
mnriem commented 10 months ago
  1. Can you try it with the latest Grizzly 4 and your test program?
  2. Can you share the curl command line?
rabbit20210221 commented 10 months ago

Thanks for your response. I ran the test with Grizzly 4.0.0 and found the same issue with curl. I modifed my original test program to include Grizzly version in response.

Test 1: curl GET -- no issues

$ curl -vv -H 'Accept: application/json' http://localhost:8080/time
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /time HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.0.1
> Accept: application/json
>
< HTTP/1.1 200 OK
< Content-Type: application/json;charset=UTF-8
< Content-Length: 79
<
{ "name": "Grizzly,"version": "4.0.0,"time": "2023-10-07T00:37:10.670102600Z" }

Test 2: curl GET with "Upgrade: h2c" -- missing Content-Type header in Grizzly response

$ curl -vv -H 'Accept: application/json' -H 'Upgrade: h2c' http://localhost:8080/time
*   Trying 127.0.0.1:8080...
* Connected to localhost (127.0.0.1) port 8080 (#0)
> GET /time HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.0.1
> Accept: application/json
> Upgrade: h2c
>
< HTTP/1.1 200 OK
< Content-Length: 76
<
{ "name": "Grizzly,"version": "4.0.0,"time": "2023-10-07T00:38:20.201669Z" }
mnriem commented 10 months ago

@rabbit20210221 I have confirmed the issue and looking into a fix

rabbit20210221 commented 10 months ago

@mnriem Thanks for your quick reply.

mnriem commented 10 months ago

@rabbit20210221 Can you try out the PR?