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;
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)
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)
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)
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)
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()
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)
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)
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)
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)
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() {}
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
{
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
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))
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<HttpEnums::StatusCode>(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
#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)
class HttpTransaction;
class HttpJsNorm;
+class HttpMsgSection;
class HttpFlowData : public FlowData
{
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 };
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;
}
{
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;
}
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;
}
}
}
delete[] temp_space;
- result_field.set(data_length, norm_value);
+ result_field.set(data_length, norm_value, true);
return;
}
#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,
HttpModule::increment_peg_counts(PEG_INSPECT);
+ HttpMsgSection*& latest_section = session_data->latest_section;
switch (session_data->section_type[source_id])
{
case SEC_REQUEST:
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;
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) &&
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 { }
{
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;
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;
};
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)
{
// Save before the <script> begins
if (js_start > ptr)
{
- if ((js_start - ptr) > (input.length - index))
+ if ((js_start - ptr) > (input.length() - index))
break;
- memmove_s(buffer + index, input.length - index, ptr, js_start - ptr);
+ memmove_s(buffer + index, input.length() - index, ptr, js_start - ptr);
index += js_start - ptr;
}
// FIXIT-L need to fix this library so we don't have to cast away const here.
JSNormalizeDecode((char*)js_start, (uint16_t)(end-js_start), (char*)buffer+index,
- (uint16_t)(input.length - index), (char**)&ptr, &bytes_copied, &js,
+ (uint16_t)(input.length() - index), (char**)&ptr, &bytes_copied, &js,
uri_param.iis_unicode ? uri_param.unicode_map : nullptr);
index += bytes_copied;
}
if (js_present)
{
- if ((ptr < end) && ((input.length - index) >= (end - ptr)))
+ if ((ptr < end) && ((input.length() - index) >= (end - ptr)))
{
- memmove_s(buffer + index, input.length - index, ptr, end - ptr); index += end - ptr;
+ memmove_s(buffer + index, input.length() - index, ptr, end - ptr); index += end - ptr;
}
if (js.alerts)
{
events.create_event(EVENT_MIXED_ENCODINGS);
}
}
- output.set(index, buffer);
- js_norm_alloc = true;
+ output.set(index, buffer, true);
}
else
{
public:
HttpJsNorm(int max_javascript_whitespaces_, const HttpParaList::UriParam& uri_param_);
~HttpJsNorm();
- void normalize(const Field& input, Field& output, bool& js_norm_alloc,
- HttpInfractions& infractions, HttpEventGen& events) const;
+ void normalize(const Field& input, Field& output, HttpInfractions& infractions,
+ HttpEventGen& events) const;
private:
enum JsSearchId { JS_JAVASCRIPT };
enum HtmlSearchId { HTML_JS, HTML_EMA, HTML_VB };
transaction->set_body(this);
}
-HttpMsgBody::~HttpMsgBody()
-{
- if (classic_client_body_alloc)
- classic_client_body.delete_buffer();
-
- if (decoded_body_alloc)
- decoded_body.delete_buffer();
-
- if (js_norm_body_alloc)
- js_norm_body.delete_buffer();
-}
-
void HttpMsgBody::analyze()
{
- do_utf_decoding(msg_text, decoded_body, decoded_body_alloc);
+ do_utf_decoding(msg_text, decoded_body);
if (session_data->detect_depth_remaining[source_id] > 0)
{
- do_js_normalization(decoded_body, js_norm_body, js_norm_body_alloc);
+ do_js_normalization(decoded_body, js_norm_body);
const int32_t detect_length =
- (js_norm_body.length <= session_data->detect_depth_remaining[source_id]) ?
- js_norm_body.length : session_data->detect_depth_remaining[source_id];
- detect_data.set(detect_length, js_norm_body.start);
+ (js_norm_body.length() <= session_data->detect_depth_remaining[source_id]) ?
+ js_norm_body.length() : session_data->detect_depth_remaining[source_id];
+ detect_data.set(detect_length, js_norm_body.start());
session_data->detect_depth_remaining[source_id] -= detect_length;
// Always set file data. File processing will later set a new value in some cases.
- set_file_data(const_cast<uint8_t*>(detect_data.start), (unsigned)detect_data.length);
+ set_file_data(const_cast<uint8_t*>(detect_data.start()), (unsigned)detect_data.length());
}
if (session_data->file_depth_remaining[source_id] > 0)
do_file_processing(decoded_body);
}
- body_octets += msg_text.length;
+ body_octets += msg_text.length();
}
-void HttpMsgBody::do_utf_decoding(const Field& input, Field& output, bool& decoded_alloc)
+void HttpMsgBody::do_utf_decoding(const Field& input, Field& output)
{
if (!params->normalize_utf || source_id == SRC_CLIENT)
{
{
int bytes_copied;
bool decoded;
- uint8_t* buffer = new uint8_t[input.length];
- decoded = session_data->utf_state->decode_utf((const char*)input.start, input.length,
- (char*)buffer, input.length, &bytes_copied);
+ uint8_t* buffer = new uint8_t[input.length()];
+ decoded = session_data->utf_state->decode_utf((const char*)input.start(), input.length(),
+ (char*)buffer, input.length(), &bytes_copied);
if (!decoded)
{
delete[] buffer;
}
else if (bytes_copied > 0)
{
- output.set(bytes_copied, buffer);
- decoded_alloc = true;
+ output.set(bytes_copied, buffer, true);
}
else
{
output.set(input);
}
-void HttpMsgBody::do_js_normalization(const Field& input, Field& output, bool& js_norm_alloc)
+void HttpMsgBody::do_js_normalization(const Field& input, Field& output)
{
if (!params->js_norm_param.normalize_javascript || source_id == SRC_CLIENT)
{
return;
}
- params->js_norm_param.js_norm->normalize(input, output, js_norm_alloc, infractions, events);
+ params->js_norm_param.js_norm->normalize(input, output, infractions, events);
}
void HttpMsgBody::do_file_processing(Field& file_data)
else file_position = SNORT_FILE_MIDDLE;
// Chunked body with nothing but the zero length chunk?
- if (front && (file_data.length == 0))
+ if (front && (file_data.length() == 0))
{
return;
}
- const int32_t fp_length = (file_data.length <= session_data->file_depth_remaining[source_id]) ?
- file_data.length : session_data->file_depth_remaining[source_id];
+ const int32_t fp_length = (file_data.length() <= session_data->file_depth_remaining[source_id])
+ ? file_data.length() : session_data->file_depth_remaining[source_id];
if (!session_data->mime_state[source_id])
{
file_index = request->get_http_uri()->get_file_proc_hash();
}
- if (file_flows->file_process(file_data.start, fp_length,
+ if (file_flows->file_process(file_data.start(), fp_length,
file_position, !download, file_index))
{
session_data->file_depth_remaining[source_id] -= fp_length;
if (request != nullptr)
{
const Field& tranaction_uri = request->get_uri_norm_classic();
- if (tranaction_uri.length > 0)
+ if (tranaction_uri.length() > 0)
{
- file_flows->set_file_name(tranaction_uri.start, tranaction_uri.length);
+ file_flows->set_file_name(tranaction_uri.start(), tranaction_uri.length());
}
}
}
}
else
{
- session_data->mime_state[source_id]->process_mime_data(flow, file_data.start,
+ session_data->mime_state[source_id]->process_mime_data(flow, file_data.start(),
fp_length, true, SNORT_FILE_POSITION_UNKNOWN);
session_data->file_depth_remaining[source_id] -= fp_length;
const Field& HttpMsgBody::get_classic_client_body()
{
- return classic_normalize(detect_data, classic_client_body, classic_client_body_alloc,
- params->uri_param);
+ return classic_normalize(detect_data, classic_client_body, params->uri_param);
}
#ifdef REG_TEST
class HttpMsgBody : public HttpMsgSection
{
public:
- virtual ~HttpMsgBody();
+ virtual ~HttpMsgBody() = default;
void analyze() override;
const Field& get_detect_buf() const override { return detect_data; }
HttpEnums::InspectSection get_inspection_section() const override
private:
void do_file_processing(Field& file_data);
- void do_utf_decoding(const Field& input, Field& output, bool& decoded_alloc);
- void do_js_normalization(const Field& input, Field& output, bool& js_norm_alloc);
+ void do_utf_decoding(const Field& input, Field& output);
+ void do_js_normalization(const Field& input, Field& output);
Field detect_data;
const bool detection_section;
Field classic_client_body; // URI normalization applied
- bool classic_client_body_alloc = false;
Field decoded_body;
- bool decoded_body_alloc = false;
Field js_norm_body;
- bool js_norm_body_alloc = false;
};
#endif
{
NormalizedHeader* temp_ptr = list_ptr;
list_ptr = list_ptr->next;
- temp_ptr->norm.delete_buffer();
delete temp_ptr;
}
- if (classic_raw_header_alloc)
- classic_raw_header.delete_buffer();
- if (classic_norm_header_alloc)
- classic_norm_header.delete_buffer();
- if (classic_norm_cookie_alloc)
- classic_norm_cookie.delete_buffer();
}
// All the header processing that is done for every message (i.e. not just-in-time) is done here.
// session_data->num_head_lines is computed without consideration of wrapping and may overstate
// actual number of headers. Rely on num_headers which is calculated correctly.
header_line = new Field[session_data->num_head_lines[source_id]];
- while (bytes_used < msg_text.length)
+ while (bytes_used < msg_text.length())
{
assert(num_headers < session_data->num_head_lines[source_id]);
- header_line[num_headers].start = msg_text.start + bytes_used;
- header_line[num_headers].length = find_header_end(header_line[num_headers].start,
- msg_text.length - bytes_used, num_seps);
- if (header_line[num_headers].length > MAX_HEADER_LENGTH)
+ header_line[num_headers].set(
+ find_header_end(msg_text.start() + bytes_used, msg_text.length() - bytes_used,
+ num_seps),
+ msg_text.start() + bytes_used);
+ if (header_line[num_headers].length() > MAX_HEADER_LENGTH)
{
infractions += INF_TOO_LONG_HEADER;
events.create_event(EVENT_LONG_HDR);
}
- bytes_used += header_line[num_headers++].length + num_seps;
+ bytes_used += header_line[num_headers++].length() + num_seps;
if (num_headers >= MAX_HEADERS)
{
break;
}
}
- if (bytes_used < msg_text.length)
+ if (bytes_used < msg_text.length())
{
// FIXIT-M eventually need to separate max header alert from internal maximum
infractions += INF_TOO_MANY_HEADERS;
int colon;
for (int k=0; k < num_headers; k++)
{
- for (colon=0; colon < header_line[k].length; colon++)
+ for (colon=0; colon < header_line[k].length(); colon++)
{
- if (header_line[k].start[colon] == ':')
+ if (header_line[k].start()[colon] == ':')
break;
}
- if (colon < header_line[k].length)
+ if (colon < header_line[k].length())
{
- header_name[k].start = header_line[k].start;
- header_name[k].length = colon;
- header_value[k].start = header_line[k].start + colon + 1;
- header_value[k].length = header_line[k].length - colon - 1;
+ header_name[k].set(colon, header_line[k].start());
+ header_value[k].set(header_line[k].length() - colon - 1,
+ header_line[k].start() + colon + 1);
}
else
{
void HttpMsgHeadShared::derive_header_name_id(int index)
{
- const int32_t& length = header_name[index].length;
- const uint8_t*& buffer = header_name[index].start;
+ const int32_t length = header_name[index].length();
+ const uint8_t* buffer = header_name[index].start();
if (length <= 0)
{
const Field& HttpMsgHeadShared::get_classic_raw_header()
{
- if (classic_raw_header.length != STAT_NOT_COMPUTE)
+ if (classic_raw_header.length() != STAT_NOT_COMPUTE)
return classic_raw_header;
const HeaderId cookie_head = (source_id == SRC_CLIENT) ? HEAD_COOKIE : HEAD_SET_COOKIE;
if (!headers_present[cookie_head])
// All header line Fields point into the buffer holding the entire message section.
// Calculation must account for separators between header lines, but there are none
// following the final header line.
- const int32_t head_len = (k == num_headers-1) ? header_line[k].length :
- header_line[k+1].start - header_line[k].start;
+ const int32_t head_len = (k == num_headers-1) ? header_line[k].length() :
+ header_line[k+1].start() - header_line[k].start();
length += head_len;
}
{
if (header_name_id[k] == cookie_head)
continue;
- const int32_t head_len = (k == num_headers-1) ? header_line[k].length :
- header_line[k+1].start - header_line[k].start;
- memcpy(buffer + current, header_line[k].start, head_len);
+ const int32_t head_len = (k == num_headers-1) ? header_line[k].length() :
+ header_line[k+1].start() - header_line[k].start();
+ memcpy(buffer + current, header_line[k].start(), head_len);
current += head_len;
}
assert(current == length);
- classic_raw_header.set(length, buffer);
- classic_raw_header_alloc = true;
+ classic_raw_header.set(length, buffer, true);
return classic_raw_header;
}
const Field& HttpMsgHeadShared::get_classic_norm_header()
{
- return classic_normalize(get_classic_raw_header(), classic_norm_header,
- classic_norm_header_alloc, params->uri_param);
+ return classic_normalize(get_classic_raw_header(), classic_norm_header, params->uri_param);
}
const Field& HttpMsgHeadShared::get_classic_raw_cookie()
const Field& HttpMsgHeadShared::get_classic_norm_cookie()
{
- return classic_normalize(get_classic_raw_cookie(), classic_norm_cookie,
- classic_norm_cookie_alloc, params->uri_param);
+ return classic_normalize(get_classic_raw_cookie(), classic_norm_cookie, params->uri_param);
}
const Field& HttpMsgHeadShared::get_header_value_raw(HeaderId header_id) const
}
for (int k=1; k <= HEAD__MAX_VALUE-1; k++)
{
- if (get_header_value_norm((HeaderId)k).length != STAT_NO_SOURCE)
+ if (get_header_value_norm((HeaderId)k).length() != STAT_NO_SOURCE)
{
snprintf(title_buf, sizeof(title_buf), "Normalized header %d", k);
get_header_value_norm((HeaderId)k).print(output, title_buf);
Field* header_value = nullptr;
Field classic_raw_header; // raw headers with cookies spliced out
- bool classic_raw_header_alloc = false;
Field classic_norm_header; // URI normalization applied
- bool classic_norm_header_alloc = false;
Field classic_norm_cookie; // URI normalization applied to concatenated cookie values
- bool classic_norm_cookie_alloc = false;
struct NormalizedHeader
{
int32_t HttpMsgHeadShared::get_next_code(const Field& field, int32_t& offset,
const StrCode table[])
{
- assert(field.length > 0);
- const uint8_t* start = field.start + offset;
+ assert(field.length() > 0);
+ const uint8_t* start = field.start() + offset;
int32_t length;
- for (length = 0; (offset+length < field.length) && (*(start+length) != ','); length++);
+ for (length = 0; (offset+length < field.length()) && (*(start+length) != ','); length++);
offset += length + 1;
return str_to_code(start, length, table);
}
// Case insensitive search for the substring "boundary="
bool HttpMsgHeadShared::boundary_present(const Field& field)
{
- assert(field.length > 0);
+ assert(field.length() > 0);
const char* const BOUNDARY = "boundary=";
const int BOUNDARY_LEN = 9;
- for (int k = 0; k + BOUNDARY_LEN <= field.length; k++)
+ for (int k = 0; k + BOUNDARY_LEN <= field.length(); k++)
{
- if (strncasecmp(BOUNDARY, (const char*)(field.start + k), BOUNDARY_LEN) == 0)
+ if (strncasecmp(BOUNDARY, (const char*)(field.start() + k), BOUNDARY_LEN) == 0)
return true;
}
return false;
}
// If there is a Transfer-Encoding header, see if the last of the encoded values is "chunked".
- if (get_header_value_norm(HEAD_TRANSFER_ENCODING).length > 0)
+ if (get_header_value_norm(HEAD_TRANSFER_ENCODING).length() > 0)
{
if (chunked_before_end(get_header_value_norm(HEAD_TRANSFER_ENCODING)))
{
// else because Transfer-Encoding header negates Content-Length header even if something was
// wrong with Transfer-Encoding header.
- else if (get_header_value_norm(HEAD_CONTENT_LENGTH).length > 0)
+ else if (get_header_value_norm(HEAD_CONTENT_LENGTH).length() > 0)
{
const int64_t content_length =
norm_decimal_integer(get_header_value_norm(HEAD_CONTENT_LENGTH));
if (source_id == SRC_CLIENT)
{
const Field& content_type = get_header_value_raw(HEAD_CONTENT_TYPE);
- if (content_type.length > 0)
+ if (content_type.length() > 0)
{
if (boundary_present(content_type))
{
// This interface is a leftover from when OHI pushed whole messages through
// this interface.
session_data->mime_state[source_id]->process_mime_data(flow,
- content_type.start, content_type.length, true,
+ content_type.start(), content_type.length(), true,
SNORT_FILE_POSITION_UNKNOWN);
session_data->mime_state[source_id]->process_mime_data(flow,
(const uint8_t*)"\r\n", 2, true, SNORT_FILE_POSITION_UNKNOWN);
const Field& norm_content_encoding = get_header_value_norm(HEAD_CONTENT_ENCODING);
int32_t cont_offset = 0;
- while (norm_content_encoding.length > cont_offset)
+ while (norm_content_encoding.length() > cont_offset)
{
const Contentcoding content_code = (Contentcoding)get_next_code(norm_content_encoding,
cont_offset, HttpMsgHeadShared::content_code_list);
const Field& norm_transfer_encoding = get_header_value_norm(HEAD_TRANSFER_ENCODING);
int32_t trans_offset = 0;
- while (norm_transfer_encoding.length > trans_offset)
+ while (norm_transfer_encoding.length() > trans_offset)
{
const Transcoding transfer_code = (Transcoding)get_next_code(norm_transfer_encoding,
trans_offset, HttpMsgHeadShared::trans_code_list);
return;
const Field& norm_content_type = get_header_value_norm(HEAD_CONTENT_TYPE);
- if (norm_content_type.length <= 0)
+ if (norm_content_type.length() <= 0)
return;
get_last_token(norm_content_type, last_token, ';');
// No semicolon in the Content-Type header
- if ( last_token.length == norm_content_type.length )
+ if ( last_token.length() == norm_content_type.length() )
{
- if( SnortStrnStr((const char*)norm_content_type.start, norm_content_type.length, "text") )
+ if (SnortStrnStr((const char*)norm_content_type.start(), norm_content_type.length(),
+ "text"))
{
charset_code = CHARSET_UNKNOWN;
}
}
else
{
-
- charset_code = (CharsetCode)str_to_code(last_token.start, last_token.length, HttpMsgHeadShared::charset_code_list);
+ charset_code = (CharsetCode)str_to_code(last_token.start(), last_token.length(),
+ HttpMsgHeadShared::charset_code_list);
if( charset_code == CHARSET_OTHER )
{
- charset_code = (CharsetCode)substr_to_code(last_token.start, last_token.length, HttpMsgHeadShared::charset_code_opt_list);
+ charset_code = (CharsetCode)substr_to_code(last_token.start(), last_token.length(),
+ HttpMsgHeadShared::charset_code_opt_list);
if ( charset_code != CHARSET_UNKNOWN )
return;
void HttpMsgRequest::parse_start_line()
{
// Check the version field
- if ((start_line.length < 10) || !is_sp_tab[start_line.start[start_line.length-9]] ||
- memcmp(start_line.start + start_line.length - 8, "HTTP/", 5))
+ if ((start_line.length() < 10) || !is_sp_tab[start_line.start()[start_line.length()-9]] ||
+ memcmp(start_line.start() + start_line.length() - 8, "HTTP/", 5))
{
if (!handle_zero_nine())
{
// Just a plain old bad request
infractions += INF_BAD_REQ_LINE;
- events.generate_misformatted_http(start_line.start, start_line.length);
+ events.generate_misformatted_http(start_line.start(), start_line.length());
}
return;
}
// octets 2-81. The following algorithm uses those assumptions.
int32_t first_space; // first whitespace in request line
- for (first_space = 1; !is_sp_tab[start_line.start[first_space]]; first_space++);
+ for (first_space = 1; !is_sp_tab[start_line.start()[first_space]]; first_space++);
int32_t first_end; // last whitespace in first clump of whitespace
- for (first_end = first_space+1; is_sp_tab[start_line.start[first_end]]; first_end++);
+ for (first_end = first_space+1; is_sp_tab[start_line.start()[first_end]]; first_end++);
first_end--;
int32_t last_begin; // first whitespace in clump of whitespace before version
- for (last_begin = start_line.length - 10; is_sp_tab[start_line.start[last_begin]];
+ for (last_begin = start_line.length() - 10; is_sp_tab[start_line.start()[last_begin]];
last_begin--);
last_begin++;
- method.start = start_line.start;
- method.length = first_space;
- method_id = (MethodId)str_to_code(method.start, method.length, method_list);
+ method.set(first_space, start_line.start());
+ method_id = (MethodId)str_to_code(method.start(), method.length(), method_list);
switch (method_id)
{
default: HttpModule::increment_peg_counts(PEG_OTHER_METHOD); break;
}
- version.start = start_line.start + (start_line.length - 8);
- version.length = 8;
+ version.set(8, start_line.start() + (start_line.length() - 8));
derive_version_id();
if (first_end < last_begin)
{
- uri = new HttpUri(start_line.start + first_end + 1, last_begin - first_end - 1,
+ uri = new HttpUri(start_line.start() + first_end + 1, last_begin - first_end - 1,
method_id, params->uri_param, infractions, events);
}
else
bool HttpMsgRequest::handle_zero_nine()
{
// 0.9 request line is supposed to be "GET <URI>\r\n"
- if ((start_line.length >= 3) &&
- !memcmp(start_line.start, "GET", 3) &&
- ((start_line.length == 3) || is_sp_tab[start_line.start[3]]))
+ if ((start_line.length() >= 3) &&
+ !memcmp(start_line.start(), "GET", 3) &&
+ ((start_line.length() == 3) || is_sp_tab[start_line.start()[3]]))
{
infractions += INF_ZERO_NINE_REQ;
events.create_event(EVENT_SIMPLE_REQUEST);
- method.set(3, start_line.start);
+ method.set(3, start_line.start());
method_id = METH_GET;
version_id = VERS_0_9;
// Eliminate the clump of whitespace following GET and possible clump of whitespace at the
// end and whatever is left is assumed to be the URI
int32_t uri_begin;
- for (uri_begin = 4; (uri_begin < start_line.length) &&
- is_sp_tab[start_line.start[uri_begin]]; uri_begin++);
- if (uri_begin < start_line.length)
+ for (uri_begin = 4; (uri_begin < start_line.length()) &&
+ is_sp_tab[start_line.start()[uri_begin]]; uri_begin++);
+ if (uri_begin < start_line.length())
{
int32_t uri_end;
- for (uri_end = start_line.length - 1; is_sp_tab[start_line.start[uri_end]]; uri_end--);
- uri = new HttpUri(start_line.start + uri_begin, uri_end - uri_begin + 1, method_id,
+ for (uri_end = start_line.length() - 1; is_sp_tab[start_line.start()[uri_end]];
+ uri_end--);
+ uri = new HttpUri(start_line.start() + uri_begin, uri_end - uri_begin + 1, method_id,
params->uri_param, infractions, events);
}
else
const bool zero_nine = infractions & INF_ZERO_NINE_REQ;
- if ((start_line.start[method.length] == '\t') ||
- (!zero_nine && (start_line.start[start_line.length - 9] == '\t')))
+ if ((start_line.start()[method.length()] == '\t') ||
+ (!zero_nine && (start_line.start()[start_line.length() - 9] == '\t')))
{
infractions += INF_REQUEST_TAB;
events.create_event(EVENT_APACHE_WS);
// Look for white space issues in and around the URI.
// Supposed to be <method><space><URI><space><version> or 0.9 format GET<space><URI>
- const int32_t version_start = !zero_nine ? start_line.length - 9 : start_line.length;
- for (int32_t k = method.length + 1; k < version_start; k++)
+ const int32_t version_start = !zero_nine ? start_line.length() - 9 : start_line.length();
+ for (int32_t k = method.length() + 1; k < version_start; k++)
{
- if (is_sp_tab[start_line.start[k]])
+ if (is_sp_tab[start_line.start()[k]])
{
- if (uri && (uri->get_uri().start <= start_line.start + k) &&
- (start_line.start + k < uri->get_uri().start + uri->get_uri().length))
+ if (uri && (uri->get_uri().start() <= start_line.start() + k) &&
+ (start_line.start() + k < uri->get_uri().start() + uri->get_uri().length()))
{
// white space inside the URI is not allowed
- if (start_line.start[k] == ' ')
+ if (start_line.start()[k] == ' ')
{
infractions += INF_URI_SPACE;
events.create_event(EVENT_UNESCAPED_SPACE_URI);
// extra white space before or after the URI
infractions += INF_REQUEST_WS;
events.create_event(EVENT_IMPROPER_WS);
- if (start_line.start[k] == '\t')
+ if (start_line.start()[k] == '\t')
{
// which is also a tab
infractions += INF_REQUEST_TAB;
HttpMsgSection::HttpMsgSection(const uint8_t* buffer, const uint16_t buf_size,
HttpFlowData* session_data_, SourceId source_id_, bool buf_owner, Flow* flow_,
const HttpParaList* params_) :
- msg_text(buf_size, buffer),
+ msg_text(buf_size, buffer, buf_owner),
session_data(session_data_),
source_id(source_id_),
flow(flow_),
events(session_data->events[source_id]),
version_id(session_data->version_id[source_id]),
method_id((source_id == SRC_CLIENT) ? session_data->method_id : METH__NOT_PRESENT),
- status_code_num((source_id == SRC_SERVER) ? session_data->status_code_num : STAT_NOT_PRESENT),
- delete_msg_on_destruct(buf_owner)
+ status_code_num((source_id == SRC_SERVER) ? session_data->status_code_num : STAT_NOT_PRESENT)
{
assert((source_id == SRC_CLIENT) || (source_id == SRC_SERVER));
}
}
}
-const Field& HttpMsgSection::classic_normalize(const Field& raw, Field& norm, bool& norm_alloc,
+const Field& HttpMsgSection::classic_normalize(const Field& raw, Field& norm,
const HttpParaList::UriParam& uri_param)
{
- if (norm.length != STAT_NOT_COMPUTE)
+ if (norm.length() != STAT_NOT_COMPUTE)
return norm;
- if ((raw.length <= 0) || !UriNormalizer::classic_need_norm(raw, true, uri_param))
+ if ((raw.length() <= 0) || !UriNormalizer::classic_need_norm(raw, true, uri_param))
{
norm.set(raw);
return norm;
}
- uint8_t* buffer = new uint8_t[raw.length + UriNormalizer::URI_NORM_EXPANSION];
- UriNormalizer::classic_normalize(raw, norm, buffer, uri_param);
- norm_alloc = true;
+ UriNormalizer::classic_normalize(raw, norm, uri_param);
return norm;
}
class HttpMsgSection
{
public:
- virtual ~HttpMsgSection() { if (delete_msg_on_destruct) delete[] msg_text.start; }
+ virtual ~HttpMsgSection() = default;
virtual HttpEnums::InspectSection get_inspection_section() const
{ return HttpEnums::IS_NONE; }
HttpEnums::SourceId get_source_id() { return source_id; }
// Convenience methods shared by multiple subclasses
void update_depth() const;
- static const Field& classic_normalize(const Field& raw, Field& norm, bool& norm_alloc,
+ static const Field& classic_normalize(const Field& raw, Field& norm,
const HttpParaList::UriParam& uri_param);
#ifdef REG_TEST
void print_section_title(FILE* output, const char* title) const;
void print_section_wrapup(FILE* output) const;
void print_peg_counts(FILE* output) const;
#endif
-
-private:
- const bool delete_msg_on_destruct;
};
#endif
void HttpMsgStart::analyze()
{
- start_line.start = msg_text.start;
- start_line.length = msg_text.length;
+ start_line.set(msg_text);
parse_start_line();
gen_events();
}
void HttpMsgStart::derive_version_id()
{
- if (version.start[6] != '.')
+ if (version.start()[6] != '.')
{
version_id = VERS__PROBLEMATIC;
infractions += INF_BAD_VERSION;
events.create_event(EVENT_BAD_VERS);
}
- else if ((version.start[5] == '1') && (version.start[7] == '1'))
+ else if ((version.start()[5] == '1') && (version.start()[7] == '1'))
{
version_id = VERS_1_1;
}
- else if ((version.start[5] == '1') && (version.start[7] == '0'))
+ else if ((version.start()[5] == '1') && (version.start()[7] == '0'))
{
version_id = VERS_1_0;
}
- else if ((version.start[5] == '2') && (version.start[7] == '0'))
+ else if ((version.start()[5] == '2') && (version.start()[7] == '0'))
{
version_id = VERS_2_0;
}
- else if ((version.start[5] == '0') && (version.start[7] == '9'))
+ else if ((version.start()[5] == '0') && (version.start()[7] == '9'))
{
// Real 0.9 traffic would never be labeled HTTP/0.9 because 0.9 is older than the version
// system. Aside from the possibility that someone might do this to make trouble,
// labeled 0.9.
version_id = VERS_0_9;
}
- else if ((version.start[5] >= '0') && (version.start[5] <= '9') &&
- (version.start[7] >= '0') && (version.start[7] <= '9'))
+ else if ((version.start()[5] >= '0') && (version.start()[5] <= '9') &&
+ (version.start()[7] >= '0') && (version.start()[7] <= '9'))
{
version_id = VERS__OTHER;
infractions += INF_UNKNOWN_VERSION;
{
// Splitter guarantees line begins with "HTTP/"
- if ((start_line.length < 12) || !is_sp_tab[start_line.start[8]])
+ if ((start_line.length() < 12) || !is_sp_tab[start_line.start()[8]])
{
infractions += INF_BAD_STAT_LINE;
events.create_event(EVENT_MISFORMATTED_HTTP);
}
int32_t first_end; // last whitespace in first clump of whitespace
- for (first_end = 9; (first_end < start_line.length) && is_sp_tab[start_line.start[first_end]];
- first_end++);
+ for (first_end = 9; (first_end < start_line.length())
+ && is_sp_tab[start_line.start()[first_end]]; first_end++);
first_end--;
- if (start_line.length < first_end + 4)
+ if (start_line.length() < first_end + 4)
{
infractions += INF_BAD_STAT_LINE;
events.create_event(EVENT_MISFORMATTED_HTTP);
return;
}
- if ((start_line.length > first_end + 4) && !is_sp_tab[start_line.start[first_end + 4]])
+ if ((start_line.length() > first_end + 4) && !is_sp_tab[start_line.start()[first_end + 4]])
{
// FIXIT-M This should not be fatal. HI supports something like "HTTP/1.1 200\\OK\r\n" as
// seen in a status line test.
HttpModule::increment_peg_counts(PEG_RESPONSE);
- version.start = start_line.start;
- version.length = 8;
+ version.set(8, start_line.start());
derive_version_id();
- status_code.start = start_line.start + first_end + 1;
- status_code.length = 3;
+ status_code.set(3, start_line.start() + first_end + 1);
derive_status_code_num();
- if (start_line.length > first_end + 5)
+ if (start_line.length() > first_end + 5)
{
- reason_phrase.start = start_line.start + first_end + 5;
- reason_phrase.length = start_line.length - first_end - 5;
+ reason_phrase.set(start_line.length() - first_end - 5, start_line.start() + first_end + 5);
}
}
void HttpMsgStatus::derive_status_code_num()
{
- if ((status_code.start[0] < '0') || (status_code.start[0] > '9') || (status_code.start[1] <
- '0') || (status_code.start[1] > '9') ||
- (status_code.start[2] < '0') || (status_code.start[2] > '9'))
+ if ((status_code.start()[0] < '0') || (status_code.start()[0] > '9') ||
+ (status_code.start()[1] < '0') || (status_code.start()[1] > '9') ||
+ (status_code.start()[2] < '0') || (status_code.start()[2] > '9'))
{
infractions += INF_BAD_STAT_CODE;
events.create_event(EVENT_INVALID_STATCODE);
status_code_num = STAT_PROBLEMATIC;
return;
}
- status_code_num = (status_code.start[0] - '0') * 100 + (status_code.start[1] - '0') * 10 +
- (status_code.start[2] - '0');
+ status_code_num = (status_code.start()[0] - '0') * 100 + (status_code.start()[1] - '0') * 10 +
+ (status_code.start()[2] - '0');
if ((status_code_num < 100) || (status_code_num > 599))
{
infractions += INF_BAD_STAT_CODE;
if (infractions & INF_BAD_STAT_LINE)
return;
- if (status_code.start > start_line.start + 9)
+ if (status_code.start() > start_line.start() + 9)
{
infractions += INF_STATUS_WS;
events.create_event(EVENT_IMPROPER_WS);
}
- for (int k = 8; k < status_code.start - start_line.start; k++)
+ for (int k = 8; k < status_code.start() - start_line.start(); k++)
{
- if (start_line.start[k] == '\t')
+ if (start_line.start()[k] == '\t')
{
infractions += INF_STATUS_TAB;
events.create_event(EVENT_APACHE_WS);
}
}
- if (status_code.start - start_line.start + 3 < start_line.length)
+ if (status_code.start() - start_line.start() + 3 < start_line.length())
{
- if (status_code.start[3] == '\t')
+ if (status_code.start()[3] == '\t')
{
infractions += INF_STATUS_TAB;
events.create_event(EVENT_APACHE_WS);
}
}
- for (int k=0; k < reason_phrase.length; k++)
+ for (int k=0; k < reason_phrase.length(); k++)
{
- if ((reason_phrase.start[k] <= 31) || (reason_phrase.start[k] >= 127))
+ if ((reason_phrase.start()[k] <= 31) || (reason_phrase.start()[k] >= 127))
{
// Illegal character in reason phrase
infractions += INF_BAD_PHRASE;
// Convert a decimal field such as Content-Length to an integer.
int64_t norm_decimal_integer(const Field& input)
{
- assert(input.length > 0);
+ assert(input.length() > 0);
// Limited to 18 decimal digits, not including leading zeros, to fit comfortably into int64_t
int64_t total = 0;
int non_leading_zeros = 0;
- for (int32_t k=0; k < input.length; k++)
+ for (int32_t k=0; k < input.length(); k++)
{
- int value = input.start[k] - '0';
+ int value = input.start()[k] - '0';
if ((non_leading_zeros > 0) || (value != 0))
non_leading_zeros++;
if (non_leading_zeros > 18)
void get_last_token(const Field& input, Field& last_token, char ichar)
{
- assert(input.length > 0);
- for (last_token.start = input.start + input.length - 1; (last_token.start >= input.start) &&
- (*(last_token.start)!= ichar); (last_token.start)--);
- (last_token.start)++;
- last_token.length = input.length - (last_token.start - input.start);
+ assert(input.length() > 0);
+ const uint8_t* last_start = input.start() + input.length() - 1;
+ for (; (last_start >= input.start()) && (*last_start != ichar); last_start--);
+ last_start++;
+ last_token.set(input.length() - (last_start - input.start()), last_start);
return;
}
Field last_token;
get_last_token(input, last_token, ',');
- return str_to_code(last_token.start, last_token.length, table);
+ return str_to_code(last_token.start(), last_token.length(), table);
}
// Given a comma-separated list of words, does "chunked" appear before the last word
bool chunked_before_end(const Field& input)
{
- for (int k=0; k < (input.length - 7); k++)
+ for (int k=0; k < (input.length() - 7); k++)
{
- if (((k == 0) || (input.start[k-1] == ',')) && !memcmp(input.start+k, "chunked,", 8))
+ if (((k == 0) || (input.start()[k-1] == ',')) && !memcmp(input.start()+k, "chunked,", 8))
{
return true;
}
HttpModule::increment_peg_counts(PEG_REASSEMBLE);
- uint8_t*& buffer = session_data->section_buffer[source_id];
-
const bool is_body = (session_data->section_type[source_id] == SEC_BODY_CHUNK) ||
(session_data->section_type[source_id] == SEC_BODY_CL) ||
(session_data->section_type[source_id] == SEC_BODY_OLD);
+ uint8_t*& buffer = session_data->section_buffer[source_id];
if (buffer == nullptr)
{
- // The type of buffer used is based on section type. All body sections reuse a single
- // static buffer. Other sections use a dynamic buffer that may be saved for a while.
- // Changes here must be mirrored below where the buffer is passed to HttpInspect::process
- // and in ~HttpFlowData where the buffer will be deleted if it has not been processed.
+ // Body sections need extra space to accommodate unzipping
if (is_body)
- {
- buffer = HttpInspect::body_buffer;
- }
+ buffer = new uint8_t[MAX_OCTETS];
else
- {
buffer = new uint8_t[total];
- }
- }
+ }
if (session_data->section_type[source_id] != SEC_BODY_CHUNK)
{
{
const Field& send_to_detection = my_inspector->process(buffer,
session_data->section_offset[source_id] - session_data->num_excess[source_id], flow,
- source_id, !is_body);
+ source_id, true);
// delete[] not necessary because HttpMsgSection is now responsible.
buffer = nullptr;
// framework and forwarded to detection even if it is empty. Other body sections and the
// trailer section are only forwarded if nonempty. The start line section and header
// sections other than the detection section are never forwarded.
- if (((send_to_detection.length > 0) && (HttpInspect::get_latest_is() != IS_NONE)) ||
- ((send_to_detection.length == 0) && (HttpInspect::get_latest_is() == IS_DETECTION)))
+ if (((send_to_detection.length() > 0) &&
+ (session_data->latest_section->get_inspection_section() != IS_NONE)) ||
+ ((send_to_detection.length() == 0) &&
+ (session_data->latest_section->get_inspection_section() == IS_DETECTION)))
{
// FIXIT-M kludge until we work out issues with returning an empty buffer
- if (send_to_detection.length > 0)
+ if (send_to_detection.length() > 0)
{
- http_buf.data = send_to_detection.start;
- http_buf.length = send_to_detection.length;
+ http_buf.data = send_to_detection.start();
+ http_buf.length = send_to_detection.length();
}
else
{
using namespace HttpEnums;
-HttpUri::~HttpUri()
-{
- if (classic_norm_allocated)
- delete[] classic_norm.start;
-}
-
void HttpUri::parse_uri()
{
// Four basic types of HTTP URI
// "*" means request does not apply to any specific resource
- if ((uri.length == 1) && (uri.start[0] == '*'))
+ if ((uri.length() == 1) && (uri.start()[0] == '*'))
{
uri_type = URI_ASTERISK;
- scheme.length = STAT_NOT_PRESENT;
- authority.length = STAT_NOT_PRESENT;
- abs_path.length = STAT_NOT_PRESENT;
+ scheme.set(STAT_NOT_PRESENT);
+ authority.set(STAT_NOT_PRESENT);
+ abs_path.set(STAT_NOT_PRESENT);
}
// CONNECT method uses an authority
else if (method_id == METH_CONNECT)
{
uri_type = URI_AUTHORITY;
- scheme.length = STAT_NOT_PRESENT;
- authority.length = uri.length;
- authority.start = uri.start;
- abs_path.length = STAT_NOT_PRESENT;
+ scheme.set(STAT_NOT_PRESENT);
+ authority.set(uri);
+ abs_path.set(STAT_NOT_PRESENT);
}
// Absolute path is a path but no scheme or authority
- else if (uri.start[0] == '/')
+ else if (uri.start()[0] == '/')
{
uri_type = URI_ABSPATH;
- scheme.length = STAT_NOT_PRESENT;
- authority.length = STAT_NOT_PRESENT;
- abs_path.length = uri.length;
- abs_path.start = uri.start;
+ scheme.set(STAT_NOT_PRESENT);
+ authority.set(STAT_NOT_PRESENT);
+ abs_path.set(uri);
}
// Absolute URI includes scheme, authority, and path
else
// Find the "://" and then the "/"
int j;
int k;
- for (j = 0; (j < uri.length) && (uri.start[j] != ':'); j++);
- for (k = j+3; (k < uri.length) && (uri.start[k] != '/'); k++);
- if ((k < uri.length) && (uri.start[j+1] == '/') && (uri.start[j+2] == '/'))
+ for (j = 0; (j < uri.length()) && (uri.start()[j] != ':'); j++);
+ for (k = j+3; (k < uri.length()) && (uri.start()[k] != '/'); k++);
+ if ((k < uri.length()) && (uri.start()[j+1] == '/') && (uri.start()[j+2] == '/'))
{
uri_type = URI_ABSOLUTE;
- scheme.length = j;
- scheme.start = uri.start;
- authority.length = k - j - 3;
- authority.start = uri.start + j + 3;
- abs_path.length = uri.length - k;
- abs_path.start = uri.start + k;
+ scheme.set(j, uri.start());
+ authority.set(k - j - 3, uri.start() + j + 3);
+ abs_path.set(uri.length() - k, uri.start() + k);
}
else
{
infractions += INF_BAD_URI;
events.create_event(EVENT_URI_BAD_FORMAT);
uri_type = URI__PROBLEMATIC;
- scheme.length = STAT_PROBLEMATIC;
- authority.length = STAT_PROBLEMATIC;
- abs_path.length = STAT_PROBLEMATIC;
+ scheme.set(STAT_PROBLEMATIC);
+ authority.set(STAT_PROBLEMATIC);
+ abs_path.set(STAT_PROBLEMATIC);
}
}
}
void HttpUri::parse_authority()
{
- if (authority.length <= 0)
+ if (authority.length() <= 0)
{
- host.length = STAT_NO_SOURCE;
- port.length = STAT_NO_SOURCE;
+ host.set(STAT_NO_SOURCE);
+ port.set(STAT_NO_SOURCE);
return;
}
- host.start = authority.start;
- for (host.length = 0; (host.length < authority.length) &&
- (authority.start[host.length] != ':'); host.length++);
- if (host.length < authority.length)
+ int32_t host_len;
+ for (host_len = 0; (host_len < authority.length()) && (authority.start()[host_len] != ':');
+ host_len++);
+ host.set(host_len, authority.start());
+ if (host.length() < authority.length())
{
- port.length = authority.length - host.length - 1;
- port.start = authority.start + host.length + 1;
+ port.set(authority.length() - host.length() - 1, authority.start() + host.length() + 1);
}
else
- port.length = STAT_NOT_PRESENT;
+ port.set(STAT_NOT_PRESENT);
}
void HttpUri::parse_abs_path()
{
// path?query#fragment
// path is always present in absolute path, while query and fragment are optional
- if (abs_path.length <= 0)
+ if (abs_path.length() <= 0)
{
- path.length = STAT_NO_SOURCE;
- query.length = STAT_NO_SOURCE;
- fragment.length = STAT_NO_SOURCE;
+ path.set(STAT_NO_SOURCE);
+ query.set(STAT_NO_SOURCE);
+ fragment.set(STAT_NO_SOURCE);
return;
}
- path.start = abs_path.start;
- for (path.length = 0; (path.length < abs_path.length) && (abs_path.start[path.length] != '?')
- && (abs_path.start[path.length] != '#'); path.length++);
- if (path.length == abs_path.length)
+ int32_t path_len;
+ for (path_len = 0; (path_len < abs_path.length()) && (abs_path.start()[path_len] != '?') &&
+ (abs_path.start()[path_len] != '#'); path_len++);
+ path.set(path_len, abs_path.start());
+ if (path.length() == abs_path.length())
{
- query.length = STAT_NOT_PRESENT;
- fragment.length = STAT_NOT_PRESENT;
+ query.set(STAT_NOT_PRESENT);
+ fragment.set(STAT_NOT_PRESENT);
return;
}
- if (abs_path.start[path.length] == '?')
+ if (abs_path.start()[path.length()] == '?')
{
- query.start = abs_path.start + path.length + 1;
- for (query.length = 0; (query.length < abs_path.length - path.length - 1) &&
- (query.start[query.length] != '#'); query.length++);
- if (abs_path.length - path.length - 1 - query.length == 0)
+ int32_t query_len;
+ const uint8_t* const query_start = abs_path.start() + path.length() + 1;
+ for (query_len = 0; (query_len < abs_path.length() - path.length() - 1) &&
+ (query_start[query_len] != '#'); query_len++);
+ query.set(query_len, query_start);
+ if (abs_path.length() - path.length() - 1 - query.length() == 0)
{
- fragment.length = STAT_NOT_PRESENT;
+ fragment.set(STAT_NOT_PRESENT);
return;
}
- fragment.start = query.start + query.length + 1;
- fragment.length = abs_path.length - path.length - 1 - query.length - 1;
+ fragment.set(abs_path.length() - path.length() - 1 - query.length() - 1,
+ query.start() + query.length() + 1);
}
else
{
- query.length = STAT_NOT_PRESENT;
- fragment.start = abs_path.start + path.length + 1;
- fragment.length = abs_path.length - path.length - 1;
+ query.set(STAT_NOT_PRESENT);
+ fragment.set(abs_path.length() - path.length() - 1, abs_path.start() + path.length() + 1);
}
}
const uint8_t* cur;
const uint8_t* end;
- if ( uri_field.length <= 0 )
+ if ( uri_field.length() <= 0 )
return;
- cur = uri_field.start;
- end = uri_field.start + uri_field.length;
+ cur = uri_field.start();
+ end = uri_field.start() + uri_field.length();
while ( cur < end )
{
// Almost all HTTP requests are honest and rarely need expensive normalization processing. We
// do a quick scan for red flags and only perform normalization if something comes up.
// Otherwise we set the normalized fields to point at the raw values.
- if ((host.length > 0) && UriNormalizer::need_norm(host, false, uri_param, infractions, events))
+ if ((host.length() > 0) &&
+ UriNormalizer::need_norm(host, false, uri_param, infractions, events))
infractions += INF_URI_NEED_NORM_HOST;
- if ((path.length > 0) && UriNormalizer::need_norm(path, true, uri_param, infractions, events))
+ if ((path.length() > 0) &&
+ UriNormalizer::need_norm(path, true, uri_param, infractions, events))
infractions += INF_URI_NEED_NORM_PATH;
- if ((query.length > 0) && UriNormalizer::need_norm(query, false, uri_param, infractions,
- events))
+ if ((query.length() > 0) &&
+ UriNormalizer::need_norm(query, false, uri_param, infractions, events))
infractions += INF_URI_NEED_NORM_QUERY;
- if ((fragment.length > 0) && UriNormalizer::need_norm(fragment, false, uri_param, infractions,
- events))
+ if ((fragment.length() > 0) &&
+ UriNormalizer::need_norm(fragment, false, uri_param, infractions, events))
infractions += INF_URI_NEED_NORM_FRAGMENT;
if (!((infractions & INF_URI_NEED_NORM_PATH) || (infractions & INF_URI_NEED_NORM_HOST) ||
(infractions & INF_URI_NEED_NORM_QUERY) || (infractions & INF_URI_NEED_NORM_FRAGMENT)))
{
// This URI is OK, normalization not required
- host_norm = host;
- path_norm = path;
- query_norm = query;
- fragment_norm = fragment;
- classic_norm = uri;
+ host_norm.set(host);
+ path_norm.set(path);
+ query_norm.set(query);
+ fragment_norm.set(fragment);
+ classic_norm.set(uri);
check_oversize_dir(path_norm);
return;
}
HttpModule::increment_peg_counts(PEG_URI_NORM);
// Create a new buffer containing the normalized URI by normalizing each individual piece.
- const uint32_t total_length = uri.length + UriNormalizer::URI_NORM_EXPANSION;
+ const uint32_t total_length = uri.length() + UriNormalizer::URI_NORM_EXPANSION;
uint8_t* const new_buf = new uint8_t[total_length];
uint8_t* current = new_buf;
- if (scheme.length >= 0)
+ if (scheme.length() >= 0)
{
- memcpy(current, scheme.start, scheme.length);
- current += scheme.length;
+ memcpy(current, scheme.start(), scheme.length());
+ current += scheme.length();
memcpy(current, "://", 3);
current += 3;
}
- if (host.length > 0)
+ if (host.length() > 0)
{
if (infractions & INF_URI_NEED_NORM_HOST)
UriNormalizer::normalize(host, host_norm, false, current, uri_param, infractions,
// We need a copy of the raw host to provide that part of the normalized URI buffer we
// are assembling. But the normalized component will refer to the original raw buffer
// on the chance that the data retention policy in use might keep it longer.
- memcpy(current, host.start, host.length);
- host_norm = host;
+ memcpy(current, host.start(), host.length());
+ host_norm.set(host);
}
- current += host_norm.length;
+ current += host_norm.length();
}
- if (port.length >= 0)
+ if (port.length() >= 0)
{
memcpy(current, ":", 1);
current += 1;
- memcpy(current, port.start, port.length);
- current += port.length;
+ memcpy(current, port.start(), port.length());
+ current += port.length();
}
- if (path.length > 0)
+ if (path.length() > 0)
{
if (infractions & INF_URI_NEED_NORM_PATH)
UriNormalizer::normalize(path, path_norm, true, current, uri_param, infractions,
events);
else
{
- memcpy(current, path.start, path.length);
- path_norm = path;
+ memcpy(current, path.start(), path.length());
+ path_norm.set(path);
}
- current += path_norm.length;
+ current += path_norm.length();
}
- if (query.length >= 0)
+ if (query.length() >= 0)
{
memcpy(current, "?", 1);
current += 1;
events);
else
{
- memcpy(current, query.start, query.length);
- query_norm = query;
+ memcpy(current, query.start(), query.length());
+ query_norm.set(query);
}
- current += query_norm.length;
+ current += query_norm.length();
}
- if (fragment.length >= 0)
+ if (fragment.length() >= 0)
{
memcpy(current, "#", 1);
current += 1;
infractions, events);
else
{
- memcpy(current, fragment.start, fragment.length);
- fragment_norm = fragment;
+ memcpy(current, fragment.start(), fragment.length());
+ fragment_norm.set(fragment);
}
- current += fragment_norm.length;
+ current += fragment_norm.length();
}
assert(current - new_buf <= total_length);
check_oversize_dir(path_norm);
- classic_norm.set(current - new_buf, new_buf);
- classic_norm_allocated = true;
+ classic_norm.set(current - new_buf, new_buf, true);
}
size_t HttpUri::get_file_proc_hash()
if (abs_path_hash)
return abs_path_hash;
- if (abs_path.length > 0 )
+ if (abs_path.length() > 0 )
{
- abs_path_hash = str_to_hash(abs_path.start, abs_path.length);
+ abs_path_hash = str_to_hash(abs_path.start(), abs_path.length());
}
return abs_path_hash;
uri(length, start), method_id(method_id_), uri_param(uri_param_),
infractions(infractions_), events(events_)
{ normalize(); }
- ~HttpUri();
const Field& get_uri() const { return uri; }
HttpEnums::UriType get_uri_type() { return uri_type; }
const Field& get_scheme() { return scheme; }
Field query_norm;
Field fragment_norm;
Field classic_norm;
- bool classic_norm_allocated = false;
size_t abs_path_hash = 0;
void normalize();
bool UriNormalizer::need_norm_no_path(const Field& uri_component,
const HttpParaList::UriParam& uri_param)
{
- const int32_t& length = uri_component.length;
- const uint8_t* const & buf = uri_component.start;
- for (int32_t k = 0; k < length; k++)
+ for (int32_t k = 0; k < uri_component.length(); k++)
{
- if ((uri_param.uri_char[buf[k]] == CHAR_PERCENT) ||
- (uri_param.uri_char[buf[k]] == CHAR_SUBSTIT))
+ if ((uri_param.uri_char[uri_component.start()[k]] == CHAR_PERCENT) ||
+ (uri_param.uri_char[uri_component.start()[k]] == CHAR_SUBSTIT))
return true;
}
return false;
bool UriNormalizer::need_norm_path(const Field& uri_component,
const HttpParaList::UriParam& uri_param)
{
- const int32_t& length = uri_component.length;
- const uint8_t* const & buf = uri_component.start;
+ const int32_t length = uri_component.length();
+ const uint8_t* const buf = uri_component.start();
for (int32_t k = 0; k < length; k++)
{
switch (uri_param.uri_char[buf[k]])
{
bool utf8_needed = false;
bool double_decoding_needed = false;
- std::vector<bool> percent_encoded(input.length, false);
+ std::vector<bool> percent_encoded(input.length(), false);
int32_t length = norm_percent_processing(input, out_buf, uri_param, utf8_needed,
percent_encoded, double_decoding_needed, infractions, events);
if (uri_param.utf8 && utf8_needed)
HttpInfractions& infractions, HttpEventGen& events)
{
int32_t length = 0;
- for (int32_t k = 0; k < input.length; k++)
+ for (int32_t k = 0; k < input.length(); k++)
{
- switch (uri_param.uri_char[input.start[k]])
+ switch (uri_param.uri_char[input.start()[k]])
{
case CHAR_EIGHTBIT:
if (uri_param.utf8_bare_byte &&
- (((input.start[k] & 0xE0) == 0xC0) || ((input.start[k] & 0xF0) == 0xE0)))
+ (((input.start()[k] & 0xE0) == 0xC0) || ((input.start()[k] & 0xF0) == 0xE0)))
utf8_needed = true;
// Fall through
case CHAR_NORMAL:
case CHAR_PATH:
case CHAR_SUBSTIT:
- out_buf[length++] = input.start[k];
+ out_buf[length++] = input.start()[k];
break;
case CHAR_PERCENT:
if (is_percent_encoding(input, k))
out_buf[length++] = hex_val;
k += 2;
}
- else if ((k+1 < input.length) && (input.start[k+1] == '%'))
+ else if ((k+1 < input.length()) && (input.start()[k+1] == '%'))
{
// %% => %
double_decoding_needed = true;
bool& double_decoding_needed, HttpInfractions& infractions, HttpEventGen& events)
{
int32_t length = 0;
- for (int32_t k=0; k < input.length; k++)
+ for (int32_t k=0; k < input.length(); k++)
{
if (percent_encoded[k] || uri_param.utf8_bare_byte)
{
// two-byte UTF-8: 110xxxxx 10xxxxxx
- if (((input.start[k] & 0xE0) == 0xC0) &&
- (k+1 < input.length) &&
+ if (((input.start()[k] & 0xE0) == 0xC0) &&
+ (k+1 < input.length()) &&
(percent_encoded[k+1] || uri_param.utf8_bare_byte) &&
- ((input.start[k+1] & 0xC0) == 0x80))
+ ((input.start()[k+1] & 0xC0) == 0x80))
{
infractions += INF_URI_PERCENT_UTF8_2B;
events.create_event(EVENT_UTF_8);
infractions += INF_BARE_BYTE;
events.create_event(EVENT_BARE_BYTE);
}
- const uint16_t utf8_val = ((input.start[k] & 0x1F) << 6) +
- (input.start[k+1] & 0x3F);
+ const uint16_t utf8_val = ((input.start()[k] & 0x1F) << 6) +
+ (input.start()[k+1] & 0x3F);
const uint8_t val8 = reduce_to_eight_bits(utf8_val, uri_param, infractions,
events);
if (val8 == '%')
k += 1;
}
// three-byte UTF-8: 1110xxxx 10xxxxxx 10xxxxxx
- else if (((input.start[k] & 0xF0) == 0xE0) &&
- (k+2 < input.length) &&
+ else if (((input.start()[k] & 0xF0) == 0xE0) &&
+ (k+2 < input.length()) &&
(percent_encoded[k+1] || uri_param.utf8_bare_byte) &&
- ((input.start[k+1] & 0xC0) == 0x80) &&
+ ((input.start()[k+1] & 0xC0) == 0x80) &&
(percent_encoded[k+2] || uri_param.utf8_bare_byte) &&
- ((input.start[k+2] & 0xC0) == 0x80))
+ ((input.start()[k+2] & 0xC0) == 0x80))
{
infractions += INF_URI_PERCENT_UTF8_3B;
events.create_event(EVENT_UTF_8);
infractions += INF_BARE_BYTE;
events.create_event(EVENT_BARE_BYTE);
}
- const uint16_t utf8_val = ((input.start[k] & 0x0F) << 12) +
- ((input.start[k+1] & 0x3F) << 6) +
- (input.start[k+2] & 0x3F);
+ const uint16_t utf8_val = ((input.start()[k] & 0x0F) << 12) +
+ ((input.start()[k+1] & 0x3F) << 6) +
+ (input.start()[k+2] & 0x3F);
const uint8_t val8 = reduce_to_eight_bits(utf8_val, uri_param, infractions,
events);
if (val8 == '%')
k += 2;
}
else
- out_buf[length++] = input.start[k];
+ out_buf[length++] = input.start()[k];
}
else
- out_buf[length++] = input.start[k];
+ out_buf[length++] = input.start()[k];
}
return length;
}
{
// Double decoding is limited to %hh and %u encoding cases
int32_t length = 0;
- for (int32_t k = 0; k < input.length; k++)
+ for (int32_t k = 0; k < input.length(); k++)
{
- if (input.start[k] != '%')
- out_buf[length++] = input.start[k];
+ if (input.start()[k] != '%')
+ out_buf[length++] = input.start()[k];
else
{
if (is_percent_encoding(input, k))
if (uri_param.bad_characters.count() == 0)
return;
- for (int32_t k = 0; k < uri_component.length; k++)
+ for (int32_t k = 0; k < uri_component.length(); k++)
{
- if (uri_param.bad_characters[uri_component.start[k]])
+ if (uri_param.bad_characters[uri_component.start()[k]])
{
infractions += INF_URI_BAD_CHAR;
events.create_event(EVENT_NON_RFC_CHAR);
}
// Provide traditional URI-style normalization for buffers that usually are not URIs
-void UriNormalizer::classic_normalize(const Field& input, Field& result, uint8_t* buffer,
+void UriNormalizer::classic_normalize(const Field& input, Field& result,
const HttpParaList::UriParam& uri_param)
{
// The requirements for generating events related to these normalizations are unclear. It
HttpInfractions unused;
HttpDummyEventGen dummy_ev;
+ uint8_t* const buffer = new uint8_t[input.length() + URI_NORM_EXPANSION];
+
// Normalize character escape sequences
int32_t data_length = norm_char_clean(input, buffer, uri_param, unused, dummy_ev);
}
}
- result.set(data_length, buffer);
+ result.set(data_length, buffer, true);
}
bool UriNormalizer::classic_need_norm(const Field& uri_component, bool do_path,
HttpEventGen& events);
static bool classic_need_norm(const Field& uri_component, bool do_path,
const HttpParaList::UriParam& uri_param);
- static void classic_normalize(const Field& input, Field& result, uint8_t* buffer,
+ static void classic_normalize(const Field& input, Field& result,
const HttpParaList::UriParam& uri_param);
static void load_default_unicode_map(uint8_t map[65536]);
static void load_unicode_map(uint8_t map[65536], const char* filename, int code_page);
bool UriNormalizer::is_percent_encoding(const Field& input, int32_t index)
{
- return (index+2 < input.length) &&
- (HttpEnums::as_hex[input.start[index+1]] != -1) &&
- (HttpEnums::as_hex[input.start[index+2]] != -1);
+ return (index+2 < input.length()) &&
+ (HttpEnums::as_hex[input.start()[index+1]] != -1) &&
+ (HttpEnums::as_hex[input.start()[index+2]] != -1);
}
uint8_t UriNormalizer::extract_percent_encoding(const Field& input, int32_t index)
{
- return HttpEnums::as_hex[input.start[index+1]] << 4 |
- HttpEnums::as_hex[input.start[index+2]];
+ return HttpEnums::as_hex[input.start()[index+1]] << 4 |
+ HttpEnums::as_hex[input.start()[index+2]];
}
bool UriNormalizer::is_u_encoding(const Field& input, int32_t index)
{
- return (index+5 < input.length) &&
- ((input.start[index+1] == 'u') || (input.start[index+1] == 'U')) &&
- (HttpEnums::as_hex[input.start[index+2]] != -1) &&
- (HttpEnums::as_hex[input.start[index+3]] != -1) &&
- (HttpEnums::as_hex[input.start[index+4]] != -1) &&
- (HttpEnums::as_hex[input.start[index+5]] != -1);
+ return (index+5 < input.length()) &&
+ ((input.start()[index+1] == 'u') || (input.start()[index+1] == 'U')) &&
+ (HttpEnums::as_hex[input.start()[index+2]] != -1) &&
+ (HttpEnums::as_hex[input.start()[index+3]] != -1) &&
+ (HttpEnums::as_hex[input.start()[index+4]] != -1) &&
+ (HttpEnums::as_hex[input.start()[index+5]] != -1);
}
uint16_t UriNormalizer::extract_u_encoding(const Field& input, int32_t index)
{
- return (HttpEnums::as_hex[input.start[index+2]] << 12) |
- (HttpEnums::as_hex[input.start[index+3]] << 8) |
- (HttpEnums::as_hex[input.start[index+4]] << 4) |
- HttpEnums::as_hex[input.start[index+5]];
+ return (HttpEnums::as_hex[input.start()[index+2]] << 12) |
+ (HttpEnums::as_hex[input.start()[index+3]] << 8) |
+ (HttpEnums::as_hex[input.start()[index+4]] << 4) |
+ HttpEnums::as_hex[input.start()[index+5]];
}
#endif
if (!p->flow || !p->flow->gadget)
return DETECTION_OPTION_NO_MATCH;
- if (HttpInspect::get_latest_is() != inspect_section)
+ if (HttpInspect::get_latest_is(p) != inspect_section)
{
// It is OK to provide a body buffer during the detection section. If there actually is
// a body buffer available then the detection section must also be the first body section.
- if (! ((inspect_section == IS_BODY) && (HttpInspect::get_latest_is() == IS_DETECTION)) )
+ if (! ((inspect_section == IS_BODY) && (HttpInspect::get_latest_is(p) == IS_DETECTION)) )
return DETECTION_OPTION_NO_MATCH;
}
InspectionBuffer hb;
if (! ((HttpInspect*)(p->flow->gadget))->
- http_get_buf((unsigned)buffer_index, sub_id, form, nullptr, hb))
+ http_get_buf((unsigned)buffer_index, sub_id, form, p, hb))
return DETECTION_OPTION_NO_MATCH;
c.set(key, hb.data, hb.len);
Field input(20, (const uint8_t*) "/uri//to/%6eormalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 17);
- CHECK(memcmp(result.start, "/uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 17);
+ CHECK(memcmp(result.start(), "/uri/to/normalize", 17) == 0);
}
TEST_GROUP(http_double_decode_test)
Field input(19, (const uint8_t*) "/uri/to%5Cnormalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 17);
- CHECK(memcmp(result.start, "/uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 17);
+ CHECK(memcmp(result.start(), "/uri/to/normalize", 17) == 0);
}
TEST(http_double_decode_test, encoded_percent)
Field input(21, (const uint8_t*) "/uri/to%255Cnormalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 17);
- CHECK(memcmp(result.start, "/uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 17);
+ CHECK(memcmp(result.start(), "/uri/to/normalize", 17) == 0);
}
TEST(http_double_decode_test, double_percent)
Field input(20, (const uint8_t*) "/uri/to%%5Cnormalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 17);
- CHECK(memcmp(result.start, "/uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 17);
+ CHECK(memcmp(result.start(), "/uri/to/normalize", 17) == 0);
}
TEST(http_double_decode_test, encoded_all)
Field input(25, (const uint8_t*) "/uri/to%25%35%43normalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 17);
- CHECK(memcmp(result.start, "/uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 17);
+ CHECK(memcmp(result.start(), "/uri/to/normalize", 17) == 0);
}
TEST(http_double_decode_test, utf8_all)
Field input(24, (const uint8_t*) "/uri/to\xE0\x80\xA5\xC0\xB5\xE0\x81\x83normalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 17);
- CHECK(memcmp(result.start, "/uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 17);
+ CHECK(memcmp(result.start(), "/uri/to/normalize", 17) == 0);
}
TEST(http_double_decode_test, u_encode_percent)
Field input(24, (const uint8_t*) "/%%uri/to%u005cnormalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 18);
- CHECK(memcmp(result.start, "/%uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 18);
+ CHECK(memcmp(result.start(), "/%uri/to/normalize", 17) == 0);
}
TEST(http_double_decode_test, u_encode_all)
Field input(52, (const uint8_t*) "/uri/to%u0025%U0075%u0030%U0030%u0035%U0063normalize");
Field result;
UriNormalizer::normalize(input, result, true, buffer, uri_param, infractions, events);
- CHECK(result.length == 17);
- CHECK(memcmp(result.start, "/uri/to/normalize", 17) == 0);
+ CHECK(result.length() == 17);
+ CHECK(memcmp(result.start(), "/uri/to/normalize", 17) == 0);
}
int main(int argc, char** argv)