]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #1849 in SNORT/snort3 from ~KATHARVE/snort3:h2i_refactor to master
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Wed, 20 Nov 2019 13:46:44 +0000 (13:46 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Wed, 20 Nov 2019 13:46:44 +0000 (13:46 +0000)
Squashed commit of the following:

commit df563843b3c042052d395ee46e72536545875718
Author: Katura Harvey <katharve@cisco.com>
Date:   Mon Nov 18 10:40:09 2019 -0500

    http2_inspect: add frame class and refactor stream splitter

21 files changed:
src/service_inspectors/http2_inspect/CMakeLists.txt
src/service_inspectors/http2_inspect/http2_flow_data.cc
src/service_inspectors/http2_inspect/http2_flow_data.h
src/service_inspectors/http2_inspect/http2_frame.cc [new file with mode: 0644]
src/service_inspectors/http2_inspect/http2_frame.h [new file with mode: 0644]
src/service_inspectors/http2_inspect/http2_headers_frame.cc [new file with mode: 0644]
src/service_inspectors/http2_inspect/http2_headers_frame.h [new file with mode: 0644]
src/service_inspectors/http2_inspect/http2_hpack.cc
src/service_inspectors/http2_inspect/http2_hpack.h
src/service_inspectors/http2_inspect/http2_inspect.cc
src/service_inspectors/http2_inspect/http2_inspect.h
src/service_inspectors/http2_inspect/http2_inspect_impl.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_start_line.cc
src/service_inspectors/http2_inspect/http2_start_line.h
src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc
src/service_inspectors/http2_inspect/test/CMakeLists.txt
src/service_inspectors/http2_inspect/test/http2_flow_data_test.h
src/service_inspectors/http2_inspect/test/http2_inspect_impl_test.cc [deleted file]
src/service_inspectors/http2_inspect/test/http2_stream_splitter_impl_test.cc

index f115997edf198f27c18b25fa438a35c3d20e1d14..53ff980a883a50480278d202e4e032a07ed8b308 100644 (file)
@@ -5,6 +5,10 @@ set (FILE_LIST
     http2_enum.h
     http2_flow_data.cc
     http2_flow_data.h
+    http2_frame.cc
+    http2_frame.h
+    http2_headers_frame.cc
+    http2_headers_frame.h
     http2_hpack.cc
     http2_hpack.h
     http2_hpack_int_decode.cc
index a7a61108851bace869b42687a613b5c4518efeb7..66be2c2d93eee6d44c3ce1655160afb90e55a123 100644 (file)
@@ -26,6 +26,7 @@
 #include "service_inspectors/http_inspect/http_test_manager.h"
 
 #include "http2_enum.h"
+#include "http2_frame.h"
 #include "http2_module.h"
 #include "http2_start_line.h"
 
@@ -71,33 +72,19 @@ Http2FlowData::~Http2FlowData()
 
     for (int k=0; k <= 1; k++)
     {
-        delete[] frame_header[k];
-        delete[] frame_data[k];
-        delete[] raw_decoded_header[k];
         delete infractions[k];
         delete events[k];
-        delete http2_decoded_header[k];
+        delete current_frame[k];
     }
 }
 
 void Http2FlowData::clear_frame_data(HttpCommon::SourceId source_id)
 {
-    // If there is more data to be inspected in the frame, leave the frame_header
-    if (leftover_data[source_id] == 0)
-    {
-        delete[] frame_header[source_id];
-        frame_header[source_id] = nullptr;
-    }
-    delete[] frame_data[source_id];
-    frame_data[source_id] = nullptr;
     frame_in_detection = false;
-    delete[] raw_decoded_header[source_id];
-    raw_decoded_header[source_id] = nullptr;
     continuation_expected[source_id] = false;
-    frames_aggregated[source_id] = 0;
-    scan_header_octets_seen[source_id] = 0;
-    delete header_start_line[source_id];
-    header_start_line[source_id] = nullptr;
-    delete http2_decoded_header[source_id];
-    http2_decoded_header[source_id] = nullptr;
+    num_frame_headers[source_id] = 0;
+    scan_octets_seen[source_id] = 0;
+    total_bytes_in_split[source_id] = 0;
+    delete current_frame[source_id];
+    current_frame[source_id] = nullptr;
 }
index 9cfa258a81d2dbc841bbb5b4f5418e98b73467d1..6d324c47148d218791ee300b6cd55053cbc32fff 100644 (file)
@@ -53,53 +53,56 @@ public:
     friend class Http2Hpack;
     friend class Http2StartLine;
     friend class Http2RequestLine;
+    friend class Http2Frame;
+    friend class Http2HeadersFrame;
     friend const snort::StreamBuffer implement_reassemble(Http2FlowData*, unsigned, unsigned,
         const uint8_t*, unsigned, uint32_t, HttpCommon::SourceId);
     friend snort::StreamSplitter::Status implement_scan(Http2FlowData*, const uint8_t*, uint32_t,
         uint32_t*, HttpCommon::SourceId);
     friend bool implement_get_buf(unsigned id, Http2FlowData*, HttpCommon::SourceId,
         snort::InspectionBuffer&);
+    friend void implement_eval(Http2FlowData* session_data, HttpCommon::SourceId source_id);
 
     size_t size_of() override
     { return sizeof(*this); }
 
 protected:
     // 0 element refers to client frame, 1 element refers to server frame
-    bool preface[2] = { true, false };
+
+    // Reassemble() signals to eval()
     uint8_t* frame_header[2] = { nullptr, nullptr };
     uint32_t frame_header_size[2] = { 0, 0 };
     uint8_t* frame_data[2] = { nullptr, nullptr };
     uint32_t frame_data_size[2] = { 0, 0 };
-    uint8_t* raw_decoded_header[2] = { nullptr, nullptr };
-    uint32_t raw_decoded_header_size[2] = { 0, 0 };
-    uint32_t pseudo_header_fragment_size[2] = { 0, 0 };
-    Field* http2_decoded_header[2] = { nullptr, nullptr };
+
+    // Used in eval()
     bool frame_in_detection = false;
+    class Http2Frame* current_frame[2] = { nullptr, nullptr };
+    Http2HpackDecoder hpack_decoder[2];
 
     // Internal to scan()
+    bool preface[2] = { true, false };
     bool continuation_expected[2] = { false, false };
-    uint8_t currently_processing_frame_header[2][Http2Enums::FRAME_HEADER_LENGTH];
-    uint32_t inspection_section_length[2] = { 0, 0 };
+    uint8_t scan_frame_header[2][Http2Enums::FRAME_HEADER_LENGTH];
+    uint32_t scan_remaining_frame_octets[2] = { 0, 0 };
+    uint32_t scan_octets_seen[2] = { 0, 0 };
     uint32_t leftover_data[2] = { 0, 0 };
-    uint32_t octets_seen[2] = { 0, 0 };
-    uint8_t scan_header_octets_seen[2] = { 0, 0 };
 
     // Scan signals to reassemble()
-    bool header_coming[2]  = { false, false };
     bool payload_discard[2] = { false, false };
-    uint32_t frames_aggregated[2] = { 0, 0 };
+    uint32_t num_frame_headers[2] = { 0, 0 };
+    uint32_t total_bytes_in_split[2] = { 0, 0 };
+    uint32_t octets_before_first_header[2] = { 0, 0 };
 
     // Used by scan, reassemble and eval to communicate
     uint8_t frame_type[2] = { Http2Enums::FT__NONE, Http2Enums::FT__NONE };
     
     // Internal to reassemble()
-    Http2Hpack hpack[2];
-    class Http2StartLine* header_start_line[2] = { nullptr, nullptr };
-    uint32_t remaining_octets_to_next_header[2] = { 0, 0 };
-    uint32_t remaining_frame_data_octets[2] = { 0, 0 };
-    uint32_t remaining_frame_data_offset[2] = { 0, 0 };
     uint32_t frame_header_offset[2] = { 0, 0 };
-    uint8_t reassemble_header_octets_seen[2] = { 0, 0 };
+    uint32_t frame_data_offset[2] = { 0, 0 };
+    uint32_t remaining_frame_octets[2] = { 0, 0 };
+    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.
diff --git a/src/service_inspectors/http2_inspect/http2_frame.cc b/src/service_inspectors/http2_inspect/http2_frame.cc
new file mode 100644 (file)
index 0000000..aeca879
--- /dev/null
@@ -0,0 +1,92 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_frame.cc author Katura Harvey <katharve@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "http2_frame.h"
+
+#include "detection/detection_engine.h"
+#include "http2_enum.h"
+#include "http2_flow_data.h"
+#include "http2_headers_frame.h"
+#include "service_inspectors/http_inspect/http_field.h"
+
+using namespace HttpCommon;
+using namespace Http2Enums;
+using namespace snort;
+
+Http2Frame::Http2Frame(const uint8_t* header_buffer, const int32_t header_len,
+    const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
+    SourceId source_id) :  session_data(session_data), source_id(source_id)
+{
+    if (header_len > 0)
+        header.set(header_len, header_buffer, true);
+    if (data_len > 0)
+    {
+        data.set(data_len, data_buffer, true);
+        set_file_data(data.start(), data.length());
+    }
+}
+
+Http2Frame* Http2Frame::new_frame(const uint8_t* header, const int32_t header_len,
+    const uint8_t* data, const int32_t data_len, Http2FlowData* session_data, SourceId source_id)
+{
+    //FIXIT-H call the appropriate frame subclass constructor based on the type
+    switch(session_data->frame_type[source_id])
+    {
+        case FT_HEADERS:
+            return new Http2HeadersFrame(header, header_len, data, data_len, session_data,
+                source_id);
+            break;
+        default:
+            return new Http2Frame(header, header_len, data, data_len, session_data, source_id);
+            break;
+    }
+}
+
+const Field& Http2Frame::get_buf(unsigned id)
+{
+    switch (id)
+    {
+    case HTTP2_BUFFER_FRAME_HEADER:
+        return header;
+    case HTTP2_BUFFER_FRAME_DATA:
+        return data;
+    default:
+        return Field::FIELD_NULL;
+    }
+}
+
+uint8_t Http2Frame::get_flags()
+{
+    if (header.length() > 0)
+        return header.start()[flags_index];
+    else
+        return 0;
+}
+
+#ifdef REG_TEST
+void Http2Frame::print_frame(FILE* output)
+{
+    header.print(output, "Frame Header");
+    data.print(output, "Frame Data");
+}
+#endif
diff --git a/src/service_inspectors/http2_inspect/http2_frame.h b/src/service_inspectors/http2_inspect/http2_frame.h
new file mode 100644 (file)
index 0000000..dc33efb
--- /dev/null
@@ -0,0 +1,62 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_frame.h author Katura Harvey <katharve@cisco.com>
+
+#ifndef HTTP2_FRAME_H
+#define HTTP2_FRAME_H
+
+#include "service_inspectors/http_inspect/http_common.h"
+#include "service_inspectors/http_inspect/http_field.h"
+
+/* This class is called Http2Frame, but an object of this class may not represent exactly one HTTP/2
+ * frame as received on the wire. For HEADERS frames, the Http2Frame object contains the initial
+ * HEADERS frame plus any following CONTINUATION frames grouped together. For DATA frames, the
+ * Http2Frame object represents approximately 16kb of data to be inspected. This may consist of
+ * part of a larger DATA frame cut into 16kb-sized pieces, or several smaller DATA frames aggregated
+ * together.
+ */
+
+class Http2FlowData;
+
+class Http2Frame
+{
+public:
+    virtual ~Http2Frame() { }
+    static Http2Frame* new_frame(const uint8_t* header_buffer, const int32_t header_len,
+        const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
+        HttpCommon::SourceId source_id);
+
+    virtual const Field& get_buf(unsigned id);
+#ifdef REG_TEST
+    virtual void print_frame(FILE* output);
+#endif
+
+protected:
+    Http2Frame(const uint8_t* header_buffer, const int32_t header_len,
+        const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
+        HttpCommon::SourceId source_id);
+    uint8_t get_flags();
+
+    Field header;
+    Field data;
+    Http2FlowData* session_data;
+    HttpCommon::SourceId source_id;
+
+    const static uint8_t flags_index = 4;
+};
+#endif
diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame.cc b/src/service_inspectors/http2_inspect/http2_headers_frame.cc
new file mode 100644 (file)
index 0000000..9b22f4f
--- /dev/null
@@ -0,0 +1,102 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_headers_frame.cc author Katura Harvey <katharve@cisco.com>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "http2_headers_frame.h"
+
+#include "http2_enum.h"
+#include "http2_flow_data.h"
+#include "http2_hpack.h"
+#include "http2_request_line.h"
+#include "http2_start_line.h"
+
+using namespace HttpCommon;
+using namespace Http2Enums;
+
+Http2HeadersFrame::Http2HeadersFrame(const uint8_t* header_buffer, const int32_t header_len,
+    const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
+    HttpCommon::SourceId source_id) : Http2Frame(header_buffer, header_len, data_buffer, data_len,
+    session_data, source_id)
+{
+    uint8_t hpack_headers_offset = 0;
+
+    // Remove stream dependency if present
+    if (get_flags() & PRIORITY)
+        hpack_headers_offset = 5;
+
+    // Set up the decoding context
+    hpack_decoder = &session_data->hpack_decoder[source_id];
+
+    // Allocate stuff
+    decoded_headers = new uint8_t[MAX_OCTETS];
+    decoded_headers_size = 0;
+    
+    // FIXIT-H Implement response start line
+    if (source_id == SRC_CLIENT)
+        start_line_generator = new Http2RequestLine(session_data->events[source_id],
+            session_data->infractions[source_id]);
+
+    // Decode headers
+    if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() -
+            hpack_headers_offset, decoded_headers, &decoded_headers_size, start_line_generator,
+            session_data->events[source_id], session_data->infractions[source_id]))
+    {
+        session_data->frame_type[source_id] = FT__ABORT;
+        error_during_decode = true;
+    }
+    //FIXIT-H remove condition once status lines implemented
+    if (source_id == SRC_CLIENT)
+        start_line = hpack_decoder->get_start_line();
+    http2_decoded_header = hpack_decoder->get_decoded_headers(decoded_headers);
+}
+
+Http2HeadersFrame::~Http2HeadersFrame()
+{
+    delete start_line;
+    delete start_line_generator;
+    delete http2_decoded_header;
+    delete[] decoded_headers;
+}
+
+const Field& Http2HeadersFrame::get_buf(unsigned id)
+{
+    switch (id)
+    {
+    case HTTP2_BUFFER_DECODED_HEADER:
+        return *http2_decoded_header;
+    default:
+        return Http2Frame::get_buf(id);
+    }
+}
+
+#ifdef REG_TEST
+void Http2HeadersFrame::print_frame(FILE* output)
+{
+    fprintf(output, "\nHEADERS frame\n");
+    if (error_during_decode)
+        fprintf(output, "Error decoding headers.\n");
+    if (start_line)
+        start_line->print(output, "Decoded start-line");
+    http2_decoded_header->print(output, "Decoded header");
+    Http2Frame::print_frame(output);
+}
+#endif
diff --git a/src/service_inspectors/http2_inspect/http2_headers_frame.h b/src/service_inspectors/http2_inspect/http2_headers_frame.h
new file mode 100644 (file)
index 0000000..e9ca111
--- /dev/null
@@ -0,0 +1,58 @@
+//--------------------------------------------------------------------------
+// Copyright (C) 2019-2019 Cisco and/or its affiliates. All rights reserved.
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License Version 2 as published
+// by the Free Software Foundation.  You may not use, modify or distribute
+// this program under any other version of the GNU General Public License.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+//--------------------------------------------------------------------------
+// http2_headers_frame.h author Katura Harvey <katharve@cisco.com>
+
+#ifndef HTTP2_HEADERS_FRAME_H
+#define HTTP2_HEADERS_FRAME_H
+
+#include "http2_frame.h"
+
+class Field;
+class Http2HpackDecoder;
+class Http2StartLine;
+class Http2Frame;
+
+class Http2HeadersFrame : public Http2Frame
+{
+public:
+    ~Http2HeadersFrame() override;
+    
+    const Field& get_buf(unsigned id) override;
+
+    friend Http2Frame* Http2Frame::new_frame(const uint8_t* header_buffer, const int32_t header_len,
+        const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
+        HttpCommon::SourceId source_id);
+
+#ifdef REG_TEST
+    void print_frame(FILE* output) override;
+#endif
+
+private:
+    Http2HeadersFrame(const uint8_t* header_buffer, const int32_t header_len,
+        const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* session_data,
+        HttpCommon::SourceId source_id);
+
+    Http2StartLine* start_line_generator = nullptr;
+    uint8_t* decoded_headers = nullptr; // working buffer to store decoded headers
+    uint32_t decoded_headers_size = 0;
+    const Field* http2_decoded_header = nullptr; // finalized headers to be passed to NHI
+    const Field* start_line = nullptr;
+    bool error_during_decode = false;
+    Http2HpackDecoder* hpack_decoder= nullptr;
+};
+#endif
index 043abbae61f6f55ae2c501fea53548ad109e6791..004b37a73b78c1dcd0e8737a30e73abd1eb7cd53 100644 (file)
 #include "service_inspectors/http_inspect/http_test_manager.h"
 
 #include "http2_enum.h"
-#include "http2_flow_data.h"
 #include "http2_request_line.h"
 
 using namespace HttpCommon;
 using namespace Http2Enums;
 
-Http2HpackIntDecode Http2Hpack::decode_int7(7);
-Http2HpackIntDecode Http2Hpack::decode_int6(6);
-Http2HpackIntDecode Http2Hpack::decode_int5(5);
-Http2HpackIntDecode Http2Hpack::decode_int4(4);
-Http2HpackStringDecode Http2Hpack::decode_string;
-Http2HpackTable Http2Hpack::table;
+Http2HpackIntDecode Http2HpackDecoder::decode_int7(7);
+Http2HpackIntDecode Http2HpackDecoder::decode_int6(6);
+Http2HpackIntDecode Http2HpackDecoder::decode_int5(5);
+Http2HpackIntDecode Http2HpackDecoder::decode_int4(4);
+Http2HpackStringDecode Http2HpackDecoder::decode_string;
+Http2HpackTable Http2HpackDecoder::table;
 
-bool Http2Hpack::write_decoded_headers(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-    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 Http2HpackDecoder::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 ret = true;
     uint32_t length = in_length;
@@ -52,8 +49,8 @@ bool Http2Hpack::write_decoded_headers(Http2FlowData* session_data, HttpCommon::
     if (in_length > decoded_header_length)
     {
         length = decoded_header_length;
-        *session_data->infractions[source_id] += INF_DECODED_HEADER_BUFF_OUT_OF_SPACE;
-        session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+        *infractions += INF_DECODED_HEADER_BUFF_OUT_OF_SPACE;
+        events->create_event(EVENT_MISFORMATTED_HTTP2);
         ret = false;
     }
 
@@ -62,9 +59,8 @@ bool Http2Hpack::write_decoded_headers(Http2FlowData* session_data, HttpCommon::
     return ret;
 }
 
-bool Http2Hpack::decode_string_literal(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-    const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
-    bool is_field_name, uint32_t &bytes_consumed,
+bool Http2HpackDecoder::decode_string_literal(const uint8_t* encoded_header_buffer,
+    const uint32_t encoded_header_length, bool is_field_name, uint32_t &bytes_consumed,
     uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
     uint32_t &bytes_written)
 {
@@ -84,7 +80,7 @@ bool Http2Hpack::decode_string_literal(Http2FlowData* session_data, HttpCommon::
     if (!decode_string.translate(encoded_header_buffer + encoded_header_offset,
         encoded_header_length - encoded_header_offset, encoded_bytes_consumed,
         decoded_header_buffer, decoded_header_length, decoded_bytes_written,
-        session_data->events[source_id], session_data->infractions[source_id]))
+        events, infractions))
     {
         return false;
     }
@@ -94,14 +90,14 @@ bool Http2Hpack::decode_string_literal(Http2FlowData* session_data, HttpCommon::
 
     if (is_field_name)
     {
-        if (!Http2Hpack::write_decoded_headers(session_data, source_id, (const uint8_t*)": ", 2,
+        if (!write_decoded_headers((const uint8_t*)": ", 2,
                 decoded_header_buffer + bytes_written, decoded_header_length -
                 bytes_written, decoded_bytes_written))
             return false;
     }
     else
     {
-        if (!Http2Hpack::write_decoded_headers(session_data, source_id, (const uint8_t*)"\r\n", 2,
+        if (!write_decoded_headers((const uint8_t*)"\r\n", 2,
                 decoded_header_buffer + bytes_written, decoded_header_length -
                 bytes_written, decoded_bytes_written))
             return false;
@@ -112,10 +108,8 @@ bool Http2Hpack::decode_string_literal(Http2FlowData* session_data, HttpCommon::
     return true;
 }
 
-bool Http2Hpack::decode_static_table_index(Http2FlowData* session_data,
-    HttpCommon::SourceId source_id, const uint64_t index, const bool decode_full_line,
-    uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
-    uint32_t& bytes_written)
+bool Http2HpackDecoder::decode_static_table_index(const uint64_t index, const bool decode_full_line,
+    uint8_t* decoded_header_buffer, const uint32_t decoded_header_length, uint32_t& bytes_written)
 {
     uint32_t local_bytes_written = 0;
     const Http2HpackTable::TableEntry* const entry = table.lookup(index);
@@ -126,28 +120,27 @@ bool Http2Hpack::decode_static_table_index(Http2FlowData* session_data,
 
     // If this is a pseudo-header, pass it to the start line
     // Remove second condition after response start line implemented
-    if (index < PSEUDO_HEADER_MAX_INDEX and session_data->header_start_line[source_id])
+    if (index < PSEUDO_HEADER_MAX_INDEX and start_line)
     {
-        if (!session_data->header_start_line[source_id]->process_pseudo_header_name(index))
+        if (start_line and !start_line->process_pseudo_header_name(index))
             return false;
     }
 
     // If this is a regular header, write header name + ': ' to decoded headers
     else
     {
-        if (session_data->header_start_line[source_id] and
-            !session_data->header_start_line[source_id]->is_finalized())
+        if (start_line and !start_line->is_finalized())
         {
-            if (!session_data->header_start_line[source_id]->finalize())
+            if (!finalize_start_line())
                 return false;
         }
 
-        if (!write_decoded_headers(session_data, source_id, (const uint8_t*) entry->name,
+        if (!write_decoded_headers((const uint8_t*) entry->name,
                 strlen(entry->name), decoded_header_buffer,
                 decoded_header_length, local_bytes_written))
             return false;
         bytes_written += local_bytes_written;
-        if (!write_decoded_headers(session_data, source_id, (const uint8_t*)": ", 2,
+        if (!write_decoded_headers((const uint8_t*)": ", 2,
                 decoded_header_buffer + bytes_written,
                 decoded_header_length - bytes_written,
                 local_bytes_written))
@@ -159,25 +152,25 @@ bool Http2Hpack::decode_static_table_index(Http2FlowData* session_data,
     {
         if (strlen(entry->value) == 0)
         {
-            *session_data->infractions[source_id] += INF_LOOKUP_EMPTY_VALUE;
-            session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+            *infractions += INF_LOOKUP_EMPTY_VALUE;
+            events->create_event(EVENT_MISFORMATTED_HTTP2);
             return false;
         }
 
         // Remove second condition after response start line implemented
-        if (index < PSEUDO_HEADER_MAX_INDEX and session_data->header_start_line[source_id])
+        if (index < PSEUDO_HEADER_MAX_INDEX and start_line)
         {
-            session_data->header_start_line[source_id]->process_pseudo_header_value(
+            start_line->process_pseudo_header_value(
                 (const uint8_t*)entry->value, strlen(entry->value));
         }
         else
         {
-            if (!write_decoded_headers(session_data, source_id, (const uint8_t*)entry->value,
+            if (!write_decoded_headers((const uint8_t*)entry->value,
                     strlen(entry->value), decoded_header_buffer + bytes_written,
                     decoded_header_length - bytes_written, local_bytes_written))
                 return false;
             bytes_written += local_bytes_written;
-            if (!write_decoded_headers(session_data, source_id, (const uint8_t*)"\r\n", 2,
+            if (!write_decoded_headers((const uint8_t*)"\r\n", 2,
                     decoded_header_buffer + bytes_written, decoded_header_length -
                     bytes_written, local_bytes_written))
                 return false;
@@ -189,23 +182,21 @@ bool Http2Hpack::decode_static_table_index(Http2FlowData* session_data,
 }
 
 // FIXIT-H Implement dynamic table. Currently copies encoded index to decoded headers
-bool Http2Hpack::decode_dynamic_table_index(Http2FlowData* session_data,
-    HttpCommon::SourceId source_id, const uint64_t index, const bool decode_full_line,
-    uint32_t &bytes_consumed, const uint8_t* encoded_header_buffer,
+bool Http2HpackDecoder::decode_dynamic_table_index(const uint64_t index,
+    const bool decode_full_line, uint32_t &bytes_consumed, const uint8_t* encoded_header_buffer,
     uint8_t* decoded_header_buffer, const uint32_t decoded_header_length, uint32_t& bytes_written)
 {
     UNUSED(index);
     UNUSED(decode_full_line);
 
     //FIXIT-H finalize header_start_line only for regular headers
-    if (session_data->header_start_line[source_id] and
-        !session_data->header_start_line[source_id]->is_finalized())
+    if (start_line and !start_line->is_finalized())
     {
-        if (!session_data->header_start_line[source_id]->finalize())
+        if (!finalize_start_line())
             return false;
     }
 
-    if(!Http2Hpack::write_decoded_headers(session_data, source_id, encoded_header_buffer,
+    if(!write_decoded_headers(encoded_header_buffer,
             bytes_consumed, decoded_header_buffer + bytes_written, decoded_header_length,
             bytes_written))
         return false;
@@ -215,33 +206,31 @@ bool Http2Hpack::decode_dynamic_table_index(Http2FlowData* session_data,
 
 // FIXIT-H Will be incrementally updated to actually decode indexes. For now just copies encoded
 // index directly to decoded_header_buffer
-bool Http2Hpack::decode_index(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-    const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
-    const Http2HpackIntDecode &decode_int, const bool decode_full_line, uint32_t &bytes_consumed,
-    uint8_t* decoded_header_buffer, const uint32_t decoded_header_length, uint32_t &bytes_written)
+bool Http2HpackDecoder::decode_index(const uint8_t* encoded_header_buffer,
+    const uint32_t encoded_header_length, const Http2HpackIntDecode &decode_int,
+    const bool decode_full_line, uint32_t &bytes_consumed, uint8_t* decoded_header_buffer,
+    const uint32_t decoded_header_length, uint32_t &bytes_written)
 {
     uint64_t index;
     bytes_written = 0;
     bytes_consumed = 0;
 
     if (!decode_int.translate(encoded_header_buffer, encoded_header_length,
-        bytes_consumed, index, session_data->events[source_id],
-        session_data->infractions[source_id]))
+        bytes_consumed, index, events, infractions))
     {
         return false;
     }
 
     if (index <= STATIC_TABLE_MAX_INDEX)
-        return decode_static_table_index(session_data, source_id, index, decode_full_line,
+        return decode_static_table_index(index, decode_full_line,
             decoded_header_buffer, decoded_header_length, bytes_written);
     else
-        return decode_dynamic_table_index(session_data, source_id, index, decode_full_line,
+        return decode_dynamic_table_index(index, decode_full_line,
             bytes_consumed, encoded_header_buffer, decoded_header_buffer,
             decoded_header_length, bytes_written);
 }
 
-bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
-    HttpCommon::SourceId source_id, const uint8_t* encoded_header_buffer,
+bool Http2HpackDecoder::decode_literal_header_line(const uint8_t* encoded_header_buffer,
     const uint32_t encoded_header_length, const uint8_t name_index_mask,
     const Http2HpackIntDecode &decode_int, uint32_t &bytes_consumed,
     uint8_t* decoded_header_buffer, const uint32_t decoded_header_length, uint32_t &bytes_written)
@@ -254,7 +243,7 @@ bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
     // indexed field name
     if (encoded_header_buffer[0] & name_index_mask)
     {
-        if (!Http2Hpack::decode_index(session_data, source_id, encoded_header_buffer,
+        if (!Http2HpackDecoder::decode_index(encoded_header_buffer,
                 encoded_header_length, decode_int, false, partial_bytes_consumed,
                 decoded_header_buffer, decoded_header_length, partial_bytes_written))
         {
@@ -265,7 +254,7 @@ bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
     // literal field name
     else
     {
-        if (!Http2Hpack::decode_string_literal(session_data, source_id, encoded_header_buffer,
+        if (!Http2HpackDecoder::decode_string_literal(encoded_header_buffer,
                 encoded_header_length, true,
                 partial_bytes_consumed, decoded_header_buffer, decoded_header_length,
                 partial_bytes_written))
@@ -274,22 +263,20 @@ bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
             return false;
         }
         // If this was a pseudo-header value, give it to the start-line.
-        if (session_data->header_start_line[source_id] and
-                session_data->header_start_line[source_id]->is_pseudo_name(
+        if (start_line and start_line->is_pseudo_name(
                 (const char*) decoded_header_buffer))
         {
             // don't include the ': ' that was written following the header name
-            if (!session_data->header_start_line[source_id]->process_pseudo_header_name(
+            if (!start_line->process_pseudo_header_name(
                     decoded_header_buffer, partial_bytes_written - 2))
                 return false;
         }
         // If not a pseudo-header value, keep it in the decoded headers
         else
         {
-            if (session_data->header_start_line[source_id] and
-                    !session_data->header_start_line[source_id]->is_finalized())
+            if (start_line and !start_line->is_finalized())
             {
-                if (!session_data->header_start_line[source_id]->finalize())
+                if (!finalize_start_line())
                     return false;
             }
         }
@@ -298,7 +285,7 @@ bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
     bytes_consumed += partial_bytes_consumed;
 
     // value is always literal
-    if (!Http2Hpack::decode_string_literal(session_data, source_id, encoded_header_buffer +
+    if (!Http2HpackDecoder::decode_string_literal(encoded_header_buffer +
             partial_bytes_consumed, encoded_header_length - partial_bytes_consumed,
             false, partial_bytes_consumed,
             decoded_header_buffer + bytes_written, decoded_header_length -
@@ -309,11 +296,10 @@ bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
     }
 
     // If this was a pseudo-header value, give it to the start-line.
-    if (session_data->header_start_line[source_id] and
-            session_data->header_start_line[source_id]->is_pseudo_value())
+    if (start_line and start_line->is_pseudo_value())
     {
         // Subtract 2 from the length to remove the trailing CRLF before passing to the start line
-        session_data->header_start_line[source_id]->process_pseudo_header_value(
+        start_line->process_pseudo_header_value(
             decoded_header_buffer + bytes_written, partial_bytes_written - 2);
     }
     bytes_written += partial_bytes_written;
@@ -323,8 +309,7 @@ bool Http2Hpack::decode_literal_header_line(Http2FlowData* session_data,
 }
 
 // FIXIT-M Will be updated to actually update dynamic table size. For now just skips over
-bool Http2Hpack::handle_dynamic_size_update(Http2FlowData* session_data,
-    HttpCommon::SourceId source_id, const uint8_t* encoded_header_buffer,
+bool Http2HpackDecoder::handle_dynamic_size_update(const uint8_t* encoded_header_buffer,
     const uint32_t encoded_header_length, const Http2HpackIntDecode &decode_int,
     uint32_t &bytes_consumed, uint32_t &bytes_written)
 {
@@ -334,8 +319,7 @@ bool Http2Hpack::handle_dynamic_size_update(Http2FlowData* session_data,
     bytes_written = 0;
 
     if (!decode_int.translate(encoded_header_buffer, encoded_header_length,
-        encoded_bytes_consumed, decoded_int, session_data->events[source_id],
-        session_data->infractions[source_id]))
+        encoded_bytes_consumed, decoded_int, events, infractions))
     {
         return false;
     }
@@ -352,27 +336,19 @@ bool Http2Hpack::handle_dynamic_size_update(Http2FlowData* session_data,
     return true;
 }
 
-bool Http2Hpack::decode_header_line(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-    const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
-    uint32_t& bytes_consumed, uint8_t* decoded_header_buffer,
+bool Http2HpackDecoder::decode_header_line(const uint8_t* encoded_header_buffer,
+    const uint32_t encoded_header_length, uint32_t& bytes_consumed, uint8_t* decoded_header_buffer,
     const uint32_t decoded_header_length, uint32_t& bytes_written)
 {
-    const uint8_t index_mask = 0x80;
-    const uint8_t literal_index_mask = 0x40;
-    const uint8_t literal_index_name_index_mask = 0x3f;
-    const uint8_t literal_no_index_mask = 0xf0;
-    const uint8_t literal_never_index_pattern = 0x10;
-    const uint8_t literal_no_index_name_index_mask = 0x0f;
-
     // indexed header representation
     if (encoded_header_buffer[0] & index_mask)
-        return Http2Hpack::decode_index(session_data, source_id, encoded_header_buffer,
+        return decode_index(encoded_header_buffer,
             encoded_header_length, decode_int7, true, bytes_consumed,
             decoded_header_buffer, decoded_header_length, bytes_written);
 
     // literal header representation to be added to dynamic table
     else if (encoded_header_buffer[0] & literal_index_mask)
-        return Http2Hpack::decode_literal_header_line(session_data, source_id,
+        return decode_literal_header_line(
             encoded_header_buffer, encoded_header_length, literal_index_name_index_mask,
             decode_int6, bytes_consumed, decoded_header_buffer,
             decoded_header_length, bytes_written);
@@ -382,94 +358,81 @@ bool Http2Hpack::decode_header_line(Http2FlowData* session_data, HttpCommon::Sou
     // literal never index. From a decoding standpoint these are identical.
     else if ((encoded_header_buffer[0] & literal_no_index_mask) == 0 or
             (encoded_header_buffer[0] & literal_no_index_mask) == literal_never_index_pattern)
-        return Http2Hpack::decode_literal_header_line(session_data, source_id,
+        return decode_literal_header_line(
             encoded_header_buffer, encoded_header_length, literal_no_index_name_index_mask,
             decode_int4, bytes_consumed, decoded_header_buffer,
             decoded_header_length, bytes_written);
     else
         // FIXIT-M dynamic table size update not yet supported, just skip
-        return handle_dynamic_size_update(session_data, source_id, encoded_header_buffer,
+        return handle_dynamic_size_update(encoded_header_buffer,
             encoded_header_length, decode_int5, bytes_consumed, bytes_written);
 }
 
 // FIXIT-H This will eventually be the decoded header buffer. String literals and static table
 // indexes are decoded. Dynamic table indexes are not yet decoded. Both the start-line and
 // http2_decoded_header need to be sent to NHI
-bool Http2Hpack::decode_headers(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-    const uint8_t* encoded_header_buffer, const uint32_t header_length)
+bool Http2HpackDecoder::decode_headers(const uint8_t* encoded_headers,
+    const uint32_t encoded_headers_length, uint8_t* decoded_headers, uint32_t* decoded_headers_len,
+    Http2StartLine *start_line_generator, Http2EventGen* stream_events,
+    Http2Infractions* stream_infractions)
 {
     uint32_t total_bytes_consumed = 0;
     uint32_t line_bytes_consumed = 0;
     uint32_t line_bytes_written = 0;
     bool success = true;
-    session_data->raw_decoded_header[source_id] = new uint8_t[MAX_OCTETS];
-    session_data->raw_decoded_header_size[source_id] = 0;
-
-    // FIXIT-H Implement response start line
-    if (source_id == SRC_CLIENT)
-        session_data->header_start_line[source_id] = new Http2RequestLine(session_data, source_id);
+    start_line = start_line_generator;
+    decoded_headers_size = decoded_headers_len;
+    events = stream_events;
+    infractions = stream_infractions;
+    pseudo_headers_fragment_size = 0;
 
-    while (success and total_bytes_consumed < header_length)
+    while (success and total_bytes_consumed < encoded_headers_length)
     {
-        success = Http2Hpack::decode_header_line(session_data, source_id,
-            encoded_header_buffer + total_bytes_consumed, header_length - total_bytes_consumed,
-            line_bytes_consumed, session_data->raw_decoded_header[source_id] +
-            session_data->raw_decoded_header_size[source_id], MAX_OCTETS -
-            session_data->raw_decoded_header_size[source_id], line_bytes_written);
+        success = decode_header_line(encoded_headers + total_bytes_consumed,
+            encoded_headers_length - total_bytes_consumed, line_bytes_consumed,
+            decoded_headers + *decoded_headers_size, MAX_OCTETS - *decoded_headers_size,
+            line_bytes_written);
         total_bytes_consumed  += line_bytes_consumed;
-        session_data->raw_decoded_header_size[source_id] += line_bytes_written;
+        *decoded_headers_size += line_bytes_written;
     }
 
     // If there were only pseudo-headers, finalize never got called, so create the start-line
-    if (session_data->header_start_line[source_id] and
-        !session_data->header_start_line[source_id]->is_finalized())
+    if (start_line and !start_line->is_finalized())
     {
-        success &= session_data->header_start_line[source_id]->finalize();
+        success &= finalize_start_line();
     }
 
     // write the last CRLF to end the header
     if (success)
     {
-        success = Http2Hpack::write_decoded_headers(session_data, source_id,
-            (const uint8_t*)"\r\n", 2, session_data->raw_decoded_header[source_id] +
-            session_data->raw_decoded_header_size[source_id], MAX_OCTETS -
-            session_data->raw_decoded_header_size[source_id], line_bytes_written);
-        session_data->raw_decoded_header_size[source_id] += line_bytes_written;
+        success = write_decoded_headers((const uint8_t*)"\r\n", 2, decoded_headers +
+            *decoded_headers_size, MAX_OCTETS - *decoded_headers_size, line_bytes_written);
+        *decoded_headers_size += line_bytes_written;
     }
+    else
+        decode_error = true;
+    return success;
+}
 
-    // set http2_decoded_header to send to NHI
-    session_data->http2_decoded_header[source_id] = new Field(
-        session_data->raw_decoded_header_size[source_id] -
-        session_data->pseudo_header_fragment_size[source_id],
-        session_data->raw_decoded_header[source_id] +
-        session_data->pseudo_header_fragment_size[source_id], false);
+bool Http2HpackDecoder::finalize_start_line()//const uint32_t decoded_headers_size)
+{
+    // Save the current position in the decoded buffer so we can set the pointer to the start
+    // of the regular headers
+    pseudo_headers_fragment_size = *decoded_headers_size;
 
+    return start_line->finalize();
+}
 
-#ifdef REG_TEST
-    if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP2))
-    {
-        if (success)
-        {
-            if (session_data->header_start_line[source_id])
-                session_data->header_start_line[source_id]->get_start_line().
-                    print(HttpTestManager::get_output_file(), "Decoded start-line");
-            session_data->http2_decoded_header[source_id]->
-                print(HttpTestManager::get_output_file(), "Decoded header");
-        }
-        else
-        {
-            fprintf(HttpTestManager::get_output_file(), "Error decoding headers.\n");
-            if (session_data->header_start_line[source_id] and
-                session_data->header_start_line[source_id]->get_start_line().length() > 0)
-                session_data->header_start_line[source_id]->get_start_line().
-                    print(HttpTestManager::get_output_file(), "Decoded start-line");
-            if (session_data->raw_decoded_header_size[source_id] > 0)
-                Field(session_data->raw_decoded_header_size[source_id],
-                    session_data->raw_decoded_header[source_id]).print(
-                    HttpTestManager::get_output_file(), "Partially decoded raw header");
-        }
-    }
-#endif
+const Field* Http2HpackDecoder::get_start_line()
+{
+    return start_line->get_start_line();
+}
 
-    return success;
+const Field* Http2HpackDecoder::get_decoded_headers(const uint8_t* const decoded_headers)
+{
+    if (decode_error)
+        return new Field(STAT_NO_SOURCE);
+    else
+        return new Field(*decoded_headers_size - pseudo_headers_fragment_size, decoded_headers +
+            pseudo_headers_fragment_size, false);
 }
index 09c1e31ce1adff5c210887359db0d7cbb530805f..97cea597284d6e2a56542cfbe4efd0d8d6dad94b 100644 (file)
 #include "http2_hpack_table.h"
 
 class Http2FlowData;
+class Field;
+class Http2StartLine;
 
 // This class implements HPACK decompression. One instance is required in each direction for each
 // HTTP/2 flow
-class Http2Hpack
+class Http2HpackDecoder
 {
 public:
-    Http2Hpack() {}
-    static bool decode_headers(Http2FlowData* session_data, HttpCommon::SourceId source_id, 
-        const uint8_t* raw_header_buffer, const uint32_t header_length);
-    static bool write_decoded_headers(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-        const uint8_t* in_buffer, const uint32_t in_length, uint8_t* decoded_header_buffer,
-        uint32_t decoded_header_length, uint32_t &bytes_written);
-    static bool decode_header_line(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-        const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
-        uint32_t& bytes_consumed, uint8_t* decoded_header_buffer,
-        const uint32_t decoded_header_length, uint32_t& bytes_written);
-    static bool decode_literal_header_line(Http2FlowData* session_data,
-        HttpCommon::SourceId source_id, const uint8_t* encoded_header_buffer,
+    Http2HpackDecoder() { }
+    bool decode_headers(const uint8_t* encoded_headers, const uint32_t encoded_headers_length,
+        uint8_t* decoded_headers, uint32_t* decoded_headers_size, Http2StartLine* start_line,
+        Http2EventGen* stream_events, Http2Infractions* stream_infractions);
+    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,
+        const uint32_t encoded_header_length, uint32_t& bytes_consumed,
+        uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
+        uint32_t& bytes_written);
+    bool decode_literal_header_line(const uint8_t* encoded_header_buffer,
         const uint32_t encoded_header_length, const uint8_t name_index_mask,
         const Http2HpackIntDecode &decode_int, uint32_t &bytes_consumed,
         uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
         uint32_t &bytes_written);
-    static bool decode_string_literal(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-        const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
-        bool is_field_name, uint32_t &bytes_consumed,
-        uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
-        uint32_t &bytes_written);
-    static bool decode_index(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-        const uint8_t* encoded_header_buffer, const uint32_t encoded_header_length,
-        const Http2HpackIntDecode &decode_int,const bool decode_full_line, uint32_t &bytes_consumed,
+    bool decode_string_literal(const uint8_t* encoded_header_buffer,
+        const uint32_t encoded_header_length, bool is_field_name, uint32_t &bytes_consumed,
         uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
         uint32_t &bytes_written);
-    static bool handle_dynamic_size_update(Http2FlowData* session_data,
-        HttpCommon::SourceId source_id, const uint8_t* encoded_header_buffer,
+    bool decode_index(const uint8_t* encoded_header_buffer,
+        const uint32_t encoded_header_length, const Http2HpackIntDecode &decode_int,
+        const bool decode_full_line, uint32_t &bytes_consumed, uint8_t* decoded_header_buffer,
+        const uint32_t decoded_header_length, uint32_t &bytes_written);
+    bool handle_dynamic_size_update(const uint8_t* encoded_header_buffer,
         const uint32_t encoded_header_length, const Http2HpackIntDecode &decode_int,
         uint32_t &bytes_consumed, uint32_t &bytes_written);
-    static bool decode_static_table_index(Http2FlowData* session_data,
-        HttpCommon::SourceId source_id, const uint64_t index, const bool decode_full_line,
+    bool decode_static_table_index(const uint64_t index, const bool decode_full_line,
         uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
         uint32_t& bytes_written);
-    static bool decode_dynamic_table_index(Http2FlowData* session_data,
-        HttpCommon::SourceId source_id, const uint64_t index, const bool decode_full_line,
+    bool decode_dynamic_table_index(const uint64_t index, const bool decode_full_line,
         uint32_t &bytes_consumed, const uint8_t* encoded_header_buffer,
         uint8_t* decoded_header_buffer, const uint32_t decoded_header_length,
         uint32_t& bytes_written);
+    bool finalize_start_line();
+    const Field* get_start_line();
+    const Field* get_decoded_headers(const uint8_t* const decoded_headers);
 
     static const int STATIC_TABLE_MAX_INDEX = 61;
 
 private:
+    Http2StartLine* start_line = nullptr;
+    uint32_t* decoded_headers_size;
+    uint32_t pseudo_headers_fragment_size = 0;
+    bool decode_error = false;
+    Http2EventGen* events;
+    Http2Infractions* infractions;
+
     static Http2HpackIntDecode decode_int7;
     static Http2HpackIntDecode decode_int6;
     static Http2HpackIntDecode decode_int5;
     static Http2HpackIntDecode decode_int4;
     static Http2HpackStringDecode decode_string;
 
-// FIXIT-H Dictionary class and object go here
     static Http2HpackTable table; //static until dynamic table is implemented
+
+    const static uint8_t index_mask = 0x80;
+    const static uint8_t literal_index_mask = 0x40;
+    const static uint8_t literal_index_name_index_mask = 0x3f;
+    const static uint8_t literal_no_index_mask = 0xf0;
+    const static uint8_t literal_never_index_pattern = 0x10;
+    const static uint8_t literal_no_index_name_index_mask = 0x0f;
+
 };
 
 #endif
index 5508afd6b6c81536db66c31929b5db8bb8a3220b..a241bdc1b9559d44bf9ff74b7ce9358901b00220 100644 (file)
@@ -29,6 +29,8 @@
 #include "service_inspectors/http_inspect/http_test_manager.h"
 #include "stream/stream.h"
 
+#include "http2_frame.h"
+
 using namespace snort;
 using namespace HttpCommon;
 using namespace Http2Enums;
@@ -103,23 +105,14 @@ void Http2Inspect::eval(Packet* p)
     if (session_data->frame_type[source_id] == FT__NONE)
         return;
 
-    session_data->frame_type[source_id] = FT__NONE;
-    
-    set_file_data(session_data->frame_data[source_id],
-        session_data->frame_data_size[source_id]);
+    implement_eval(session_data, source_id);
+
     session_data->frame_in_detection = true;
 
 #ifdef REG_TEST
     if (HttpTestManager::use_test_output(HttpTestManager::IN_HTTP2))
     {
-        Field((session_data->frame_header[source_id] != nullptr) ?
-            (int) session_data->frame_header_size[source_id]  : HttpCommon::STAT_NOT_PRESENT,
-            session_data->frame_header[source_id]).print(HttpTestManager::get_output_file(),
-            "Frame Header");
-        Field((session_data->frame_data[source_id] != nullptr) ?
-            (int) session_data->frame_data_size[source_id] : HttpCommon::STAT_NOT_PRESENT,
-            session_data->frame_data[source_id]).print(HttpTestManager::get_output_file(),
-            "Frame Data");
+        session_data->current_frame[source_id]->print_frame(HttpTestManager::get_output_file());
         if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP2))
         {
             printf("Finished processing section from test %" PRIi64 "\n",
index 0cabdb9a201c20d519f06612bb246f7890bf1fab..8249654f5d7aa4336ca8f86c7374460096522d97 100644 (file)
 #include "service_inspectors/http_inspect/http_common.h"
 
 #include "http2_enum.h"
-#include "http2_flow_data.h"
 #include "http2_module.h"
 #include "http2_stream_splitter.h"
 
 class Http2Api;
+class Http2FlowData;
 
 class Http2Inspect : public snort::Inspector
 {
@@ -61,6 +61,7 @@ private:
 
 bool implement_get_buf(unsigned id, Http2FlowData* session_data, HttpCommon::SourceId source_id,
     snort::InspectionBuffer& b);
+void implement_eval(Http2FlowData* session_data, HttpCommon::SourceId source_id);
 
 #endif
 
index 9109b7b07d6b94d46c21f74b6312b6550422f8e5..82a1e362aa9dd2e79326dbb9d356e72264a83bf9 100644 (file)
@@ -24,6 +24,7 @@
 #include "http2_inspect.h"
 #include "http2_enum.h"
 #include "http2_flow_data.h"
+#include "http2_frame.h"
 #include "service_inspectors/http_inspect/http_common.h"
 
 using namespace snort;
@@ -33,30 +34,22 @@ using namespace Http2Enums;
 bool implement_get_buf(unsigned id, Http2FlowData* session_data, SourceId source_id,
     InspectionBuffer& b)
 {
-    switch (id)
-    {
-    case HTTP2_BUFFER_FRAME_HEADER:
-        if (session_data->frame_header[source_id] == nullptr)
-            return false;
-        b.data = session_data->frame_header[source_id];
-        b.len = session_data->frame_header_size[source_id];
-        break;
-    case HTTP2_BUFFER_FRAME_DATA:
-        if (session_data->frame_data[source_id] == nullptr)
-            return false;
-        b.data = session_data->frame_data[source_id];
-        b.len = session_data->frame_data_size[source_id];
-        break;
-    case HTTP2_BUFFER_DECODED_HEADER:
-        if (!session_data->http2_decoded_header[source_id] or
-                session_data->http2_decoded_header[source_id]->length() <= 0)
-            return false;
-        b.data = session_data->http2_decoded_header[source_id]->start();
-        b.len = session_data->http2_decoded_header[source_id]->length();
-        break;
-    default:
+    const Field& buffer = session_data->current_frame[source_id]->get_buf(id);
+    if (buffer.length() <= 0)
         return false;
-    }
+    b.data = buffer.start();
+    b.len = buffer.length();
     return true;
 }
 
+void implement_eval(Http2FlowData* session_data, SourceId source_id)
+{
+    // Construct the appropriate frame class
+    session_data->current_frame[source_id] = Http2Frame::new_frame(
+        session_data->frame_header[source_id], session_data->frame_header_size[source_id],
+        session_data->frame_data[source_id], session_data->frame_data_size[source_id],
+        session_data, source_id);
+    // The current frame now owns these buffers, clear them from the flow data
+    session_data->frame_header[source_id] = nullptr;
+    session_data->frame_data[source_id] = nullptr;
+}
index 1db8d2d351a4cad7fcd75a96b888159d69e9005d..61473ad0d6460c764f4a519d8ccda4439f6add81 100644 (file)
@@ -42,13 +42,6 @@ const char* Http2RequestLine::SCHEME_NAME = ":scheme";
 const char* Http2RequestLine::OPTIONS = "OPTIONS";
 const char* Http2RequestLine::CONNECT = "CONNECT";
 
-Http2RequestLine::Http2RequestLine(Http2FlowData* _session_data, SourceId _source_id)
-    : Http2StartLine(_session_data, _source_id)
-{ }
-
-Http2RequestLine::~Http2RequestLine()
-{ }
-
 bool Http2RequestLine::process_pseudo_header_name(const uint64_t index)
 {
     if (!process_pseudo_header_precheck())
@@ -64,8 +57,8 @@ bool Http2RequestLine::process_pseudo_header_name(const uint64_t index)
         value_coming = SCHEME;
     else
     {
-        *session_data->infractions[source_id] += INF_INVALID_PSEUDO_HEADER;
-        session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+        infractions += INF_INVALID_PSEUDO_HEADER;
+        events->create_event(EVENT_MISFORMATTED_HTTP2);
         return false;
     }
     return true;
@@ -90,8 +83,8 @@ bool Http2RequestLine::process_pseudo_header_name(const uint8_t* const& name, ui
         value_coming = SCHEME;
     else
     {
-        *session_data->infractions[source_id] += INF_INVALID_PSEUDO_HEADER;
-        session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+        infractions += INF_INVALID_PSEUDO_HEADER;
+        events->create_event(EVENT_MISFORMATTED_HTTP2);
         return false;
     }
     return true;
@@ -124,7 +117,6 @@ void Http2RequestLine::process_pseudo_header_value(const uint8_t* const& value,
 // provided pseudo-headers and generate the start line
 bool Http2RequestLine::generate_start_line()
 {
-    uint8_t *start_line_buffer;
     uint32_t bytes_written = 0;
 
     // Asterisk form - used for OPTIONS requests
@@ -132,8 +124,8 @@ bool Http2RequestLine::generate_start_line()
     {
         if (method.length() <= 0)
         {
-            *session_data->infractions[source_id] += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
-            session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+            infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+            events->create_event(EVENT_MISFORMATTED_HTTP2);
             return false;
         }
         start_line_length = method.length() + path.length() + http_version_length +
@@ -159,8 +151,8 @@ bool Http2RequestLine::generate_start_line()
         // FIXIT-L May want to be more lenient than RFC on generating start line
         if ( scheme.length() > 0 or path.length() > 0 or authority.length() <= 0)
         {
-            *session_data->infractions[source_id] += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
-            session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+            infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+            events->create_event(EVENT_MISFORMATTED_HTTP2);
             return false;
         }
         start_line_length = method.length() + authority.length() + http_version_length +
@@ -228,8 +220,8 @@ bool Http2RequestLine::generate_start_line()
     else
     {
         // FIXIT-L May want to be more lenient than RFC on generating start line
-        *session_data->infractions[source_id] += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
-        session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+        infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+        events->create_event(EVENT_MISFORMATTED_HTTP2);
         return false;
     }
 
@@ -237,7 +229,5 @@ bool Http2RequestLine::generate_start_line()
     bytes_written += 2;
     assert(bytes_written == start_line_length);
 
-    start_line.set(start_line_length, start_line_buffer, true);
-
     return true;
 }
index 088f41ad2877e67d2eb89f8b0e51a854a21d5c3d..3ef8e35d48c3317bc4a547f5504dcd4ab29c7e7d 100644 (file)
@@ -29,8 +29,8 @@
 class Http2RequestLine : public Http2StartLine
 {
 public:
-    Http2RequestLine(Http2FlowData* session_data, HttpCommon::SourceId source_id);
-    ~Http2RequestLine() override;
+    Http2RequestLine(Http2EventGen* events, Http2Infractions* infractions) : Http2StartLine(events,
+        infractions) { }
 
     bool process_pseudo_header_name(const uint64_t index) override;
     bool process_pseudo_header_name(const uint8_t* const& name, uint32_t length) override;
index 2515e1342ab1027774aadc581096b50429040bc9..04c95c9cb13b716da807941481503ba2f2ab6958 100644 (file)
@@ -34,16 +34,17 @@ using namespace Http2Enums;
 
 const char* Http2StartLine::http_version_string = "HTTP/1.1";
 
-Http2StartLine::Http2StartLine(Http2FlowData* _session_data, HttpCommon::SourceId _source_id) :
-   session_data(_session_data), source_id(_source_id)
-{ }
+Http2StartLine::~Http2StartLine()
+{
+    delete[] start_line_buffer;
+}
 
 bool Http2StartLine::process_pseudo_header_precheck()
 {
     if (finalized)
     {
-        *session_data->infractions[source_id] += INF_PSEUDO_HEADER_AFTER_REGULAR_HEADER;
-        session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+        infractions += INF_PSEUDO_HEADER_AFTER_REGULAR_HEADER;
+        events->create_event(EVENT_MISFORMATTED_HTTP2);
         return false;
     }
     return true;
@@ -52,11 +53,10 @@ bool Http2StartLine::process_pseudo_header_precheck()
 bool Http2StartLine::finalize()
 {
     finalized = true;
-
-    // Save the current position in the raw decoded buffer so we can set the pointer to the start
-    // of the regular headers
-    session_data->pseudo_header_fragment_size[source_id] =
-        session_data->raw_decoded_header_size[source_id];
-
     return generate_start_line();
 }
+
+const Field* Http2StartLine::get_start_line()
+{
+    return new Field(start_line_length, start_line_buffer, false);
+}
index df5a92f2c5397f803583c7d1ff1feb8837b65c69..08927b66e94fce80fe2beffafd6e5f5adb2a11c4 100644 (file)
 
 #include "service_inspectors/http_inspect/http_common.h"
 #include "service_inspectors/http_inspect/http_field.h"
+#include "utils/event_gen.h"
+#include "utils/infractions.h"
 
 #include "http2_enum.h"
 
+using Http2Infractions = Infractions<Http2Enums::INF__MAX_VALUE, Http2Enums::INF__NONE>;
+using Http2EventGen = EventGen<Http2Enums::EVENT__MAX_VALUE, Http2Enums::EVENT__NONE,
+    Http2Enums::HTTP2_GID>;
+
 class Http2FlowData;
 
 class Http2StartLine
 {
 public:
-    Http2StartLine(Http2FlowData* _session_data, HttpCommon::SourceId _source_id);
-    virtual ~Http2StartLine() = default;
+    Http2StartLine(Http2EventGen* events, Http2Infractions* infractions) : events(events),
+        infractions(infractions) { }
+
+    virtual ~Http2StartLine();
 
     friend class Http2Hpack;
 
-    const Field& get_start_line() { return start_line; }
+    const Field* get_start_line();
     virtual bool process_pseudo_header_name(const uint64_t index) = 0;
     virtual bool 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;
     bool finalize();
     bool is_finalized() { return finalized; }
-    uint32_t get_start_line_length() { return start_line_length; }
     bool is_pseudo_value() { return value_coming != Http2Enums::HEADER_NONE; }
     bool is_pseudo_name(const char* const& name) { return name[0] == ':'; }
 
@@ -49,12 +56,13 @@ protected:
     bool process_pseudo_header_precheck();
     virtual bool generate_start_line() = 0;
 
-    Field start_line;
-    Http2FlowData* session_data;
-    HttpCommon::SourceId source_id;
+    Http2EventGen* events;
+    Http2Infractions* infractions;
     bool finalized = false;
     uint32_t start_line_length = 0;
+    uint8_t *start_line_buffer = nullptr;
     Http2Enums::PseudoHeaders value_coming = Http2Enums::HEADER_NONE;
+    uint32_t pseudo_header_fragment_size = 0;
 
     // Version string is HTTP/1.1
     static const char* http_version_string;
index 9120a32590c595d4f9d235a3d3eec41ae8ee749f..8f3142b7e3e843a0aee7f8afc760d07301842446 100644 (file)
@@ -45,8 +45,9 @@ static uint8_t get_frame_type(const uint8_t* frame_buffer)
     const uint8_t frame_type_index = 3;
     if (frame_buffer)
         return frame_buffer[frame_type_index];
+    // If there was no frame header, this must be a piece of a long data frame
     else
-       return FT__NONE;
+       return FT_DATA;
 }
 
 static uint8_t get_frame_flags(const uint8_t* frame_buffer)
@@ -66,7 +67,7 @@ StreamSplitter::Status implement_scan(Http2FlowData* session_data, const uint8_t
     {
         // 24-byte preface, not a real frame, no frame header
         // Verify preface is correct, else generate loss of sync event and abort
-        switch (validate_preface(data, length, session_data->octets_seen[source_id]))
+        switch (validate_preface(data, length, session_data->scan_octets_seen[source_id]))
         {
             case V_GOOD:
                 break;
@@ -74,168 +75,171 @@ StreamSplitter::Status implement_scan(Http2FlowData* session_data, const uint8_t
                 session_data->events[source_id]->create_event(EVENT_PREFACE_MATCH_FAILURE);
                 return StreamSplitter::ABORT;
             case V_TBD:
-                session_data->octets_seen[source_id] += length;
+                session_data->scan_octets_seen[source_id] += length;
                 return StreamSplitter::SEARCH;
         }
 
-        *flush_offset = 24 - session_data->octets_seen[source_id];
-        session_data->header_coming[source_id] = false;
+        *flush_offset = 24 - session_data->scan_octets_seen[source_id];
         session_data->preface[source_id] = false;
         session_data->payload_discard[source_id] = true;
+        session_data->scan_octets_seen[source_id] = 0;
     }
+    //FIXIT-M This should get split points from NHI
     else if (session_data->leftover_data[source_id] > 0)
     {
         // Continuation of ongoing data frame
-        session_data->header_coming[source_id] = false;
+        session_data->num_frame_headers[source_id] = 0;
  
-        // If this is a new section, update next inspection_section_length
-        if (session_data->octets_seen[source_id] == 0)
+        // If this is a new frame section, update next frame section length
+        if (session_data->scan_remaining_frame_octets[source_id] == 0)
         {
             if (session_data->leftover_data[source_id] > DATA_SECTION_SIZE)
-                session_data->inspection_section_length[source_id] = DATA_SECTION_SIZE;
+                session_data->scan_remaining_frame_octets[source_id] = DATA_SECTION_SIZE;
             else
-                 session_data->inspection_section_length[source_id] = 
+                 session_data->scan_remaining_frame_octets[source_id] =
                      session_data->leftover_data[source_id];
+            session_data->total_bytes_in_split[source_id] = 0;
         }
 
-        // Don't have full inspection section, keep scanning
-        if (session_data->octets_seen[source_id] + length < 
-            session_data->inspection_section_length[source_id])
+        // Don't have full frame section, keep scanning
+        if (session_data->scan_remaining_frame_octets[source_id] > length)
         {
-            session_data->octets_seen[source_id] += length;
+            session_data->scan_remaining_frame_octets[source_id] -= length;
+            session_data->total_bytes_in_split[source_id] += length;
             return status = StreamSplitter::SEARCH;
         } 
 
-        // Have full inspection section, flush and update leftover
-        *flush_offset = session_data->inspection_section_length[source_id] -
-            session_data->octets_seen[source_id];
+        // Have full frame section, flush and update leftover
+        session_data->total_bytes_in_split[source_id] +=
+            session_data->scan_remaining_frame_octets[source_id];
+        *flush_offset = session_data->scan_remaining_frame_octets[source_id];
         session_data->leftover_data[source_id] -=
-            session_data->inspection_section_length[source_id];
-        session_data->octets_seen[source_id] = 0;
+            session_data->total_bytes_in_split[source_id];
+        session_data->octets_before_first_header[source_id] =
+            session_data->total_bytes_in_split[source_id];
+        session_data->scan_remaining_frame_octets[source_id] = 0;
     }
     else
     {
-        // frame with header
+        // Frame with header
+        *flush_offset = 0;
+        uint32_t data_offset = 0;
+        session_data->octets_before_first_header[source_id] = 0;
         // If there is a header frame followed by a continuation frame in the same tcp segment,
         // need to process multiple frames in a single scan
-        *flush_offset = 0;
-        uint32_t remaining_length = length;    
-        const uint8_t *data_pos = data;
         do
         {
-            if (session_data->scan_header_octets_seen[source_id] == 0)
-            {
-                session_data->header_coming[source_id] = true;
-                session_data->octets_seen[source_id] = 0;
-            }
+            // Scanning a new frame
+            if (session_data->scan_octets_seen[source_id] == 0)
+                session_data->num_frame_headers[source_id] += 1;
 
             // The first nine bytes are the frame header. But all nine might not all be present in
             // the first TCP segment we receive.
-            if (session_data->scan_header_octets_seen[source_id] < FRAME_HEADER_LENGTH)
-            {
-                uint32_t remaining_header = FRAME_HEADER_LENGTH -
-                    session_data->scan_header_octets_seen[source_id];
-                uint32_t remaining_header_in_data = remaining_header > remaining_length ?
-                    remaining_length : remaining_header;
-                memcpy(session_data->currently_processing_frame_header[source_id] +
-                    session_data->scan_header_octets_seen[source_id],
-                    data_pos, remaining_header_in_data);
-                session_data->scan_header_octets_seen[source_id] += remaining_header_in_data;
-                if (session_data->scan_header_octets_seen[source_id] < FRAME_HEADER_LENGTH)
-                {
-                    session_data->octets_seen[source_id] += remaining_header_in_data;
-                    status = StreamSplitter::SEARCH;
-                    break;
-                }
-                session_data->frames_aggregated[source_id] += 1;
-            }
-            
-            uint8_t type = get_frame_type(session_data->currently_processing_frame_header[source_id]);
-
-            if (session_data->continuation_expected[source_id] && type != FT_CONTINUATION)
+            uint32_t remaining_header = FRAME_HEADER_LENGTH -
+                session_data->scan_octets_seen[source_id];
+            uint32_t remaining_header_in_data = remaining_header > length - data_offset ?
+                length - data_offset : remaining_header;
+            memcpy(session_data->scan_frame_header[source_id] +
+                session_data->scan_octets_seen[source_id], data + data_offset,
+                remaining_header_in_data);
+            session_data->scan_octets_seen[source_id] += remaining_header_in_data;
+            data_offset += remaining_header_in_data;
+
+            if (session_data->scan_octets_seen[source_id] < FRAME_HEADER_LENGTH)
             {
-                *session_data->infractions[source_id] += INF_MISSING_CONTINUATION;
-                session_data->events[source_id]->create_event(EVENT_MISSING_CONTINUATION);
-                status = StreamSplitter::ABORT;
+                status = StreamSplitter::SEARCH;
                 break;
             }
 
-            // Frame length does not include the frame header
-            uint32_t const frame_length = get_frame_length(session_data->
-                currently_processing_frame_header[source_id]);
-
-            // For non-data frames, send a full frame to detection
-            session_data->inspection_section_length[source_id] = frame_length + FRAME_HEADER_LENGTH;
+            // We have the full frame header, compute some variables
+            const uint32_t frame_length = get_frame_length(session_data->
+                scan_frame_header[source_id]);
+            uint8_t type = get_frame_type(session_data->scan_frame_header[source_id]);
 
-            if ((type == FT_DATA) && (frame_length > DATA_SECTION_SIZE))
+            // Compute frame section length once per frame
+            if (session_data->scan_remaining_frame_octets[source_id] == 0)
             {
-                // Break up long data frames into pieces for detection
-                session_data->inspection_section_length[source_id] = DATA_SECTION_SIZE +
-                    FRAME_HEADER_LENGTH;
-            }
-            else if (frame_length + FRAME_HEADER_LENGTH > MAX_OCTETS)
-            {
-                // FIXIT-M long non-data frame needs to be supported
-                status = StreamSplitter::ABORT;
-                break;
+                if (session_data->continuation_expected[source_id] && type != FT_CONTINUATION)
+                {
+                    *session_data->infractions[source_id] += INF_MISSING_CONTINUATION;
+                    session_data->events[source_id]->create_event(EVENT_MISSING_CONTINUATION);
+                    status = StreamSplitter::ABORT;
+                    break;
+                }
+                if ((type == FT_DATA) && (frame_length > DATA_SECTION_SIZE))
+                {
+                    // Break up long data frames into pieces for detection
+                    session_data->scan_remaining_frame_octets[source_id] = DATA_SECTION_SIZE;
+                    session_data->total_bytes_in_split[source_id] = DATA_SECTION_SIZE +
+                        FRAME_HEADER_LENGTH;
+                }
+                else if (frame_length + FRAME_HEADER_LENGTH > MAX_OCTETS)
+                {
+                    // FIXIT-M long non-data frame needs to be supported
+                    status = StreamSplitter::ABORT;
+                    break;
+                }
+                else
+                {
+                    session_data->scan_remaining_frame_octets[source_id] = frame_length;
+                    session_data->total_bytes_in_split[source_id] += FRAME_HEADER_LENGTH +
+                        frame_length;
+                }
             }
 
-            if (length + session_data->octets_seen[source_id] < 
-                session_data->inspection_section_length[source_id])
+            // If we don't have the full frame, keep scanning
+            if (length - data_offset < session_data->scan_remaining_frame_octets[source_id])
             {
-                // If we don't have the full inspection length, keep scanning
-                session_data->octets_seen[source_id] += length;
+                session_data->scan_remaining_frame_octets[source_id] -= (length - data_offset);
                 status = StreamSplitter::SEARCH;
                 break;
             }
-            else
-            {
-                // we have the full frame section to flush to detection
-                *flush_offset += session_data->inspection_section_length[source_id] -
-                    session_data->octets_seen[source_id];
-                session_data->leftover_data[source_id] = frame_length + FRAME_HEADER_LENGTH 
-                    - session_data->inspection_section_length[source_id];
-                session_data->octets_seen[source_id] = 0;
-            }
 
-            // Process all header frames as one unit - if the END_HEADERS flag is not set and scan 
-            // is out of data, tell stream to keep searching 
-            uint8_t frame_flags = get_frame_flags(session_data->
-                    currently_processing_frame_header[source_id]);
-            if (type == FT_HEADERS && !(frame_flags & END_HEADERS))
+            // Have the full frame
+            uint8_t frame_flags = get_frame_flags(session_data->scan_frame_header[source_id]);
+            switch(type)
             {
-                session_data->continuation_expected[source_id] = true;
-                
-                session_data->scan_header_octets_seen[source_id] = 0;
-                status = StreamSplitter::SEARCH;
-                data_pos = data + *flush_offset;
-                remaining_length = length - *flush_offset;
-            }
-            else if ( type == FT_CONTINUATION && session_data->continuation_expected[source_id])
-            {
-                if (!(frame_flags & END_HEADERS))
-                {
-                    session_data->scan_header_octets_seen[source_id] = 0;
-                    status = StreamSplitter::SEARCH;
-                    data_pos = data + *flush_offset;
-                    remaining_length = length - *flush_offset;
-                }
-                else
-                {
-                    // continuation frame ending headers
-                    status = StreamSplitter::FLUSH;
-                    session_data->continuation_expected[source_id] = false;
-                }
-            }
-            //FIXIT-M CONTINUATION frames can also follow PUSH_PROMISE frames, which is not
-            //currently supported
-            else if (type == FT_CONTINUATION)
-            {
-                *session_data->infractions[source_id] += INF_UNEXPECTED_CONTINUATION;
-                session_data->events[source_id]->create_event(EVENT_UNEXPECTED_CONTINUATION);
-                status = StreamSplitter::ABORT;
+                case FT_HEADERS:
+                    if (!(frame_flags & END_HEADERS))
+                    {
+                        session_data->continuation_expected[source_id] = true;
+                        status = StreamSplitter::SEARCH;
+                    }
+                    break;
+                case FT_CONTINUATION:
+                    if (session_data->continuation_expected[source_id])
+                    {
+                        if (!(frame_flags & END_HEADERS))
+                            status = StreamSplitter::SEARCH;
+                        else
+                        {
+                            // continuation frame ending headers
+                            status = StreamSplitter::FLUSH;
+                            session_data->continuation_expected[source_id] = false;
+                        }
+                    }
+                    else
+                    {
+                        // FIXIT-M CONTINUATION frames can also follow PUSH_PROMISE frames, which is
+                        // not currently supported
+                        *session_data->infractions[source_id] += INF_UNEXPECTED_CONTINUATION;
+                        session_data->events[source_id]->create_event(
+                            EVENT_UNEXPECTED_CONTINUATION);
+                        status = StreamSplitter::ABORT;
+                    }
+                    break;
+                case FT_DATA:
+                    session_data->leftover_data[source_id] = frame_length -
+                        (session_data->total_bytes_in_split[source_id] - FRAME_HEADER_LENGTH);
+                    break;
             }
-        } while (status == StreamSplitter::SEARCH && remaining_length > 0);
+
+            data_offset += session_data->scan_remaining_frame_octets[source_id];
+            *flush_offset = data_offset;
+            session_data->scan_octets_seen[source_id] = 0;
+            session_data->scan_remaining_frame_octets[source_id] = 0;
+
+        } while (status == StreamSplitter::SEARCH && data_offset < length);
     }
     return status;
 }
@@ -249,175 +253,105 @@ const StreamBuffer implement_reassemble(Http2FlowData* session_data, unsigned to
     assert(offset+len <= total);
     assert(total >= FRAME_HEADER_LENGTH);
     assert(total <= MAX_OCTETS);
+    assert(total == session_data->total_bytes_in_split[source_id]);
 
     StreamBuffer frame_buf { nullptr, 0 };
 
+    uint32_t data_offset = 0;
+
     if (offset == 0)
     {
         // This is the first reassemble() for this frame and we need to allocate some buffers
-        if (!session_data->header_coming[source_id])
-            session_data->frame_data[source_id] = new uint8_t[total];
-        else
-        {
-            const uint32_t header_length = FRAME_HEADER_LENGTH * 
-                session_data->frames_aggregated[source_id];
-            session_data->frame_header[source_id] = new uint8_t[header_length];
-            session_data->frame_header_size[source_id] = header_length;
-            if (total > FRAME_HEADER_LENGTH)
-                session_data->frame_data[source_id] = new uint8_t[total - header_length];
-        }
-        session_data->reassemble_header_octets_seen[source_id] = 0;
-        session_data->frame_data_size[source_id] = 0;
+        session_data->frame_header_size[source_id] = FRAME_HEADER_LENGTH *
+            session_data->num_frame_headers[source_id];
+        if (session_data->frame_header_size[source_id] > 0)
+            session_data->frame_header[source_id] = new uint8_t[
+                session_data->frame_header_size[source_id]];
+
+        session_data->frame_data_size[source_id]= total -
+            session_data->frame_header_size[source_id];
+        if (session_data->frame_data_size[source_id] > 0)
+            session_data->frame_data[source_id] = new uint8_t[
+                session_data->frame_data_size[source_id]];
+
         session_data->frame_header_offset[source_id] = 0;
+        session_data->frame_data_offset[source_id] = 0;
+        session_data->remaining_frame_octets[source_id] =
+            session_data->octets_before_first_header[source_id];
+        session_data->padding_octets_in_frame[source_id] = 0;
     }
 
-    if (!session_data->header_coming[source_id])
-    {
-        memcpy(session_data->frame_data[source_id] + offset, data, len);
-        session_data->frame_data_size[source_id] += len;
-    }
-    else
+    do
     {
-        uint32_t data_pos = 0;
-        do
-        {
-            // Each pass through the loop handles one frame
-            // Multiple frames occur when a Headers frame and Continuation frame(s) are flushed
-            // together
-            uint32_t remaining_len = len - data_pos;
+        uint32_t octets_to_copy;
 
-            // Process the frame header
-            if (session_data->reassemble_header_octets_seen[source_id] < FRAME_HEADER_LENGTH)
-            {
-                uint8_t remaining_header = FRAME_HEADER_LENGTH -
-                    session_data->reassemble_header_octets_seen[source_id];
-                if (remaining_header > remaining_len)
-                {
-                    memcpy(session_data->frame_header[source_id] +
-                        session_data->frame_header_offset[source_id] +
-                        session_data->reassemble_header_octets_seen[source_id], data + data_pos,
-                        remaining_len);
-                    session_data->reassemble_header_octets_seen[source_id] += remaining_len;
-                    break;
-                }
-                memcpy(session_data->frame_header[source_id] +
-                    session_data->frame_header_offset[source_id] +
-                    session_data->reassemble_header_octets_seen[source_id], data + data_pos,
-                    remaining_header);
-                session_data->reassemble_header_octets_seen[source_id] += remaining_header;
-                data_pos += remaining_header;
-                remaining_len -= remaining_header;
-            }
-
-            // done once per frame after we have the entire header
-            if (session_data->remaining_frame_data_octets[source_id] == 0)
-            {
-                uint32_t frame_length = 0;
-                uint32_t frame_data_offset = 0;
-                uint8_t pad_len = 0;
-                uint8_t frame_flags = 0;
-
-                frame_length = get_frame_length(session_data->frame_header[source_id] +
-                    session_data->frame_header_offset[source_id]);
-
-                if (frame_length == 0)
-                    break;
-                if (remaining_len == 0)
-                    return frame_buf;
-
-                // handle split long data frames
-                if (frame_length > total)
-                    frame_length = total - data_pos;
-                frame_flags = get_frame_flags(session_data->frame_header[source_id] +
-                    session_data->frame_header_offset[source_id]);
-
-                if (frame_flags & PADDED)
-                {
-                    frame_data_offset += 1;
-                    pad_len = *(data + data_pos);
-                }
-                //FIXIT-M handle stream dependency and weight. For now just skip over
-                if (frame_flags & PRIORITY)
-                {
-                    frame_data_offset += 5;
-                }
-                session_data->remaining_octets_to_next_header[source_id] = frame_length;
-                session_data->remaining_frame_data_octets[source_id] =
-                    frame_length - pad_len - frame_data_offset;
-                session_data->remaining_frame_data_offset[source_id] = frame_data_offset;
-            }
+        // Read the padding length if necessary
+        if (session_data->get_padding_len[source_id])
+        {
+            session_data->get_padding_len[source_id] = false;
+            session_data->padding_octets_in_frame[source_id] = *(data + data_offset);
+            data_offset += 1;
+            session_data->remaining_frame_octets[source_id] -= 1;
+            // Subtract the padding and padding length from the frame data size
+            session_data->frame_data_size[source_id] -=
+                (session_data->padding_octets_in_frame[source_id] + 1);
+        }
 
-            if (remaining_len >= session_data->remaining_octets_to_next_header[source_id])
-            {
-                // have the remainder of the full frame
-                memcpy(session_data->frame_data[source_id] + session_data->frame_data_size[source_id],
-                    data + data_pos + session_data->remaining_frame_data_offset[source_id],
-                    session_data->remaining_frame_data_octets[source_id]);
-                session_data->frame_data_size[source_id] +=
-                    session_data->remaining_frame_data_octets[source_id];
-                data_pos += session_data->remaining_octets_to_next_header[source_id];
-                session_data->remaining_octets_to_next_header[source_id] = 0;
-                session_data->remaining_frame_data_octets[source_id] = 0;
-                session_data->remaining_frame_data_offset[source_id] = 0;
-                session_data->reassemble_header_octets_seen[source_id] = 0;
-                session_data->frame_header_offset[source_id] += FRAME_HEADER_LENGTH;
-            }
-            else if (remaining_len < session_data->remaining_frame_data_offset[source_id])
-            {
-                // don't have the full stream dependency/weight, which precedes frame data
-                session_data->remaining_frame_data_offset[source_id] -= remaining_len;
-                session_data->remaining_octets_to_next_header[source_id] -= remaining_len;
-                return frame_buf;
-            }
-            else if (remaining_len < session_data->remaining_frame_data_octets[source_id])
-            {
-                // don't have the full frame data
-                uint32_t data_len = remaining_len - session_data->remaining_frame_data_offset[source_id];
-                memcpy(session_data->frame_data[source_id] + session_data->frame_data_size[source_id],
-                    data + data_pos + session_data->remaining_frame_data_offset[source_id],
-                    data_len);
-                session_data->frame_data_size[source_id] += data_len;
-                session_data->remaining_octets_to_next_header[source_id] -= remaining_len;
-                session_data->remaining_frame_data_octets[source_id] -= data_len;
-                session_data->remaining_frame_data_offset[source_id] = 0;
-                return frame_buf;
-            }
-            else
-            {
-                // have all the data but not all the padding following the data
-                memcpy(session_data->frame_data[source_id] + session_data->frame_data_size[source_id],
-                    data + data_pos + session_data->remaining_frame_data_offset[source_id],
-                    session_data->remaining_frame_data_octets[source_id]);
-                session_data->frame_data_size[source_id] +=
-                    session_data->remaining_frame_data_octets[source_id];
-                session_data->remaining_octets_to_next_header[source_id] -= remaining_len;
-                session_data->remaining_frame_data_octets[source_id] = 0;
-                session_data->remaining_frame_data_offset[source_id] = 0;
-            }
-        } while (data_pos < len);
-    }
+        // Copy data into the frame buffer until we run out of data or reach the end of the current
+        // frame's data
+        const uint32_t remaining_frame_payload =
+            session_data->remaining_frame_octets[source_id] -
+            session_data->padding_octets_in_frame[source_id];
+        octets_to_copy = remaining_frame_payload > len - data_offset ? len - data_offset :
+            remaining_frame_payload;
+        if (octets_to_copy > 0)
+        {
+            memcpy(session_data->frame_data[source_id] + session_data->frame_data_offset[source_id],
+                data + data_offset, octets_to_copy);
+        }
+        session_data->frame_data_offset[source_id] += octets_to_copy;
+        session_data->remaining_frame_octets[source_id] -= octets_to_copy;
+        data_offset += octets_to_copy;
+
+        if (data_offset == len)
+            break;
+
+        // Skip over any padding
+        uint32_t padding_bytes_to_skip = session_data->padding_octets_in_frame[source_id] >
+            len - data_offset ? len - data_offset :
+            session_data->padding_octets_in_frame[source_id];
+        session_data->remaining_frame_octets[source_id] -= padding_bytes_to_skip;
+        data_offset += padding_bytes_to_skip;
+
+        if (data_offset == len)
+            break;
+
+        // Copy headers
+        const uint32_t remaining_frame_header =  FRAME_HEADER_LENGTH -
+            (session_data->frame_header_offset[source_id] % FRAME_HEADER_LENGTH);
+        octets_to_copy = remaining_frame_header > len - data_offset ? len - data_offset :
+            remaining_frame_header;
+        memcpy(session_data->frame_header[source_id] + session_data->frame_header_offset[source_id],
+            data + data_offset, octets_to_copy);
+        session_data->frame_header_offset[source_id] += octets_to_copy;
+        data_offset += octets_to_copy;
+
+        if (session_data->frame_header_offset[source_id] % FRAME_HEADER_LENGTH != 0)
+            break;
+
+        // If we just finished copying a header, parse and update frame variables
+        session_data->remaining_frame_octets[source_id] =
+            get_frame_length(session_data->frame_header[source_id] +
+            session_data->frame_header_offset[source_id] - FRAME_HEADER_LENGTH);
+
+        uint8_t frame_flags = get_frame_flags(session_data->frame_header[source_id] +
+            session_data->frame_header_offset[source_id] - FRAME_HEADER_LENGTH);
+        if (frame_flags & PADDED)
+            session_data->get_padding_len[source_id] = true;
+    } while (data_offset < len);
 
     if (flags & PKT_PDU_TAIL)
     {
-        if (session_data->header_coming[source_id])
-        {
-            if (get_frame_type(session_data->frame_header[source_id]) == FT_HEADERS)
-            {
-                assert(session_data->raw_decoded_header[source_id] == nullptr);
-
-                // FIXIT-H This will eventually be the decoded header buffer. Under development.
-                if (!Http2Hpack::decode_headers(session_data, source_id,
-                    session_data->frame_data[source_id], session_data->frame_data_size[source_id]))
-                {
-                    // Since this doesn't go to detection, clear() doesn't get called, so need to
-                    // clear frame data from flow data directly
-                    session_data->clear_frame_data(source_id);
-
-                    session_data->frame_type[source_id] = FT__ABORT;
-                    return frame_buf;
-                }
-            }
-        }
         // Return 0-length non-null buffer to stream which signals detection required, but don't 
         // create pkt_data buffer
         frame_buf.data = (const uint8_t*)"";
index c3882abd79d99cf49482933abf95123743d17899..87b644e8fdd3777504c74aa87b8b6b22fe948cca 100644 (file)
@@ -1,23 +1,8 @@
-add_cpputest( http2_inspect_impl_test
-    SOURCES
-        ../http2_flow_data.cc
-        ../http2_inspect_impl.cc
-        ../http2_module.cc
-        ../http2_tables.cc
-        ../../../framework/module.cc
-)
 add_cpputest( http2_stream_splitter_impl_test
     SOURCES
         ../http2_flow_data.cc
-        ../http2_hpack_int_decode.cc
-        ../http2_hpack_table.cc
-        ../http2_hpack_string_decode.cc
-        ../http2_huffman_state_machine.cc
         ../http2_stream_splitter_impl.cc
-        ../http2_hpack.cc
         ../http2_module.cc
-        ../http2_request_line.cc
-        ../http2_start_line.cc
         ../http2_tables.cc
         ../../../framework/module.cc
 )
index 818d250815f5ad2bb5e86948b82b9f694a95e1ca..ab902d2ccca29a6c055faeffc9a8d362d1120d46 100644 (file)
@@ -38,26 +38,36 @@ class Http2FlowDataTest : public Http2FlowData
 public:
     bool get_preface(HttpCommon::SourceId source_id) { return preface[source_id]; }
     void set_preface(bool value, HttpCommon::SourceId source_id) { preface[source_id] = value; }
-    bool get_header_coming(HttpCommon::SourceId source_id) { return header_coming[source_id]; }
-    void set_header_coming(bool value, HttpCommon::SourceId source_id)
-        { header_coming[source_id] = value; }
+    bool get_num_frame_headers(HttpCommon::SourceId source_id) { return num_frame_headers[source_id]; }
+    void set_num_frame_headers(bool value, HttpCommon::SourceId source_id)
+        { num_frame_headers[source_id] = value; }
     uint8_t* get_frame_header(HttpCommon::SourceId source_id) { return frame_header[source_id]; }
     void set_frame_header(uint8_t* value, uint32_t length, HttpCommon::SourceId source_id)
         { frame_header[source_id] = value; frame_header_size[source_id] = length; }
-    uint8_t* get_currently_processing_frame_header(HttpCommon::SourceId source_id)
-        { return currently_processing_frame_header[source_id]; }
-    void set_aggregated_frames(uint32_t value, HttpCommon::SourceId source_id)
-        { frames_aggregated[source_id] = value; }
+    uint8_t* get_scan_frame_header(HttpCommon::SourceId source_id)
+        { return scan_frame_header[source_id]; }
     uint8_t* get_frame_data(HttpCommon::SourceId source_id) { return frame_data[source_id]; }
     void set_frame_data(uint8_t* value, HttpCommon::SourceId source_id)
         { frame_data[source_id] = value; }
     uint32_t get_frame_data_size(HttpCommon::SourceId source_id)
-        { return frame_data_size[source_id]; }
+        { return frame_data_offset[source_id]; }
     void set_frame_data_size(uint32_t value, HttpCommon::SourceId source_id)
         { frame_data_size[source_id] = value; }
     uint32_t get_leftover_data(HttpCommon::SourceId source_id) { return leftover_data[source_id]; }
     void set_leftover_data(uint32_t value, HttpCommon::SourceId source_id)
         { leftover_data[source_id] = value; }
+    void set_total_bytes_in_split(uint32_t value, HttpCommon::SourceId source_id)
+        { total_bytes_in_split[source_id] = value; }
+    void set_octets_before_first_header(uint32_t value, HttpCommon::SourceId source_id)
+        { octets_before_first_header[source_id] = value; }
+    void cleanup()
+    {
+        for (int k = 0; k < 2; k++)
+        {
+            delete[] frame_header[k];
+            delete[] frame_data[k];
+        }
+    }
 };
 
 #endif
diff --git a/src/service_inspectors/http2_inspect/test/http2_inspect_impl_test.cc b/src/service_inspectors/http2_inspect/test/http2_inspect_impl_test.cc
deleted file mode 100644 (file)
index 6a9e999..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-//--------------------------------------------------------------------------
-// Copyright (C) 2018-2019 Cisco and/or its affiliates. All rights reserved.
-//
-// This program is free software; you can redistribute it and/or modify it
-// under the terms of the GNU General Public License Version 2 as published
-// by the Free Software Foundation.  You may not use, modify or distribute
-// this program under any other version of the GNU General Public License.
-//
-// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License along
-// with this program; if not, write to the Free Software Foundation, Inc.,
-// 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
-//--------------------------------------------------------------------------
-
-// http2_inspect_test.cc author Tom Peters <thopeter@cisco.com>
-// unit test main
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "service_inspectors/http2_inspect/http2_stream_splitter.h"
-
-#include "protocols/packet.h"
-#include "service_inspectors/http_inspect/http_common.h"
-#include "service_inspectors/http_inspect/http_field.h"
-#include "service_inspectors/http_inspect/http_test_manager.h"
-#include "service_inspectors/http2_inspect/http2_enum.h"
-
-#include "http2_flow_data_test.h"
-
-#include <CppUTest/CommandLineTestRunner.h>
-#include <CppUTest/TestHarness.h>
-#include <CppUTestExt/MockSupport.h>
-
-#include <cstdio>
-
-using namespace snort;
-using namespace HttpCommon;
-using namespace Http2Enums;
-
-// Stubs whose sole purpose is to make the test code link
-unsigned HttpTestManager::test_input = IN_NONE;
-unsigned HttpTestManager::test_output = IN_NONE;
-int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
-
-#ifdef REG_TEST
-void Field::print(FILE*, char const*) const {}
-#endif
-
-TEST_GROUP(http2_get_buf_test)
-{
-    Http2FlowDataTest* session_data = nullptr;
-    InspectionBuffer b;
-
-    void setup() override
-    {
-        session_data = new Http2FlowDataTest();
-        CHECK(session_data != nullptr);
-    }
-
-    void teardown() override
-    {
-        delete session_data;
-    }
-};
-
-TEST(http2_get_buf_test, frame_header)
-{
-    uint8_t* head_buf = new uint8_t[9];
-    memcpy(head_buf, "\x01\x02\x03\x04\x05\x06\x07\x08\x09", 9);
-    session_data->set_frame_header(head_buf, 9, SRC_CLIENT);
-    session_data->set_aggregated_frames (1, SRC_CLIENT);
-    const bool result = implement_get_buf(HTTP2_BUFFER_FRAME_HEADER, session_data, SRC_CLIENT, b);
-    CHECK(result == true);
-    CHECK(b.len == 9);
-    CHECK(memcmp(b.data, "\x01\x02\x03\x04\x05\x06\x07\x08\x09", 9) == 0);
-}
-
-TEST(http2_get_buf_test, frame_header_absent)
-{
-    const bool result = implement_get_buf(HTTP2_BUFFER_FRAME_HEADER, session_data, SRC_SERVER, b);
-    CHECK(result == false);
-    CHECK(b.len == 0);
-    CHECK(b.data == nullptr);
-}
-
-TEST(http2_get_buf_test, frame_data)
-{
-    uint8_t* data_buf = new uint8_t[26];
-    memcpy(data_buf, "zyxwvutsrqponmlkjihgfedcba", 26);
-    session_data->set_frame_data(data_buf, SRC_SERVER);
-    session_data->set_frame_data_size(26, SRC_SERVER);
-    const bool result = implement_get_buf(HTTP2_BUFFER_FRAME_DATA, session_data, SRC_SERVER, b);
-    CHECK(result == true);
-    CHECK(b.len == 26);
-    CHECK(memcmp(b.data, "zyxwvutsrqponmlkjihgfedcba", 26) == 0);
-}
-
-TEST(http2_get_buf_test, frame_data_absent)
-{
-    const bool result = implement_get_buf(HTTP2_BUFFER_FRAME_DATA, session_data, SRC_CLIENT, b);
-    CHECK(result == false);
-    CHECK(b.len == 0);
-    CHECK(b.data == nullptr);
-}
-
-int main(int argc, char** argv)
-{
-    return CommandLineTestRunner::RunAllTests(argc, argv);
-}
-
index 2e1227c479823c7ab2f7e4f560b876a192fc8b4d..1b825720a7b2f16f99adfa2e877538099f4cd458 100644 (file)
@@ -29,9 +29,6 @@
 #include "service_inspectors/http_inspect/http_test_manager.h"
 #include "service_inspectors/http2_inspect/http2_enum.h"
 #include "service_inspectors/http2_inspect/http2_flow_data.h"
-#include "service_inspectors/http2_inspect/http2_hpack_int_decode.h"
-#include "service_inspectors/http2_inspect/http2_hpack_table.h"
-#include "service_inspectors/http2_inspect/http2_hpack_string_decode.h"
 #include "service_inspectors/http2_inspect/http2_stream_splitter.h"
 
 #include "http2_flow_data_test.h"
@@ -80,7 +77,7 @@ TEST(http2_scan_test, basic_with_header)
         26, &flush_offset, SRC_CLIENT);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == 19);
-    CHECK(session_data->get_header_coming(SRC_CLIENT));
+    CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 1);
 }
 
 TEST(http2_scan_test, basic_with_header_s2c)
@@ -90,7 +87,7 @@ TEST(http2_scan_test, basic_with_header_s2c)
         26, &flush_offset, SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == 19);
-    CHECK(session_data->get_header_coming(SRC_SERVER));
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1);
 }
 
 TEST(http2_scan_test, header_without_data)
@@ -101,7 +98,7 @@ TEST(http2_scan_test, header_without_data)
         9, &flush_offset, SRC_CLIENT);
     CHECK(result == StreamSplitter::SEARCH);
     CHECK(flush_offset == 0);
-    CHECK(session_data->get_header_coming(SRC_CLIENT));
+    CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 1);
 }
 
 TEST(http2_scan_test, preface_and_more)
@@ -111,7 +108,7 @@ TEST(http2_scan_test, preface_and_more)
         50, &flush_offset, SRC_CLIENT);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == 24);
-    CHECK(!session_data->get_header_coming(SRC_CLIENT));
+    CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 0);
 }
 
 TEST(http2_scan_test, preface_exactly)
@@ -121,7 +118,7 @@ TEST(http2_scan_test, preface_exactly)
         24, &flush_offset, SRC_CLIENT);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == 24);
-    CHECK(!session_data->get_header_coming(SRC_CLIENT));
+    CHECK(session_data->get_num_frame_headers(SRC_CLIENT) == 0);
 }
 
 TEST(http2_scan_test, short_input)
@@ -138,8 +135,8 @@ TEST(http2_scan_test, short_input)
         SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == 19);
-    CHECK(session_data->get_header_coming(SRC_SERVER));
-    CHECK(memcmp(session_data->get_currently_processing_frame_header(SRC_SERVER),
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1);
+    CHECK(memcmp(session_data->get_scan_frame_header(SRC_SERVER),
         "\x00\x00\x10\x04\x05\x06\x07\x08\x09", 9) == 0);
 }
 
@@ -160,7 +157,7 @@ TEST(http2_scan_test, maximum_frame)
         data, 63780, &flush_offset, SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == 63780);
-    CHECK(session_data->get_header_coming(SRC_SERVER));
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1);
 }
 
 TEST(http2_scan_test, data_sections)
@@ -171,28 +168,28 @@ TEST(http2_scan_test, data_sections)
         data, DATA_SECTION_SIZE + 9, &flush_offset, SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == DATA_SECTION_SIZE + 9);
-    CHECK(session_data->get_header_coming(SRC_SERVER));
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 1);
     CHECK(session_data->get_leftover_data(SRC_SERVER) == 0xE13C);
     result = implement_scan(session_data,
         data, DATA_SECTION_SIZE, &flush_offset, SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == DATA_SECTION_SIZE);
-    CHECK(!session_data->get_header_coming(SRC_SERVER));
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0);
     result = implement_scan(session_data,
         data, DATA_SECTION_SIZE, &flush_offset, SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == DATA_SECTION_SIZE);
-    CHECK(!session_data->get_header_coming(SRC_SERVER));
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0);
     result = implement_scan(session_data,
         data, DATA_SECTION_SIZE, &flush_offset, SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == DATA_SECTION_SIZE);
-    CHECK(!session_data->get_header_coming(SRC_SERVER));
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0);
     result = implement_scan(session_data,
         data, 8508, &flush_offset, SRC_SERVER);
     CHECK(result == StreamSplitter::FLUSH);
     CHECK(flush_offset == 8508);
-    CHECK(!session_data->get_header_coming(SRC_SERVER));
+    CHECK(session_data->get_num_frame_headers(SRC_SERVER) == 0);
     CHECK(session_data->get_leftover_data(SRC_SERVER) == 0);
 }
 
@@ -208,14 +205,15 @@ TEST_GROUP(http2_reassemble_test)
 
     void teardown() override
     {
+        session_data->cleanup();
         delete session_data;
     }
 };
 
 TEST(http2_reassemble_test, basic_with_header)
 {
-    session_data->set_header_coming(true, SRC_CLIENT);
-    session_data->set_aggregated_frames (1, SRC_CLIENT);
+    session_data->set_num_frame_headers(1, SRC_CLIENT);
+    session_data->set_total_bytes_in_split(19, SRC_CLIENT);
     implement_reassemble(session_data, 19, 0,
         (const uint8_t*)"\x00\x00\x0A\x02\x00\x00\x00\x00\x00" "0123456789",
         19, PKT_PDU_TAIL, SRC_CLIENT);
@@ -225,8 +223,8 @@ TEST(http2_reassemble_test, basic_with_header)
 
 TEST(http2_reassemble_test, basic_with_header_s2c)
 {
-    session_data->set_header_coming(true, SRC_SERVER);
-    session_data->set_aggregated_frames (1, SRC_SERVER);
+    session_data->set_num_frame_headers(1, SRC_SERVER);
+    session_data->set_total_bytes_in_split(19, SRC_SERVER);
     implement_reassemble(session_data, 19, 0,
         (const uint8_t*)"\x00\x00\x0A\x02\x00\x00\x00\x00\x00" "0123456789",
         19, PKT_PDU_TAIL, SRC_SERVER);
@@ -236,7 +234,9 @@ TEST(http2_reassemble_test, basic_with_header_s2c)
 
 TEST(http2_reassemble_test, basic_without_header)
 {
-    session_data->set_header_coming(false, SRC_CLIENT);
+    session_data->set_num_frame_headers(0, SRC_CLIENT);
+    session_data->set_octets_before_first_header(24, SRC_CLIENT);
+    session_data->set_total_bytes_in_split(24, SRC_CLIENT);
     implement_reassemble(session_data, 24, 0,
         (const uint8_t*)"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n",
         24, PKT_PDU_TAIL, SRC_CLIENT);
@@ -246,8 +246,8 @@ TEST(http2_reassemble_test, basic_without_header)
 
 TEST(http2_reassemble_test, basic_three_pieces)
 {
-    session_data->set_header_coming(true, SRC_CLIENT);
-    session_data->set_aggregated_frames (1, SRC_CLIENT);
+    session_data->set_num_frame_headers(1, SRC_CLIENT);
+    session_data->set_total_bytes_in_split(19, SRC_CLIENT);
     StreamBuffer buffer = implement_reassemble(session_data, 19, 0,
         (const uint8_t*)"\x00\x00\x0A\x02\x00\x00",
         6, 0, SRC_CLIENT);
@@ -266,7 +266,9 @@ TEST(http2_reassemble_test, basic_three_pieces)
 
 TEST(http2_reassemble_test, basic_without_header_two_pieces)
 {
-    session_data->set_header_coming(false, SRC_CLIENT);
+    session_data->set_num_frame_headers(0, SRC_CLIENT);
+    session_data->set_octets_before_first_header(24, SRC_CLIENT);
+    session_data->set_total_bytes_in_split(24, SRC_CLIENT);
     implement_reassemble(session_data, 24, 0,
         (const uint8_t*)"P",
         1, 0, SRC_CLIENT);