// *** StreamSplitter internal data - reassemble()
uint8_t* section_buffer[2] = { nullptr, nullptr };
+ uint32_t section_total[2] = { 0, 0 };
uint32_t section_offset[2] = { 0, 0 };
HttpEnums::ChunkState chunk_state[2] = { HttpEnums::CHUNK_NUMBER, HttpEnums::CHUNK_NUMBER };
uint32_t chunk_expected_length[2] = { 0, 0 };
+ uint32_t running_total[2] = { 0, 0 };
// *** StreamSplitter internal data - scan() => reassemble()
uint32_t num_excess[2] = { 0, 0 };
bool is_broken_chunk[2] = { false, false };
uint32_t num_good_chunks[2] = { 0, 0 };
+ uint32_t octets_expected[2] = { 0, 0 };
+ bool strict_length[2] = { false, false };
// *** StreamSplitter => Inspector (facts about the most recent message section)
HttpEnums::SectionType section_type[2] = { HttpEnums::SEC__NOT_COMPUTE,
copied = len;
- assert(total <= MAX_OCTETS);
-
HttpFlowData* session_data = (HttpFlowData*)flow->get_flow_data(HttpFlowData::http_flow_id);
assert(session_data != nullptr);
}
#endif
+ // FIXIT-H Workaround for TP Bug 149662
if (session_data->section_type[source_id] == SEC__NOT_COMPUTE)
- { // FIXIT-M In theory this check should not be necessary
+ {
return nullptr;
}
- // FIXIT-P stream should be ehanced to do discarding for us. For now flush-then-discard here
+ assert(session_data->section_type[source_id] != SEC__NOT_COMPUTE);
+ assert(total <= MAX_OCTETS);
+
+ session_data->running_total[source_id] += len;
+ assert(session_data->running_total[source_id] <= total);
+
+ // FIXIT-P stream should be enhanced to do discarding for us. For now flush-then-discard here
// is how scan() handles things we don't need to examine.
if (session_data->section_type[source_id] == SEC_DISCARD)
{
#endif
if (flags & PKT_PDU_TAIL)
{
+ assert(session_data->running_total[source_id] == total);
+ assert(
+ (session_data->octets_expected[source_id] == total) ||
+ (!session_data->strict_length[source_id] &&
+ (total <= session_data->octets_expected[source_id])));
+ session_data->running_total[source_id] = 0;
session_data->section_type[source_id] = SEC__NOT_COMPUTE;
// When we are skipping through a message body beyond flow depth this is the end of
buffer = new uint8_t[MAX_OCTETS];
else
buffer = new uint8_t[total];
- }
+ session_data->section_total[source_id] = total;
+ }
+ else
+ assert(session_data->section_total[source_id] == total);
if (session_data->section_type[source_id] != SEC_BODY_CHUNK)
{
if (flags & PKT_PDU_TAIL)
{
+ uint32_t& running_total = session_data->running_total[source_id];
+ // FIXIT-H workaround for TP Bug 149980: if we get shorted it must be because the TCP
+ // connection closed
+ if ((running_total < session_data->octets_expected[source_id]) &&
+ !session_data->strict_length[source_id])
+ session_data->tcp_close[source_id] = true;
+ // FIXIT-L workaround for TP Bug 148058: for now number of bytes provided following a
+ // connection close may be slightly less than total
+ assert((running_total == total) || session_data->tcp_close[source_id]);
+ assert(
+ (session_data->octets_expected[source_id] == running_total) ||
+ (!session_data->strict_length[source_id] &&
+ (running_total <= session_data->octets_expected[source_id])));
+ running_total = 0;
const Field& send_to_detection = my_inspector->process(buffer,
session_data->section_offset[source_id] - session_data->num_excess[source_id], flow,
source_id, true);
// Convenience function. All housekeeping that must be done before we can return FLUSH to stream.
void HttpStreamSplitter::prepare_flush(HttpFlowData* session_data, uint32_t* flush_offset,
SectionType section_type, uint32_t num_flushed, uint32_t num_excess, int32_t num_head_lines,
- bool is_broken_chunk, uint32_t num_good_chunks) const
+ bool is_broken_chunk, uint32_t num_good_chunks, uint32_t octets_seen, bool strict_length) const
{
session_data->section_type[source_id] = section_type;
session_data->num_excess[source_id] = num_excess;
session_data->num_head_lines[source_id] = num_head_lines;
session_data->is_broken_chunk[source_id] = is_broken_chunk;
session_data->num_good_chunks[source_id] = num_good_chunks;
+ session_data->octets_expected[source_id] = octets_seen + num_flushed;
+ session_data->strict_length[source_id] = strict_length;
#ifdef REG_TEST
if (HttpTestManager::use_test_input())
}
else if (HttpTestManager::use_test_output())
{
- printf("Scan from flow data %" PRIu64 " direction %d length %u\n", session_data->seq_num,
- source_id, length);
+ printf("Scan from flow data %" PRIu64
+ " direction %d length %u client port %u server port %u\n", session_data->seq_num,
+ source_id, length, flow->client_port, flow->server_port);
fflush(stdout);
}
#endif
// us to overcome this limitation and reuse the entire HTTP infrastructure.
type = SEC_BODY_OLD;
uint32_t not_used;
- prepare_flush(session_data, ¬_used, SEC_STATUS, 14, 0, 0, false, 0);
+ prepare_flush(session_data, ¬_used, SEC_STATUS, 14, 0, 0, false, 0, 14, true);
my_inspector->process((const uint8_t*)"HTTP/0.9 200 .", 14, flow, SRC_SERVER, false);
- prepare_flush(session_data, ¬_used, SEC_HEADER, 0, 0, 0, false, 0);
+ prepare_flush(session_data, ¬_used, SEC_HEADER, 0, 0, 0, false, 0, 0, true);
my_inspector->process((const uint8_t*)"", 0, flow, SRC_SERVER, false);
}
if (cutter->get_octets_seen() == MAX_OCTETS)
{
session_data->infractions[source_id] += INF_ENDLESS_HEADER;
+ // FIXIT-L the following call seems inappropriate for headers and trailers. Those cases
+ // should be an unconditional EVENT_LOSS_OF_SYNC.
session_data->events[source_id].generate_misformatted_http(data, length);
// FIXIT-H need to process this data not just discard it.
session_data->type_expected[source_id] = SEC_ABORT;
case SCAN_DISCARD:
case SCAN_DISCARD_PIECE:
prepare_flush(session_data, flush_offset, SEC_DISCARD, cutter->get_num_flush(), 0, 0,
- false, 0);
+ false, 0, cutter->get_octets_seen(), true);
if (cut_result == SCAN_DISCARD)
{
delete cutter;
const uint32_t flush_octets = cutter->get_num_flush();
prepare_flush(session_data, flush_offset, type, flush_octets, cutter->get_num_excess(),
cutter->get_num_head_lines(), cutter->get_is_broken_chunk(),
- cutter->get_num_good_chunks());
+ cutter->get_num_good_chunks(), cutter->get_octets_seen(),
+ !((type == SEC_BODY_CL) || (type == SEC_BODY_OLD)));
if (cut_result == SCAN_FOUND)
{
delete cutter;
(session_data->type_expected[source_id] == SEC_STATUS))
{
session_data->infractions[source_id] += INF_PARTIAL_START;
+ // FIXIT-M why not use generate_misformatted_http()?
session_data->events[source_id].create_event(EVENT_LOSS_OF_SYNC);
return false;
}
prepare_flush(session_data, ¬_used, session_data->type_expected[source_id], 0, 0,
session_data->cutter[source_id]->get_num_head_lines() + 1,
session_data->cutter[source_id]->get_is_broken_chunk(),
- session_data->cutter[source_id]->get_num_good_chunks());
+ session_data->cutter[source_id]->get_num_good_chunks(),
+ session_data->cutter[source_id]->get_octets_seen(),
+ true);
return true;
}