INF_BAD_CHAR_IN_HEADER_NAME,
INF_HEADER_WRAPPING,
INF_CHUNK_BAD_SEP,
+ INF_MULTIPLE_100_RESPONSES,
+ INF_UNEXPECTED_100_RESPONSE,
+ INF_UNKNOWN_1XX_STATUS,
+ INF_EXPECT_WITHOUT_BODY_CL0,
+ INF_EXPECT_WITHOUT_BODY_NO_CL,
INF__MAX_VALUE
};
EVENT_CR_WITHOUT_LF,
EVENT_CHUNK_BAD_SEP,
EVENT_CHUNK_BARE_LF,
+ EVENT_MULTIPLE_100_RESPONSES,
+ EVENT_UNEXPECTED_100_RESPONSE,
+ EVENT_UNKNOWN_1XX_STATUS,
+ EVENT_EXPECT_WITHOUT_BODY, // 90
EVENT__MAX_VALUE
};
else if (content_length == 0)
{
// No body
+ if (get_header_count(HEAD_EXPECT) > 0)
+ {
+ add_infraction(INF_EXPECT_WITHOUT_BODY_CL0);
+ create_event(EVENT_EXPECT_WITHOUT_BODY);
+ }
session_data->half_reset(source_id);
return;
}
add_infraction(INF_POST_WO_BODY);
create_event(EVENT_UNBOUNDED_POST);
}
+ if (get_header_count(HEAD_EXPECT) > 0)
+ {
+ add_infraction(INF_EXPECT_WITHOUT_BODY_NO_CL);
+ create_event(EVENT_EXPECT_WITHOUT_BODY);
+ }
session_data->half_reset(source_id);
return;
}
#include "http_msg_status.h"
#include "http_api.h"
+#include "http_msg_header.h"
#include "stream/stream.h"
using namespace HttpEnums;
add_infraction(INF_BAD_STAT_CODE);
create_event(EVENT_INVALID_STATCODE);
}
+ if ((status_code_num >= 102) && (status_code_num <= 199))
+ {
+ add_infraction(INF_UNKNOWN_1XX_STATUS);
+ create_event(EVENT_UNKNOWN_1XX_STATUS);
+ }
}
void HttpMsgStatus::gen_events()
}
}
- if( !transaction->get_request() && (trans_num == 1) )
+ if (!transaction->get_request() && (trans_num == 1))
{
- if( flow->is_pdu_inorder(SSN_DIR_FROM_SERVER) )
+ if (flow->is_pdu_inorder(SSN_DIR_FROM_SERVER))
{
// HTTP response without a request. Possible ssh tunneling
add_infraction(INF_RSP_WO_REQ);
// responses to all be included in the same transaction. It's not obvious whether that is
// the best way to handle what should be a highly abnormal situation.
if (status_code_num == 100)
- transaction->second_response_coming();
+ {
+ // Were we "Expect"-ing this?
+ HttpMsgHeader* const req_header = transaction->get_header(SRC_CLIENT);
+ if ((req_header != nullptr) && (req_header->get_header_count(HEAD_EXPECT) == 0))
+ {
+ add_infraction(INF_UNEXPECTED_100_RESPONSE);
+ create_event(EVENT_UNEXPECTED_100_RESPONSE);
+ }
+ transaction->set_one_hundred_response();
+ }
}
session_data->section_type[source_id] = SEC__NOT_COMPUTE;
}
{ EVENT_CR_WITHOUT_LF, "HTTP header line terminated by CR without a LF" },
{ EVENT_CHUNK_BAD_SEP, "chunk terminated by nonstandard separator" },
{ EVENT_CHUNK_BARE_LF, "chunk length terminated by LF without CR" },
+ { EVENT_MULTIPLE_100_RESPONSES, "more than one response with 100 status code" },
+ { EVENT_UNEXPECTED_100_RESPONSE, "100 status code not in response to Expect header" },
+ { EVENT_UNKNOWN_1XX_STATUS, "1XX status code other than 100 or 101" },
+ { EVENT_EXPECT_WITHOUT_BODY, "Expect header sent without a message body" },
{ 0, nullptr }
};
(session_data->transaction[SRC_SERVER] != nullptr) &&
session_data->transaction[SRC_SERVER]->second_response_expected)
{
- assert(session_data->transaction[SRC_SERVER] != nullptr);
session_data->transaction[SRC_SERVER]->second_response_expected = false;
delete session_data->transaction[SRC_SERVER]->status;
session_data->transaction[SRC_SERVER]->status = nullptr;
return events[source_id];
}
+void HttpTransaction::set_one_hundred_response()
+{
+ assert(response_seen);
+ if (one_hundred_response)
+ {
+ *infractions[SRC_SERVER] += INF_MULTIPLE_100_RESPONSES;
+ events[SRC_SERVER]->create_event(EVENT_MULTIPLE_100_RESPONSES);
+ }
+ one_hundred_response = true;
+ second_response_expected = true;
+}
+
HttpInfractions* get_infractions(HttpEnums::SourceId source_id);
HttpEventGen* get_events(HttpEnums::SourceId source_id);
- void second_response_coming() { assert(response_seen); second_response_expected = true; }
+ void set_one_hundred_response();
bool final_response() const { return !second_response_expected; }
private:
HttpEventGen* events[2] = { nullptr, nullptr };
bool response_seen = false;
+ bool one_hundred_response = false;
bool second_response_expected = false;
// This is a form of reference counting that prevents premature/double deletion of a
// Interim response
section_type[SRC_SERVER] = SEC_STATUS;
CHECK(trans == HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER));
- trans->second_response_coming();
+ trans->set_one_hundred_response();
section_type[SRC_SERVER] = SEC_HEADER;
CHECK(trans == HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER));
{
section_type[SRC_SERVER] = SEC_STATUS;
CHECK(trans == HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER));
- trans->second_response_coming();
+ trans->set_one_hundred_response();
section_type[SRC_SERVER] = SEC_HEADER;
CHECK(trans == HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER));
}
section_type[SRC_SERVER] = SEC_STATUS;
HttpTransaction* trans = HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER);
CHECK(trans != nullptr);
- trans->second_response_coming();
+ trans->set_one_hundred_response();
section_type[SRC_SERVER] = SEC_HEADER;
CHECK(trans == HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER));
section_type[SRC_SERVER] = SEC_BODY_CHUNK;
// Interim response to fourth request
section_type[SRC_SERVER] = SEC_STATUS;
CHECK(trans[3] == HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER));
- trans[3]->second_response_coming();
+ trans[3]->set_one_hundred_response();
section_type[SRC_SERVER] = SEC_HEADER;
CHECK(trans[3] == HttpTransaction::attach_my_transaction(flow_data, SRC_SERVER));