]> git.ipfire.org Git - thirdparty/snort3.git/commitdiff
Merge pull request #2192 in SNORT/snort3 from ~KATHARVE/snort3:h2i_concurrent_files...
authorMike Stepanek (mstepane) <mstepane@cisco.com>
Tue, 5 May 2020 13:47:52 +0000 (13:47 +0000)
committerMike Stepanek (mstepane) <mstepane@cisco.com>
Tue, 5 May 2020 13:47:52 +0000 (13:47 +0000)
Squashed commit of the following:

commit fa388955bae45e95f80034a69f010a7fa9b5a84b
Author: Katura Harvey <katharve@cisco.com>
Date:   Thu Apr 30 09:21:22 2020 -0400

    file_api: mark processing of file complete after type detection if signature not enabled

commit 2aff0ce2b10432111d836a82537187e2676be998
Author: Katura Harvey <katharve@cisco.com>
Date:   Thu Apr 30 09:20:06 2020 -0400

    http2_inspect: add peg count to track max concurrent http2 file transfers

19 files changed:
src/file_api/file_lib.cc
src/mime/file_mime_process.cc
src/service_inspectors/http2_inspect/http2_data_cutter.cc
src/service_inspectors/http2_inspect/http2_data_frame.cc
src/service_inspectors/http2_inspect/http2_data_frame.h
src/service_inspectors/http2_inspect/http2_enum.h
src/service_inspectors/http2_inspect/http2_flow_data.h
src/service_inspectors/http2_inspect/http2_frame.cc
src/service_inspectors/http2_inspect/http2_frame.h
src/service_inspectors/http2_inspect/http2_headers_frame.cc
src/service_inspectors/http2_inspect/http2_headers_frame.h
src/service_inspectors/http2_inspect/http2_hpack_dynamic_table.cc
src/service_inspectors/http2_inspect/http2_settings_frame.cc
src/service_inspectors/http2_inspect/http2_settings_frame.h
src/service_inspectors/http2_inspect/http2_stream.cc
src/service_inspectors/http2_inspect/http2_stream.h
src/service_inspectors/http2_inspect/http2_stream_splitter_impl.cc
src/service_inspectors/http2_inspect/http2_tables.cc
src/service_inspectors/http_inspect/http_stream_splitter_finish.cc

index 20911bc8aa6ca9ad93e42ca5d89454bbeac36be8..4b85144278df46086d2d20f5ef5a752ade0537b3 100644 (file)
@@ -405,6 +405,7 @@ bool FileContext::process(Packet* p, const uint8_t* file_data, int data_size,
     if ((!is_file_type_enabled()) and (!is_file_signature_enabled()))
     {
         update_file_size(data_size, position);
+        processing_complete = true;
         if (PacketTracer::is_active())
             PacketTracer::log("File: Type and Sig not enabled\n");
         return false;
index 4cfcc4603f2a85da072438b56183bc5cff64f2b9..8e028bfceb5f6e51475ca6ad91ee9eaed63cdcff 100644 (file)
@@ -839,7 +839,7 @@ void MimeSession::mime_file_process(Packet* p, const uint8_t* data, int data_siz
     if(!file_flows)
         return;
 
-    if (continue_inspecting_file or position == SNORT_FILE_END)
+    if (continue_inspecting_file)
     {
         if (session_base_file_id)
         {
index 5164c248c03a267367022ee199ab1aeb21496ca4..9ddf91f78800d3cc3f5364f439b496093c6e9f98 100644 (file)
@@ -327,8 +327,9 @@ void Http2DataCutter::finish_msg_body()
     Http2DummyPacket dummy_pkt;
     dummy_pkt.flow = session_data->flow;
     uint32_t unused = 0;
-    session_data->get_current_stream(source_id)->get_hi_flow_data()->
-    finish_h2_body(source_id);
+    Http2Stream* const stream = session_data->get_current_stream(source_id);
+    stream->get_hi_flow_data()->finish_h2_body(source_id);
+    stream->set_last_data_flush(source_id);
     const snort::StreamSplitter::Status scan_result = session_data->hi_ss[source_id]->scan(
         &dummy_pkt, nullptr, 0, unused, &http_flush_offset);
     assert(scan_result == snort::StreamSplitter::FLUSH);
index b3a18b8e64c0bc374c8291c427fae715aa5dc9c1..06dd661caa5d49f62e2df8e7a7c197d3b4f79c5f 100644 (file)
 
 #include "http2_dummy_packet.h"
 #include "http2_flow_data.h"
+#include "http2_module.h"
 
 using namespace HttpCommon;
 using namespace snort;
+using namespace Http2Enums;
 
 Http2DataFrame::Http2DataFrame(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, nullptr, 0, session_data_, source_id_)
+    HttpCommon::SourceId source_id_, Http2Stream* stream_) :
+    Http2Frame(header_buffer, header_len, nullptr, 0, session_data_, source_id_, stream_),
+    data_length(data_len)
 {
     if ((data_len != 0) || !session_data->flushing_data[source_id])
     {
@@ -65,3 +68,34 @@ void Http2DataFrame::clear()
     session_data->hi->clear(&dummy_pkt);
 }
 
+void Http2DataFrame::update_stream_state()
+{
+    switch (stream->get_state(source_id))
+    {
+        case STATE_OPEN:
+            if (data_length > 0)
+            {
+                session_data->concurrent_files += 1;
+                stream->set_state(source_id, STATE_OPEN_DATA);
+                if (session_data->concurrent_files >
+                    Http2Module::get_peg_counts(PEG_MAX_CONCURRENT_FILES))
+                {
+                    Http2Module::increment_peg_counts(PEG_MAX_CONCURRENT_FILES);
+                }
+            }
+            if (stream->is_last_data_flush(source_id))
+                stream->set_state(source_id, STATE_CLOSED);
+            break;
+        case STATE_OPEN_DATA:
+            if (stream->is_last_data_flush(source_id))
+            {
+                assert(session_data->concurrent_files > 0);
+                session_data->concurrent_files -= 1;
+                stream->set_state(source_id, STATE_CLOSED);
+            }
+            break;
+        default:
+            // Stream state is idle or closed - this is caught in scan so should not get here
+            assert(false);
+    }
+}
index 08ff4cc4ac195f5b04db5460e5f5d22082446d05..5ee0d9997f4337a9c1549053b1fd3e1134d5c5ee 100644 (file)
@@ -23,6 +23,7 @@
 #include "http2_frame.h"
 
 class Http2Frame;
+class Http2Stream;
 
 class Http2DataFrame : public Http2Frame
 {
@@ -32,13 +33,16 @@ public:
 
     uint32_t get_xtradata_mask() override { return xtradata_mask; }
     bool is_detection_required() const override { return detection_required; }
+    void update_stream_state() override;
 
     friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const int32_t, const uint8_t*,
-        const int32_t, Http2FlowData*, HttpCommon::SourceId);
+        const int32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
 
 private:
-    Http2DataFrame(const uint8_t* header_buffer, const int32_t header_len,const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* ssn_data,
-        HttpCommon::SourceId src_id);
+    Http2DataFrame(const uint8_t* header_buffer, const int32_t header_len,
+        const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* ssn_data,
+        HttpCommon::SourceId src_id, Http2Stream* stream);
+    uint32_t data_length = 0;
     uint32_t xtradata_mask = 0;
     bool detection_required = false;
 };
index b042b3d24b1b1225954600b65266218cc829a80f..0550c07a4a5461bd0c49b763cca941c48f106925 100644 (file)
@@ -36,6 +36,8 @@ enum FrameType : uint8_t { FT_DATA=0, FT_HEADERS=1, FT_PRIORITY=2, FT_RST_STREAM
     FT_PUSH_PROMISE=5, FT_PING=6, FT_GOAWAY=7, FT_WINDOW_UPDATE=8, FT_CONTINUATION=9, FT__ABORT=254,
     FT__NONE=255 };
 
+enum StreamState { STATE_IDLE, STATE_OPEN, STATE_OPEN_DATA, STATE_CLOSED };
+
 // Message buffers available to clients
 // This enum must remain synchronized with Http2Api::classic_buffer_names[]
 enum HTTP2_BUFFER { HTTP2_BUFFER_FRAME_HEADER = 1, HTTP2_BUFFER_FRAME_DATA,
@@ -44,7 +46,7 @@ enum HTTP2_BUFFER { HTTP2_BUFFER_FRAME_HEADER = 1, HTTP2_BUFFER_FRAME_DATA,
 // Peg counts
 // This enum must remain synchronized with Http2Module::peg_names[] in http2_tables.cc
 enum PEG_COUNT { PEG_FLOW = 0, PEG_CONCURRENT_SESSIONS, PEG_MAX_CONCURRENT_SESSIONS,
-    PEG_MAX_ENTRIES, PEG_COUNT__MAX };
+    PEG_MAX_TABLE_ENTRIES, PEG_MAX_CONCURRENT_FILES, PEG_COUNT__MAX };
 
 enum EventSid
 {
@@ -100,6 +102,7 @@ enum Infraction
     INF_INVALID_STARTLINE = 25,
     INF_INVALID_HEADER = 26,
     INF_PADDING_LEN = 27,
+    INF_TRAILERS_AFTER_END_STREAM = 28,
     INF__MAX_VALUE
 };
 
index 79f6c32fcca8190e001ec4901b349fe3514acda4..46dd2b1fdb0d092a967331b9af4a72aceec253c8 100644 (file)
@@ -120,6 +120,7 @@ protected:
     Http2ConnectionSettings connection_settings[2];
     Http2HpackDecoder hpack_decoder[2];
     std::list<class StreamInfo> streams;
+    uint32_t concurrent_files = 0;
 
     // Internal to scan()
     bool preface[2] = { true, false };
index f5a331e11ce6ff8fdb1f30fb3ae60c615a04b071..87fab4036f26d86e706389cf85e662a859982f45 100644 (file)
@@ -28,6 +28,7 @@
 #include "http2_flow_data.h"
 #include "http2_headers_frame.h"
 #include "http2_settings_frame.h"
+#include "http2_stream.h"
 #include "service_inspectors/http_inspect/http_field.h"
 
 using namespace HttpCommon;
@@ -36,32 +37,33 @@ 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)
+    SourceId source_id, Http2Stream* stream_) :  session_data(session_data), source_id(source_id),
+    stream(stream_)
 {
     if (header_len > 0)
         header.set(header_len, header_buffer, true);
     if (data_len > 0)
-    {
         data.set(data_len, data_buffer, true);
-    }
 }
 
 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)
+    const uint8_t* data, const int32_t data_len, Http2FlowData* session_data, SourceId source_id,
+    Http2Stream* stream)
 {
     // FIXIT-E 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);
+                source_id, stream);
         case FT_SETTINGS:
             return new Http2SettingsFrame(header, header_len, data, data_len, session_data,
-                source_id);
+                source_id, stream);
         case FT_DATA:
-            return new Http2DataFrame(header, header_len, data, data_len, session_data, source_id);
+            return new Http2DataFrame(header, header_len, data, data_len, session_data, source_id,
+                stream);
         default:
-            return new Http2Frame(header, header_len, data, data_len, session_data, source_id);
+            return new Http2Frame(header, header_len, data, data_len, session_data, source_id, stream);
     }
 }
 
index 861f43e9651938fad7dbe8a9b2ac909be818b8f1..9fe27e7255f6d8a1b98ba29b5dd53ee04096b1da 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 class Http2FlowData;
+class Http2Stream;
 
 class Http2Frame
 {
@@ -39,11 +40,12 @@ 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);
+        HttpCommon::SourceId source_id, Http2Stream* stream);
     virtual void clear() { }
     virtual const Field& get_buf(unsigned id);
     virtual uint32_t get_xtradata_mask() { return 0; }
     virtual bool is_detection_required() const { return true; }
+    virtual void update_stream_state() { }
 
 #ifdef REG_TEST
     virtual void print_frame(FILE* output);
@@ -52,7 +54,7 @@ public:
 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);
+        HttpCommon::SourceId source_id, Http2Stream* stream);
     uint8_t get_flags();
     uint32_t get_stream_id();
 
@@ -60,6 +62,7 @@ protected:
     Field data;
     Http2FlowData* session_data;
     HttpCommon::SourceId source_id;
+    Http2Stream* stream;
 
     const static uint8_t flags_index = 4;
     const static uint8_t stream_id_index = 5;
index 3ac0d0a1145bf350e36bcedc53e26c7675aeeed4..07098c6055cbb523c81b60e505c10a385b0ae549 100644 (file)
@@ -34,6 +34,7 @@
 #include "http2_flow_data.h"
 #include "http2_hpack.h"
 #include "http2_start_line.h"
+#include "http2_stream.h"
 
 using namespace snort;
 using namespace HttpCommon;
@@ -41,12 +42,16 @@ 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_)
+    HttpCommon::SourceId source_id_, Http2Stream* stream_) :
+    Http2Frame(header_buffer, header_len, data_buffer, data_len, session_data_, source_id_, stream_)
 {
-    Http2Stream* const stream = session_data->find_stream(get_stream_id());
-    if (get_flags() & END_STREAM)
-        stream->set_end_stream(source_id);
+    // FIXIT-E If the stream state is not IDLE, we've already received the headers. Trailers are
+    // not yet being processed
+    if (stream->get_state(source_id) >= STATE_OPEN)
+    {
+        trailer = true;
+        return;
+    }
 
     // No need to process an empty headers frame
     if (data.length() <= 0)
@@ -203,10 +208,48 @@ const Field& Http2HeadersFrame::get_buf(unsigned id)
     }
 }
 
+void Http2HeadersFrame::update_stream_state()
+{
+    switch (stream->get_state(source_id))
+    {
+        case STATE_IDLE:
+            if (get_flags() & END_STREAM)
+                stream->set_state(source_id, STATE_CLOSED);
+            else
+                stream->set_state(source_id, STATE_OPEN);
+            break;
+        case STATE_OPEN:
+            // fallthrough
+        case STATE_OPEN_DATA:
+            if (get_flags() & END_STREAM)
+            {
+                if (stream->get_state(source_id) == STATE_OPEN_DATA)
+                    session_data->concurrent_files -= 1;
+                stream->set_state(source_id, STATE_CLOSED);
+            }
+            else
+            {
+                // Headers frame without end_stream flag set after initial Headers frame
+                *session_data->infractions[source_id] += INF_FRAME_SEQUENCE;
+                session_data->events[source_id]->create_event(EVENT_FRAME_SEQUENCE);
+            }
+            break;
+        case STATE_CLOSED:
+            // Trailers in closed state
+            *session_data->infractions[source_id] += INF_TRAILERS_AFTER_END_STREAM;
+            session_data->events[source_id]->create_event(EVENT_FRAME_SEQUENCE);
+            break;
+    }
+}
+
+
 #ifdef REG_TEST
 void Http2HeadersFrame::print_frame(FILE* output)
 {
-    fprintf(output, "\nHeaders frame\n");
+    if (!trailer)
+        fprintf(output, "\nHeaders frame\n");
+    else
+        fprintf(output, "Trailing Headers frame\n");
     if (error_during_decode)
         fprintf(output, "Error decoding headers.\n");
     if (start_line)
index 43fce110a0231020f2aaef53ffac27d919c545ca..99f7d7d35fdca5aace8b9ab48c6630c05d9d4d40 100644 (file)
@@ -26,6 +26,7 @@ class Field;
 class Http2HpackDecoder;
 class Http2StartLine;
 class Http2Frame;
+class Http2Stream;
 
 class Http2HeadersFrame : public Http2Frame
 {
@@ -36,9 +37,10 @@ public:
     const Field& get_buf(unsigned id) override;
     uint32_t get_xtradata_mask() override { return xtradata_mask; }
     bool is_detection_required() const override { return detection_required; }
+    void update_stream_state() override;
 
     friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const int32_t, const uint8_t*,
-        const int32_t, Http2FlowData*, HttpCommon::SourceId);
+        const int32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
 
 #ifdef REG_TEST
     void print_frame(FILE* output) override;
@@ -47,7 +49,7 @@ public:
 private:
     Http2HeadersFrame(const uint8_t* header_buffer, const int32_t header_len,
         const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* ssn_data,
-        HttpCommon::SourceId src_id);
+        HttpCommon::SourceId src_id, Http2Stream* stream);
 
     Http2StartLine* start_line_generator = nullptr;
     uint8_t* decoded_headers = nullptr; // working buffer to store decoded headers
@@ -58,5 +60,8 @@ private:
     bool hi_abort = false;
     uint32_t xtradata_mask = 0;
     bool detection_required = false;
+
+    // FIXIT-E Process trailers
+    bool trailer = false;
 };
 #endif
index 3bb7518009f7854c0ff39ebcd6bcb794435e8373..f90d77a41483724f6360514ccbc93c962762004d 100644 (file)
@@ -65,8 +65,8 @@ bool HpackDynamicTable::add_entry(const Field& name, const Field& value)
     circular_array[start] = new_entry;
 
     num_entries++;
-    if (num_entries > Http2Module::get_peg_counts(PEG_MAX_ENTRIES))
-        Http2Module::increment_peg_counts(PEG_MAX_ENTRIES);
+    if (num_entries > Http2Module::get_peg_counts(PEG_MAX_TABLE_ENTRIES))
+        Http2Module::increment_peg_counts(PEG_MAX_TABLE_ENTRIES);
 
     rfc_table_size += new_entry_size;
     return true;
index 980a35c3b60d21d80e734ddd1625b4ba66b3fbd4..943350c2d7a05b10f801f4814ef79dae15298939 100644 (file)
@@ -48,8 +48,8 @@ static uint32_t get_parameter_value(const uint8_t* data_buffer)
 
 Http2SettingsFrame::Http2SettingsFrame(const uint8_t* header_buffer, const int32_t header_len,
     const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* ssn_data,
-    HttpCommon::SourceId src_id) : Http2Frame(header_buffer, header_len, data_buffer, data_len,
-    ssn_data, src_id)
+    HttpCommon::SourceId src_id, Http2Stream* stream_) : Http2Frame(header_buffer, header_len, data_buffer, data_len,
+    ssn_data, src_id, stream_)
 {
     if (!sanity_check())
     {
index f788038194749eaba0ac2c084f2f4bb3f817b973..ad910862ead3d5cb5628159a79e23a5df838a60d 100644 (file)
@@ -30,7 +30,7 @@ class Http2SettingsFrame : public Http2Frame
 {
 public:
     friend Http2Frame* Http2Frame::new_frame(const uint8_t*, const int32_t, const uint8_t*,
-        const int32_t, Http2FlowData*, HttpCommon::SourceId);
+        const int32_t, Http2FlowData*, HttpCommon::SourceId, Http2Stream* stream);
     bool is_detection_required() const override { return false; }
 
 #ifdef REG_TEST
@@ -40,7 +40,7 @@ public:
 private:
     Http2SettingsFrame(const uint8_t* header_buffer, const int32_t header_len,
         const uint8_t* data_buffer, const int32_t data_len, Http2FlowData* ssn_data,
-        HttpCommon::SourceId src_id);
+        HttpCommon::SourceId src_id, Http2Stream* stream);
 
     void parse_settings_frame();
     bool sanity_check();
index ea96b2734fe56a491c1559e3432c7f212d2afd95..3e6c453786f8f8e92fa06ad9de1b7d3679ffeed5 100644 (file)
@@ -21,6 +21,7 @@
 #include "config.h"
 #endif
 
+#include "http2_enum.h"
 #include "http2_stream.h"
 
 #include "service_inspectors/http_inspect/http_flow_data.h"
@@ -28,6 +29,7 @@
 #include "http2_data_cutter.h"
 
 using namespace HttpCommon;
+using namespace Http2Enums;
 
 Http2Stream::Http2Stream(uint32_t stream_id_, Http2FlowData* session_data_) :
     stream_id(stream_id_),
@@ -48,7 +50,8 @@ void Http2Stream::eval_frame(const uint8_t* header_buffer, int32_t header_len,
 {
     delete current_frame;
     current_frame = Http2Frame::new_frame(header_buffer, header_len, data_buffer,
-        data_len, session_data, source_id);
+        data_len, session_data, source_id, this);
+    current_frame->update_stream_state();
 }
 
 void Http2Stream::clear_frame()
@@ -80,3 +83,8 @@ Http2DataCutter* Http2Stream::get_data_cutter(HttpCommon::SourceId source_id)
         data_cutter[source_id] = new Http2DataCutter(session_data, source_id);
     return data_cutter[source_id];
 }
+
+bool Http2Stream::is_open(HttpCommon::SourceId source_id)
+{
+    return (state[source_id] == STATE_OPEN) || (state[source_id] == STATE_OPEN_DATA);
+}
index 9189bad33e11474af60b96e88eb7adc5eae4aa69..bbbf7f0cca889e2057c6a6f1a73ffb2a9133b313 100644 (file)
@@ -23,6 +23,7 @@
 #include "service_inspectors/http_inspect/http_common.h"
 #include "service_inspectors/http_inspect/http_field.h"
 
+#include "http2_enum.h"
 #include "http2_frame.h"
 
 class Http2DataCutter;
@@ -53,9 +54,6 @@ public:
     void set_data_cutter(Http2DataCutter* cutter, HttpCommon::SourceId source_id)
         { data_cutter[source_id] = cutter; }
 
-    void set_end_stream(HttpCommon::SourceId source_id) { end_stream_set[source_id] = true; }
-    bool end_stream_is_set(HttpCommon::SourceId source_id) { return end_stream_set[source_id]; }
-
     void set_partial_buf_pending(HttpCommon::SourceId source_id)
     { partial_buf_pending[source_id] = true; }
     void reset_partial_buf_pending(HttpCommon::SourceId source_id)
@@ -63,6 +61,13 @@ public:
     bool is_partial_buf_pending(HttpCommon::SourceId source_id)
     { return partial_buf_pending[source_id]; }
 
+    void set_state(HttpCommon::SourceId source_id, Http2Enums::StreamState new_state) 
+        { state[source_id] = new_state; }
+    Http2Enums::StreamState get_state(HttpCommon::SourceId source_id) { return state[source_id]; }
+    bool is_open(HttpCommon::SourceId source_id);
+    void set_last_data_flush(HttpCommon::SourceId source_id) { last_data_flush[source_id] = true; }
+    bool is_last_data_flush(HttpCommon::SourceId source_id) { return last_data_flush[source_id]; }
+
 #ifdef REG_TEST
     void print_frame(FILE* output);
 #endif
@@ -74,9 +79,9 @@ private:
     HttpFlowData* hi_flow_data = nullptr;
     HttpMsgSection* hi_msg_section = nullptr;
     Http2DataCutter* data_cutter[2] = { nullptr, nullptr};
-    bool end_stream_set[2] = { false, false };
     bool partial_buf_pending[2] = { false, false }; // used to indicate a partial buffer
-                                                    // is pending from a previous partial flush
+    bool last_data_flush[2] = { false, false };
+    Http2Enums::StreamState state[2] = { Http2Enums::STATE_IDLE, Http2Enums::STATE_IDLE };
 };
 
 #endif
index 58aa1fdc867681ed34f4e5f9bc62409b2d9430e4..685f192b68fae9bc3cc19368457b654fd22c8954 100644 (file)
@@ -70,10 +70,11 @@ StreamSplitter::Status Http2StreamSplitter::data_scan(Http2FlowData* session_dat
 {
     Http2Stream* const stream = session_data->find_stream(session_data->current_stream[source_id]);
 
-    if (!stream || stream->end_stream_is_set(source_id))
+    if (!stream || !stream->is_open(source_id))
     {
         *session_data->infractions[source_id] += INF_FRAME_SEQUENCE;
         session_data->events[source_id]->create_event(EVENT_FRAME_SEQUENCE);
+        // FIXIT-E We should not be aborting here
         return StreamSplitter::ABORT;
     }
 
@@ -96,6 +97,7 @@ StreamSplitter::Status Http2StreamSplitter::data_scan(Http2FlowData* session_dat
 
         *session_data->infractions[source_id] += INF_FRAME_SEQUENCE;
         session_data->events[source_id]->create_event(EVENT_FRAME_SEQUENCE);
+        // FIXIT-E We should not be aborting here
         return StreamSplitter::ABORT;
     }
 
@@ -129,15 +131,6 @@ StreamSplitter::Status Http2StreamSplitter::non_data_scan(Http2FlowData* session
         session_data->scan_remaining_frame_octets[source_id] = frame_length;
         session_data->total_bytes_in_split[source_id] += FRAME_HEADER_LENGTH +
             frame_length;
-
-        // If the stream object exists and the end_stream flag is set, save that state in the
-        // stream object. If this is the first headers frame in the current stream, the stream
-        // object has not been created yet. The end_stream flag will be handled in the headers
-        // frame processing
-        Http2Stream* const stream = session_data->find_stream(
-            session_data->current_stream[source_id]);
-        if (stream and frame_flags & END_STREAM)
-            stream->set_end_stream(source_id);
     }
 
     // If we don't have the full frame, keep scanning
@@ -193,8 +186,9 @@ StreamSplitter::Status Http2StreamSplitter::non_data_scan(Http2FlowData* session
 }
 
 // Flush pending data
-void Http2StreamSplitter::partial_flush_data(Http2FlowData* session_data, HttpCommon::SourceId source_id,
-    uint32_t* flush_offset, uint32_t data_offset, uint32_t old_stream)
+void Http2StreamSplitter::partial_flush_data(Http2FlowData* session_data,
+    HttpCommon::SourceId source_id, uint32_t* flush_offset, uint32_t data_offset, uint32_t
+    old_stream)
 {
     session_data->current_stream[source_id] = session_data->stream_in_hi = old_stream;
     session_data->frame_type[source_id] = FT_DATA;
@@ -311,7 +305,8 @@ StreamSplitter::Status Http2StreamSplitter::implement_scan(Http2FlowData* sessio
                     ((old_stream != session_data->current_stream[source_id] && type == FT_DATA)
                     || type != FT_DATA))
                 {
-                    partial_flush_data(session_data, source_id, flush_offset, data_offset, old_stream);
+                    partial_flush_data(session_data, source_id, flush_offset, data_offset,
+                        old_stream);
                     return StreamSplitter::FLUSH;
                 }
 
index 76b8d5998bdeaa751a7e8dcbd94d1d3b11489f3a..535f9345afbfb3d5c08ca9b19a45af3483f479bc 100644 (file)
@@ -52,10 +52,12 @@ const RuleMap Http2Module::http2_events[] =
 
 const PegInfo Http2Module::peg_names[PEG_COUNT__MAX+1] =
 {
-    { CountType::SUM, "flows", "HTTP connections inspected" },
+    { CountType::SUM, "flows", "HTTP/2 connections inspected" },
     { CountType::NOW, "concurrent_sessions", "total concurrent HTTP/2 sessions" },
     { CountType::MAX, "max_concurrent_sessions", "maximum concurrent HTTP/2 sessions" },
     { CountType::MAX, "max_table_entries", "maximum entries in an HTTP/2 dynamic table" },
+    { CountType::MAX, "max_concurrent_files", "maximum concurrent file transfers per HTTP/2 "
+        "connection" },
     { CountType::END, nullptr, nullptr }
 };
 
index ade06bc9f250dc52e0317e778c75f4f4e6ba4e51..dba08efc63c145ec3d71de9916dff03bf2f1053c 100644 (file)
@@ -161,10 +161,11 @@ bool HttpStreamSplitter::init_partial_flush(Flow* flow)
 {
     Profile profile(HttpModule::get_profile_stats());
 
-    assert(source_id == SRC_SERVER);
-
     HttpFlowData* session_data = HttpInspect::http_get_flow_data(flow);
     assert(session_data != nullptr);
+
+    assert(session_data->for_http2 || source_id == SRC_SERVER);
+
     assert((session_data->type_expected[source_id] == SEC_BODY_CL)      ||
            (session_data->type_expected[source_id] == SEC_BODY_OLD)     ||
            (session_data->type_expected[source_id] == SEC_BODY_CHUNK)   ||