]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2253 in SNORT/snort3 from ~KATHARVE/snort3:h2i_infraction_fix...
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 12 Jun 2020 17:16:16 +0000 (17:16 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Fri, 12 Jun 2020 17:16:16 +0000 (17:16 +0000)
Squashed commit of the following:

commit 5a681a75529c10aef7f6efd802f91e7673ec4ff5
Author: Katura Harvey <katharve@cisco.com>
Date:   Tue Jun 9 12:32:36 2020 -0400

    http2_inspect: fix hpack infractions

19 files changed:
src/service_inspectors/http2_inspect/http2_data_frame.cc
src/service_inspectors/http2_inspect/http2_data_frame.h
src/service_inspectors/http2_inspect/http2_flow_data.cc
src/service_inspectors/http2_inspect/http2_flow_data.h
src/service_inspectors/http2_inspect/http2_headers_frame.cc
src/service_inspectors/http2_inspect/http2_hpack.cc
src/service_inspectors/http2_inspect/http2_hpack.h
src/service_inspectors/http2_inspect/http2_hpack_int_decode.cc
src/service_inspectors/http2_inspect/http2_hpack_int_decode.h
src/service_inspectors/http2_inspect/http2_hpack_string_decode.cc
src/service_inspectors/http2_inspect/http2_hpack_string_decode.h
src/service_inspectors/http2_inspect/http2_inspect.cc
src/service_inspectors/http2_inspect/http2_request_line.cc
src/service_inspectors/http2_inspect/http2_request_line.h
src/service_inspectors/http2_inspect/http2_settings_frame.cc
src/service_inspectors/http2_inspect/http2_start_line.cc
src/service_inspectors/http2_inspect/http2_start_line.h
src/service_inspectors/http2_inspect/http2_status_line.cc
src/service_inspectors/http2_inspect/http2_status_line.h

index 06dd661caa5d49f62e2df8e7a7c197d3b4f79c5f..c4ae5d36bea2fec36dbbd3dbaf27bd28e84acf39 100644 (file)
@@ -99,3 +99,11 @@ void Http2DataFrame::update_stream_state()
             assert(false);
     }
 }
+
+#ifdef REG_TEST
+void Http2DataFrame::print_frame(FILE* output)
+{
+    fprintf(output, "Data frame\n");
+    Http2Frame::print_frame(output);
+}
+#endif
index 5ee0d9997f4337a9c1549053b1fd3e1134d5c5ee..b16db7c752cf6db638325386607faaf8dd842d81 100644 (file)
@@ -38,6 +38,10 @@ public:
     friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const int32_t, const uint8_t*,
         const int32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
 
+#ifdef REG_TEST
+    void print_frame(FILE* output) override;
+#endif
+
 private:
     Http2DataFrame(const uint8_t* header_buffer, const int32_t header_len,
         const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* ssn_data,
index 0a559b58a603af2db2b47b76482509006c85c4b0..89d8d055127530d86e301c6654c1dee684fed60b 100644 (file)
@@ -46,7 +46,10 @@ Http2FlowData::Http2FlowData(Flow* flow_) :
     FlowData(inspector_id),
     flow(flow_),
     hi((HttpInspect*)(flow->assistant_gadget)),
-    hpack_decoder{Http2HpackDecoder(this, SRC_CLIENT), Http2HpackDecoder(this, SRC_SERVER)}
+    hpack_decoder { Http2HpackDecoder(this, SRC_CLIENT, events[SRC_CLIENT],
+                        infractions[SRC_CLIENT]),
+                    Http2HpackDecoder(this, SRC_SERVER, events[SRC_SERVER],
+                        infractions[SRC_SERVER]) }
 {
     if (hi != nullptr)
     {
index 974f2d050c15a573ecc2159a67fbe1b23626ffea..53608c22979d4e7ee3fbfb72c1c2e1481fc6dd85 100644 (file)
@@ -103,6 +103,11 @@ protected:
 
     // 0 element refers to client frame, 1 element refers to server frame
 
+    // There is currently one infraction and one event object per flow per direction. This may
+    // change in the future.
+    Http2Infractions* const infractions[2] = { new Http2Infractions, new Http2Infractions };
+    Http2EventGen* const events[2] = { new Http2EventGen, new Http2EventGen };
+
     // Stream ID of the frame currently being read in and processed
     uint32_t current_stream[2] = { Http2Enums::NO_STREAM_ID, Http2Enums::NO_STREAM_ID };
     // At any given time there may be different streams going in each direction. But only one of
@@ -151,11 +156,6 @@ protected:
     uint8_t padding_octets_in_frame[2] = { 0, 0 };
     bool get_padding_len[2] = { false, false };
 
-    // These will eventually be moved over to the frame/stream object, as they are moved to the
-    // transaction in NHI. Also as in NHI accessor methods will need to be added.
-    Http2Infractions* infractions[2] = { new Http2Infractions, new Http2Infractions };
-    Http2EventGen* events[2] = { new Http2EventGen, new Http2EventGen };
-
 #ifdef REG_TEST
     static uint64_t instance_count;
     uint64_t seq_num;
index 07098c6055cbb523c81b60e505c10a385b0ae549..a3b60dc055125fa34ad91ebfecf17e25a7264287 100644 (file)
@@ -74,8 +74,7 @@ Http2HeadersFrame::Http2HeadersFrame(const uint8_t* header_buffer, const int32_t
 
     // Decode headers
     if (!hpack_decoder.decode_headers((data.start() + hpack_headers_offset), data.length() -
-        hpack_headers_offset, decoded_headers, start_line_generator,
-        session_data->events[source_id], session_data->infractions[source_id]))
+        hpack_headers_offset, decoded_headers, start_line_generator))
     {
         session_data->frame_type[source_id] = FT__ABORT;
         error_during_decode = true;
@@ -247,7 +246,7 @@ void Http2HeadersFrame::update_stream_state()
 void Http2HeadersFrame::print_frame(FILE* output)
 {
     if (!trailer)
-        fprintf(output, "\nHeaders frame\n");
+        fprintf(output, "Headers frame\n");
     else
         fprintf(output, "Trailing Headers frame\n");
     if (error_during_decode)
index 5afa143c00cdb1ae282834df5bea4395ee5ad657..c58c134827e596b244220e2f43a72d704d436527 100644 (file)
@@ -94,7 +94,7 @@ bool Http2HpackDecoder::decode_indexed_name(const uint8_t* encoded_header_buffer
 
     if (!entry)
     {
-        infractions += INF_HPACK_INDEX_OUT_OF_BOUNDS;
+        *infractions += INF_HPACK_INDEX_OUT_OF_BOUNDS;
         events->create_event(EVENT_MISFORMATTED_HTTP2);
         return false;
     }
@@ -199,7 +199,7 @@ bool Http2HpackDecoder::decode_literal_header_line(const uint8_t* encoded_header
         // table exceeds the Snort hard-coded limit of 512
         if (!decode_table.add_index(name, value))
         {
-            infractions += INF_DYNAMIC_TABLE_OVERFLOW;
+            *infractions += INF_DYNAMIC_TABLE_OVERFLOW;
             events->create_event(EVENT_DYNAMIC_TABLE_OVERFLOW);
             return false;
         }
@@ -226,14 +226,14 @@ bool Http2HpackDecoder::decode_indexed_header(const uint8_t* encoded_header_buff
 
     if (!entry)
     {
-        infractions += INF_HPACK_INDEX_OUT_OF_BOUNDS;
+        *infractions += INF_HPACK_INDEX_OUT_OF_BOUNDS;
         events->create_event(EVENT_MISFORMATTED_HTTP2);
         return false;
     }
 
     if (entry->value.length() <= 0)
     {
-        infractions += INF_LOOKUP_EMPTY_VALUE;
+        *infractions += INF_LOOKUP_EMPTY_VALUE;
         events->create_event(EVENT_MISFORMATTED_HTTP2);
     }
 
@@ -353,8 +353,7 @@ bool Http2HpackDecoder::decode_header_line(const uint8_t* encoded_header_buffer,
 // get_start_line() and get_decoded_headers() to generate and obtain these fields.
 bool Http2HpackDecoder::decode_headers(const uint8_t* encoded_headers,
     const uint32_t encoded_headers_length, uint8_t* decoded_headers,
-    Http2StartLine *start_line_generator, Http2EventGen* stream_events,
-    Http2Infractions* stream_infractions)
+    Http2StartLine *start_line_generator)
 {
     uint32_t total_bytes_consumed = 0;
     uint32_t line_bytes_consumed = 0;
@@ -362,8 +361,6 @@ bool Http2HpackDecoder::decode_headers(const uint8_t* encoded_headers,
     bool success = true;
     start_line = start_line_generator;
     decoded_headers_size = 0;
-    events = stream_events;
-    infractions = stream_infractions;
     pseudo_headers_fragment_size = 0;
     decode_error = false;
 
index 54a56a6f43d999d2ec05eef558be4d61ab6bdd39..ce554d981b3606331d0891f0f42be9564506ecb4 100644 (file)
@@ -35,11 +35,11 @@ class Http2StartLine;
 class Http2HpackDecoder
 {
 public:
-    Http2HpackDecoder(Http2FlowData* flow_data, HttpCommon::SourceId src_id) :
-        decode_table(flow_data, src_id) { }
+    Http2HpackDecoder(Http2FlowData* flow_data, HttpCommon::SourceId src_id,
+        Http2EventGen* const _events, Http2Infractions* const _infractions) :
+        events(_events), infractions(_infractions), decode_table(flow_data, src_id) { }
     bool decode_headers(const uint8_t* encoded_headers, const uint32_t encoded_headers_length,
-        uint8_t* decoded_headers, Http2StartLine* start_line,
-        Http2EventGen* stream_events, Http2Infractions* stream_infractions);
+        uint8_t* decoded_headers, Http2StartLine* start_line);
     bool write_decoded_headers(const uint8_t* in_buffer, const uint32_t in_length,
         uint8_t* decoded_header_buffer, uint32_t decoded_header_length, uint32_t& bytes_written);
     bool decode_header_line(const uint8_t* encoded_header_buffer,
@@ -76,8 +76,8 @@ private:
     uint32_t decoded_headers_size;
     uint32_t pseudo_headers_fragment_size;
     bool decode_error;
-    Http2EventGen* events;
-    Http2Infractions* infractions;
+    Http2EventGen* const events;
+    Http2Infractions* const infractions;
 
     static Http2HpackIntDecode decode_int7;
     static Http2HpackIntDecode decode_int6;
index c595d2992fbb39278b43fd75b02c6d7317daccf7..289698cc01f6583db30179f7dc34c33bdd9f9cae 100644 (file)
@@ -36,8 +36,8 @@ Http2HpackIntDecode::Http2HpackIntDecode(uint8_t prefix) : prefix_mask(((uint16_
 }
 
 bool Http2HpackIntDecode::translate(const uint8_t* in_buff, const uint32_t in_len,
-    uint32_t& bytes_consumed, uint64_t& result, Http2EventGen* events,
-    Http2Infractions* infractions) const
+    uint32_t& bytes_consumed, uint64_t& result, Http2EventGen* const events,
+    Http2Infractions* const infractions) const
 {
     bytes_consumed = 0;
     result = 0;
index 372ac591d26c1e04ba1c72e01b8b764b885b7502..f4ae9732aa2563bf6079ecb6fe3e3699ba056f07 100644 (file)
@@ -35,7 +35,7 @@ class Http2HpackIntDecode
 public:
     Http2HpackIntDecode(uint8_t prefix);
     bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed,
-        uint64_t& result, Http2EventGen* events, Http2Infractions* infractions) const;
+        uint64_t& result, Http2EventGen* const events, Http2Infractions* const infractions) const;
 
 private:
     const uint8_t prefix_mask;
index d8e03da998c3ae1123752b148fa5ccbc05068ba2..7dabf14282d31303231beb580442a44c1cc55851 100644 (file)
@@ -38,7 +38,7 @@ static const uint8_t min_decode_len[HUFFMAN_LOOKUP_MAX + 1] =
 
 bool Http2HpackStringDecode::translate(const uint8_t* in_buff, const uint32_t in_len,
     uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
-    Http2EventGen* events, Http2Infractions* infractions) const
+    Http2EventGen* const events, Http2Infractions* const infractions) const
 {
     bytes_consumed = 0;
     bytes_written = 0;
@@ -77,7 +77,7 @@ bool Http2HpackStringDecode::translate(const uint8_t* in_buff, const uint32_t in
 
 bool Http2HpackStringDecode::get_string(const uint8_t* in_buff, const uint32_t encoded_len,
     uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
-    Http2EventGen* events, Http2Infractions* infractions) const
+    Http2EventGen* const events, Http2Infractions* const infractions) const
 {
     if (encoded_len > out_len)
     {
@@ -141,7 +141,7 @@ bool Http2HpackStringDecode::get_next_byte(const uint8_t* in_buff, const uint32_
 
 bool Http2HpackStringDecode::get_huffman_string(const uint8_t* in_buff, const uint32_t encoded_len,
     uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
-    Http2EventGen* events, Http2Infractions* infractions) const
+    Http2EventGen* const events, Http2Infractions* const infractions) const
 {
     const uint32_t last_encoded_byte = bytes_consumed + encoded_len;
     uint8_t byte;
index 8bc29727d3966a74fd8b8cd1b3b6a7f8ebaaebd5..7869ec377175bcc8685ff06efab90d8296b62cd4 100644 (file)
@@ -33,15 +33,15 @@ public:
     Http2HpackStringDecode() : decode7(7) { }
     bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed,
         uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
-        Http2EventGen* events, Http2Infractions* infractions) const;
+        Http2EventGen* const events, Http2Infractions* const infractions) const;
 
 private:
     bool get_string(const uint8_t* in_buff, const uint32_t encoded_len, uint32_t& bytes_consumed,
-        uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, Http2EventGen* events,
-        Http2Infractions* infractions) const;
+        uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, Http2EventGen* const
+        events, Http2Infractions* const infractions) const;
     bool get_huffman_string(const uint8_t* in_buff, const uint32_t encoded_len,
         uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t&
-        bytes_written, Http2EventGen* events, Http2Infractions* infractions) const;
+        bytes_written, Http2EventGen* const events, Http2Infractions* const infractions) const;
     bool get_next_byte(const uint8_t* in_buff, const uint32_t last_byte,
         uint32_t& bytes_consumed, uint8_t& cur_bit, uint8_t match_len, uint8_t& byte,
         bool& another_search) const;
index 607910d65df0a3e8d44ac3cbaed2bc636adebc0b..cfc889052ba4fec95de089e16210a9c393e38254 100644 (file)
@@ -38,6 +38,8 @@ using namespace snort;
 using namespace HttpCommon;
 using namespace Http2Enums;
 
+static void print_flow_issues(FILE*, Http2Infractions* const, Http2EventGen* const);
+
 Http2Inspect::Http2Inspect(const Http2ParaList* params_) : params(params_)
 {
 #ifdef REG_TEST
@@ -154,6 +156,8 @@ void Http2Inspect::eval(Packet* p)
             printf("Finished processing section from test %" PRIi64 "\n",
                 HttpTestManager::get_test_number());
         }
+        print_flow_issues(HttpTestManager::get_output_file(), session_data->infractions[source_id],
+            session_data->events[source_id]);
     }
 #endif
 }
@@ -173,3 +177,9 @@ void Http2Inspect::clear(Packet* p)
     stream->clear_frame();
 }
 
+static void print_flow_issues(FILE* output, Http2Infractions* const infractions,
+    Http2EventGen* const events)
+{
+    fprintf(output, "Infractions: %016" PRIx64 ", Events: %016" PRIx64 "\n\n",
+        infractions->get_raw(), events->get_raw());
+}
index 18edd85dd0b84a9790207b55c1a1f1b11fc5a4c6..ebfd226308fd715ff04ccb3d114d2670b2419fa2 100644 (file)
@@ -60,7 +60,7 @@ void Http2RequestLine::process_pseudo_header_name(const uint8_t* const& name, ui
         value_coming = SCHEME;
     else
     {
-        infractions += INF_INVALID_PSEUDO_HEADER;
+        *infractions += INF_INVALID_PSEUDO_HEADER;
         events->create_event(EVENT_INVALID_HEADER);
         value_coming = HEADER__INVALID;
     }
@@ -100,7 +100,7 @@ bool Http2RequestLine::generate_start_line()
     {
         if (method.length() <= 0)
         {
-            infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+            *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
             events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
             return false;
         }
@@ -127,14 +127,14 @@ bool Http2RequestLine::generate_start_line()
         // FIXIT-L May want to be more lenient than RFC on generating start line
         if (authority.length() <= 0)
         {
-            infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+            *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
             events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
             return false;
         }
         // Should not have a scheme or path
         if ( scheme.length() > 0 or path.length() > 0)
         {
-            infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+            *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
             events->create_event(EVENT_INVALID_HEADER);
         }
         start_line_length = method.length() + authority.length() + http_version_length +
@@ -202,7 +202,7 @@ bool Http2RequestLine::generate_start_line()
     else
     {
         // FIXIT-L May want to be more lenient than RFC on generating start line
-        infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+        *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
         events->create_event(EVENT_MISFORMATTED_HTTP2);
         return false;
     }
index f83f08898c5a1bca78552ed1cf1e0a2f84409580..db76a765b5d000e4fc3ddc2a954d62310b9d3b68 100644 (file)
@@ -34,10 +34,11 @@ public:
     bool generate_start_line() override;
 
     friend Http2StartLine* Http2StartLine::new_start_line_generator(HttpCommon::SourceId source_id,
-        Http2EventGen* events, Http2Infractions* infractions);
+        Http2EventGen* const events, Http2Infractions* const infractions);
 
 private:
-    Http2RequestLine(Http2EventGen* evs, Http2Infractions* infrs) : Http2StartLine(evs, infrs) { }
+    Http2RequestLine(Http2EventGen* const evs, Http2Infractions* const infrs) :
+        Http2StartLine(evs, infrs) { }
 
     Field method;
     Field path;
index 943350c2d7a05b10f801f4814ef79dae15298939..bee617999cf076d9edf5471c1bc7ada5a1608491 100644 (file)
@@ -119,7 +119,7 @@ void Http2SettingsFrame::handle_update(uint16_t id, uint32_t value)
 #ifdef REG_TEST
 void Http2SettingsFrame::print_frame(FILE* output)
 {
-    fprintf(output, "Settings frame:");
+    fprintf(output, "\nSettings frame:");
 
     if (bad_frame)
         fprintf(output, " Error in settings frame.");
@@ -130,7 +130,6 @@ void Http2SettingsFrame::print_frame(FILE* output)
 
     fprintf(output, "\n");
     Http2Frame::print_frame(output);
-    fprintf(output, "\n");
 }
 #endif
 
index 7b9dc9be83616d972255ce2eb63ac858535e9e42..aeb99056d23dc98266ff130dead5f5e1e7881419 100644 (file)
@@ -42,7 +42,7 @@ Http2StartLine::~Http2StartLine()
 }
 
 Http2StartLine* Http2StartLine::new_start_line_generator(SourceId source_id,
-        Http2EventGen* events, Http2Infractions* infractions)
+    Http2EventGen* const events, Http2Infractions* const infractions)
 {
     if (source_id == SRC_CLIENT)
         return new Http2RequestLine(events, infractions);
@@ -54,7 +54,7 @@ void Http2StartLine::process_pseudo_header_precheck()
 {
     if (finalized)
     {
-        infractions += INF_PSEUDO_HEADER_AFTER_REGULAR_HEADER;
+        *infractions += INF_PSEUDO_HEADER_AFTER_REGULAR_HEADER;
         events->create_event(EVENT_INVALID_HEADER);
     }
 }
index ea68fc2a4d94339f76018ac89c6034f424ce9e7a..0ffeceb0b2712b7049369e98a67f96f3435aeb93 100644 (file)
@@ -37,7 +37,7 @@ class Http2StartLine
 {
 public:
     static Http2StartLine* new_start_line_generator(HttpCommon::SourceId source_id,
-        Http2EventGen* events, Http2Infractions* infractions);
+        Http2EventGen* const events, Http2Infractions* const infractions);
 
     virtual ~Http2StartLine();
 
@@ -45,21 +45,22 @@ public:
 
     const Field* get_start_line();
     virtual void process_pseudo_header_name(const uint8_t* const& name, uint32_t length) = 0;
-    virtual void process_pseudo_header_value(const uint8_t* const& value, const uint32_t length) = 0;
+    virtual void process_pseudo_header_value(const uint8_t* const& value, const uint32_t length) =
+        0;
     bool finalize();
     bool is_finalized() { return finalized; }
     bool is_pseudo_value() { return value_coming != Http2Enums::HEADER__NONE; }
     bool is_pseudo_name(const uint8_t* const& name) { return name[0] == ':'; }
 
 protected:
-    Http2StartLine(Http2EventGen* events, Http2Infractions* infractions)   : events(events),
-        infractions(infractions) { }
+    Http2StartLine(Http2EventGen* const events, Http2Infractions* const infractions) :
+        events(events), infractions(infractions) { }
 
     void process_pseudo_header_precheck();
     virtual bool generate_start_line() = 0;
 
-    Http2EventGen* events;
-    Http2Infractions* infractions;
+    Http2EventGen* const events;
+    Http2Infractions* const infractions;
     bool finalized = false;
     uint32_t start_line_length = 0;
     uint8_t *start_line_buffer = nullptr;
index 12f6f46304da211bde3bd91185168362f1e6b2fb..6b5998431c613e22ed6b1f29bf6c360d7d423f26 100644 (file)
@@ -45,7 +45,7 @@ void Http2StatusLine::process_pseudo_header_name(const uint8_t* const& name, uin
         value_coming = STATUS;
     else
     {
-        infractions += INF_INVALID_PSEUDO_HEADER;
+        *infractions += INF_INVALID_PSEUDO_HEADER;
         events->create_event(EVENT_INVALID_HEADER);
         value_coming = HEADER__INVALID;
     }
@@ -70,7 +70,7 @@ bool Http2StatusLine::generate_start_line()
 
     if (status.length() <= 0)
     {
-        infractions += INF_RESPONSE_WITHOUT_STATUS;
+        *infractions += INF_RESPONSE_WITHOUT_STATUS;
         events->create_event(EVENT_RESPONSE_WITHOUT_STATUS);
         return false;
     }
index df1def7bb8492513677da73f8270a0853e98bf1f..2ef5dad966d5c8d080fe597fe6baf679db79e335 100644 (file)
@@ -33,10 +33,11 @@ public:
     bool generate_start_line() override;
 
     friend Http2StartLine* Http2StartLine::new_start_line_generator(HttpCommon::SourceId source_id,
-        Http2EventGen* events, Http2Infractions* infractions);
+        Http2EventGen* const events, Http2Infractions* const infractions);
 
 private:
-    Http2StatusLine(Http2EventGen* evs, Http2Infractions* infrs) : Http2StartLine(evs, infrs) { }
+    Http2StatusLine(Http2EventGen* const evs, Http2Infractions* const infrs) :
+        Http2StartLine(evs, infrs) { }
 
     Field status;