From: Michael Altizer (mialtize) Date: Wed, 21 Dec 2016 18:35:37 +0000 (-0500) Subject: Merge pull request #761 in SNORT/snort3 from nhttp62 to master X-Git-Tag: 3.0.0-233~127 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=577559d30e473248bb1cdd54f2c49b15176a526a;p=thirdparty%2Fsnort3.git Merge pull request #761 in SNORT/snort3 from nhttp62 to master Squashed commit of the following: commit ad012fd47facac9599f369baac37ae33b292af13 Author: Tom Peters Date: Wed Dec 14 11:18:29 2016 -0500 Improve NHI Field class --- diff --git a/src/network_inspectors/appid/test/appid_http_event_test.cc b/src/network_inspectors/appid/test/appid_http_event_test.cc index 14f60a161..2e7ec084d 100644 --- a/src/network_inspectors/appid/test/appid_http_event_test.cc +++ b/src/network_inspectors/appid/test/appid_http_event_test.cc @@ -68,10 +68,11 @@ const char *uri = nullptr; const char *useragent = nullptr; const char *via = nullptr; -void Field::set(int32_t length_, const uint8_t* start_) +void Field::set(int32_t length, const uint8_t* start, bool own_the_buffer_) { - start = start_; - length = length_; + strt = start; + len = length; + own_the_buffer = own_the_buffer_; } Field global_field; @@ -158,8 +159,8 @@ const uint8_t* HttpEvent::get_content_type(int32_t &length) global_field.set(0, nullptr); if(content_type) global_field.set(strlen(content_type), (const uint8_t*)content_type); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_cookie(int32_t &length) @@ -167,8 +168,8 @@ const uint8_t* HttpEvent::get_cookie(int32_t &length) global_field.set(0, nullptr); if(cookie) global_field.set(strlen(cookie), (const uint8_t*)cookie); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_host(int32_t &length) @@ -176,8 +177,8 @@ const uint8_t* HttpEvent::get_host(int32_t &length) global_field.set(0, nullptr); if(host) global_field.set(strlen(host), (const uint8_t*)host); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_location(int32_t &length) @@ -185,8 +186,8 @@ const uint8_t* HttpEvent::get_location(int32_t &length) global_field.set(0, nullptr); if(location) global_field.set(strlen(location), (const uint8_t*)location); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_referer(int32_t &length) @@ -194,8 +195,8 @@ const uint8_t* HttpEvent::get_referer(int32_t &length) global_field.set(0, nullptr); if(referer) global_field.set(strlen(referer), (const uint8_t*)referer); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } int32_t HttpEvent::get_response_code() @@ -208,8 +209,8 @@ const uint8_t* HttpEvent::get_server(int32_t &length) global_field.set(0, nullptr); if(server) global_field.set(strlen(server), (const uint8_t*)server); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_uri(int32_t &length) @@ -217,8 +218,8 @@ const uint8_t* HttpEvent::get_uri(int32_t &length) global_field.set(0, nullptr); if(uri) global_field.set(strlen(uri), (const uint8_t*)uri); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_user_agent(int32_t &length) @@ -226,8 +227,8 @@ const uint8_t* HttpEvent::get_user_agent(int32_t &length) global_field.set(0, nullptr); if(useragent) global_field.set(strlen(useragent), (const uint8_t*)useragent); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_via(int32_t &length) @@ -235,8 +236,8 @@ const uint8_t* HttpEvent::get_via(int32_t &length) global_field.set(0, nullptr); if(via) global_field.set(strlen(via), (const uint8_t*)via); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } const uint8_t* HttpEvent::get_x_working_with(int32_t &length) @@ -244,8 +245,8 @@ const uint8_t* HttpEvent::get_x_working_with(int32_t &length) global_field.set(0, nullptr); if(x_working_with) global_field.set(strlen(x_working_with), (const uint8_t*)x_working_with); - length = global_field.length; - return global_field.start; + length = global_field.length(); + return global_field.start(); } Flow::Flow() {} diff --git a/src/pub_sub/http_events.cc b/src/pub_sub/http_events.cc index d24175b75..0cff64975 100644 --- a/src/pub_sub/http_events.cc +++ b/src/pub_sub/http_events.cc @@ -25,12 +25,11 @@ const uint8_t* HttpEvent::get_header(unsigned id, uint64_t sub_id, int32_t& length) { - Field field; - field = http_msg_header->get_classic_buffer(id, sub_id, 0); - if(field.length > 0) + const Field& field = http_msg_header->get_classic_buffer(id, sub_id, 0); + if(field.length() > 0) { - length = field.length; - return field.start; + length = field.length(); + return field.start(); } else { diff --git a/src/service_inspectors/http_inspect/dev_notes.txt b/src/service_inspectors/http_inspect/dev_notes.txt index 2fe512559..f6ccfb8e7 100644 --- a/src/service_inspectors/http_inspect/dev_notes.txt +++ b/src/service_inspectors/http_inspect/dev_notes.txt @@ -73,10 +73,14 @@ former case the original message is constant and there is no reason for a Field the latter case, once the value has been derived from the original message there is no reason to derive it again. -Once Field is set to a non-null value it should never change. The set functions will assert if this -rule is disregarded. Because the set functions are much newer than the class there are still large -amounts of code that have not yet been converted to use them. Meanwhile adhere to the rule even -when not using the set functions. +Once Field is set to a non-null value it should never change. The set() functions will assert if +this rule is disregarded. + +A Field may own the buffer containing the message or it may point to a buffer that belongs to +someone else. When a Field owning a buffer is deleted the buffer is deleted as well. Ownership is +determined with the Field is initially set. In general any dynamically allocated buffer should be +owned by a Field. If you follow this rule you won't need to keep track of allocated buffers or have +delete[]s all over the place. HI implements flow depth using the request_depth and response_depth parameters. HI seeks to provide a consistent experience to detection by making flow depth independent of factors that a sender diff --git a/src/service_inspectors/http_inspect/http_field.cc b/src/service_inspectors/http_inspect/http_field.cc index d9c7c6b8d..e3dfcf642 100644 --- a/src/service_inspectors/http_inspect/http_field.cc +++ b/src/service_inspectors/http_inspect/http_field.cc @@ -29,60 +29,62 @@ using namespace HttpEnums; const Field Field::FIELD_NULL { STAT_NO_SOURCE }; -void Field::set(int32_t length_, const uint8_t* start_) + +void Field::set(int32_t length, const uint8_t* start, bool own_the_buffer_) { - assert(length == STAT_NOT_COMPUTE); - assert(start == nullptr); - assert(start_ != nullptr); - assert(length_ >= 0); - assert(length_ <= MAX_OCTETS); - start = start_; - length = length_; + assert(len == STAT_NOT_COMPUTE); + assert(strt == nullptr); + assert(start != nullptr); + assert(length >= 0); + assert(length <= MAX_OCTETS); + strt = start; + len = length; + own_the_buffer = own_the_buffer_; } void Field::set(StatusCode stat_code) { - assert(length == STAT_NOT_COMPUTE); - assert(start == nullptr); + assert(len == STAT_NOT_COMPUTE); + assert(strt == nullptr); assert(stat_code <= 0); - start = nullptr; - length = stat_code; + len = stat_code; } void Field::set(const Field& f) { - assert(length == STAT_NOT_COMPUTE); - assert(start == nullptr); - start = f.start; - length = f.length; + assert(len == STAT_NOT_COMPUTE); + assert(strt == nullptr); + strt = f.strt; + len = f.len; + // Both Fields cannot be responsible for deleting the buffer so do not copy own_the_buffer } #ifdef REG_TEST void Field::print(FILE* output, const char* name) const { - if ((length == STAT_NOT_PRESENT) || (length == STAT_NOT_COMPUTE) || (length == STAT_NO_SOURCE)) + if ((len == STAT_NOT_PRESENT) || (len == STAT_NOT_COMPUTE) || (len == STAT_NO_SOURCE)) { return; } - const int out_count = fprintf(output, "%s, length = %d, ", name, length); - if (length <= 0) + const int out_count = fprintf(output, "%s, length = %d, ", name, len); + if (len <= 0) { fprintf(output, "\n"); return; } // Limit the amount of data printed - const int32_t print_length = (length <= HttpTestManager::get_print_amount()) ? length : + const int32_t print_length = (len <= HttpTestManager::get_print_amount()) ? len : HttpTestManager::get_print_amount(); for (int32_t k=0; k < print_length; k++) { - if ((start[k] >= 0x20) && (start[k] <= 0x7E)) - fprintf(output, "%c", (char)start[k]); - else if (start[k] == 0xD) + if ((strt[k] >= 0x20) && (strt[k] <= 0x7E)) + fprintf(output, "%c", (char)strt[k]); + else if (strt[k] == 0xD) fprintf(output, "~"); - else if (start[k] == 0xA) + else if (strt[k] == 0xA) fprintf(output, "^"); else if (HttpTestManager::get_print_hex()) - fprintf(output, "[%.2x]", (uint8_t)start[k]); + fprintf(output, "[%.2x]", (uint8_t)strt[k]); else fprintf(output, "*"); if ((k%120 == (119 - out_count)) && (k+1 < print_length)) diff --git a/src/service_inspectors/http_inspect/http_field.h b/src/service_inspectors/http_inspect/http_field.h index 3ab1736fb..26e7691da 100644 --- a/src/service_inspectors/http_inspect/http_field.h +++ b/src/service_inspectors/http_inspect/http_field.h @@ -32,30 +32,30 @@ class Field { public: - int32_t length = HttpEnums::STAT_NOT_COMPUTE; - const uint8_t* start = nullptr; - static const Field FIELD_NULL; - Field(int32_t length_, const uint8_t* start_) : length(length_), start(start_) { } - explicit Field(int32_t length_) : length(length_) { assert(length<=0); } + Field(int32_t length, const uint8_t* start, bool own_the_buffer_ = false) : len(length), + own_the_buffer(own_the_buffer_), strt(start) { } + explicit Field(int32_t length) : len(length) { assert(length<=0); } Field() = default; - void set(int32_t length_, const uint8_t* start_); + ~Field() { if (own_the_buffer) delete[] strt; } + int32_t length() const { return len; } + const uint8_t* start() const { return strt; } + void set(int32_t length, const uint8_t* start, bool own_the_buffer_ = false); void set(const Field& f); void set(HttpEnums::StatusCode stat_code); void set(int32_t length) { set(static_cast(length)); } - // Only call this method if the field owns the dynamically allocated buffer you are deleting. - // This method is a convenience but you still must know where the buffer came from. Many fields - // refer to static buffers or a subfield of someone else's buffer. - - // FIXIT-M the following test should undoubtedly be > 0. But this cannot be changed until a - // survey is done to ensure that no old code creates zero-length buffers. In practice this will - // happen naturally when start and length become private. - void delete_buffer() { if (length >= 0) delete[] start; } #ifdef REG_TEST void print(FILE* output, const char* name) const; #endif + +private: + Field& operator=(const Field&) = delete; + + int32_t len = HttpEnums::STAT_NOT_COMPUTE; + bool own_the_buffer = false; + const uint8_t* strt = nullptr; }; #endif diff --git a/src/service_inspectors/http_inspect/http_flow_data.cc b/src/service_inspectors/http_inspect/http_flow_data.cc index 2ea6c3657..fdbfc5785 100644 --- a/src/service_inspectors/http_inspect/http_flow_data.cc +++ b/src/service_inspectors/http_inspect/http_flow_data.cc @@ -57,11 +57,7 @@ HttpFlowData::~HttpFlowData() #endif for (int k=0; k <= 1; k++) { - if ((section_type[k] != SEC_BODY_CHUNK) && - (section_type[k] != SEC_BODY_CL) && - (section_type[k] != SEC_BODY_OLD)) - // Body sections are reassembled in a static buffer - delete[] section_buffer[k]; + delete[] section_buffer[k]; HttpTransaction::delete_transaction(transaction[k]); delete cutter[k]; if (compress_stream[k] != nullptr) diff --git a/src/service_inspectors/http_inspect/http_flow_data.h b/src/service_inspectors/http_inspect/http_flow_data.h index ff858fddc..2c858f376 100644 --- a/src/service_inspectors/http_inspect/http_flow_data.h +++ b/src/service_inspectors/http_inspect/http_flow_data.h @@ -33,6 +33,7 @@ class HttpTransaction; class HttpJsNorm; +class HttpMsgSection; class HttpFlowData : public FlowData { @@ -111,6 +112,7 @@ private: MimeSession* mime_state[2] = { nullptr, nullptr }; UtfDecodeSession* utf_state = nullptr; // SRC_SERVER only uint64_t expected_trans_num[2] = { 1, 1 }; + HttpMsgSection* latest_section = nullptr; // number of user data octets seen so far (regular body or chunks) int64_t body_octets[2] = { HttpEnums::STAT_NOT_PRESENT, HttpEnums::STAT_NOT_PRESENT }; diff --git a/src/service_inspectors/http_inspect/http_head_norm.cc b/src/service_inspectors/http_inspect/http_head_norm.cc index 7266706c8..ff5925edc 100644 --- a/src/service_inspectors/http_inspect/http_head_norm.cc +++ b/src/service_inspectors/http_inspect/http_head_norm.cc @@ -63,7 +63,7 @@ void HeaderNormalizer::normalize(const HeaderId head_id, const int count, HttpInfractions& infractions, HttpEventGen& events, const HeaderId header_name_id[], const Field header_value[], const int32_t num_headers, Field& result_field) const { - if (result_field.length != STAT_NOT_COMPUTE) + if (result_field.length() != STAT_NOT_COMPUTE) { return; } @@ -84,7 +84,7 @@ void HeaderNormalizer::normalize(const HeaderId head_id, const int count, { if (++num_matches == 1) curr_match = k; // remembering location of the first matching header - buffer_length += header_value[k].length; + buffer_length += header_value[k].length(); if (!concatenate_repeats || (num_matches >= count)) break; } @@ -114,8 +114,8 @@ void HeaderNormalizer::normalize(const HeaderId head_id, const int count, data_length++; while (header_name_id[++curr_match] != head_id); } - int32_t growth = derive_header_content(header_value[curr_match].start, - header_value[curr_match].length, working); + int32_t growth = derive_header_content(header_value[curr_match].start(), + header_value[curr_match].length(), working); working += growth; data_length += growth; } @@ -132,7 +132,7 @@ void HeaderNormalizer::normalize(const HeaderId head_id, const int count, } } delete[] temp_space; - result_field.set(data_length, norm_value); + result_field.set(data_length, norm_value, true); return; } diff --git a/src/service_inspectors/http_inspect/http_inspect.cc b/src/service_inspectors/http_inspect/http_inspect.cc index ebccff036..18d83ab59 100644 --- a/src/service_inspectors/http_inspect/http_inspect.cc +++ b/src/service_inspectors/http_inspect/http_inspect.cc @@ -55,71 +55,86 @@ HttpInspect::HttpInspect(const HttpParaList* params_) : params(params_) #endif } -THREAD_LOCAL uint8_t HttpInspect::body_buffer[MAX_OCTETS]; +InspectSection HttpInspect::get_latest_is(const Packet* p) +{ + const HttpFlowData* const session_data = + (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::http_flow_id); + + if ((session_data == nullptr) || (session_data->latest_section == nullptr)) + return HttpEnums::IS_NONE; -THREAD_LOCAL HttpMsgSection* HttpInspect::latest_section = nullptr; + return session_data->latest_section->get_inspection_section(); +} -HttpEnums::InspectSection HttpInspect::get_latest_is() +SourceId HttpInspect::get_latest_src(const Packet* p) { - return (latest_section != nullptr) ? - latest_section->get_inspection_section() : HttpEnums::IS_NONE; + const HttpFlowData* const session_data = + (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::http_flow_id); + + if ((session_data == nullptr) || (session_data->latest_section == nullptr)) + return HttpEnums::SRC__NOT_COMPUTE; + + return session_data->latest_section->get_source_id(); } -bool HttpInspect::get_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) +bool HttpInspect::get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b) { switch (ibt) { case InspectionBuffer::IBT_KEY: - return http_get_buf(HTTP_BUFFER_URI, 0, 0, nullptr, b); + return http_get_buf(HTTP_BUFFER_URI, 0, 0, p, b); case InspectionBuffer::IBT_HEADER: - if (get_latest_is() == IS_TRAILER) - return http_get_buf(HTTP_BUFFER_TRAILER, 0, 0, nullptr, b); + if (get_latest_is(p) == IS_TRAILER) + return http_get_buf(HTTP_BUFFER_TRAILER, 0, 0, p, b); else - return http_get_buf(HTTP_BUFFER_HEADER, 0, 0, nullptr, b); + return http_get_buf(HTTP_BUFFER_HEADER, 0, 0, p, b); case InspectionBuffer::IBT_BODY: - return http_get_buf(HTTP_BUFFER_CLIENT_BODY, 0, 0, nullptr, b); + return http_get_buf(HTTP_BUFFER_CLIENT_BODY, 0, 0, p, b); default: return false; } } -bool HttpInspect::http_get_buf(unsigned id, uint64_t sub_id, uint64_t form, Packet*, +bool HttpInspect::http_get_buf(unsigned id, uint64_t sub_id, uint64_t form, Packet* p, InspectionBuffer& b) { - if (latest_section == nullptr) + const HttpFlowData* const session_data = + (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::http_flow_id); + + if ((session_data == nullptr) || (session_data->latest_section == nullptr)) return false; - const Field& buffer = latest_section->get_classic_buffer(id, sub_id, form); + const Field& buffer = session_data->latest_section->get_classic_buffer(id, sub_id, form); - if (buffer.length <= 0) + if (buffer.length() <= 0) return false; - b.data = buffer.start; - b.len = buffer.length; + b.data = buffer.start(); + b.len = buffer.length(); return true; } -bool HttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) +bool HttpInspect::get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b) { // Fast pattern buffers only supplied at specific times switch (ibt) { case InspectionBuffer::IBT_KEY: - if ((get_latest_is() != IS_DETECTION) || (get_latest_src() != SRC_CLIENT)) + if ((get_latest_is(p) != IS_DETECTION) || (get_latest_src(p) != SRC_CLIENT)) return false; break; case InspectionBuffer::IBT_HEADER: - if ((get_latest_is() != IS_DETECTION) && (get_latest_is() != IS_TRAILER)) + if ((get_latest_is(p) != IS_DETECTION) && (get_latest_is(p) != IS_TRAILER)) return false; break; case InspectionBuffer::IBT_BODY: - if ((get_latest_is() != IS_DETECTION) && (get_latest_is() != IS_BODY)) + if ((get_latest_is(p) != IS_DETECTION) && (get_latest_is(p) != IS_BODY)) return false; break; default: return false; } - return get_buf(ibt, nullptr, b); + return get_buf(ibt, p, b); } const Field& HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flow* const flow, @@ -130,6 +145,7 @@ const Field& HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flo HttpModule::increment_peg_counts(PEG_INSPECT); + HttpMsgSection*& latest_section = session_data->latest_section; switch (session_data->section_type[source_id]) { case SEC_REQUEST: @@ -192,13 +208,13 @@ const Field& HttpInspect::process(const uint8_t* data, const uint16_t dsize, Flo void HttpInspect::clear(Packet* p) { - latest_section = nullptr; - HttpFlowData* session_data = (HttpFlowData*)p->flow->get_flow_data(HttpFlowData::http_flow_id); if (session_data == nullptr) return; + session_data->latest_section = nullptr; + assert((p->is_from_client()) || (p->is_from_server())); assert(!((p->is_from_client()) && (p->is_from_server()))); SourceId source_id = (p->is_from_client()) ? SRC_CLIENT : SRC_SERVER; @@ -211,7 +227,7 @@ void HttpInspect::clear(Packet* p) void HttpInspect::clear(HttpFlowData* session_data, SourceId source_id) { - latest_section = nullptr; + session_data->latest_section = nullptr; // If current transaction is complete then we are done with it and should reclaim the space if ((source_id == SRC_SERVER) && (session_data->type_expected[SRC_SERVER] == SEC_STATUS) && diff --git a/src/service_inspectors/http_inspect/http_inspect.h b/src/service_inspectors/http_inspect/http_inspect.h index 415cc19f8..01cb18ed2 100644 --- a/src/service_inspectors/http_inspect/http_inspect.h +++ b/src/service_inspectors/http_inspect/http_inspect.h @@ -37,14 +37,12 @@ class HttpApi; class HttpInspect : public Inspector { public: - static THREAD_LOCAL uint8_t body_buffer[HttpEnums::MAX_OCTETS]; - HttpInspect(const HttpParaList* params_); ~HttpInspect() { delete params; } - bool get_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) override; - bool http_get_buf(unsigned id, uint64_t sub_id, uint64_t form, Packet*, InspectionBuffer& b); - bool get_fp_buf(InspectionBuffer::Type ibt, Packet*, InspectionBuffer& b) override; + bool get_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b) override; + bool http_get_buf(unsigned id, uint64_t sub_id, uint64_t form, Packet* p, InspectionBuffer& b); + bool get_fp_buf(InspectionBuffer::Type ibt, Packet* p, InspectionBuffer& b) override; bool configure(SnortConfig*) override { return true; } void show(SnortConfig*) override { LogMessage("HttpInspect\n"); } void eval(Packet*) override { } @@ -55,7 +53,7 @@ public: { return new HttpStreamSplitter(is_client_to_server, this); } - static HttpEnums::InspectSection get_latest_is(); + static HttpEnums::InspectSection get_latest_is(const Packet* p); private: friend HttpApi; @@ -64,10 +62,7 @@ private: const Field& process(const uint8_t* data, const uint16_t dsize, Flow* const flow, HttpEnums::SourceId source_id_, bool buf_owner) const; void clear(HttpFlowData* session_data, HttpEnums::SourceId source_id); - static HttpEnums::SourceId get_latest_src() { return (latest_section != nullptr) ? - latest_section->get_source_id() : HttpEnums::SRC__NOT_COMPUTE; } - - static THREAD_LOCAL HttpMsgSection* latest_section; + static HttpEnums::SourceId get_latest_src(const Packet* p); const HttpParaList* const params; }; diff --git a/src/service_inspectors/http_inspect/http_js_norm.cc b/src/service_inspectors/http_inspect/http_js_norm.cc index ba51b1eeb..f65525a5c 100644 --- a/src/service_inspectors/http_inspect/http_js_norm.cc +++ b/src/service_inspectors/http_inspect/http_js_norm.cc @@ -60,20 +60,20 @@ HttpJsNorm::~HttpJsNorm() delete htmltype_search_mpse; } -void HttpJsNorm::normalize(const Field& input, Field& output, bool& js_norm_alloc, - HttpInfractions& infractions, HttpEventGen& events) const +void HttpJsNorm::normalize(const Field& input, Field& output, HttpInfractions& infractions, + HttpEventGen& events) const { bool js_present = false; int index = 0; - const char* ptr = (const char*)input.start; - const char* const end = ptr + input.length; + const char* ptr = (const char*)input.start(); + const char* const end = ptr + input.length(); JSState js; js.allowed_spaces = max_javascript_whitespaces; js.allowed_levels = MAX_ALLOWED_OBFUSCATION; js.alerts = 0; - uint8_t* buffer = new uint8_t[input.length]; + uint8_t* buffer = new uint8_t[input.length()]; while (ptr < end) { @@ -119,9 +119,9 @@ void HttpJsNorm::normalize(const Field& input, Field& output, bool& js_norm_allo // Save before the