Uploaded image for project: 'Undertow'
  1. Undertow
  2. UNDERTOW-2031

protocol error with HTTP/2 and Expect: 100-continue

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Done
    • Icon: Blocker Blocker
    • 2.3.0.Alpha2, 2.2.21.Final
    • 2.2.12.Final
    • Core
    • None
    • Hide

      Hello world from undertow, enriched with HttpContinueAcceptingHandler and HTTP/2 support:

      public class HelloWorldServer {
      
          public static void main(final String[] args) {
              Undertow server = Undertow.builder()
                      .addHttpListener(8080, "localhost")
                      .setServerOption(UndertowOptions.ENABLE_HTTP2, true)
                      .setHandler(
                          new HttpContinueAcceptingHandler(
                          new HttpHandler() {
                          @Override
                          public void handleRequest(final HttpServerExchange exchange) throws Exception {
                              exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
                              exchange.getResponseSender().send("Hello World");
                          }
                      })).build();
              server.start();
          }
      }
      

      Sending something with curl:

      $ curl --http2 -X PUT  localhost:8080/ -d foo -X PUT -H 'Expect: 100-continue' --http2-prior-knowledge -v
      *   Trying 127.0.0.1:8080...
      * TCP_NODELAY set
      * Connected to localhost (127.0.0.1) port 8080 (#0)
      * Using HTTP2, server supports multi-use
      * Connection state changed (HTTP/2 confirmed)
      * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
      * Using Stream ID: 1 (easy handle 0x5642a7ea1e30)
      > PUT / HTTP/2
      > Host: localhost:8080
      > user-agent: curl/7.68.0
      > accept: */*
      > expect: 100-continue
      > content-length: 3
      > content-type: application/x-www-form-urlencoded
      > 
      * Connection state changed (MAX_CONCURRENT_STREAMS == 4294967295)!
      * http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [content-length], value: [0]
      * HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
      * stopped the pause stream!
      * Connection #0 to host localhost left intact
      curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
      

      I am trying to reproduce an issue we initially had with haproxy and an application running on EAP 7.4.3:

      • haproxy doing TLS reencrypt, having negotiated HTTP/1.1 with client and HTTP2 with backend
      • client sends a curl -X PUT that automatically adds a Expect
      • traffic breaks in the middle

      From the RFC I read as example:

      
           HTTP/1.1 100 Continue            HEADERS
           Extension-Field: bar       ==>     - END_STREAM
                                              + END_HEADERS
                                                :status = 100
                                                extension-field = bar
      

      I am not sure the content-length should be sent, but also it looks like the 100-continue replied by Undertow contains the "END_STREAM" flag.

      Show
      Hello world from undertow, enriched with HttpContinueAcceptingHandler and HTTP/2 support: public class HelloWorldServer { public static void main( final String [] args) { Undertow server = Undertow.builder() .addHttpListener(8080, "localhost" ) .setServerOption(UndertowOptions.ENABLE_HTTP2, true ) .setHandler( new HttpContinueAcceptingHandler( new HttpHandler() { @Override public void handleRequest( final HttpServerExchange exchange) throws Exception { exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain" ); exchange.getResponseSender().send( "Hello World" ); } })).build(); server.start(); } } Sending something with curl: $ curl --http2 -X PUT localhost:8080/ -d foo -X PUT -H 'Expect: 100- continue ' --http2-prior-knowledge -v * Trying 127.0.0.1:8080... * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8080 (#0) * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x5642a7ea1e30) > PUT / HTTP/2 > Host: localhost:8080 > user-agent: curl/7.68.0 > accept: */* > expect: 100- continue > content-length: 3 > content-type: application/x-www-form-urlencoded > * Connection state changed (MAX_CONCURRENT_STREAMS == 4294967295)! * http2 error: Invalid HTTP header field was received: frame type: 1, stream: 1, name: [content-length], value: [0] * HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1) * stopped the pause stream! * Connection #0 to host localhost left intact curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1) I am trying to reproduce an issue we initially had with haproxy and an application running on EAP 7.4.3: haproxy doing TLS reencrypt, having negotiated HTTP/1.1 with client and HTTP2 with backend client sends a curl -X PUT that automatically adds a Expect traffic breaks in the middle From the RFC I read as example: HTTP/1.1 100 Continue HEADERS Extension-Field: bar ==> - END_STREAM + END_HEADERS :status = 100 extension-field = bar I am not sure the content-length should be sent, but also it looks like the 100-continue replied by Undertow contains the "END_STREAM" flag.

      Curl complains of PROTOCOL_ERROR when in HTTP2, sending a Expect: 100-continue, and using the HttpContinueAcceptingHandler.

              flaviarnn Flavia Rainone
              frigault Francois Rigault
              Votes:
              1 Vote for this issue
              Watchers:
              11 Start watching this issue

                Created:
                Updated:
                Resolved: