Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8263031

HttpClient throws Exception if it receives a Push Promise that is too large

XMLWordPrintable

    • b18
    • Verified

        ADDITIONAL SYSTEM INFORMATION :
        Version: openjdk 11.0.9.1 2020-11-04

        A DESCRIPTION OF THE PROBLEM :
        Whenever HttpClient.send() sends a request to a Webservice that returns a Push Promise that exceeds the size of a single Push Promise Frame (Push Promise Frame + Continuation frames, for example because it adds a lot of headers to the Push Promise) the following Exception is thrown by the HttpClient (even if handling of Push Promises is not enabled):

        java.io.IOException: no statuscode in response
        at java.net.http/jdk.internal.net.http.HttpClientImpl.send(HttpClientImpl.java:565)
        at java.net.http/jdk.internal.net.http.HttpClientFacade.send(HttpClientFacade.java:119)
        at matthias.test.MinimalTest.clientTest(MinimalTest.java:237)
        at matthias.test.MinimalTest.httpClientFailsWhenTooManyHeadersInPushPromise(MinimalTest.java:252)
        at matthias.test.MinimalTest.main(MinimalTest.java:276)
        Caused by: java.io.IOException: no statuscode in response
        at java.net.http/jdk.internal.net.http.Stream.lambda$handleResponse$4(Stream.java:442)
        at java.base/java.util.OptionalLong.orElseThrow(OptionalLong.java:271)
        at java.net.http/jdk.internal.net.http.Stream.handleResponse(Stream.java:442)
        at java.net.http/jdk.internal.net.http.Stream.incoming(Stream.java:402)
        at java.net.http/jdk.internal.net.http.Http2Connection.processFrame(Http2Connection.java:785)
        at java.net.http/jdk.internal.net.http.frame.FramesDecoder.decode(FramesDecoder.java:155)
        at java.net.http/jdk.internal.net.http.Http2Connection$FramesController.processReceivedData(Http2Connection.java:232)
        at java.net.http/jdk.internal.net.http.Http2Connection.asyncReceive(Http2Connection.java:649)
        at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.processQueue(Http2Connection.java:1275)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run(SequentialScheduler.java:175)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:147)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:271)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:224)
        at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.runOrSchedule(Http2Connection.java:1293)
        at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.onNext(Http2Connection.java:1319)
        at java.net.http/jdk.internal.net.http.Http2Connection$Http2TubeSubscriber.onNext(Http2Connection.java:1253)
        at java.net.http/jdk.internal.net.http.common.SSLTube$DelegateWrapper.onNext(SSLTube.java:202)
        at java.net.http/jdk.internal.net.http.common.SSLTube$SSLSubscriberWrapper.onNext(SSLTube.java:484)
        at java.net.http/jdk.internal.net.http.common.SSLTube$SSLSubscriberWrapper.onNext(SSLTube.java:287)
        at java.net.http/jdk.internal.net.http.common.SubscriberWrapper$DownstreamPusher.run1(SubscriberWrapper.java:318)
        at java.net.http/jdk.internal.net.http.common.SubscriberWrapper$DownstreamPusher.run(SubscriberWrapper.java:261)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run(SequentialScheduler.java:175)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:147)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:271)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler.runOrSchedule(SequentialScheduler.java:224)
        at java.net.http/jdk.internal.net.http.common.SubscriberWrapper.outgoing(SubscriberWrapper.java:234)
        at java.net.http/jdk.internal.net.http.common.SubscriberWrapper.outgoing(SubscriberWrapper.java:200)
        at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader.processData(SSLFlowDelegate.java:403)
        at java.net.http/jdk.internal.net.http.common.SSLFlowDelegate$Reader$ReaderDownstreamPusher.run(SSLFlowDelegate.java:264)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SynchronizedRestartableTask.run(SequentialScheduler.java:175)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$CompleteRestartableTask.run(SequentialScheduler.java:147)
        at java.net.http/jdk.internal.net.http.common.SequentialScheduler$SchedulableTask.run(SequentialScheduler.java:198)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at java.base/java.lang.Thread.run(Thread.java:834)


        STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
        Use HttpClient to send a request to a Webservice that returns a large push promise.

        EXPECTED VERSUS ACTUAL BEHAVIOR :
        EXPECTED -
        A HttpResponse is received.
        ACTUAL -
        'java.io.IOException: no statuscode in response' is thrown

        ---------- BEGIN SOURCE ----------
        A simple Servlet running on Tomcat9:

        @WebServlet("/serverpush1")
        public class Http2TestServlet extends HttpServlet {
        @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
                PushBuilder pushBuilder = req.newPushBuilder();
               
                for(int i=0; i<=100; i++) {
                 pushBuilder.addHeader("x-additionalHeader"+i, "headervalue"+i);
                }
                
                
                pushBuilder
                 .path("resources/images/tile-0.png")
                        .push();
                
                try(PrintWriter respWriter = resp.getWriter();){
                    respWriter.write("<html>" +
                            "<img src='resources/images/tile-0.png'>" +
                            "</html>");
                }
            }
        }

        A simple client that connects to it:

        URI target = URI.create("https://localhost:9443/serverpush1");
        HttpRequest httpRequest = HttpRequest.newBuilder().uri(target).build();
        HttpClient httpClient = HttpClient.newBuilder().version(Version.HTTP_2).build();
        try {
        HttpResponse<String> response = httpClient.send(httpRequest, BodyHandlers.ofString());
        System.out.println(response.body());
        } catch(IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        } catch(InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
        }
        ---------- END SOURCE ----------

        FREQUENCY : always


          1. HttpClientTest.java
            0.9 kB
          2. keystore.jks
            3 kB
          3. server.xml
            8 kB
          4. ServerPushTestServlet.java
            0.8 kB
          5. truststore.jks
            1 kB
          6. web.xml
            0.4 kB

              ccleary Conor Cleary (Inactive)
              webbuggrp Webbug Group
              Votes:
              0 Vote for this issue
              Watchers:
              7 Start watching this issue

                Created:
                Updated:
                Resolved: