#include "config.h"
#endif
+#include "http_enum.h"
#include "http_header_normalizer.h"
#include <cstring>
// This derivation removes leading and trailing linear white space and replaces internal strings of
// linear whitespace with a single <SP>
-int32_t HeaderNormalizer::derive_header_content(const uint8_t* value, int32_t length,
- uint8_t* buffer)
+static int32_t derive_header_content(const uint8_t* value, int32_t length, uint8_t* buffer,
+ bool alert_ws, HttpInfractions* infractions, HttpEventGen* events)
{
int32_t out_length = 0;
+ bool beginning = true;
bool last_white = true;
for (int32_t k=0; k < length; k++)
{
if (!is_sp_tab_cr_lf[value[k]])
{
+ if (alert_ws && last_white && !beginning)
+ {
+ // white space which is not at beginning or end
+ *infractions += INF_BAD_HEADER_WHITESPACE;
+ events->create_event(EVENT_BAD_HEADER_WHITESPACE);
+ }
+ beginning = false;
last_white = false;
buffer[out_length++] = value[k];
}
// number of normalization functions is odd or even, the initial buffer is chosen so that the
// final normalization leaves the normalized header value in norm_value.
- uint8_t* const norm_value = new uint8_t[buffer_length]();
- uint8_t* const temp_space = new uint8_t[buffer_length]();
+ uint8_t* const norm_value = new uint8_t[buffer_length];
+ uint8_t* const temp_space = new uint8_t[buffer_length];
uint8_t* const norm_start = (num_normalizers%2 == 0) ? norm_value : temp_space;
uint8_t* working = norm_start;
int32_t data_length = 0;
while (header_name_id[++curr_match] != head_id);
}
int32_t growth = derive_header_content(header_value[curr_match].start(),
- header_value[curr_match].length(), working);
+ header_value[curr_match].length(), working, alert_ws, infractions, events);
working += growth;
data_length += growth;
}
{
public:
constexpr HeaderNormalizer(HttpEnums::EventSid _repeat_event,
- HttpEnums::Infraction _repeat_inf, NormFunc* f1, NormFunc* f2, NormFunc* f3)
- : repeat_event(_repeat_event), repeat_inf(_repeat_inf), normalizer { f1, f2, f3 },
+ HttpEnums::Infraction _repeat_inf, bool _alert_ws,
+ NormFunc* f1, NormFunc* f2, NormFunc* f3)
+ : repeat_event(_repeat_event), repeat_inf(_repeat_inf), alert_ws(_alert_ws),
+ normalizer { f1, f2, f3 },
num_normalizers((f1 != nullptr) + (f1 != nullptr)*(f2 != nullptr) + (f1 != nullptr)*(f2 !=
nullptr)*(f3 != nullptr)) { }
const int32_t num_headers, Field& result_field) const;
private:
- static int32_t derive_header_content(const uint8_t* value, int32_t length, uint8_t* buffer);
-
const HttpEnums::EventSid repeat_event;
const HttpEnums::Infraction repeat_inf;
+ const bool alert_ws; // alert if white space in middle of value
NormFunc* const normalizer[3];
const int num_normalizers;
};
};
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_BASIC
- { EVENT__NONE, INF__NONE, nullptr, nullptr, nullptr };
+ { EVENT__NONE, INF__NONE, false, nullptr, nullptr, nullptr };
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_NO_REPEAT
- { EVENT_REPEATED_HEADER, INF_REPEATED_HEADER, nullptr, nullptr, nullptr };
+ { EVENT_REPEATED_HEADER, INF_REPEATED_HEADER, false, nullptr, nullptr, nullptr };
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_CASE_INSENSITIVE
- { EVENT__NONE, INF__NONE, norm_to_lower, nullptr, nullptr };
+ { EVENT__NONE, INF__NONE, false, norm_to_lower, nullptr, nullptr };
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_NUMBER
- { EVENT_REPEATED_HEADER, INF_REPEATED_HEADER, norm_remove_lws, nullptr, nullptr };
+ { EVENT_REPEATED_HEADER, INF_REPEATED_HEADER, false, norm_remove_lws, nullptr, nullptr };
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_TOKEN_LIST
- { EVENT__NONE, INF__NONE, norm_remove_lws, norm_to_lower, nullptr };
+ { EVENT__NONE, INF__NONE, false, norm_remove_lws, norm_to_lower, nullptr };
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_METHOD_LIST
- { EVENT__NONE, INF__NONE, norm_remove_lws, nullptr, nullptr };
+ { EVENT__NONE, INF__NONE, false, norm_remove_lws, nullptr, nullptr };
// FIXIT-L implement a date normalization function that converts the three legal formats into a
// single standard format. For now we do nothing special for dates. This object is a placeholder
// to keep track of which headers have date values.
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_DATE
- { EVENT__NONE, INF__NONE, nullptr, nullptr, nullptr };
+ { EVENT__NONE, INF__NONE, false, nullptr, nullptr, nullptr };
// FIXIT-M implement a URI normalization function, probably by extending existing URI capabilities
// to cover relative formats
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_URI
- { EVENT__NONE, INF__NONE, nullptr, nullptr, nullptr };
+ { EVENT__NONE, INF__NONE, false, nullptr, nullptr, nullptr };
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_CONTENT_LENGTH
- { EVENT_MULTIPLE_CONTLEN, INF_MULTIPLE_CONTLEN, norm_remove_lws, nullptr, nullptr };
+ { EVENT_MULTIPLE_CONTLEN, INF_MULTIPLE_CONTLEN, true, norm_remove_lws, nullptr, nullptr };
const HeaderNormalizer HttpMsgHeadShared::NORMALIZER_CHARSET
- { EVENT__NONE, INF__NONE, norm_remove_quotes_lws, norm_to_lower, nullptr };
+ { EVENT__NONE, INF__NONE, false, norm_remove_quotes_lws, norm_to_lower, nullptr };
#if defined(__clang__)
// Designated initializers are not supported in C++11. However we're going to play compilation
{ EVENT_CONTENT_ENCODING_CHUNKED, "invalid value chunked in Content-Encoding header" },
{ EVENT_206_WITHOUT_RANGE, "206 response sent to a request without a Range header" },
{ EVENT_VERSION_NOT_UPPERCASE, "'HTTP' in version field not all upper case" },
+ { EVENT_BAD_HEADER_WHITESPACE, "white space embedded in critical header value" },
{ 0, nullptr }
};