From: Tom Peters Date: Wed, 24 Sep 2014 18:16:26 +0000 (-0400) Subject: splitter understands chunk headers X-Git-Tag: 3.0.0-233~1405 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b27e9ee17fd5738d98e8c58c2be4cd007ba087be;p=thirdparty%2Fsnort3.git splitter understands chunk headers --- diff --git a/src/service_inspectors/nhttp_inspect/CMakeLists.txt b/src/service_inspectors/nhttp_inspect/CMakeLists.txt index 63148f6d9..ed0c8d6cc 100644 --- a/src/service_inspectors/nhttp_inspect/CMakeLists.txt +++ b/src/service_inspectors/nhttp_inspect/CMakeLists.txt @@ -16,10 +16,8 @@ set (FILE_LIST nhttp_msg_header.h nhttp_msg_body.cc nhttp_msg_body.h - nhttp_msg_chunk_head.cc - nhttp_msg_chunk_head.h - nhttp_msg_chunk_body.cc - nhttp_msg_chunk_body.h + nhttp_msg_chunk.cc + nhttp_msg_chunk.h nhttp_msg_trailer.cc nhttp_msg_trailer.h nhttp_head_norm.cc diff --git a/src/service_inspectors/nhttp_inspect/Makefile.am b/src/service_inspectors/nhttp_inspect/Makefile.am index b32aa79df..6937754c0 100644 --- a/src/service_inspectors/nhttp_inspect/Makefile.am +++ b/src/service_inspectors/nhttp_inspect/Makefile.am @@ -9,8 +9,7 @@ nhttp_msg_status.cc nhttp_msg_status.h \ nhttp_msg_head_shared.cc nhttp_msg_head_shared.h \ nhttp_msg_header.cc nhttp_msg_header.h \ nhttp_msg_body.cc nhttp_msg_body.h \ -nhttp_msg_chunk_head.cc nhttp_msg_chunk_head.h \ -nhttp_msg_chunk_body.cc nhttp_msg_chunk_body.h \ +nhttp_msg_chunk.cc nhttp_msg_chunk.h \ nhttp_msg_trailer.cc nhttp_msg_trailer.h \ nhttp_head_norm.cc nhttp_head_norm.h \ nhttp_uri.cc nhttp_uri.h \ diff --git a/src/service_inspectors/nhttp_inspect/nhttp_enum.h b/src/service_inspectors/nhttp_inspect/nhttp_enum.h index 87a2098eb..a4842d250 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_enum.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_enum.h @@ -47,13 +47,13 @@ typedef enum { SRC__NOTCOMPUTE=-4, SRC_CLIENT=0, SRC_SERVER=1 } SourceId; // Type of message section typedef enum { SEC_DISCARD = -10, SEC_CLOSED = -9, SEC_ABORT = -8, SEC__NOTCOMPUTE=-4, SEC__NOTPRESENT=-1, SEC_REQUEST = 2, - SEC_STATUS, SEC_HEADER, SEC_BODY, SEC_CHUNKHEAD, SEC_CHUNKBODY, SEC_TRAILER } SectionType; + SEC_STATUS, SEC_HEADER, SEC_BODY, SEC_CHUNK, SEC_TRAILER } SectionType; // Result of scanning by splitter -typedef enum { SCAN_NOTFOUND, SCAN_FOUND, SCAN_DISCARD } ScanResult; +typedef enum { SCAN_NOTFOUND, SCAN_FOUND, SCAN_DISCARD, SCAN_ABORT } ScanResult; // Result of processing a message section--what needs to happen next -typedef enum { RES_INSPECT, RES_IGNORE, RES_AGGREGATE, RES_FLUSHCHUNKS } ProcessResult; +typedef enum { RES_INSPECT, RES_IGNORE, RES_AGGREGATE } ProcessResult; // List of possible HTTP versions. Version 0.9 omitted because 0.9 predates creation of the HTTP/X.Y token. There would // never be a message with "HTTP/0.9" diff --git a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc index aab974dd2..4bd6455bb 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.cc @@ -58,7 +58,6 @@ void NHttpFlowData::half_reset(SourceId source_id) { data_length[source_id] = STAT_NOTPRESENT; body_octets[source_id] = STAT_NOTPRESENT; - num_chunks[source_id] = STAT_NOTPRESENT; } void NHttpFlowData::show(FILE* out_file) const { @@ -70,7 +69,6 @@ void NHttpFlowData::show(FILE* out_file) const { fprintf(out_file, "Type expected: %d/%d\n", type_expected[0], type_expected[1]); fprintf(out_file, "Data length: %" PRIi64 "/%" PRIi64 "\n", data_length[0], data_length[1]); fprintf(out_file, "Body octets: %" PRIi64 "/%" PRIi64 "\n", body_octets[0], body_octets[1]); - fprintf(out_file, "Number of chunks: %" PRIi64 "/%" PRIi64 "\n", num_chunks[0], num_chunks[1]); fprintf(out_file, "Unused octets visible: %u/%u\n", unused_octets_visible[0], unused_octets_visible[1]); fprintf(out_file, "Header octets visible: %u/%u\n", header_octets_visible[0], header_octets_visible[1]); fprintf(out_file, "Section buffer length: %d/%d\n", section_buffer_length[0], section_buffer_length[1]); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h index 3c3f037c1..626fe2b0f 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_flow_data.h @@ -51,8 +51,7 @@ public: friend class NHttpMsgRequest; friend class NHttpMsgStatus; friend class NHttpMsgBody; - friend class NHttpMsgChunkHead; - friend class NHttpMsgChunkBody; + friend class NHttpMsgChunk; friend class NHttpMsgTrailer; friend class NHttpStreamSplitter; friend class NHttpTransaction; @@ -64,7 +63,7 @@ private: NHttpRequestSplitter request_splitter[2]; NHttpStatusSplitter status_splitter[2]; NHttpHeaderSplitter header_splitter[2]; - NHttpChunkHeaderSplitter chunkhead_splitter[2]; + NHttpChunkSplitter chunk_splitter[2]; NHttpTrailerSplitter trailer_splitter[2]; uint32_t unused_octets_visible[2] = { 0, 0 }; uint32_t header_octets_visible[2] = { 0, 0 }; @@ -81,7 +80,7 @@ private: // Inspector => StreamSplitter (facts about the message section that is coming next) NHttpEnums::SectionType type_expected[2] = { NHttpEnums::SEC_REQUEST, NHttpEnums::SEC_STATUS }; - int64_t data_length[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // length of the data from Content-Length field or chunk header. + int64_t data_length[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // length of the data from Content-Length field // Inspector's internal data about the current message // Some items don't apply in both directions. Have two copies anyway just to simplify code and minimize @@ -91,7 +90,6 @@ private: int32_t status_code_num[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; int64_t body_octets[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of user data octets seen so far (regular body or chunks) - int64_t num_chunks[2] = { NHttpEnums::STAT_NOTPRESENT, NHttpEnums::STAT_NOTPRESENT }; // number of chunks seen so far // Transaction management including pipelining NHttpTransaction* transaction[2] = { nullptr, nullptr }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc index aea9ff86a..ecf4ddeae 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.cc @@ -113,8 +113,7 @@ ProcessResult NHttpInspect::process(const uint8_t* data, const uint16_t dsize, F case SEC_STATUS: msg_section = new NHttpMsgStatus(data, dsize, session_data, source_id, buf_owner); break; case SEC_HEADER: msg_section = new NHttpMsgHeader(data, dsize, session_data, source_id, buf_owner); break; case SEC_BODY: msg_section = new NHttpMsgBody(data, dsize, session_data, source_id, buf_owner); break; - case SEC_CHUNKHEAD: msg_section = new NHttpMsgChunkHead(data, dsize, session_data, source_id, buf_owner); break; - case SEC_CHUNKBODY: msg_section = new NHttpMsgChunkBody(data, dsize, session_data, source_id, buf_owner); break; + case SEC_CHUNK: msg_section = new NHttpMsgChunk(data, dsize, session_data, source_id, buf_owner); break; case SEC_TRAILER: msg_section = new NHttpMsgTrailer(data, dsize, session_data, source_id, buf_owner); break; case SEC_DISCARD: if (buf_owner) delete[] data; return RES_IGNORE; default: assert(0); if (buf_owner) delete[] data; return RES_IGNORE; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h index 8409aaebe..2db56a415 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_inspect.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_inspect.h @@ -32,8 +32,7 @@ #include "nhttp_msg_status.h" #include "nhttp_msg_header.h" #include "nhttp_msg_body.h" -#include "nhttp_msg_chunk_head.h" -#include "nhttp_msg_chunk_body.h" +#include "nhttp_msg_chunk.h" #include "nhttp_msg_trailer.h" #include "nhttp_test_manager.h" #include "nhttp_stream_splitter.h" diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk.cc similarity index 73% rename from src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.cc rename to src/service_inspectors/nhttp_inspect/nhttp_msg_chunk.cc index 9755a29bb..04ce04b86 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk.cc @@ -23,7 +23,7 @@ // // @author Tom Peters // -// @brief NHttpMsgChunkBody class analyzes data portion (not start line) of an HTTP chunk. +// @brief NHttpMsgChunk class analyzes HTTP chunked body. // @@ -34,41 +34,32 @@ #include "snort.h" #include "nhttp_enum.h" -#include "nhttp_msg_chunk_body.h" +#include "nhttp_msg_chunk.h" using namespace NHttpEnums; -NHttpMsgChunkBody::NHttpMsgChunkBody(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, +NHttpMsgChunk::NHttpMsgChunk(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, SourceId source_id_, bool buf_owner) : NHttpMsgBody(buffer, buf_size, session_data_, source_id_, buf_owner) { transaction->set_body(this); } -void NHttpMsgChunkBody::analyze() { - body_octets += msg_text.length; +void NHttpMsgChunk::gen_events() {} - data.start = msg_text.start; - data.length = msg_text.length; - - if (tcp_close) infractions |= INF_TRUNCATED; -} - - -void NHttpMsgChunkBody::gen_events() {} - -void NHttpMsgChunkBody::print_section(FILE *output) { - NHttpMsgSection::print_message_title(output, "chunk body"); +void NHttpMsgChunk::print_section(FILE *output) { + NHttpMsgSection::print_message_title(output, "chunk"); fprintf(output, "Cumulative octets %" PRIi64 "\n", body_octets); data.print(output, "Data"); NHttpMsgSection::print_message_wrapup(output); } -void NHttpMsgChunkBody::update_flow() { +void NHttpMsgChunk::update_flow() { if (tcp_close) { session_data->type_expected[source_id] = SEC_CLOSED; session_data->half_reset(source_id); } else { + // Zero-length chunk is not visible here. StreamSplitter updates expected_type to SEC_TRAILER when necessary. session_data->body_octets[source_id] = body_octets; } } diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk.h similarity index 82% rename from src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.h rename to src/service_inspectors/nhttp_inspect/nhttp_msg_chunk.h index 06de6e841..1ec187ff3 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_body.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk.h @@ -23,23 +23,22 @@ // // @author Tom Peters // -// @brief NHttpMsgChunkBody class declaration +// @brief NHttpMsgChunk class declaration // -#ifndef NHTTP_MSG_CHUNK_BODY_H -#define NHTTP_MSG_CHUNK_BODY_H +#ifndef NHTTP_MSG_CHUNK_H +#define NHTTP_MSG_CHUNK_H #include "nhttp_msg_body.h" //------------------------------------------------------------------------- -// NHttpMsgChunkBody class +// NHttpMsgChunk class //------------------------------------------------------------------------- -class NHttpMsgChunkBody : public NHttpMsgBody { +class NHttpMsgChunk : public NHttpMsgBody { public: - NHttpMsgChunkBody(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, + NHttpMsgChunk(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, NHttpEnums::SourceId source_id_, bool buf_owner); - void analyze(); void print_section(FILE *output); void gen_events(); void update_flow(); diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.cc deleted file mode 100644 index ac00a6179..000000000 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.cc +++ /dev/null @@ -1,155 +0,0 @@ -/**************************************************************************** - * -** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. - * Copyright (C) 2003-2013 Sourcefire, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2 as - * published by the Free Software Foundation. You may not use, modify or - * distribute this program under any other version of the GNU General - * Public License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - ****************************************************************************/ - -// -// @author Tom Peters -// -// @brief NHttpMsgChunkHead class analyzes header line for a chunk. -// - - -#include -#include -#include -#include - -#include "snort.h" -#include "nhttp_enum.h" -#include "nhttp_msg_chunk_head.h" - -using namespace NHttpEnums; - -NHttpMsgChunkHead::NHttpMsgChunkHead(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, - SourceId source_id_, bool buf_owner) : - NHttpMsgSection(buffer, buf_size, session_data_, source_id_, buf_owner), - num_chunks(session_data->num_chunks[source_id]) -{ - transaction->set_body(this); -} - - -// Convert the hexadecimal chunk length. -// RFC says that zero may be written with multiple digits "000000". -// Arbitrary limit of 15 hex digits not including leading zeros ensures in a simple way against 64-bit overflow and should be -// vastly bigger than any legitimate chunk. -void NHttpMsgChunkHead::derive_chunk_length() { - if (chunk_size.length <= 0) { - data_length = STAT_NOSOURCE; - infractions |= INF_BADCHUNKSIZE; - return; - } - data_length = 0; - int non_leading_zeros = 0; - for (int k=0; k < chunk_size.length; k++) { - if (non_leading_zeros || (chunk_size.start[k] != '0')) non_leading_zeros++; - if (non_leading_zeros > 15) { - data_length = STAT_PROBLEMATIC; - infractions |= INF_BADCHUNKSIZE; - return; - } - - data_length *= 16; - if ((chunk_size.start[k] >= '0') && (chunk_size.start[k] <= '9')) data_length += chunk_size.start[k] - '0'; - else if ((chunk_size.start[k] >= 'A') && (chunk_size.start[k] <= 'F')) data_length += chunk_size.start[k] - 'A' + 10; - else if ((chunk_size.start[k] >= 'a') && (chunk_size.start[k] <= 'f')) data_length += chunk_size.start[k] - 'a' + 10; - else { - data_length = STAT_PROBLEMATIC; - infractions |= INF_BADCHUNKSIZE; - return; - } - } -} - -void NHttpMsgChunkHead::analyze() { - // First section in a new chunk is just the start line. - num_chunks++; - start_line.start = msg_text.start; - if (!tcp_close) { - start_line.length = msg_text.length - 2; - } - else { - start_line.length = find_crlf(start_line.start, msg_text.length, false); - } - chunk_size.start = msg_text.start; - // Start line format is chunk size in hex followed by optional semicolon and extensions field - for (chunk_size.length = 0; (chunk_size.length < start_line.length) && (start_line.start[chunk_size.length] != ';'); chunk_size.length++); - if (chunk_size.length == start_line.length) { - chunk_extensions.length = STAT_NOTPRESENT; - } - else if (chunk_size.length == start_line.length - 1) { - chunk_extensions.length = STAT_EMPTYSTRING; - } - else { - chunk_extensions.start = msg_text.start + chunk_size.length + 1; - chunk_extensions.length = start_line.length - chunk_size.length - 1; - } - derive_chunk_length(); - if (tcp_close) infractions |= INF_TRUNCATED; -} - -void NHttpMsgChunkHead::gen_events() {} - -void NHttpMsgChunkHead::print_section(FILE *output) { - NHttpMsgSection::print_message_title(output, "chunk header"); - fprintf(output, "Chunk size: %" PRIi64 "\n", data_length); - chunk_extensions.print(output, "Chunk extensions"); - NHttpMsgSection::print_message_wrapup(output); -} - -void NHttpMsgChunkHead::update_flow() { - if (tcp_close) { - session_data->type_expected[source_id] = SEC_CLOSED; - session_data->half_reset(source_id); - } - else if (data_length > 0) { - session_data->type_expected[source_id] = SEC_CHUNKBODY; - session_data->num_chunks[source_id] = num_chunks; - session_data->data_length[source_id] = data_length; - } - else { // FIXIT-H what if data_length is bad (probable loss of sync)? - // This was zero-length last chunk, trailer comes next - session_data->type_expected[source_id] = SEC_TRAILER; - } -} - -ProcessResult NHttpMsgChunkHead::worth_detection() { - return ((data_length > 0) && !tcp_close) ? RES_IGNORE : RES_FLUSHCHUNKS; -} - -// Legacy support function. Puts message fields into the buffers used by old Snort. -void NHttpMsgChunkHead::legacy_clients() { - ClearHttpBuffers(); - legacy_request(); - legacy_status(); - legacy_header(false); - if (start_line.length > 0) SetHttpBuffer(HTTP_BUFFER_CLIENT_BODY, start_line.start, (unsigned)start_line.length); -} - - - - - - - - - - diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.h b/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.h deleted file mode 100644 index 606b9fb41..000000000 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_chunk_head.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** - * -** Copyright (C) 2014 Cisco and/or its affiliates. All rights reserved. - * Copyright (C) 2003-2013 Sourcefire, Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License Version 2 as - * published by the Free Software Foundation. You may not use, modify or - * distribute this program under any other version of the GNU General - * Public License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - ****************************************************************************/ - -// -// @author Tom Peters -// -// @brief NHttpMsgChunkHead class declaration -// - -#ifndef NHTTP_MSG_CHUNK_HEAD_H -#define NHTTP_MSG_CHUNK_HEAD_H - -#include "nhttp_msg_section.h" -#include "nhttp_field.h" - -//------------------------------------------------------------------------- -// NHttpMsgChunkHead class -//------------------------------------------------------------------------- - -class NHttpMsgChunkHead : public NHttpMsgSection { -public: - NHttpMsgChunkHead(const uint8_t *buffer, const uint16_t buf_size, NHttpFlowData *session_data_, - NHttpEnums::SourceId source_id_, bool buf_owner); - void analyze(); - void print_section(FILE *output); - void gen_events(); - void update_flow(); - void legacy_clients(); - NHttpEnums::ProcessResult worth_detection(); - -private: - void derive_chunk_length(); - - Field start_line; - Field chunk_size; - Field chunk_extensions; - - int64_t data_length = NHttpEnums::STAT_NOTCOMPUTE; - int64_t num_chunks; -}; - -#endif - - - - - - - - - - - - - - - - - diff --git a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc index ab039d601..c7f5bd5b2 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_msg_header.cc @@ -90,9 +90,8 @@ void NHttpMsgHeader::update_flow() { (get_header_value_norm(HEAD_TRANSFER_ENCODING).length - 8))) == TRANSCODE_CHUNKED) ) { // FIXIT-M inspect for Content-Length header which should not be present // Chunked body - session_data->type_expected[source_id] = SEC_CHUNKHEAD; + session_data->type_expected[source_id] = SEC_CHUNK; session_data->body_octets[source_id] = 0; - session_data->num_chunks[source_id] = 0; } else if ((get_header_value_norm(HEAD_CONTENT_LENGTH).length > 0) && (*(int64_t*)header_value_norm[HEAD_CONTENT_LENGTH].start > 0)) { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc b/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc index b1eb274ce..419aa13d2 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_splitter.cc @@ -26,11 +26,22 @@ // @brief Section-specific splitters // +//#include "nhttp_uri_norm.h" #include "nhttp_splitter.h" using namespace NHttpEnums; +void NHttpSplitter::conditional_reset() { + if (complete) { + octets_seen = 0; + num_crlf = 0; + num_flush = 0; + complete = false; + } +} + ScanResult NHttpRequestSplitter::split(const uint8_t* buffer, uint32_t length) { + conditional_reset(); for (uint32_t k = 0; k < length; k++) { // Count the alternating and characters we have seen in a row if (((buffer[k] == '\r') && (num_crlf == 0)) || @@ -46,6 +57,7 @@ ScanResult NHttpRequestSplitter::split(const uint8_t* buffer, uint32_t length) { } num_flush = k+1; // If the first two octets are CRLF then they must be discarded. + complete = true; return ((octets_seen + k + 1) == 2) ? SCAN_DISCARD : SCAN_FOUND; } octets_seen += length; @@ -53,6 +65,7 @@ ScanResult NHttpRequestSplitter::split(const uint8_t* buffer, uint32_t length) { } ScanResult NHttpStatusSplitter::split(const uint8_t* buffer, uint32_t length) { + conditional_reset(); for (uint32_t k = 0; k < length; k++) { // Count the alternating and characters we have seen in a row if (((buffer[k] == '\r') && (num_crlf == 0)) || @@ -74,29 +87,78 @@ ScanResult NHttpStatusSplitter::split(const uint8_t* buffer, uint32_t length) { return SCAN_NOTFOUND; } -ScanResult NHttpChunkHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { +ScanResult NHttpChunkSplitter::split(const uint8_t* buffer, uint32_t length) { + conditional_reset(); + if (header_complete) { + // Previously read the chunk header. Now just flush the length. + num_flush = expected_length; + complete = true; + return SCAN_FOUND; + } for (uint32_t k = 0; k < length; k++) { - // Count the alternating and characters we have seen in a row - if (((buffer[k] == '\r') && (num_crlf == 0)) || - ((buffer[k] == '\n') && (num_crlf == 1))) { - num_crlf++; - if (num_crlf < 2) { - continue; + if (buffer[k] == '\r') { + num_crlf = 1; + continue; + } + if ((buffer[k] == '\n') && (num_crlf == 1)) { + if ((octets_seen + k + 1) == 2) { + // \r\n leftover from previous chunk + complete = true; + num_flush = k+1; + return SCAN_DISCARD; + } + if (!length_started) { + // chunk header specifies no length + complete = true; + return SCAN_ABORT; } + // flush completed chunk header + header_complete = true; + num_flush = k+1; + return SCAN_DISCARD; } - else { - num_crlf = 0; + num_crlf = 0; + if (buffer[k] == ';') { + semicolon = true; + } + if (semicolon) { + // we don't look at chunk header extensions continue; } - num_flush = k+1; - // If the first two octets are CRLF then they must be discarded. - return ((octets_seen + k + 1) == 2) ? SCAN_DISCARD : SCAN_FOUND; + if (as_hex[buffer[k]] == -1) { + // illegal character present in chunk length + complete = true; + return SCAN_ABORT; + } + length_started = true; + if (digits_seen >= 8) { + // overflow protection: must fit into 32 bits + complete = true; + return SCAN_ABORT; + } + expected_length = expected_length * 16 + as_hex[buffer[k]]; + if (expected_length > 0) { + // leading zeroes don't count + digits_seen++; + } } octets_seen += length; return SCAN_NOTFOUND; } +void NHttpChunkSplitter::conditional_reset() { + if (complete) { + expected_length = 0; + length_started = false; + digits_seen = 0; + semicolon = false; + header_complete = false; + } + NHttpSplitter::conditional_reset(); +} + ScanResult NHttpHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { + conditional_reset(); if (peek_status == SCAN_FOUND) { return SCAN_FOUND; } @@ -110,6 +172,7 @@ ScanResult NHttpHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { num_crlf++; if ((num_crlf == 2) && (octets_seen + k + 1) == 2) { num_flush = k+1; + complete = true; return SCAN_FOUND; } if (num_crlf < 4) { @@ -121,6 +184,7 @@ ScanResult NHttpHeaderSplitter::split(const uint8_t* buffer, uint32_t length) { continue; } num_flush = k + 1 + peek_octets; + complete = true; return SCAN_FOUND; } octets_seen += length; @@ -134,8 +198,16 @@ ScanResult NHttpHeaderSplitter::peek(const uint8_t* buffer, uint32_t length) { return peek_status; } +void NHttpHeaderSplitter::conditional_reset() { + if (complete) { + peek_octets = 0; + peek_status = SCAN_NOTFOUND; + } + NHttpSplitter::conditional_reset(); +} ScanResult NHttpTrailerSplitter::split(const uint8_t* buffer, uint32_t length) { + conditional_reset(); for (uint32_t k = 0; k < length; k++) { // Count the alternating and characters we have seen in a row if (((buffer[k] == '\r') && (num_crlf%2 == 0)) || @@ -143,6 +215,7 @@ ScanResult NHttpTrailerSplitter::split(const uint8_t* buffer, uint32_t length) { num_crlf++; if ((num_crlf == 2) && (octets_seen + k + 1) == 2) { num_flush = k+1; + complete = true; return SCAN_FOUND; } if (num_crlf < 4) { @@ -154,6 +227,7 @@ ScanResult NHttpTrailerSplitter::split(const uint8_t* buffer, uint32_t length) { continue; } num_flush = k+1; + complete = true; return SCAN_FOUND; } octets_seen += length; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_splitter.h b/src/service_inspectors/nhttp_inspect/nhttp_splitter.h index 24c819bd1..ecf745a7a 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_splitter.h +++ b/src/service_inspectors/nhttp_inspect/nhttp_splitter.h @@ -39,16 +39,20 @@ class NHttpSplitter { public: virtual ~NHttpSplitter() = default; - virtual void reset() { octets_seen = 0; num_crlf = 0; num_flush = 0; }; virtual NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length) = 0; virtual NHttpEnums::ScanResult peek(const uint8_t*, uint32_t) { assert(0); return NHttpEnums::SCAN_NOTFOUND; }; uint32_t get_num_flush() { return num_flush; }; virtual uint32_t get_octets_seen() { return octets_seen; }; protected: + static const int8_t as_hex[256]; + uint32_t octets_seen = 0; uint32_t num_crlf = 0; uint32_t num_flush = 0; + bool complete = false; + + virtual void conditional_reset(); }; class NHttpRequestSplitter : public NHttpSplitter { @@ -65,16 +69,23 @@ class NHttpHeaderSplitter : public NHttpSplitter { public: NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length); NHttpEnums::ScanResult peek(const uint8_t* buffer, uint32_t length); - void reset() { NHttpSplitter::reset(); peek_octets = 0; peek_status = NHttpEnums::SCAN_NOTFOUND; }; + void conditional_reset(); uint32_t get_octets_seen() { return octets_seen - peek_octets; }; private: uint32_t peek_octets = 0; NHttpEnums::ScanResult peek_status = NHttpEnums::SCAN_NOTFOUND; }; -class NHttpChunkHeaderSplitter : public NHttpSplitter { +class NHttpChunkSplitter : public NHttpSplitter { public: NHttpEnums::ScanResult split(const uint8_t* buffer, uint32_t length); + void conditional_reset(); +private: + uint32_t expected_length = 0; + bool length_started = false; + uint32_t digits_seen = 0; + bool semicolon = false; + bool header_complete = false; }; class NHttpTrailerSplitter : public NHttpSplitter { diff --git a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc index 5d3b8eda0..21a382b0e 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_stream_splitter.cc @@ -43,28 +43,42 @@ using namespace NHttpEnums; // Convenience function. All the housekeeping that must be done before we can return FLUSH to stream. void NHttpStreamSplitter::prepare_flush(NHttpFlowData* session_data, uint32_t* flush_offset, SourceId source_id, SectionType section_type, bool tcp_close, uint64_t infractions, uint32_t num_octets, uint32_t length) { - assert(num_octets > 0); session_data->section_type[source_id] = section_type; session_data->tcp_close[source_id] = tcp_close; session_data->infractions[source_id] = infractions; + switch (section_type) { + case SEC_BODY: + paf_max = 16384; + break; + case SEC_CHUNK: + paf_max = 16384 - session_data->chunk_buffer_length[source_id]; + if (num_octets == 0) { + session_data->type_expected[source_id] = SEC_TRAILER; + } + break; + default: + paf_max = 63780; + break; + } if (tcp_close) { session_data->type_expected[source_id] = SEC_CLOSED; } if (!NHttpTestManager::use_test_input()) { - *flush_offset = num_octets; + // when TCP connection closes do not flush octets that have not arrived yet + *flush_offset = (!tcp_close || (num_octets <= length)) ? num_octets : length; } else { - NHttpTestManager::get_test_input_source()->flush(num_octets); + NHttpTestManager::get_test_input_source()->flush((!tcp_close || (num_octets <= length)) ? num_octets : length); } - session_data->unused_octets_visible[source_id] = length - num_octets; + session_data->unused_octets_visible[source_id] = (length >= num_octets) ? length - num_octets : 0; session_data->header_octets_visible[source_id] = 0; } -// Convenience function. Size buffer required to accommodate the current section plus possible aggregation. +// Convenience function. Size buffer required to reassemble the current section plus possible aggregation. uint32_t NHttpStreamSplitter::size_buffer_needed(unsigned total, NHttpEnums::SectionType type, uint32_t possible_additional) { switch (type) { - case SEC_CHUNKBODY: + case SEC_CHUNK: return 16384; case SEC_REQUEST: case SEC_STATUS: @@ -116,16 +130,15 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat switch (type) { case SEC_REQUEST: case SEC_STATUS: - case SEC_CHUNKHEAD: + case SEC_CHUNK: case SEC_HEADER: case SEC_TRAILER: { - paf_max = 63780; NHttpSplitter* splitter; switch (type) { case SEC_REQUEST: splitter = (NHttpSplitter*)&session_data->request_splitter[source_id]; break; case SEC_STATUS: splitter = (NHttpSplitter*)&session_data->status_splitter[source_id]; break; - case SEC_CHUNKHEAD: splitter = (NHttpSplitter*)&session_data->chunkhead_splitter[source_id]; break; + case SEC_CHUNK: splitter = (NHttpSplitter*)&session_data->chunk_splitter[source_id]; break; case SEC_HEADER: splitter = (NHttpSplitter*)&session_data->header_splitter[source_id]; break; case SEC_TRAILER: splitter = (NHttpSplitter*)&session_data->trailer_splitter[source_id]; break; default: assert(0); break; @@ -134,42 +147,45 @@ StreamSplitter::Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* dat const uint32_t max_length = (length <= (63780 - splitter->get_octets_seen())) ? length : (63780 - splitter->get_octets_seen()); const ScanResult split_result = splitter->split(data, max_length); - if (split_result == SCAN_NOTFOUND) { + switch (split_result) { + case SCAN_NOTFOUND: if (splitter->get_octets_seen() == 63780) { - // FIXIT-M need to implement processing and detection instead of just discarding this data + prepare_flush(session_data, flush_offset, source_id, SEC_DISCARD, false, 0, 0, length); session_data->type_expected[source_id] = SEC_ABORT; return StreamSplitter::ABORT; } - if (!tcp_close) { - // Incomplete headers wait patiently for more data - return StreamSplitter::SEARCH; + if (tcp_close) { + prepare_flush(session_data, flush_offset, source_id, type, true, INF_TRUNCATED, length, length); + return StreamSplitter::FLUSH; } - prepare_flush(session_data, flush_offset, source_id, type, true, INF_TRUNCATED, length, length); - splitter->reset(); + // Incomplete headers wait patiently for more data + return StreamSplitter::SEARCH; + case SCAN_ABORT: + prepare_flush(session_data, flush_offset, source_id, SEC_DISCARD, false, 0, 0, length); + session_data->type_expected[source_id] = SEC_ABORT; return StreamSplitter::FLUSH; - } - const uint32_t flush_octets = splitter->get_num_flush(); - if (split_result == SCAN_DISCARD) { - prepare_flush(session_data, flush_offset, source_id, SEC_DISCARD, tcp_close && (flush_octets == length), 0, + case SCAN_DISCARD: { + const uint32_t flush_octets = splitter->get_num_flush(); + prepare_flush(session_data, flush_offset, source_id, SEC_DISCARD, tcp_close && (flush_octets >= length), 0, flush_octets, length); - splitter->reset(); return StreamSplitter::FLUSH; - } - prepare_flush(session_data, flush_offset, source_id, type, tcp_close && (flush_octets == length), 0, - flush_octets, length); - splitter->reset(); - if ((type == SEC_REQUEST) || (type == SEC_STATUS)) { - // Look ahead to see if entire header section is already here so we can aggregate it for detection. - const uint32_t peek_max_length = ((length - flush_octets <= 63780)) ? (length - flush_octets) : 63780; - if (session_data->header_splitter[source_id].peek(data + flush_octets, peek_max_length) == SCAN_FOUND) { - session_data->header_octets_visible[source_id] = session_data->header_splitter[source_id].get_num_flush(); + } + case SCAN_FOUND: { + const uint32_t flush_octets = splitter->get_num_flush(); + prepare_flush(session_data, flush_offset, source_id, type, tcp_close && (flush_octets == length), 0, + flush_octets, length); + if ((type == SEC_REQUEST) || (type == SEC_STATUS)) { + // Look ahead to see if entire header section is already here so we can aggregate it for detection. + const uint32_t peek_max_length = ((length - flush_octets <= 63780)) ? (length - flush_octets) : 63780; + if (session_data->header_splitter[source_id].peek(data + flush_octets, peek_max_length) == SCAN_FOUND) { + session_data->header_octets_visible[source_id] = session_data->header_splitter[source_id].get_num_flush(); + } } + return StreamSplitter::FLUSH; + } } - return StreamSplitter::FLUSH; } case SEC_BODY: - case SEC_CHUNKBODY: - paf_max = 16384 - session_data->chunk_buffer_length[source_id]; if ((!tcp_close) || (length > session_data->data_length[source_id])) { prepare_flush(session_data, flush_offset, source_id, type, false, 0, session_data->data_length[source_id], length); @@ -203,7 +219,7 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total, } uint8_t* test_buffer; NHttpTestManager::get_test_input_source()->reassemble(&test_buffer, len, source_id, session_data); - if (len == 0) { + if (test_buffer == nullptr) { // There is no more test data return nullptr; } @@ -215,12 +231,12 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total, assert(total <= 63780); assert(offset+len <= total); - bool is_chunk_body = session_data->section_type[source_id] == SEC_CHUNKBODY; + bool is_chunk = session_data->section_type[source_id] == SEC_CHUNK; uint8_t*& chunk_buffer = session_data->chunk_buffer[source_id]; int32_t& chunk_buffer_length = session_data->chunk_buffer_length[source_id]; - uint8_t*& buffer = !is_chunk_body ? session_data->section_buffer[source_id] : chunk_buffer; - int32_t& buffer_length = !is_chunk_body ? session_data->section_buffer_length[source_id] : chunk_buffer_length; + uint8_t*& buffer = !is_chunk ? session_data->section_buffer[source_id] : chunk_buffer; + int32_t& buffer_length = !is_chunk ? session_data->section_buffer_length[source_id] : chunk_buffer_length; if (buffer == nullptr) { buffer = new uint8_t[size_buffer_needed(total, session_data->section_type[source_id], @@ -230,29 +246,28 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total, memcpy(buffer + buffer_length + offset, data, len); if (flags & PKT_PDU_TAIL) { ProcessResult send_to_detection; - if (!is_chunk_body) { + if (!is_chunk) { // start line/headers/body individual section processing with aggregation prior to being sent to detection // only the last section added to the buffer goes to the inspector send_to_detection = my_inspector->process(buffer + buffer_length, offset + len, flow, source_id, buffer_length == 0); } else { - // Because of aggregation chunk body sections do not go to Inspector on schedule or in chronological order - // with respect to chunk header sections. That means NHttpMsgChunkBody::update_flow() cannot do it design-intended - // job of updating type_expected in time for StreamSplitter to find the next chunk header. So we do it here. - session_data->type_expected[source_id] = SEC_CHUNKHEAD; - // small chunks are aggregated before processing and are kept here until the buffer is full (paf_max) - // all the chunks in the buffer go to the inspector together + // all the chunks in the buffer go to the inspector together. Zero-length chunk flushes accumulated chunks. int32_t total_chunk_len = chunk_buffer_length + offset + len; - if (total_chunk_len < 16384) { - paf_max = 16384 - total_chunk_len; + if ((total_chunk_len < 16384) && (len != 0)) { chunk_buffer_length = total_chunk_len; return nullptr; } - else { - paf_max = 16384; + if (total_chunk_len == 0) { + // Zero-length chunk cannot be processed by itself. + delete[] chunk_buffer; + chunk_buffer = nullptr; + chunk_buffer_length = 0; + return nullptr; } + paf_max = 16384; send_to_detection = my_inspector->process(chunk_buffer, total_chunk_len, flow, source_id, true); } @@ -274,26 +289,6 @@ const StreamBuffer* NHttpStreamSplitter::reassemble(Flow* flow, unsigned total, case RES_AGGREGATE: buffer_length += offset + len; return nullptr; - case RES_FLUSHCHUNKS: - buffer = nullptr; - buffer_length = 0; - if (chunk_buffer != nullptr) { - // FIXIT-M these three variables about the buffered chunks need to be managed properly - session_data->section_type[source_id] = SEC_CHUNKBODY; - session_data->tcp_close[source_id] = false; - session_data->infractions[source_id] = 0; - - my_inspector->process(chunk_buffer, chunk_buffer_length, flow, source_id, true); - nhttp_buf.data = chunk_buffer; - nhttp_buf.length = chunk_buffer_length; - chunk_buffer = nullptr; - chunk_buffer_length = 0; - if (NHttpTestManager::use_test_output()) { - fprintf(NHttpTestManager::get_output_file(), "Flushed chunks for detection %u octets\n\n", nhttp_buf.length); - } - return &nhttp_buf; - } - return nullptr; } } return nullptr; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc index 3615f822c..5f637fa70 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_tables.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_tables.cc @@ -43,6 +43,7 @@ #include "nhttp_msg_header.h" #include "nhttp_module.h" #include "nhttp_uri_norm.h" +#include "nhttp_splitter.h" using namespace NHttpEnums; @@ -301,22 +302,29 @@ const RuleMap NHttpModule::nhttp_events[] = { 0, nullptr } }; +const int8_t NHttpSplitter::as_hex[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - - - - - - - - - - + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc index 4c7a6af83..1fafd20ce 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_input.cc @@ -224,6 +224,11 @@ void NHttpTestInput::flush(uint32_t length) { void NHttpTestInput::reassemble(uint8_t **buffer, unsigned &length, SourceId &source_id, NHttpFlowData* session_data) { + if (!just_flushed) { + length = 0; + *buffer = nullptr; + return; + } source_id = last_source_id; *buffer = msg_buf; diff --git a/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt b/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt index 15f223bab..4693d4164 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt +++ b/src/service_inspectors/nhttp_inspect/nhttp_test_msgs.txt @@ -1,11 +1,11 @@ -# Enter HTTP test message text as you want it to be presented to PAF. +# Enter HTTP test message text as you want it to be presented to the StreamSplitter. # -# The easiest way to format is to put a blank line between message sections so that each message section is its own "paragraph". -# Within a paragraph the placement of new lines does not have any effect. Format a paragraph any way you are comfortable. Extra blank lines -# between paragraphs also do not have any effect. +# The easiest way to format is to put a blank line between message sections so that each message section is its own "paragraph". Within a paragraph +# the placement of single new lines does not have any effect. Format a paragraph any way you are comfortable. Extra blank lines between paragraphs +# also do not have any effect. # # Each paragraph represents a TCP segment. The splitter can be tested by putting multiple sections in the same paragraph (splitter must split) -# or continuing a section in the next paragraph (splitter must search and reassamble). +# or continuing a section in the next paragraph (splitter must search and reassemble). # # It is not necessary to specify complete body and chunk body sections. Specify at least one octet that will begin the section and the # remainder will be autofilled in 16384-octet sections up to the length flushed. @@ -34,12 +34,12 @@ # least one character of body/chunk data either as part of the previous header segment or at the beginning of a new segment following the headers. # All data bytes included in the file will be used followed by required fill data in the pattern ABC...XYZABC... # +# Fill data will not be provided for a paragraph that is preceded by tcpclose. The body or chunk will terminate at the end of the paragraph. +# # There must not be excess data for a test case. Once a data stream ends with a TCP close there must be a break command before further data is sent. # Similarly a message section that triggers an abort of processing must end the paragraph and be followed by a break. These rules apply half-duplex # so it would be possible to send data in the opposite direction before the break. # -# FIXIT-L it would be useful if a paragraph could continue following an abort to simulate a processing abort mid-segment. -# # This test tool does not implement the feature of being hardened against bad input. If you write a badly formatted or improper test case the # program may assert or crash. The responsibility is on the developer to get it right. Currently that is the best use of resources. @@ -605,9 +605,9 @@ HTTP/1.1 208 Example with chunks\r\nTransfer-Encoding: chunked\r\n\r\n chunkoflength138 -e6\r\nchunkoflength230 +\r\ne6\r\nchunkoflength230 -0\r\n +\r\n0\r\n \r\n @@ -627,27 +627,27 @@ Accept: *\r\n 1C320\r\n chunk1 -1F40; testing-the-extension-feature\r\n +\r\n1F40; testing-the-extension-feature\r\n chunk2 -13FFE; \r\n +\r\n13FFE; \r\n chunk3 -4000;\r\n +\r\n4000;\r\n chunk4 -3FFF;\r\n +\r\n3FFF;\r\n chunk5 -3FFE\r\n +\r\n3FFE\r\n chunk6 -4001;\r\n +\r\n4001;\r\n chunk7 -00000;chunkextension=3\r\n +\r\n00000;chunkextension=3\r\n date: Sun, 01 Oct 2000 23:25:17 GMT\r\n X-madeupdate: Mon, 02 Oct 2000 23:25:17 GMT\r\n @@ -749,13 +749,15 @@ Transfer-Encoding: chunked\r\n A000\r\n chunk1-start -B000\r\n +\r\nB000\r\n chunk2-start -C000\r\n +\r\nC000\r\n chunk3-start +\r\n + 0\r\n date: Mon, 02 Oct 2000 20:25:00 GMT\r\n fakeheader: 1234\r\n diff --git a/src/service_inspectors/nhttp_inspect/nhttp_transaction.cc b/src/service_inspectors/nhttp_inspect/nhttp_transaction.cc index 4d0f46bdd..3998d34c6 100644 --- a/src/service_inspectors/nhttp_inspect/nhttp_transaction.cc +++ b/src/service_inspectors/nhttp_inspect/nhttp_transaction.cc @@ -33,9 +33,6 @@ #include "nhttp_msg_request.h" #include "nhttp_msg_status.h" #include "nhttp_msg_header.h" -#include "nhttp_msg_body.h" -#include "nhttp_msg_chunk_head.h" -#include "nhttp_msg_chunk_body.h" #include "nhttp_msg_trailer.h" using namespace NHttpEnums; @@ -107,5 +104,3 @@ NHttpTransaction* NHttpTransaction::attach_my_transaction(NHttpFlowData* session } - -