Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HTTP2 #881

Draft
wants to merge 98 commits into
base: master
Choose a base branch
from
Draft

HTTP2 #881

wants to merge 98 commits into from

Conversation

bamkrs
Copy link
Member

@bamkrs bamkrs commented Oct 24, 2023

HTTP2

This PR contains my long lost efforts to bring HTTP2 to OAT++ and its users. Development stopped in 2021 after OAT++ v1.3.0 was released since newer versions introduced some major changes in how OAT++ handles headers which basically made it impossible to integrate HTTP2 in OAT++ in such a way, that both HTTP1 and HTTP2 requests are indistinguishable for the user when writing his endpoints.

The Good

Most of HTTP2 works! The development was done in a test-driven approach using h2spec. Of 146 tests, 130 passed. HTTP2 implementation in most browsers is so sloppy that every major browser (Firefox, Chromium, Safari) I tested worked in perfect harmony with OAT++ HTTP2 (back then).
HTTP2 and HTTP1 work together nicely and the user does not need to care if a request is HTTP1 or HTTP2. Adding HTTP2 to a project is pretty easy for the user since the HTTP2 is implemented as a normal network::ConnectionHandler which gracefully handles checking for and upgrading to HTTP2 for each new request.

The Bad

The changes aren't compatible with OAT++ newer than v1.3.0. This is mostly due to the major changes in OAT++'s streams implementation as well as the changes in HTTP header parsing and handling. In the end, I was stuck converting HTTP2 headers to the generic HTTP header container class in an efficient/performant way to pass it to the endpoint controllers.

The Ugly

Oh, there is a lot of ugly. Where do I start? This implementation of HTTP2 was never intended to be merged the way it is right now. I started it as a PoC to show @lganzzzo how HTTP2 could be integrated in OAT++ without breaking existing API's or major refactoring of OAT++'s ways. It should then be reimplemented as a joined effort since many details "under the hood" where misused and repurposed to speed up the development of the PoC. In 2021 I created some PR's that show these repurposing efforts (#463, #464, #465, #466, #474, #469, #482, #484, #494), especially these PR's around the streams and headers.

Next, there where 2 iterations of the implementation.
First, I implemented HTTP2 pretty straight forward in an "Simple-API" fashion. However, the Simple-API did not give me the right feature-set to implement some of HTTP2's specifications. Thus, I refactored the whole implementation to use the Async-API. This greatly improved the handling and performance of the HTTP2 implementation. Now, HTTP2 uses the framework of the Async-API under its hood while maintaining the users ability to use the Simple-API for their projects. The user does not see and does not need to care about this at all since its all hidden behind the well-known OAT++ workflow.

Whats Next?

I really don't known. I implemented the PoC as a small challenge while I was in lock-down due to covid. Now, post-covid, society returned back to normal (well, its not normal... look at Ukraine, Gaza or the military coups in Africa) and I'm pretty occupied with life in general.

Thus I invite everyone to contribute, rewrite or do whatever they want with this code. I won't be able to finish it.
Best would be if you create a PR in my fork to update this one. I try my best to look out for those PR's or any comments asking for guidance.

Appendix

Test-App

To test the implementation, just use the oatpp-starter repository and modify AppComponent.hpp and App.cpp like in this diff. This shows how simple it is to add HTTP2 to the users app.

diff --git a/src/App.cpp b/src/App.cpp
index c7161f9..e5cb8fa 100644
--- a/src/App.cpp
+++ b/src/App.cpp
@@ -2,6 +2,7 @@
 #include "./AppComponent.hpp"
 
 #include "oatpp/network/Server.hpp"
+#include "oatpp/web/server/HttpVersionSwitch.hpp"
 
 #include <iostream>
 
@@ -17,8 +18,12 @@ void run() {
   auto myController = std::make_shared<MyController>();
   myController->addEndpointsToRouter(router);
 
-  /* Get connection handler component */
-  OATPP_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, connectionHandler);
+  /* Get both HTTP1 and HTTP2 connection handlers */
+  OATPP_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, http1ConnectionHandler, "http1");
+  OATPP_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, http2ConnectionHandler, "http2");
+
+  /* Create an HTTP version switch which passes http1 and http2 requests to their correct connection handler */
+  auto connectionHandler = oatpp::web::server::HttpVersionSwitch::createShared(http1ConnectionHandler, http2ConnectionHandler);
 
   /* Get connection provider component */
   OATPP_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, connectionProvider);
diff --git a/src/AppComponent.hpp b/src/AppComponent.hpp
index 878784e..23cd02f 100644
--- a/src/AppComponent.hpp
+++ b/src/AppComponent.hpp
@@ -9,6 +9,8 @@
 
 #include "oatpp/core/macro/component.hpp"
 
+#include "oatpp/web/server/http2/Http2ConnectionHandler.hpp"
+
 /**
  *  Class which creates and holds Application components and registers components in oatpp::base::Environment
  *  Order of components initialization is from top to bottom
@@ -33,11 +35,19 @@ public:
   /**
    *  Create ConnectionHandler component which uses Router component to route requests
    */
-  OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, serverConnectionHandler)([] {
+  OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, http1ConnectionHandler)("http1", [] {
     OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); // get Router component
     return oatpp::web::server::HttpConnectionHandler::createShared(router);
   }());
-  
+
+  /**
+ *  Create Http2ConnectionHandler component which uses Router component to route requests
+ */
+  OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ConnectionHandler>, http2ConnectionHandler)("http2", [] {
+    OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); // get Router component
+    return std::make_shared<oatpp::web::server::http2::Http2ConnectionHandler>(router);
+  }());
+
   /**
    *  Create ObjectMapper component to serialize/deserialize DTOs in Contoller's API
    */

h2spec report

This is the h2spec report of the current state:

./h2spec -p 8000
Generic tests for HTTP/2 server
  1. Starting HTTP/2
    ✔ 1: Sends a client connection preface

  2. Streams and Multiplexing
    ✔ 1: Sends a PRIORITY frame on idle stream
    ✔ 2: Sends a WINDOW_UPDATE frame on half-closed (remote) stream
    ✔ 3: Sends a PRIORITY frame on half-closed (remote) stream
    ✔ 4: Sends a RST_STREAM frame on half-closed (remote) stream
    ✔ 5: Sends a PRIORITY frame on closed stream

  3. Frame Definitions
    3.1. DATA
      ✔ 1: Sends a DATA frame
      ✔ 2: Sends multiple DATA frames
      ✔ 3: Sends a DATA frame with padding

    3.2. HEADERS
      ✔ 1: Sends a HEADERS frame
      ✔ 2: Sends a HEADERS frame with padding
      ✔ 3: Sends a HEADERS frame with priority

    3.3. PRIORITY
      ✔ 1: Sends a PRIORITY frame with priority 1
      ✔ 2: Sends a PRIORITY frame with priority 256
      ✔ 3: Sends a PRIORITY frame with stream dependency
      ✔ 4: Sends a PRIORITY frame with exclusive
      ✔ 5: Sends a PRIORITY frame for an idle stream, then send a HEADER frame for a lower stream ID

    3.4. RST_STREAM
      ✔ 1: Sends a RST_STREAM frame

    3.5. SETTINGS
      ✔ 1: Sends a SETTINGS frame

    3.7. PING
      ✔ 1: Sends a PING frame

    3.8. GOAWAY
      ✔ 1: Sends a GOAWAY frame

    3.9. WINDOW_UPDATE
      ✔ 1: Sends a WINDOW_UPDATE frame with stream ID 0
      ✔ 2: Sends a WINDOW_UPDATE frame with stream ID 1

    3.10. CONTINUATION
      ✔ 1: Sends a CONTINUATION frame
      ✔ 2: Sends multiple CONTINUATION frames

  4. HTTP Message Exchanges
    ✔ 1: Sends a GET request
    ✔ 2: Sends a HEAD request
    ✔ 3: Sends a POST request
    ✔ 4: Sends a POST request with trailers

  5. HPACK
    ✔ 1: Sends a indexed header field representation
    ✔ 2: Sends a literal header field with incremental indexing - indexed name
    ✔ 3: Sends a literal header field with incremental indexing - indexed name (with Huffman coding)
    ✔ 4: Sends a literal header field with incremental indexing - new name
    ✔ 5: Sends a literal header field with incremental indexing - new name (with Huffman coding)
    ✔ 6: Sends a literal header field without indexing - indexed name
    ✔ 7: Sends a literal header field without indexing - indexed name (with Huffman coding)
    ✔ 8: Sends a literal header field without indexing - new name
    ✔ 9: Sends a literal header field without indexing - new name (huffman encoded)
    ✔ 10: Sends a literal header field never indexed - indexed name
    ✔ 11: Sends a literal header field never indexed - indexed name (huffman encoded)
    ✔ 12: Sends a literal header field never indexed - new name
    ✔ 13: Sends a literal header field never indexed - new name (huffman encoded)
    ✔ 14: Sends a dynamic table size update
    ✔ 15: Sends multiple dynamic table size update

Hypertext Transfer Protocol Version 2 (HTTP/2)
  3. Starting HTTP/2
    3.5. HTTP/2 Connection Preface
      ✔ 1: Sends client connection preface
      × 2: Sends invalid connection preface
        -> The endpoint MUST terminate the TCP connection.
           Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                     Connection closed
             Actual: Error: unexpected EOF

  4. HTTP Frames
    4.1. Frame Format
      ✔ 1: Sends a frame with unknown type
      ✔ 2: Sends a frame with undefined flag
      ✔ 3: Sends a frame with reserved field bit

    4.2. Frame Size
      ✔ 1: Sends a DATA frame with 2^14 octets in length
      ✔ 2: Sends a large size DATA frame that exceeds the SETTINGS_MAX_FRAME_SIZE
      ✔ 3: Sends a large size HEADERS frame that exceeds the SETTINGS_MAX_FRAME_SIZE

    4.3. Header Compression and Decompression
      ✔ 1: Sends invalid header block fragment
      ✔ 2: Sends a PRIORITY frame while sending the header blocks
      ✔ 3: Sends a HEADERS frame to another stream while sending the header blocks

  5. Streams and Multiplexing
    5.1. Stream States
      ✔ 1: idle: Sends a DATA frame
      ✔ 2: idle: Sends a RST_STREAM frame
      ✔ 3: idle: Sends a WINDOW_UPDATE frame
      ✔ 4: idle: Sends a CONTINUATION frame
      ✔ 5: half closed (remote): Sends a DATA frame
      ✔ 6: half closed (remote): Sends a HEADERS frame
      ✔ 7: half closed (remote): Sends a CONTINUATION frame
      ✔ 8: closed: Sends a DATA frame after sending RST_STREAM frame
      ✔ 9: closed: Sends a HEADERS frame after sending RST_STREAM frame
      ✔ 10: closed: Sends a CONTINUATION frame after sending RST_STREAM frame
      ✔ 11: closed: Sends a DATA frame
      ✔ 12: closed: Sends a HEADERS frame
      ✔ 13: closed: Sends a CONTINUATION frame

      5.1.1. Stream Identifiers
        ✔ 1: Sends even-numbered stream identifier
        ✔ 2: Sends stream identifier that is numerically smaller than previous

      5.1.2. Stream Concurrency
        1: Sends HEADERS frames that causes their advertised concurrent stream limit to be exceededed

    5.3. Stream Priority
      5.3.1. Stream Dependencies
        ✔ 1: Sends HEADERS frame that depends on itself
        ✔ 2: Sends PRIORITY frame that depend on itself

    5.4. Error Handling
      5.4.1. Connection Error Handling
        ✔ 1: Sends an invalid PING frame for connection close

    5.5. Extending HTTP/2
      ✔ 1: Sends an unknown extension frame
      ✔ 2: Sends an unknown extension frame in the middle of a header block

  6. Frame Definitions
    6.1. DATA
      ✔ 1: Sends a DATA frame with 0x0 stream identifier
      ✔ 2: Sends a DATA frame on the stream that is not in "open" or "half-closed (local)" state
      ✔ 3: Sends a DATA frame with invalid pad length

    6.2. HEADERS
      ✔ 1: Sends a HEADERS frame without the END_HEADERS flag, and a PRIORITY frame
      ✔ 2: Sends a HEADERS frame to another stream while sending a HEADERS frame
      ✔ 3: Sends a HEADERS frame with 0x0 stream identifier
      ✔ 4: Sends a HEADERS frame with invalid pad length

    6.3. PRIORITY
      ✔ 1: Sends a PRIORITY frame with 0x0 stream identifier
      ✔ 2: Sends a PRIORITY frame with a length other than 5 octets

    6.4. RST_STREAM
      ✔ 1: Sends a RST_STREAM frame with 0x0 stream identifier
      ✔ 2: Sends a RST_STREAM frame on a idle stream
      ✔ 3: Sends a RST_STREAM frame with a length other than 4 octets

    6.5. SETTINGS
      ✔ 1: Sends a SETTINGS frame with ACK flag and payload
      ✔ 2: Sends a SETTINGS frame with a stream identifier other than 0x0
      ✔ 3: Sends a SETTINGS frame with a length other than a multiple of 6 octets

      6.5.2. Defined SETTINGS Parameters
        ✔ 1: SETTINGS_ENABLE_PUSH (0x2): Sends the value other than 0 or 1
        ✔ 2: SETTINGS_INITIAL_WINDOW_SIZE (0x4): Sends the value above the maximum flow control window size
        ✔ 3: SETTINGS_MAX_FRAME_SIZE (0x5): Sends the value below the initial value
        ✔ 4: SETTINGS_MAX_FRAME_SIZE (0x5): Sends the value above the maximum allowed frame size
        ✔ 5: Sends a SETTINGS frame with unknown identifier

      6.5.3. Settings Synchronization
        × 1: Sends multiple values of SETTINGS_INITIAL_WINDOW_SIZE
        Error: Timeout
        ✔ 2: Sends a SETTINGS frame without ACK flag

    6.7. PING
      ✔ 1: Sends a PING frame
      ✔ 2: Sends a PING frame with ACK
      ✔ 3: Sends a PING frame with a stream identifier field value other than 0x0
      ✔ 4: Sends a PING frame with a length field value other than 8

    6.8. GOAWAY
      ✔ 1: Sends a GOAWAY frame with a stream identifier other than 0x0

    6.9. WINDOW_UPDATE
      ✔ 1: Sends a WINDOW_UPDATE frame with a flow control window increment of 0
      ✔ 2: Sends a WINDOW_UPDATE frame with a flow control window increment of 0 on a stream
      ✔ 3: Sends a WINDOW_UPDATE frame with a length other than 4 octets

      6.9.1. The Flow-Control Window
        × 1: Sends SETTINGS frame to set the initial window size to 1 and sends HEADERS frame
        Error: Timeout
        × 2: Sends multiple WINDOW_UPDATE frames increasing the flow control window to above 2^31-1
          -> The endpoint MUST sends a GOAWAY frame with a FLOW_CONTROL_ERROR code.
             Expected: GOAWAY Frame (Error Code: FLOW_CONTROL_ERROR)
               Actual: Connection closed
        × 3: Sends multiple WINDOW_UPDATE frames increasing the flow control window to above 2^31-1 on a stream
          -> The endpoint MUST sends a RST_STREAM frame with a FLOW_CONTROL_ERROR code.
             Expected: RST_STREAM Frame (Error Code: FLOW_CONTROL_ERROR)
               Actual: Connection closed

      6.9.2. Initial Flow-Control Window Size
        × 1: Changes SETTINGS_INITIAL_WINDOW_SIZE after sending HEADERS frame
        Error: Timeout
        × 2: Sends a SETTINGS frame for window size to be negative
        Error: Timeout
        ✔ 3: Sends a SETTINGS_INITIAL_WINDOW_SIZE settings with an exceeded maximum window size value

    6.10. CONTINUATION
      × 1: Sends multiple CONTINUATION frames preceded by a HEADERS frame
        -> The endpoint must accept the frame.
           Expected: HEADERS Frame (stream_id:1)
             Actual: GOAWAY Frame (length:8, flags:0x00, stream_id:0)
      ✔ 2: Sends a CONTINUATION frame followed by any frame other than CONTINUATION
      ✔ 3: Sends a CONTINUATION frame with 0x0 stream identifier
      ✔ 4: Sends a CONTINUATION frame preceded by a HEADERS frame with END_HEADERS flag
      ✔ 5: Sends a CONTINUATION frame preceded by a CONTINUATION frame with END_HEADERS flag
      ✔ 6: Sends a CONTINUATION frame preceded by a DATA frame

  7. Error Codes
    ✔ 1: Sends a GOAWAY frame with unknown error code
    ✔ 2: Sends a RST_STREAM frame with unknown error code

  8. HTTP Message Exchanges
    8.1. HTTP Request/Response Exchange
      ✔ 1: Sends a second HEADERS frame without the END_STREAM flag

      8.1.2. HTTP Header Fields
        × 1: Sends a HEADERS frame that contains the header field name in uppercase letters
          -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
             Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                       RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                       Connection closed
               Actual: DATA Frame (length:43, flags:0x01, stream_id:1)

        8.1.2.1. Pseudo-Header Fields
          × 1: Sends a HEADERS frame that contains a unknown pseudo-header field
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)
          × 2: Sends a HEADERS frame that contains the pseudo-header field defined for response
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)
          ✔ 3: Sends a HEADERS frame that contains a pseudo-header field as trailers
          ✔ 4: Sends a HEADERS frame that contains a pseudo-header field that appears in a header block after a regular header field

        8.1.2.2. Connection-Specific Header Fields
          × 1: Sends a HEADERS frame that contains the connection-specific header field
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)
          × 2: Sends a HEADERS frame that contains the TE header field with any value other than "trailers"
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)

        8.1.2.3. Request Pseudo-Header Fields
          × 1: Sends a HEADERS frame with empty ":path" pseudo-header field
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: Timeout
          ✔ 2: Sends a HEADERS frame that omits ":method" pseudo-header field
          ✔ 3: Sends a HEADERS frame that omits ":scheme" pseudo-header field
          ✔ 4: Sends a HEADERS frame that omits ":path" pseudo-header field
          ✔ 5: Sends a HEADERS frame with duplicated ":method" pseudo-header field
          ✔ 6: Sends a HEADERS frame with duplicated ":scheme" pseudo-header field
          ✔ 7: Sends a HEADERS frame with duplicated ":path" pseudo-header field

        8.1.2.6. Malformed Requests and Responses
          ✔ 1: Sends a HEADERS frame with the "content-length" header field which does not equal the DATA frame payload length
          ✔ 2: Sends a HEADERS frame with the "content-length" header field which does not equal the sum of the multiple DATA frames payload length

    8.2. Server Push
      ✔ 1: Sends a PUSH_PROMISE frame

HPACK: Header Compression for HTTP/2
  2. Compression Process Overview
    2.3. Indexing Tables
      2.3.3. Index Address Space
        ✔ 1: Sends a indexed header field representation with invalid index
        ✔ 2: Sends a literal header field representation with invalid index

  4. Dynamic Table Management
    4.2. Maximum Table Size
      ✔ 1: Sends a dynamic table size update at the end of header block

  5. Primitive Type Representations
    5.2. String Literal Representation
      ✔ 1: Sends a Huffman-encoded string literal representation with padding longer than 7 bits
      ✔ 2: Sends a Huffman-encoded string literal representation padded by zero
      ✔ 3: Sends a Huffman-encoded string literal representation containing the EOS symbol

  6. Binary Format
    6.1. Indexed Header Field Representation
      ✔ 1: Sends a indexed header field representation with index 0

    6.3. Dynamic Table Size Update
      × 1: Sends a dynamic table size update larger than the value of SETTINGS_HEADER_TABLE_SIZE
        -> The endpoint MUST treat this as a decoding error.
           Expected: GOAWAY Frame (Error Code: COMPRESSION_ERROR)
                     Connection closed
             Actual: DATA Frame (length:43, flags:0x01, stream_id:1)

Failures: 

Hypertext Transfer Protocol Version 2 (HTTP/2)
  3. Starting HTTP/2
    3.5. HTTP/2 Connection Preface
      × 2: Sends invalid connection preface
        -> The endpoint MUST terminate the TCP connection.
           Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                     Connection closed
             Actual: Error: unexpected EOF

  6. Frame Definitions
    6.5. SETTINGS
      6.5.3. Settings Synchronization
        × 1: Sends multiple values of SETTINGS_INITIAL_WINDOW_SIZE
        Error: Timeout

    6.9. WINDOW_UPDATE
      6.9.1. The Flow-Control Window
        × 1: Sends SETTINGS frame to set the initial window size to 1 and sends HEADERS frame
        Error: Timeout
        × 2: Sends multiple WINDOW_UPDATE frames increasing the flow control window to above 2^31-1
          -> The endpoint MUST sends a GOAWAY frame with a FLOW_CONTROL_ERROR code.
             Expected: GOAWAY Frame (Error Code: FLOW_CONTROL_ERROR)
               Actual: Connection closed
        × 3: Sends multiple WINDOW_UPDATE frames increasing the flow control window to above 2^31-1 on a stream
          -> The endpoint MUST sends a RST_STREAM frame with a FLOW_CONTROL_ERROR code.
             Expected: RST_STREAM Frame (Error Code: FLOW_CONTROL_ERROR)
               Actual: Connection closed

      6.9.2. Initial Flow-Control Window Size
        × 1: Changes SETTINGS_INITIAL_WINDOW_SIZE after sending HEADERS frame
        Error: Timeout
        × 2: Sends a SETTINGS frame for window size to be negative
        Error: Timeout

    6.10. CONTINUATION
      × 1: Sends multiple CONTINUATION frames preceded by a HEADERS frame
        -> The endpoint must accept the frame.
           Expected: HEADERS Frame (stream_id:1)
             Actual: GOAWAY Frame (length:8, flags:0x00, stream_id:0)

  8. HTTP Message Exchanges
    8.1. HTTP Request/Response Exchange
      8.1.2. HTTP Header Fields
        × 1: Sends a HEADERS frame that contains the header field name in uppercase letters
          -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
             Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                       RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                       Connection closed
               Actual: DATA Frame (length:43, flags:0x01, stream_id:1)

        8.1.2.1. Pseudo-Header Fields
          × 1: Sends a HEADERS frame that contains a unknown pseudo-header field
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)
          × 2: Sends a HEADERS frame that contains the pseudo-header field defined for response
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)

        8.1.2.2. Connection-Specific Header Fields
          × 1: Sends a HEADERS frame that contains the connection-specific header field
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)
          × 2: Sends a HEADERS frame that contains the TE header field with any value other than "trailers"
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: DATA Frame (length:43, flags:0x01, stream_id:1)

        8.1.2.3. Request Pseudo-Header Fields
          × 1: Sends a HEADERS frame with empty ":path" pseudo-header field
            -> The endpoint MUST respond with a stream error of type PROTOCOL_ERROR.
               Expected: GOAWAY Frame (Error Code: PROTOCOL_ERROR)
                         RST_STREAM Frame (Error Code: PROTOCOL_ERROR)
                         Connection closed
                 Actual: Timeout

HPACK: Header Compression for HTTP/2
  6. Binary Format
    6.3. Dynamic Table Size Update
      × 1: Sends a dynamic table size update larger than the value of SETTINGS_HEADER_TABLE_SIZE
        -> The endpoint MUST treat this as a decoding error.
           Expected: GOAWAY Frame (Error Code: COMPRESSION_ERROR)
                     Connection closed
             Actual: DATA Frame (length:43, flags:0x01, stream_id:1)

Finished in 27.5056 seconds
146 tests, 130 passed, 1 skipped, 15 failed

Benedikt-Alexander Mokroß and others added 30 commits August 6, 2021 19:34
- Refactored `hpack::Hpack` to an interchangeable interface class
- Refactored `hpack::Table` to an interchangeable interface class
- Implemented interfaces as `hpack::SimpleTable` and `hpack::SimpleHpack`
- `hpack::SimpleHpack` Accepts an shared pointer to an hpack::Table implementation instead of creating its own
- Rudimentarily implemented hpack inflating in `hpack::SimpleHpack`
Implemented rudimentary `h2c` handshake even if its not implemented by any mayor browser.
Still a memory management bug somewhere because `auto inflatedmap = inflated.getAll();` for the stream results in an segfault.
…ode size.

However, its roughly 5x slower. Added a note for reference.
Removed async support for now, but should be implemented further down the road! Async+Http2 would be a perfect harmony.
…tion, priority and resetStream handlers in Http2StreamHandler.
…o RFC7540:

Mainly added Flow-Control and refactored Http2Processor to be easier to read and to follow RFC7540 which frames should be applied to a connection and which are applied to streams
…code-pieces to run first h2spec checks.

Warning: May contain ugly hacks that have to be cleaned before release!
Still some places that are simple-api but we are getting there.
…eam::InputStream` instead of `data::stream::IOStream`.

Output capabilities are not needed.
…ttpVersionSwitch`)

Handling switching to HTTP2 with an upgrade-handler interceptor was not feasible anymore.
Since we moved to async and an executor handles the rest, `HandleConnection` returns immediately.
Thus, the HTTP connection handler always answered with some generic response to the peer and broke the HTTP2 stream.
Now we have a designated `ConnectionHandler` for this which allows for more control.

The `Http2ConnectionHandler` is implemented in a way which allows it to be chained behind the `HttpVersionSwitch` or directly be called from an `ConnectionProvider`. It carries its own PRI-Message evaluation in an async context.
…sionHandler`.

Also fixed ping-data reading to correctly work in async.
…ctored error-handling and started fixing coroutine-flow.
…is observeable at http2/6.5.3

Somehow, no data is received anymore. Even in the HttpVersionSwitch. Without this fixed, there is no chance of proceeding.
# Conflicts:
#	src/oatpp/parser/json/mapping/Serializer.cpp
#	src/oatpp/web/protocol/http/incoming/Request.cpp
#	src/oatpp/web/protocol/http/incoming/Response.cpp
#	src/oatpp/web/protocol/http/outgoing/Request.cpp
#	src/oatpp/web/protocol/http/outgoing/Response.cpp
@bamkrs bamkrs added Won't Fix This will not be worked on Proposal labels Oct 24, 2023
@lganzzzo
Copy link
Member

lganzzzo commented Oct 24, 2023

Hey Benedikt @bamkrs ,

Thank you so much for posting this! ❤️

I hope I'll be able to handle it from here.

@bamkrs
Copy link
Member Author

bamkrs commented Nov 2, 2023

@lganzzzo I always hoped to find some time to pick up my work on this PR again since its so close to being finished and it would be a major benefit for OAT++. Well, we talked about pros and cons of HTTP2 in a REST backend, but since its such an heavily requested feature...
You can always contact me via IG and maybe have a quick call or something if you start working on it and need some help.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Proposal Won't Fix This will not be worked on
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants