enum EventSid
{
EVENT__NONE = -1,
- EVENT_INT_DECODE_FAILURE = 1,
+ EVENT_INVALID_FLAG = 1,
EVENT_INT_LEADING_ZEROS = 2,
- EVENT_STRING_DECODE_FAILURE = 3,
+ EVENT_INVALID_STREAM_ID = 3,
EVENT_MISSING_CONTINUATION = 4,
EVENT_UNEXPECTED_CONTINUATION = 5,
EVENT_MISFORMATTED_HTTP2 = 6,
EVENT_PREFACE_MATCH_FAILURE = 7,
EVENT_REQUEST_WITHOUT_REQUIRED_FIELD = 8,
EVENT_RESPONSE_WITHOUT_STATUS = 9,
- EVENT_INVALID_HEADER = 10,
+ EVENT_CONNECT_WITH_SCHEME_OR_PATH = 10,
EVENT_SETTINGS_FRAME_ERROR = 11,
EVENT_SETTINGS_FRAME_UNKN_PARAM = 12,
EVENT_FRAME_SEQUENCE = 13,
EVENT_DYNAMIC_TABLE_OVERFLOW = 14,
- EVENT_INVALID_STARTLINE = 15,
+ EVENT_INVALID_PROMISED_STREAM = 15,
EVENT_PADDING_LEN = 16,
EVENT_PSEUDO_HEADER_AFTER_REGULAR_HEADER = 17,
EVENT_PSEUDO_HEADER_IN_TRAILERS = 18,
EVENT_BAD_PUSH_SEQUENCE = 25,
EVENT_BAD_SETTINGS_VALUE = 26,
EVENT_PUSH_WHEN_PROHIBITED = 27,
- EVENT_INVALID_PROMISED_STREAM = 28,
- EVENT_INVALID_STREAM_ID = 29,
- EVENT_INVALID_FLAG = 30,
EVENT__MAX_VALUE
};
INF_C2S_PUSH = 12,
INF_INVALID_PSEUDO_HEADER = 13,
INF_PSEUDO_HEADER_AFTER_REGULAR_HEADER = 14,
- INF_PSEUDO_HEADER_URI_FORM_MISMATCH = 15,
+ INF_REQUEST_WITHOUT_REQUIRED_FIELD = 15,
INF_RESPONSE_WITHOUT_STATUS = 16,
INF_HPACK_INDEX_OUT_OF_BOUNDS = 17,
INF_INVALID_SETTINGS_FRAME = 18,
INF_INVALID_PROMISED_STREAM = 36,
INF_INVALID_STREAM_ID = 37,
INF_INVALID_FLAG = 38,
+ INF_TRUNCATED_HEADER_LINE = 39,
+ INF_REQUEST_WITHOUT_METHOD = 40,
+ INF_CONNECT_WITHOUT_AUTHORITY = 41,
+ INF_CONNECT_WITH_SCHEME_OR_PATH = 42,
INF__MAX_VALUE
};
class Http2Stream* get_processing_stream();
uint32_t get_processing_stream_id() const;
void set_processing_stream_id(const HttpCommon::SourceId source_id);
+ bool is_processing_partial_header() const { return processing_partial_header; }
Http2HpackDecoder* get_hpack_decoder(const HttpCommon::SourceId source_id)
{ return &hpack_decoder[source_id]; }
uint8_t frame_type[2] = { Http2Enums::FT__NONE, Http2Enums::FT__NONE };
bool abort_flow[2] = { false, false };
std::queue<uint32_t> frame_lengths[2];
+ bool processing_partial_header = false;
// Internal to reassemble()
uint32_t frame_header_offset[2] = { 0, 0 };
http1_header = hpack_decoder->get_decoded_headers(decoded_headers);
StreamBuffer stream_buf;
+
// http_inspect scan() of headers
+ // If we're processing a header truncated immediately after the start line, http1_header will
+ // be empty. Don't call scan on the empty buffer because it will create a cutter and the check
+ // for this condition in HI::finish() will fail. Truncated headers with non-empty http1_header
+ // buffers are still sent to HI::scan().
+ assert ((http1_header.length() > 0) or session_data->is_processing_partial_header());
+ if (http1_header.length() > 0)
{
uint32_t flush_offset;
Http2DummyPacket dummy_pkt;
const StreamSplitter::Status header_scan_result =
session_data->hi_ss[hi_source_id]->scan(&dummy_pkt, http1_header.start(),
http1_header.length(), unused, &flush_offset);
- assert(header_scan_result == StreamSplitter::FLUSH);
+ assert((session_data->is_processing_partial_header() and
+ (header_scan_result == StreamSplitter::SEARCH)) or
+ ((!session_data->is_processing_partial_header() and
+ (header_scan_result == StreamSplitter::FLUSH))));
+ assert(session_data->is_processing_partial_header() ^
+ ((int64_t)flush_offset == http1_header.length()));
UNUSED(header_scan_result);
- assert((int64_t)flush_offset == http1_header.length());
}
+ // If this is a truncated headers frame, call http_inspect finish()
+ if (session_data->is_processing_partial_header())
+ session_data->hi_ss[hi_source_id]->finish(session_data->flow);
+
// http_inspect reassemble() of headers
{
unsigned copied;
dummy_pkt.data = stream_buf.data;
dummy_pkt.xtradata_mask = 0;
session_data->hi->eval(&dummy_pkt);
- // Following if condition won't get exercised until finish() (during Headers) is
- // implemented for H2I. Without finish() H2I will only flush complete header blocks. Below
- // ABORT is only possible if tcp connection closes unexpectedly in middle of a header.
if (http_flow->get_type_expected(hi_source_id) == HttpEnums::SEC_ABORT)
{
- *session_data->infractions[source_id] += INF_INVALID_HEADER;
- session_data->events[source_id]->create_event(EVENT_INVALID_HEADER);
- stream->set_state(source_id, STREAM_ERROR);
- return;
+ assert(session_data->is_processing_partial_header());
+ stream->set_state(hi_source_id, STREAM_ERROR);
}
detection_required = dummy_pkt.is_detection_required();
xtradata_mask = dummy_pkt.xtradata_mask;
if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() -
hpack_headers_offset, decoded_headers, start_line_generator, false))
{
- session_data->abort_flow[source_id] = true;
- session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
- return;
+ if (!(*session_data->infractions[source_id] & INF_TRUNCATED_HEADER_LINE))
+ {
+ session_data->abort_flow[source_id] = true;
+ session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+ return;
+ }
}
// process start line
- if (!start_line_generator->generate_start_line(start_line))
+ if (!start_line_generator->generate_start_line(start_line, are_pseudo_headers_complete()))
{
- // FIXIT-E should only be a stream error
- session_data->abort_flow[source_id] = true;
- session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+ stream->set_state(source_id, STREAM_ERROR);
}
}
if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() -
hpack_headers_offset, decoded_headers, nullptr, true))
{
- session_data->abort_flow[source_id] = true;
- session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+ if (!(*session_data->infractions[source_id] & INF_TRUNCATED_HEADER_LINE))
+ {
+ session_data->abort_flow[source_id] = true;
+ session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+ }
}
}
if (http_flow->get_type_expected(source_id) != HttpEnums::SEC_TRAILER)
{
- // If there was no unflushed data on this stream when the trailers arrived, http_inspect
- // will not yet be expecting trailers. Flush empty buffer through scan, reassemble, and
- // eval to prepare http_inspect for trailers.
+ // http_inspect is not yet expecting trailers. Flush empty buffer through scan, reassemble,
+ // and eval to prepare http_inspect for trailers.
assert(http_flow->get_type_expected(source_id) == HttpEnums::SEC_BODY_H2);
stream->finish_msg_body(source_id, true, true); // calls http_inspect scan()
session_data->hi->eval(&dummy_pkt);
if (http_flow->get_type_expected(hi_source_id) != HttpEnums::SEC_HEADER)
{
- *session_data->infractions[source_id] += INF_INVALID_STARTLINE;
- session_data->events[source_id]->create_event(EVENT_INVALID_STARTLINE);
stream->set_state(hi_source_id, STREAM_ERROR);
return false;
}
return true;
}
+// If we are not processing a truncated headers frame or we have seen a non-pseudoheader, we know
+// we've seen all the (valid) pseudoheaders in the frame. Otherwise we could be missing some due
+// to truncation
+bool Http2HeadersFrameWithStartline::are_pseudo_headers_complete()
+{
+ return !session_data->is_processing_partial_header() or
+ !hpack_decoder->are_pseudo_headers_allowed();
+}
#ifdef REG_TEST
void Http2HeadersFrameWithStartline::print_frame(FILE* output)
Http2HeadersFrame(header_buffer, header_len, data_buffer, data_len, ssn_data, src_id,
stream_) { }
bool process_start_line(HttpFlowData*& http_flow, HttpCommon::SourceId hi_source_id);
+ bool are_pseudo_headers_complete();
Http2StartLine* start_line_generator = nullptr;
Field start_line;
#include "service_inspectors/http_inspect/http_test_manager.h"
#include "http2_enum.h"
+#include "http2_flow_data.h"
#include "http2_start_line.h"
using namespace HttpCommon;
bytes_consumed = 0;
if (!decode_string.translate(encoded_header_buffer, encoded_header_length, bytes_consumed,
- decoded_header_buffer, decoded_header_length, bytes_written, events, infractions))
+ decoded_header_buffer, decoded_header_length, bytes_written, events, infractions,
+ session_data->is_processing_partial_header()))
{
return false;
}
bytes_consumed = 0;
if (!decode_int.translate(encoded_header_buffer, encoded_header_length, bytes_consumed,
- index, events, infractions))
+ index, events, infractions, session_data->is_processing_partial_header()))
{
return nullptr;
}
bytes_consumed = 0;
if (!decode_int5.translate(encoded_header_buffer, encoded_header_length,
- encoded_bytes_consumed, decoded_int, events, infractions))
+ encoded_bytes_consumed, decoded_int, events, infractions,
+ session_data->is_processing_partial_header()))
{
return false;
}
decoded_headers_size += line_bytes_written;
}
- // Write the last CRLF to end the header
- if (success)
+ // Write the last CRLF to end the header. A truncated header may not have encountered an error
+ // if the truncation is between header lines, but still shouldn't complete the header block
+ // with the final CRLF.
+ if (success and !session_data->is_processing_partial_header())
{
success = write_decoded_headers((const uint8_t*)"\r\n", 2, decoded_headers +
decoded_headers_size, MAX_OCTETS - decoded_headers_size, line_bytes_written);
#define HTTP2_HPACK_H
#include "service_inspectors/http_inspect/http_common.h"
+#include "utils/event_gen.h"
+#include "utils/infractions.h"
#include "http2_hpack_int_decode.h"
#include "http2_hpack_string_decode.h"
class Http2FlowData;
class Http2StartLine;
+using Http2Infractions = Infractions<Http2Enums::INF__MAX_VALUE, Http2Enums::INF__NONE>;
+using Http2EventGen = EventGen<Http2Enums::EVENT__MAX_VALUE, Http2Enums::EVENT__NONE,
+ Http2Enums::HTTP2_GID>;
+
// This class implements HPACK decompression. One instance is required in each direction for each
// HTTP/2 flow
class Http2HpackDecoder
public:
Http2HpackDecoder(Http2FlowData* flow_data, HttpCommon::SourceId src_id,
Http2EventGen* const _events, Http2Infractions* const _infractions) :
- events(_events), infractions(_infractions), decode_table(flow_data, src_id) { }
+ session_data(flow_data), events(_events), infractions(_infractions),
+ decode_table(flow_data, src_id) { }
bool decode_headers(const uint8_t* encoded_headers, const uint32_t encoded_headers_length,
uint8_t* decoded_headers, Http2StartLine* start_line, bool trailers);
bool write_decoded_headers(const uint8_t* in_buffer, const uint32_t in_length,
const Field* get_start_line();
Field get_decoded_headers(const uint8_t* const decoded_headers);
HpackIndexTable* get_decode_table() { return &decode_table; }
+ bool are_pseudo_headers_allowed() { return pseudo_headers_allowed; }
private:
Http2StartLine* start_line;
bool pseudo_headers_allowed;
uint32_t decoded_headers_size;
+ Http2FlowData* session_data;
Http2EventGen* const events;
Http2Infractions* const infractions;
bool Http2HpackIntDecode::translate(const uint8_t* in_buff, const uint32_t in_len,
uint32_t& bytes_consumed, uint64_t& result, Http2EventGen* const events,
- Http2Infractions* const infractions) const
+ Http2Infractions* const infractions, bool partial_header) const
{
bytes_consumed = 0;
result = 0;
if (in_len == 0)
{
- *infractions += INF_INT_EMPTY_BUFF;
- events->create_event(EVENT_INT_DECODE_FAILURE);
+ if (!partial_header)
+ *infractions += INF_INT_EMPTY_BUFF;
+ else
+ *infractions += INF_TRUNCATED_HEADER_LINE;
return false;
}
{
if (bytes_consumed >= in_len)
{
- *infractions += INF_INT_MISSING_BYTES;
- events->create_event(EVENT_INT_DECODE_FAILURE);
+ if (!partial_header)
+ *infractions += INF_INT_MISSING_BYTES;
+ else
+ *infractions += INF_TRUNCATED_HEADER_LINE;
return false;
}
byte = in_buff[bytes_consumed++];
((result + ((uint64_t)(byte & VAL_MASK) << multiplier) + prefix_mask) < result))
{
*infractions += INF_INT_OVERFLOW;
- events->create_event(EVENT_INT_DECODE_FAILURE);
return false;
}
}
public:
Http2HpackIntDecode(uint8_t prefix);
bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed,
- uint64_t& result, Http2EventGen* const events, Http2Infractions* const infractions) const;
+ uint64_t& result, Http2EventGen* const events, Http2Infractions* const infractions,
+ bool partial_header) const;
private:
const uint8_t prefix_mask;
bool Http2HpackStringDecode::translate(const uint8_t* in_buff, const uint32_t in_len,
uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
- Http2EventGen* const events, Http2Infractions* const infractions) const
+ Http2EventGen* const events, Http2Infractions* const infractions, bool partial_header) const
{
bytes_consumed = 0;
bytes_written = 0;
if (in_len == 0)
{
- *infractions += INF_STRING_EMPTY_BUFF;
- events->create_event(EVENT_STRING_DECODE_FAILURE);
+ if (!partial_header)
+ *infractions += INF_STRING_EMPTY_BUFF;
+ else
+ *infractions += INF_TRUNCATED_HEADER_LINE;
return false;
}
// Get length
uint64_t encoded_len;
- if (!decode7.translate(in_buff, in_len, bytes_consumed, encoded_len, events, infractions))
+ if (!decode7.translate(in_buff, in_len, bytes_consumed, encoded_len, events, infractions,
+ partial_header))
return false;
if (encoded_len > (uint64_t)(in_len - bytes_consumed))
{
- *infractions += INF_STRING_MISSING_BYTES;
- events->create_event(EVENT_STRING_DECODE_FAILURE);
+ if (!partial_header)
+ *infractions += INF_STRING_MISSING_BYTES;
+ else
+ *infractions += INF_TRUNCATED_HEADER_LINE;
return false;
}
if (!isHuffman)
return get_string(in_buff, encoded_len, bytes_consumed, out_buff, out_len, bytes_written,
- events, infractions);
+ infractions);
return get_huffman_string(in_buff, encoded_len, bytes_consumed, out_buff, out_len,
- bytes_written, events, infractions);
+ bytes_written, infractions);
}
bool Http2HpackStringDecode::get_string(const uint8_t* in_buff, const uint32_t encoded_len,
uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
- Http2EventGen* const events, Http2Infractions* const infractions) const
+ Http2Infractions* const infractions) const
{
if (encoded_len > out_len)
{
*infractions += INF_DECODED_HEADER_BUFF_OUT_OF_SPACE;
- events->create_event(EVENT_MISFORMATTED_HTTP2);
return false;
}
bool Http2HpackStringDecode::get_huffman_string(const uint8_t* in_buff, const uint32_t encoded_len,
uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
- Http2EventGen* const events, Http2Infractions* const infractions) const
+ Http2Infractions* const infractions) const
{
const uint32_t last_encoded_byte = bytes_consumed + encoded_len;
uint8_t byte;
if (max_length > out_len)
{
*infractions += INF_DECODED_HEADER_BUFF_OUT_OF_SPACE;
- events->create_event(EVENT_STRING_DECODE_FAILURE);
return false;
}
case HUFFMAN_FAILURE:
*infractions += INF_HUFFMAN_DECODED_EOS;
- events->create_event(EVENT_STRING_DECODE_FAILURE);
return false;
- break;
default:
break;
if (byte != 0xff)
{
*infractions += INF_HUFFMAN_BAD_PADDING;
- events->create_event(EVENT_STRING_DECODE_FAILURE);
return false;
}
}
else if (result.state != HUFFMAN_MATCH)
{
*infractions += INF_HUFFMAN_INCOMPLETE_CODE_PADDING;
- events->create_event(EVENT_STRING_DECODE_FAILURE);
return false;
}
Http2HpackStringDecode() : decode7(7) { }
bool translate(const uint8_t* in_buff, const uint32_t in_len, uint32_t& bytes_consumed,
uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
- Http2EventGen* const events, Http2Infractions* const infractions) const;
+ Http2EventGen* const events, Http2Infractions* const infractions,
+ bool partial_header) const;
private:
bool get_string(const uint8_t* in_buff, const uint32_t encoded_len, uint32_t& bytes_consumed,
- uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written, Http2EventGen* const
- events, Http2Infractions* const infractions) const;
+ uint8_t* out_buff, const uint32_t out_len, uint32_t& bytes_written,
+ Http2Infractions* const infractions) const;
bool get_huffman_string(const uint8_t* in_buff, const uint32_t encoded_len,
uint32_t& bytes_consumed, uint8_t* out_buff, const uint32_t out_len, uint32_t&
- bytes_written, Http2EventGen* const events, Http2Infractions* const infractions) const;
+ bytes_written, Http2Infractions* const infractions) const;
bool get_next_byte(const uint8_t* in_buff, const uint32_t last_byte,
uint32_t& bytes_consumed, uint8_t& cur_bit, uint8_t match_len, uint8_t& byte,
bool& another_search) const;
stream->clear_frame();
session_data->stream_in_hi = NO_STREAM_ID;
session_data->processing_stream_id = NO_STREAM_ID;
+ session_data->processing_partial_header = false;
}
#ifdef REG_TEST
if (!hpack_decoder->decode_headers((data.start() + hpack_headers_offset), data.length() -
hpack_headers_offset, decoded_headers, start_line_generator, false))
{
- session_data->abort_flow[source_id] = true;
- session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
- return;
+ if (!(*session_data->infractions[source_id] & INF_TRUNCATED_HEADER_LINE))
+ {
+ session_data->abort_flow[source_id] = true;
+ session_data->events[source_id]->create_event(EVENT_MISFORMATTED_HTTP2);
+ }
}
}
void Http2PushPromiseFrame::analyze_http1()
{
- if (!start_line_generator->generate_start_line(start_line))
+ if (!start_line_generator->generate_start_line(start_line, are_pseudo_headers_complete()))
{
// can't send request or push-promise headers to http_inspect, but response will still
// be processed
}
// Select the appropriate URI form based on the provided pseudo-headers and generate the start line
-bool Http2RequestLine::generate_start_line(Field& start_line)
+bool Http2RequestLine::generate_start_line(Field& start_line, bool pseudo_headers_complete)
{
uint32_t bytes_written = 0;
- // Asterisk form - used for OPTIONS requests
- if (path.length() > 0 and path.start()[0] == '*')
+ if (method.length() <= 0)
{
- if (method.length() <= 0)
+ if (pseudo_headers_complete)
{
- *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
+ *infractions += INF_REQUEST_WITHOUT_METHOD;
events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
- return false;
}
+ return false;
+ }
+
+ // Asterisk form - used for OPTIONS requests
+ if (path.length() > 0 and path.start()[0] == '*')
+ {
start_line_length = method.length() + path.length() + http_version_length +
NUM_REQUEST_LINE_EXTRA_CHARS;
start_line_buffer = new uint8_t[start_line_length];
// FIXIT-L May want to be more lenient than RFC on generating start line
if (authority.length() <= 0)
{
- *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
- events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
+ if (pseudo_headers_complete)
+ {
+ *infractions += INF_CONNECT_WITHOUT_AUTHORITY;
+ events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
+ }
return false;
}
// Should not have a scheme or path
if ( scheme.length() > 0 or path.length() > 0)
{
- *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
- events->create_event(EVENT_INVALID_HEADER);
+ *infractions += INF_CONNECT_WITH_SCHEME_OR_PATH;
+ events->create_event(EVENT_CONNECT_WITH_SCHEME_OR_PATH);
}
start_line_length = method.length() + authority.length() + http_version_length +
NUM_REQUEST_LINE_EXTRA_CHARS;
bytes_written += http_version_length;
}
// HTTP/2 requests with URIs in absolute or origin form must have a method, scheme, and length
- else if (method.length() > 0 and scheme.length() > 0 and path.length() > 0)
+ else if (scheme.length() > 0 and path.length() > 0)
{
// If there is an authority, the URI is in absolute form
if (authority.length() > 0)
else
{
// FIXIT-E May want to be more lenient than RFC on generating start line
- *infractions += INF_PSEUDO_HEADER_URI_FORM_MISMATCH;
- events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
+ if (pseudo_headers_complete)
+ {
+ *infractions += INF_REQUEST_WITHOUT_REQUIRED_FIELD;
+ events->create_event(EVENT_REQUEST_WITHOUT_REQUIRED_FIELD);
+ }
return false;
}
Http2RequestLine(Http2EventGen* const evs, Http2Infractions* const infrs) :
Http2StartLine(evs, infrs) { }
void process_pseudo_header(const Field& name, const Field& value) override;
- bool generate_start_line(Field& start_line) override;
+ bool generate_start_line(Field& start_line, bool pseudo_headers_complete) override;
private:
Field method;
friend class Http2Hpack;
- virtual bool generate_start_line(Field& start_line) = 0;
+ virtual bool generate_start_line(Field& start_line, bool pseudo_headers_complete) = 0;
virtual void process_pseudo_header(const Field& name, const Field& value) = 0;
protected:
}
}
-bool Http2StatusLine::generate_start_line(Field& start_line)
+bool Http2StatusLine::generate_start_line(Field& start_line, bool pseudo_headers_complete)
{
uint32_t bytes_written = 0;
if (status.length() <= 0)
{
- *infractions += INF_RESPONSE_WITHOUT_STATUS;
- events->create_event(EVENT_RESPONSE_WITHOUT_STATUS);
+ if (pseudo_headers_complete)
+ {
+ *infractions += INF_RESPONSE_WITHOUT_STATUS;
+ events->create_event(EVENT_RESPONSE_WITHOUT_STATUS);
+ }
return false;
}
Http2StartLine(evs, infrs) { }
void process_pseudo_header(const Field& name, const Field& value) override;
- bool generate_start_line(Field& start_line) override;
+ bool generate_start_line(Field& start_line, bool pseudo_headers_complete) override;
private:
Field status;
}
#endif
- // Loop through all nonzero streams and call NHI finish()
bool need_reassemble = false;
+
+ // First check if there is a partial header that needs to be processed. If we have a partial
+ // trailer don't call finish on that stream below
+ if (((session_data->frame_type[source_id] == FT_HEADERS) or
+ (session_data->frame_type[source_id] == FT_PUSH_PROMISE)) and
+ ((session_data->scan_remaining_frame_octets[source_id] > 0) or
+ (session_data->continuation_expected[source_id])))
+ {
+ session_data->processing_partial_header = true;
+ need_reassemble = true;
+#ifdef REG_TEST
+ if (HttpTestManager::use_test_input(HttpTestManager::IN_HTTP2))
+ HttpTestManager::get_test_input_source()->flush(0);
+#endif
+ }
+
+ // Loop through all nonzero streams with open message bodies and call NHI finish()
for (const Http2FlowData::StreamInfo& stream_info : session_data->streams)
{
if ((stream_info.id == 0) ||
(stream_info.stream->get_state(source_id) >= STREAM_COMPLETE) ||
(stream_info.stream->get_hi_flow_data() == nullptr) ||
(stream_info.stream->get_hi_flow_data()->get_type_expected(source_id)
- != HttpEnums::SEC_BODY_H2))
+ != HttpEnums::SEC_BODY_H2) ||
+ (session_data->processing_partial_header &&
+ (stream_info.id == session_data->current_stream[source_id])))
{
continue;
}
const RuleMap Http2Module::http2_events[] =
{
- { EVENT_INT_DECODE_FAILURE, "error in HPACK integer value" },
+ { EVENT_INVALID_FLAG, "invalid flag set on HTTP/2 frame" },
{ EVENT_INT_LEADING_ZEROS, "HPACK integer value has leading zeros" },
- { EVENT_STRING_DECODE_FAILURE, "error in HPACK string value" },
+ { EVENT_INVALID_STREAM_ID, "HTTP/2 stream initiated with invalid stream id" },
{ EVENT_MISSING_CONTINUATION, "missing HTTP/2 continuation frame" },
{ EVENT_UNEXPECTED_CONTINUATION, "unexpected HTTP/2 continuation frame" },
{ EVENT_MISFORMATTED_HTTP2, "misformatted HTTP/2 traffic" },
{ EVENT_PREFACE_MATCH_FAILURE, "HTTP/2 connection preface does not match" },
{ EVENT_REQUEST_WITHOUT_REQUIRED_FIELD, "HTTP/2 request missing required header field" },
{ EVENT_RESPONSE_WITHOUT_STATUS, "HTTP/2 response has no status code" },
- { EVENT_INVALID_HEADER, "HTTP/2 invalid header field" },
+ { EVENT_CONNECT_WITH_SCHEME_OR_PATH, "HTTP/2 CONNECT request with scheme or path" },
{ EVENT_SETTINGS_FRAME_ERROR, "error in HTTP/2 settings frame" },
{ EVENT_SETTINGS_FRAME_UNKN_PARAM, "unknown parameter in HTTP/2 settings frame" },
{ EVENT_FRAME_SEQUENCE, "invalid HTTP/2 frame sequence" },
{ EVENT_DYNAMIC_TABLE_OVERFLOW, "HTTP/2 dynamic table size limit exceeded" },
- { EVENT_INVALID_STARTLINE, "invalid HTTP/2 start line" },
+ { EVENT_INVALID_PROMISED_STREAM, "HTTP/2 push promise frame with invalid promised stream id" },
{ EVENT_PADDING_LEN, "HTTP/2 padding length is bigger than frame data size" },
{ EVENT_PSEUDO_HEADER_AFTER_REGULAR_HEADER, "HTTP/2 pseudo-header after regular header" },
{ EVENT_PSEUDO_HEADER_IN_TRAILERS, "HTTP/2 pseudo-header in trailers" },
{ EVENT_BAD_PUSH_SEQUENCE, "HTTP/2 push promise frame sent at invalid time" },
{ EVENT_BAD_SETTINGS_VALUE, "invalid parameter value sent in HTTP/2 settings frame" },
{ EVENT_PUSH_WHEN_PROHIBITED, "HTTP/2 push promise frame sent when prohibited by receiver" },
- { EVENT_INVALID_PROMISED_STREAM, "HTTP/2 push promise frame with invalid promised stream id" },
- { EVENT_INVALID_STREAM_ID, "HTTP/2 stream initiated with invalid stream id" },
- { EVENT_INVALID_FLAG, "invalid flag set on HTTP/2 frame" },
{ 0, nullptr }
};
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf);
+ bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == 10);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf);
+ bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == 10);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode->translate(buf, 3, bytes_processed, res, &events, &inf);
+ bool success = decode->translate(buf, 3, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == 1337);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode_8.translate(&buf, 1, bytes_processed, res, &events, &inf);
+ bool success = decode_8.translate(&buf, 1, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == 42);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode->translate(buf, 11, bytes_processed, res, &events, &inf);
+ bool success = decode->translate(buf, 11, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == 0xFFFFFFFFFFFFFFFF);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf);
+ bool success = decode->translate(buf, 2, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == 31);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf);
+ bool success = decode->translate(&buf, 1, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == 0);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode_7.translate(buf, 6, bytes_processed, res, &events, &inf);
+ bool success = decode_7.translate(buf, 6, bytes_processed, res, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(res == UINT32_MAX);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = decode_8.translate(&buf, 0, bytes_processed, res, &local_events, &local_inf);
+ bool success = decode_8.translate(&buf, 0, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 0);
CHECK(local_inf.get_raw() == (1<<INF_INT_EMPTY_BUFF));
- CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
}
TEST(http2_hpack_int_decode_failure, too_short)
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = local_decode.translate(buf, 2, bytes_processed, res, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 2, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 2);
CHECK(local_inf.get_raw() == (1<<INF_INT_MISSING_BYTES));
- CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
}
TEST(http2_hpack_int_decode_failure, multiplier_bigger_than_63)
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = local_decode.translate(buf, 13, bytes_processed, res, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 13, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 11);
CHECK(local_inf.get_raw() == (1<<INF_INT_OVERFLOW));
- CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
}
TEST(http2_hpack_int_decode_failure, add_val_overflow)
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = local_decode.translate(buf, 12, bytes_processed, res, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 12, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 11);
CHECK(local_inf.get_raw() == (1<<INF_INT_OVERFLOW));
- CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
}
TEST(http2_hpack_int_decode_failure, add_val_overflow2)
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = local_decode.translate(buf, 11, bytes_processed, res, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 11, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 11);
CHECK(local_inf.get_raw() == (1<<INF_INT_OVERFLOW));
- CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
}
TEST(http2_hpack_int_decode_failure, 2_64_using_5_bit)
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = local_decode.translate(buf, 11, bytes_processed, res, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 11, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 11);
CHECK(local_inf.get_raw() == (1<<INF_INT_OVERFLOW));
- CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
}
//
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = local_decode.translate(buf, 3, bytes_processed, res, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 3, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == true);
CHECK(res == 31);
// decode
uint32_t bytes_processed = 0;
uint64_t res = 0;
- bool success = local_decode.translate(buf, 11, bytes_processed, res, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 11, bytes_processed, res, &local_events, &local_inf,
+ false);
// check results
CHECK(success == true);
CHECK(res == 0x7FFFFFFFFFFFFFFF);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[10];
- bool success = decode->translate(buf, 11, bytes_processed, res, 10, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 11, bytes_processed, res, 10, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(memcmp(res, "custom-key", 10) == 0);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[12];
- bool success = decode->translate(buf, 12, bytes_processed, res, 12, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 12, bytes_processed, res, 12, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(memcmp(res, "custom-key", 10) == 0);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[130];
- bool success = decode->translate(buf, 130, bytes_processed, res, 130, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 130, bytes_processed, res, 130, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 130);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res = 10; // random value, just to check it wasn't overwritten
- bool success = decode->translate(&buf, 1, bytes_processed, &res, 1, bytes_written, &events, &inf);
+ bool success = decode->translate(&buf, 1, bytes_processed, &res, 1, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 1);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res = 0;
- bool success = decode->translate(buf, 2, bytes_processed, &res, 1, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 2, bytes_processed, &res, 1, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 2);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[MAX_OCTETS];
bool success = decode->translate(buf, MAX_OCTETS, bytes_processed, res,
- MAX_OCTETS, bytes_written, &events, &inf);
+ MAX_OCTETS, bytes_written, &events, &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == MAX_OCTETS);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[1];
- bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf,
+ false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 2);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[1];
- bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 2, bytes_processed, res, 1, bytes_written, &events, &inf,
+ false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 2);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[3];
- bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf,
+ false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 3);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[3];
- bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf,
+ false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 3);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[19];
- bool success = decode->translate(buf, 13, bytes_processed, res, 19, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 13, bytes_processed, res, 19, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 13);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[9];
- bool success = decode->translate(buf, 7, bytes_processed, res, 9, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 7, bytes_processed, res, 9, bytes_written, &events, &inf,
+ false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 7);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[12];
- bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 9);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[14];
- bool success = decode->translate(buf, 10, bytes_processed, res, 14, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 10, bytes_processed, res, 14, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 10);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[35];
- bool success = decode->translate(buf, 23, bytes_processed, res, 35, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 23, bytes_processed, res, 35, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 23);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[73];
- bool success = decode->translate(buf, 46, bytes_processed, res, 73, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 46, bytes_processed, res, 73, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 46);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[6];
- bool success = decode->translate(buf, 5, bytes_processed, res, 6, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 5, bytes_processed, res, 6, bytes_written, &events, &inf,
+ false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 5);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[32];
- bool success = decode->translate(buf, 21, bytes_processed, res, 32, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 21, bytes_processed, res, 32, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 21);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[36];
- bool success = decode->translate(buf, 24, bytes_processed, res, 36, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 24, bytes_processed, res, 36, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 24);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[12];
- bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 9, bytes_processed, res, 12, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 9);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[70];
- bool success = decode->translate(buf, 45, bytes_processed, res, 70, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 45, bytes_processed, res, 70, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 45);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[88];
uint8_t expected[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F};
- bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 55);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[93];
uint8_t expected[16] = {0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F};
- bool success = decode->translate(buf, 58, bytes_processed, res, 93, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 58, bytes_processed, res, 93, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 58);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[79];
uint8_t expected[17] = {0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F};
- bool success = decode->translate(buf, 49, bytes_processed, res, 79, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 49, bytes_processed, res, 79, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 49);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[76];
uint8_t expected[16] = {0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F};
- bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 47);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[74];
uint8_t expected[16] = {0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF};
- bool success = decode->translate(buf, 46, bytes_processed, res, 74, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 46, bytes_processed, res, 74, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 46);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[73];
uint8_t expected[16] = {0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF};
- bool success = decode->translate(buf, 45, bytes_processed, res, 73, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 45, bytes_processed, res, 73, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 45);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[80];
uint8_t expected[16] = {0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF};
- bool success = decode->translate(buf, 50, bytes_processed, res, 80, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 50, bytes_processed, res, 80, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 50);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[82];
uint8_t expected[16] = {0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF};
- bool success = decode->translate(buf, 51, bytes_processed, res, 82, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 51, bytes_processed, res, 82, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 51);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[76];
uint8_t expected[16] = {0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF};
- bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 47, bytes_processed, res, 76, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 47);
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[88];
uint8_t expected[16] = {0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF};
- bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 55, bytes_processed, res, 88, bytes_written, &events,
+ &inf, false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 55);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[3];
- bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf);
+ bool success = decode->translate(buf, 3, bytes_processed, res, 3, bytes_written, &events, &inf,
+ false);
// check results
CHECK(success == true);
CHECK(bytes_processed == 3);
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res;
- bool success = local_decode.translate(&buf, 0, bytes_processed, &res, 1, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(&buf, 0, bytes_processed, &res, 1, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 0);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_STRING_EMPTY_BUFF));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, missing_bytes)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[2];
- bool success = local_decode.translate(&buf, 1, bytes_processed, res, 2, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(&buf, 1, bytes_processed, res, 2, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_written == 0);
CHECK(bytes_processed == 1);
CHECK(local_inf.get_raw() == (1<<INF_STRING_MISSING_BYTES));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, bad_int)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[2];
- bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 2);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_INT_MISSING_BYTES));
- CHECK(local_events.get_raw() == (1<<(EVENT_INT_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, max_field_length_plus_1)
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[MAX_OCTETS];
bool success = local_decode.translate(buf, MAX_OCTETS, bytes_processed, res,
- MAX_OCTETS, bytes_written, &local_events, &local_inf);
+ MAX_OCTETS, bytes_written, &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 4);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_STRING_MISSING_BYTES));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, out_buf_out_of_space)
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[MAX_OCTETS-5];
bool success = local_decode.translate(buf, MAX_OCTETS, bytes_processed, res,
- MAX_OCTETS-5, bytes_written, &local_events, &local_inf);
+ MAX_OCTETS-5, bytes_written, &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 4);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_DECODED_HEADER_BUFF_OUT_OF_SPACE));
- CHECK(local_events.get_raw() == (1<<(EVENT_MISFORMATTED_HTTP2-1)));
}
TEST(http2_hpack_string_decode_infractions, huffman_1_byte_bad_padding)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[2];
- bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 2);
CHECK(bytes_written == 1);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_BAD_PADDING));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, huffman_1_byte_incomplete_FF)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[2];
- bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 2);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_INCOMPLETE_CODE_PADDING));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, huffman_1_byte_incomplete_FE)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[2];
- bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 2, bytes_processed, res, 2, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 2);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_INCOMPLETE_CODE_PADDING));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, huffman_2_bytes_incomplete_FF_FE)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[5];
- bool success = local_decode.translate(buf, 3, bytes_processed, res, 5, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 3, bytes_processed, res, 5, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 3);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_INCOMPLETE_CODE_PADDING));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, huffman_3_bytes_incomplete)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[7];
- bool success = local_decode.translate(buf, 4, bytes_processed, res, 7, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 4, bytes_processed, res, 7, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 4);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_INCOMPLETE_CODE_PADDING));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
TEST(http2_hpack_string_decode_infractions, huffman_FB_incomplete_FF)
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[5];
- bool success = local_decode.translate(buf, 3, bytes_processed, res, 5, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 3, bytes_processed, res, 5, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 3);
CHECK(bytes_written == 1);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_INCOMPLETE_CODE_PADDING));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
CHECK(memcmp(res, ";", 1) == 0);
}
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[5];
- bool success = local_decode.translate(buf, 3, bytes_processed, res, 5, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 3, bytes_processed, res, 5, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 3);
CHECK(bytes_written == 1);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_INCOMPLETE_CODE_PADDING));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
CHECK(memcmp(res, "0", 1) == 0);
}
// decode
uint32_t bytes_processed = 0, bytes_written = 0;
uint8_t res[10];
- bool success = local_decode.translate(buf, 5, bytes_processed, res, 10, bytes_written, &local_events, &local_inf);
+ bool success = local_decode.translate(buf, 5, bytes_processed, res, 10, bytes_written,
+ &local_events, &local_inf, false);
// check results
CHECK(success == false);
CHECK(bytes_processed == 4);
CHECK(bytes_written == 0);
CHECK(local_inf.get_raw() == (1<<INF_HUFFMAN_DECODED_EOS));
- CHECK(local_events.get_raw() == (1<<(EVENT_STRING_DECODE_FAILURE-1)));
}
int main(int argc, char** argv)
(session_data->cutter[source_id] == nullptr) &&
(session_data->section_type[source_id] == SEC__NOT_COMPUTE))
{
- assert(!session_data->for_http2);
// Set up to process empty header section
uint32_t not_used;
prepare_flush(session_data, ¬_used, SEC_HEADER, 0, 0, 0, false, 0, 0);