return current_stream[source_id];
}
-void Http2FlowData::allocate_hi_memory()
+void Http2FlowData::allocate_hi_memory(HttpFlowData* hi_flow_data)
{
- update_allocations(HttpFlowData::get_memory_usage_estimate());
+ update_allocations(hi_flow_data->size_of());
}
-void Http2FlowData::deallocate_hi_memory()
+void Http2FlowData::deallocate_hi_memory(HttpFlowData* hi_flow_data)
{
- update_deallocations(HttpFlowData::get_memory_usage_estimate());
+ update_deallocations(hi_flow_data->size_of());
}
bool Http2FlowData::is_mid_frame() const
// When H2I allocates http_inspect flows, it bypasses the usual FlowData memory allocation
// bookkeeping. So H2I needs to update memory allocations and deallocations itself.
- void allocate_hi_memory();
- void deallocate_hi_memory();
+ void allocate_hi_memory(HttpFlowData* hi_flow_data);
+ void deallocate_hi_memory(HttpFlowData* hi_flow_data);
};
#endif
{
delete current_frame;
if (hi_flow_data)
- session_data->deallocate_hi_memory();
+ session_data->deallocate_hi_memory(hi_flow_data);
delete hi_flow_data;
}
if ((state[SRC_CLIENT] >= STREAM_COMPLETE) && (state[SRC_SERVER] >= STREAM_COMPLETE) &&
(hi_flow_data != nullptr))
{
+ session_data->deallocate_hi_memory(hi_flow_data);
delete hi_flow_data;
hi_flow_data = nullptr;
- session_data->deallocate_hi_memory();
}
}
{
assert(hi_flow_data == nullptr);
hi_flow_data = flow_data;
- session_data->allocate_hi_memory();
+ session_data->allocate_hi_memory(hi_flow_data);
}
const Field& Http2Stream::get_buf(unsigned id)
PEG_OTHER_METHOD, PEG_REQUEST_BODY, PEG_CHUNKED, PEG_URI_NORM, PEG_URI_PATH, PEG_URI_CODING,
PEG_CONCURRENT_SESSIONS, PEG_MAX_CONCURRENT_SESSIONS, PEG_DETAINED, PEG_SCRIPT_DETECTION,
PEG_PARTIAL_INSPECT, PEG_EXCESS_PARAMS, PEG_PARAMS, PEG_CUTOVERS, PEG_SSL_SEARCH_ABND_EARLY,
- PEG_COUNT_MAX };
+ PEG_PIPELINED_FLOWS, PEG_PIPELINED_REQUESTS, PEG_COUNT_MAX };
// Result of scanning by splitter
enum ScanResult { SCAN_NOT_FOUND, SCAN_NOT_FOUND_ACCELERATE, SCAN_FOUND, SCAN_FOUND_PIECE,
uint64_t HttpFlowData::instance_count = 0;
#endif
-const uint16_t HttpFlowData::memory_usage_estimate = sizeof(HttpFlowData) + sizeof(HttpTransaction)
- + sizeof(HttpMsgRequest) + sizeof(HttpMsgStatus) + (2 * sizeof(HttpMsgHeader)) + sizeof(HttpUri)
- + header_size_estimate + small_things;
-
HttpFlowData::HttpFlowData() : FlowData(inspector_id)
{
#ifdef REG_TEST
delete events[k];
delete[] section_buffer[k];
delete[] partial_buffer[k];
+ update_deallocations(partial_buffer_length[k]);
delete[] partial_detect_buffer[k];
+ update_deallocations(partial_detect_length[k]);
HttpTransaction::delete_transaction(transaction[k], nullptr);
delete cutter[k];
if (compress_stream[k] != nullptr)
}
}
+size_t HttpFlowData::size_of()
+{
+ return sizeof(HttpFlowData) + (2 * sizeof(HttpEventGen));
+}
+
void HttpFlowData::half_reset(SourceId source_id)
{
assert((source_id == SRC_CLIENT) || (source_id == SRC_SERVER));
if (pipeline == nullptr)
{
pipeline = new HttpTransaction*[MAX_PIPELINE];
+ HttpModule::increment_peg_counts(PEG_PIPELINED_FLOWS);
}
assert(!pipeline_overflow && !pipeline_underflow);
int new_back = (pipeline_back+1) % MAX_PIPELINE;
}
pipeline[pipeline_back] = latest;
pipeline_back = new_back;
+ HttpModule::increment_peg_counts(PEG_PIPELINED_REQUESTS);
return true;
}
return transaction[source_id]->get_infractions(source_id);
}
-uint16_t HttpFlowData::get_memory_usage_estimate()
-{
- return memory_usage_estimate;
-}
-
void HttpFlowData::finish_h2_body(HttpCommon::SourceId source_id, HttpEnums::H2BodyState state,
bool clear_partial_buffer)
{
{
// We've already sent all data through detection so no need to reinspect. Just need to
// prep for trailers
+ update_deallocations(partial_buffer_length[source_id]);
partial_buffer_length[source_id] = 0;
delete[] partial_buffer[source_id];
partial_buffer[source_id] = nullptr;
- body_octets[source_id] += partial_inspected_octets[source_id];
- partial_inspected_octets[source_id] = 0;
+
+ update_deallocations(partial_detect_length[source_id]);
partial_detect_length[source_id] = 0;
delete[] partial_detect_buffer[source_id];
partial_detect_buffer[source_id] = nullptr;
+
+ body_octets[source_id] += partial_inspected_octets[source_id];
+ partial_inspected_octets[source_id] = 0;
}
}
~HttpFlowData() override;
static unsigned inspector_id;
static void init() { inspector_id = snort::FlowData::create_flow_data_id(); }
- size_t size_of() override { return sizeof(*this); }
+ size_t size_of() override;
friend class HttpInspect;
friend class HttpMsgSection;
void reset_partial_flush(HttpCommon::SourceId source_id)
{ partial_flush[source_id] = false; }
- static uint16_t get_memory_usage_estimate();
-
private:
// HTTP/2 handling
bool for_http2 = false;
// Transactions with uncleared sections awaiting deletion
HttpTransaction* discard_list = nullptr;
- // Estimates of how much memory http_inspect uses to process a stream for H2I
- static const uint16_t header_size_estimate = 3000; // combined raw size of request and
- //response message headers
- static const uint16_t small_things = 400; // minor memory costs not otherwise accounted for
- static const uint16_t memory_usage_estimate;
-
#ifdef REG_TEST
static uint64_t instance_count;
uint64_t seq_num;
}
delete[] partial_detect_buffer;
+ session_data->update_deallocations(partial_detect_length);
if (!session_data->partial_flush[source_id])
{
memcpy(save_partial, detect_data.start(), detect_data.length());
partial_detect_buffer = save_partial;
partial_detect_length = detect_data.length();
+ session_data->update_allocations(partial_detect_length);
}
set_file_data(const_cast<uint8_t*>(detect_data.start()),
using namespace HttpEnums;
using namespace snort;
+HttpMsgHeadShared::HttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
+ HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
+ const HttpParaList* params_): HttpMsgSection(buffer, buf_size, session_data_, source_id_,
+ buf_owner, flow_, params_), own_msg_buffer(buf_owner)
+{
+ if (own_msg_buffer)
+ session_data->update_allocations(msg_text.length());
+}
+
HttpMsgHeadShared::~HttpMsgHeadShared()
{
delete[] header_line;
list_ptr = list_ptr->next;
delete temp_ptr;
}
+
+ if (own_msg_buffer)
+ session_data->update_deallocations(msg_text.length());
}
// All the header processing that is done for every message (i.e. not just-in-time) is done here.
protected:
HttpMsgHeadShared(const uint8_t* buffer, const uint16_t buf_size,
HttpFlowData* session_data_, HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
- const HttpParaList* params_)
- : HttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
- { }
+ const HttpParaList* params_);
~HttpMsgHeadShared() override;
// Get the next item in a comma-separated header value and convert it to an enum value
static int32_t get_next_code(const Field& field, int32_t& offset, const StrCode table[]);
Field content_disposition_filename;
uint64_t file_cache_index = 0;
bool file_cache_index_computed = false;
+
+ bool own_msg_buffer;
};
#endif
using namespace HttpEnums;
+HttpMsgStart::HttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
+ HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
+ const HttpParaList* params_) : HttpMsgSection(buffer, buf_size, session_data_, source_id_,
+ buf_owner, flow_, params_), own_msg_buffer(buf_owner)
+{
+ if (own_msg_buffer)
+ session_data->update_allocations(msg_text.length());
+}
+
+HttpMsgStart::~HttpMsgStart()
+{
+ if (own_msg_buffer)
+ session_data->update_deallocations(msg_text.length());
+}
+
void HttpMsgStart::analyze()
{
start_line.set(msg_text);
protected:
HttpMsgStart(const uint8_t* buffer, const uint16_t buf_size, HttpFlowData* session_data_,
HttpCommon::SourceId source_id_, bool buf_owner, snort::Flow* flow_,
- const HttpParaList* params_)
- : HttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner, flow_, params_)
- { }
+ const HttpParaList* params_);
+ ~HttpMsgStart() override;
virtual void parse_start_line() = 0;
void derive_version_id();
Field start_line;
Field version;
+ bool own_msg_buffer;
};
#endif
assert(session_data->section_offset[source_id] == 0);
memcpy(buffer, partial_buffer, partial_buffer_length);
session_data->section_offset[source_id] = partial_buffer_length;
- partial_buffer_length = 0;
delete[] partial_buffer;
+ session_data->update_deallocations(partial_buffer_length);
+ partial_buffer_length = 0;
partial_buffer = nullptr;
}
memcpy(partial_buffer, buffer, buf_size);
partial_buffer_length = buf_size;
partial_raw_bytes += total;
+ session_data->update_allocations(partial_buffer_length);
}
else
partial_raw_bytes = 0;
{ CountType::SUM, "parameters", "HTTP parameters inspected" },
{ CountType::SUM, "connect_tunnel_cutovers", "CONNECT tunnel flow cutovers to wizard" },
{ CountType::SUM, "ssl_srch_abandoned_early", "total SSL search abandoned too soon" },
+ { CountType::SUM, "pipelined_flows", "total HTTP connections containing pipelined requests" },
+ { CountType::SUM, "pipelined_requests", "total requests placed in a pipeline" },
{ CountType::END, nullptr, nullptr }
};
using namespace HttpEnums;
using namespace snort;
+const uint16_t HttpTransaction::transaction_memory_usage_estimate = sizeof(HttpTransaction) +
+ sizeof(HttpMsgRequest) + sizeof(HttpMsgStatus) + (2 * sizeof(HttpMsgHeader)) + sizeof(HttpUri)
+ + (2 * sizeof(HttpInfractions)) + small_things;
+
static void delete_section_list(HttpMsgSection* section_list)
{
while (section_list != nullptr)
}
}
+HttpTransaction::HttpTransaction(HttpFlowData* session_data_): session_data(session_data_)
+{
+ infractions[0] = nullptr;
+ infractions[1] = nullptr;
+ session_data->update_allocations(transaction_memory_usage_estimate);
+}
+
HttpTransaction::~HttpTransaction()
{
delete request;
}
delete_section_list(body_list);
delete_section_list(discard_list);
+ session_data->update_deallocations(transaction_memory_usage_estimate);
}
HttpTransaction* HttpTransaction::attach_my_transaction(HttpFlowData* session_data, SourceId
HttpTransaction* next = nullptr;
private:
- HttpTransaction(HttpFlowData* session_data_) : session_data(session_data_)
- {
- infractions[0] = nullptr;
- infractions[1] = nullptr;
- }
+ HttpTransaction(HttpFlowData* session_data_);
void discard_section(HttpMsgSection* section);
HttpFlowData* const session_data;
// transaction in the fairly rare case where the request and response are received in
// parallel.
bool shared_ownership = false;
+
+ // Estimates of how much memory http_inspect uses to process a transaction
+ static const uint16_t small_things = 400; // minor memory costs not otherwise accounted for
+ static const uint16_t transaction_memory_usage_estimate;
};
#endif
int DetectionEngine::queue_event(unsigned int, unsigned int, Actions::Type) { return 0; }
fd_status_t File_Decomp_StopFree(fd_session_t*) { return File_Decomp_OK; }
uint32_t str_to_hash(const uint8_t *, size_t) { return 0; }
+void FlowData::update_allocations(unsigned long) {}
+void FlowData::update_deallocations(unsigned long) {}
}
THREAD_LOCAL PegCount HttpModule::peg_counts[PEG_COUNT_MAX] = { };