unsigned NHttpFlowData::nhttp_flow_id = 0;
-NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id) {}
+NHttpFlowData::NHttpFlowData() : FlowData(nhttp_flow_id) { }
NHttpFlowData::~NHttpFlowData() {
delete request_line;
msg_section->legacy_clients();
if (test_output) {
- if (!NHttpTestInput::test_input) msg_section->print_section(stdout);
+ if (!NHttpTestInput::test_input) {
+ msg_section->print_section(stdout);
+ }
else {
if (NHttpTestInput::test_input_source->get_test_number() != file_test_number) {
if (test_out) fclose (test_out);
msg_section->print_section(test_out);
printf("Finished processing section from test %" PRIi64 "\n", file_test_number);
}
+ fflush(nullptr);
}
}
section_buffer = new uint8_t[65536];
}
- SourceId source_id = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER;
+ SourceId source_id = to_server() ? SRC_CLIENT : SRC_SERVER;
copied = len;
return nullptr;
}
-PAF_Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flush_offset) {
+PAF_Status NHttpStreamSplitter::scan (Flow* flow, const uint8_t* data, uint32_t length, uint32_t, uint32_t* flush_offset) {
// When the system begins providing TCP connection close information this won't always be false. &&&
bool tcp_close = false;
- // This is the session state information we share with HTTP Inspect and store with stream. A session is defined by a TCP connection.
- // Since PAF is the first to see a new TCP connection the new flow data object is created here.
+ // This is the session state information we share with HTTP Inspect and store with stream. A session is defined
+ // by a TCP connection. Since PAF is the first to see a new TCP connection the new flow data object is created here.
NHttpFlowData* session_data = (NHttpFlowData*)flow->get_application_data(NHttpFlowData::nhttp_flow_id);
if (session_data == nullptr) flow->set_application_data(session_data = new NHttpFlowData);
assert(session_data != nullptr);
- SourceId source_id = (flags & PKT_FROM_CLIENT) ? SRC_CLIENT : SRC_SERVER;
+ SourceId source_id = to_server() ? SRC_CLIENT : SRC_SERVER;
if (NHttpTestInput::test_input) {
+ // This block substitutes a completely new data buffer supplied by the test tool in place of the "real" data.
+ // It also rewrites the buffer length, source ID, and TCP close indicator.
*flush_offset = length;
bool need_break;
- NHttpTestInput::test_input_source->scan((uint8_t*&)data, length, source_id, tcp_close, need_break);
+ uint8_t* test_data = nullptr;
+ NHttpTestInput::test_input_source->scan(test_data, length, source_id, tcp_close, need_break);
if (length == 0) return PAF_FLUSH;
+ data = test_data;
if (need_break) flow->set_application_data(session_data = new NHttpFlowData);
}
case SEC_BODY:
case SEC_CHUNKBODY:
paf_max = 16384;
- prepare_flush(session_data, flush_offset, source_id, type,
- tcp_close && (session_data->octets_expected[source_id] >= length),
- 0, session_data->octets_expected[source_id]);
+ if ((!tcp_close) || (length > session_data->octets_expected[source_id])) {
+ prepare_flush(session_data, flush_offset, source_id, type, false, 0, session_data->octets_expected[source_id]);
+ }
+ else {
+ // The TCP connection has closed and this is the possibly incomplete final section
+ prepare_flush(session_data, flush_offset, source_id, type, true, 0, length);
+ }
return PAF_FLUSH;
case SEC_ABORT:
return PAF_ABORT;
class NHttpStreamSplitter : public StreamSplitter {
public:
NHttpStreamSplitter(bool is_client_to_server, NHttpInspect* my_inspector_) : StreamSplitter(is_client_to_server),
- my_inspector(my_inspector_) {};
+ my_inspector(my_inspector_) { };
~NHttpStreamSplitter() { delete[] section_buffer; };
- PAF_Status scan(Flow* flow, const uint8_t* data, uint32_t length, uint32_t flags, uint32_t* flush_offset);
+ PAF_Status scan(Flow* flow, const uint8_t* data, uint32_t length, uint32_t not_used, uint32_t* flush_offset);
const StreamBuffer* reassemble(Flow* flow, unsigned total, unsigned offset, const uint8_t* data, unsigned len,
uint32_t flags, unsigned& copied);
bool is_paf() { return true; };
// Must present unflushed leftovers to PAF again.
// If we don't take this opportunity to left justify our data in the buffer we may "walk" to the right until we run out of buffer space
memmove(msg_buf, msg_buf+flush_octets, length);
- tcp_close = tcp_already_closed;
+ tcp_close = tcp_closed;
return;
}
// If we reach here then PAF has already flushed all the data we have read so far.
- tcp_already_closed = false;
+ tcp_closed = false;
}
else {
// The data we gave PAF last time was not flushed
else if ((command_length == strlen("break")) && !memcmp(command_value, "break", strlen("break"))) {
need_break = true;
}
+ else if ((command_length == strlen("tcpclose")) && !memcmp(command_value, "tcpclose", strlen("tcpclose"))) {
+ tcp_close = true;
+ tcp_closed = true;
+ }
else if ((command_length == strlen("bodyend")) && !memcmp(command_value, "bodyend", strlen("bodyend"))) {
term_bytes[0] = 'x';
term_bytes[1] = 'y';
FILE *test_data_file;
uint8_t msg_buf[2 * NHttpEnums::MAXOCTETS];
bool just_flushed = true; // all octets sent to inspection and must resume reading the file
- bool tcp_already_closed = false; // so we can keep presenting a TCP close to PAF until all the remaining octets are consumed and flushed
+ bool tcp_closed = false; // so we can keep presenting a TCP close to PAF until all the remaining octets are consumed and flushed
uint32_t flush_octets = 0; // number of octets that have been flushed and must go to inspection
uint32_t previous_offset = 0; // last character in the buffer shown to PAF but not flushed yet
uint32_t end_offset = 0; // last read character in the buffer
# 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.
#
+# 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).
+#
+# 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.
+#
# Lines beginning with # are comments. Lines beginning with @ are commands. This does not apply to lines in the middle of a paragraph.
#
# Command lines are left justified, lower case, with no whitespace:
@break
@request
+POST /basic/request/response/pair/with/large/bodies/both/ways HTTP/1.1\r\n
+Host: www.testcase.com\r\n
+Content-Length: 50000\r\n
+\r\n
+
+body1-start
+
+@response
+
+HTTP/1.1 200 OK\r\n
+Content-Length: 60000\r\n
+\r\n
+body2-start
# ***********************************************************************************************