blob: cfbdab63b8fd02ad5ef7740dd1397b66b8f369cd [file] [edit]
// Copyright 2026 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef QUICHE_BALSA_HTTP_PROTOCOL_DEFECTS_H_
#define QUICHE_BALSA_HTTP_PROTOCOL_DEFECTS_H_
#include "absl/strings/string_view.h"
#include "quiche/common/platform/api/quiche_export.h"
#include "quiche/common/quiche_callbacks.h"
namespace quiche {
class QUICHE_EXPORT HttpProtocolDefects {
public:
bool invalid_method_in_request_first_line = false;
bool multiple_content_length_keys = false;
bool missing_semicolon_in_chunk_extension = false;
bool token_before_semicolon_in_chunk_extension = false;
bool invalid_response_code = false;
bool multiple_spaces_in_firstline = false;
bool obs_fold_in_header_values = false;
bool obs_fold_in_trailer_values = false;
bool chunked_body_does_not_end_with_crlf_crlf = false;
bool stray_data_after_chunk = false;
bool lone_cr_in_request_headers = false;
bool header_name_contains_double_quote = false;
bool header_missing_colon = false;
bool tab_or_cr_found_in_firstline = false;
bool obs_text_found_in_header_name = false;
bool transfer_encoding_and_content_length = false;
bool unknown_transfer_encoding = false;
bool multiple_transfer_encoding_keys = false;
void Merge(const HttpProtocolDefects& other) {
invalid_method_in_request_first_line |=
other.invalid_method_in_request_first_line;
multiple_content_length_keys |= other.multiple_content_length_keys;
missing_semicolon_in_chunk_extension |=
other.missing_semicolon_in_chunk_extension;
token_before_semicolon_in_chunk_extension |=
other.token_before_semicolon_in_chunk_extension;
invalid_response_code |= other.invalid_response_code;
multiple_spaces_in_firstline |= other.multiple_spaces_in_firstline;
obs_fold_in_header_values |= other.obs_fold_in_header_values;
obs_fold_in_trailer_values |= other.obs_fold_in_trailer_values;
chunked_body_does_not_end_with_crlf_crlf |=
other.chunked_body_does_not_end_with_crlf_crlf;
stray_data_after_chunk |= other.stray_data_after_chunk;
lone_cr_in_request_headers |= other.lone_cr_in_request_headers;
header_name_contains_double_quote |=
other.header_name_contains_double_quote;
header_missing_colon |= other.header_missing_colon;
tab_or_cr_found_in_firstline |= other.tab_or_cr_found_in_firstline;
obs_text_found_in_header_name |= other.obs_text_found_in_header_name;
transfer_encoding_and_content_length |=
other.transfer_encoding_and_content_length;
unknown_transfer_encoding |= other.unknown_transfer_encoding;
multiple_transfer_encoding_keys |= other.multiple_transfer_encoding_keys;
}
void ForEachDefect(
UnretainedCallback<void(absl::string_view)> callback) const {
if (invalid_method_in_request_first_line) {
callback("invalid_method_in_request_first_line");
}
if (multiple_content_length_keys) {
callback("multiple_content_length_keys");
}
if (missing_semicolon_in_chunk_extension) {
callback("missing_semicolon_in_chunk_extension");
}
if (token_before_semicolon_in_chunk_extension) {
callback("token_before_semicolon_in_chunk_extension");
}
if (invalid_response_code) {
callback("invalid_response_code");
}
if (multiple_spaces_in_firstline) {
callback("multiple_spaces_in_firstline");
}
if (obs_fold_in_header_values) {
callback("obs_fold_in_header_values");
}
if (obs_fold_in_trailer_values) {
callback("obs_fold_in_trailer_values");
}
if (chunked_body_does_not_end_with_crlf_crlf) {
callback("chunked_body_does_not_end_with_crlf_crlf");
}
if (stray_data_after_chunk) {
callback("stray_data_after_chunk");
}
if (lone_cr_in_request_headers) {
callback("lone_cr_in_request_headers");
}
if (header_name_contains_double_quote) {
callback("header_name_contains_double_quote");
}
if (header_missing_colon) {
callback("header_missing_colon");
}
if (tab_or_cr_found_in_firstline) {
callback("tab_or_cr_found_in_firstline");
}
if (obs_text_found_in_header_name) {
callback("obs_text_found_in_header_name");
}
if (transfer_encoding_and_content_length) {
callback("transfer_encoding_and_content_length");
}
if (unknown_transfer_encoding) {
callback("unknown_transfer_encoding");
}
if (multiple_transfer_encoding_keys) {
callback("multiple_transfer_encoding_keys");
}
}
// T should ideally be strongly typed as
// logs::gfe::GfeLog::HttpProtocolDefects but since Quiche can only depend on
// targets that are compatible with non_prod, a template is used instead.
template <typename T>
void PopulateLogDefects(T& log_defects) const {
if (invalid_method_in_request_first_line) {
log_defects.set_invalid_method_in_request_first_line(true);
}
if (multiple_content_length_keys) {
log_defects.set_multiple_content_length_keys_detected(true);
}
if (missing_semicolon_in_chunk_extension) {
log_defects.set_missing_semicolon_in_chunk_extension(true);
}
if (token_before_semicolon_in_chunk_extension) {
log_defects.set_token_before_semicolon_in_chunk_extension(true);
}
if (invalid_response_code) {
log_defects.set_invalid_response_code(true);
}
if (multiple_spaces_in_firstline) {
log_defects.set_multiple_spaces_found_in_first_line(true);
}
if (obs_fold_in_header_values) {
log_defects.set_obs_fold_in_header_value(true);
}
if (obs_fold_in_trailer_values) {
log_defects.set_obs_fold_in_trailer_value(true);
}
if (chunked_body_does_not_end_with_crlf_crlf) {
log_defects.set_chunked_request_ends_with_crlflf(true);
}
if (stray_data_after_chunk) {
log_defects.set_stray_data_after_chunk(true);
}
if (lone_cr_in_request_headers) {
log_defects.set_cr_found_in_header_value(true);
}
if (header_name_contains_double_quote) {
log_defects.set_header_name_contains_double_quote(true);
}
if (header_missing_colon) {
log_defects.set_header_missing_colon(true);
}
if (transfer_encoding_and_content_length) {
log_defects.set_transfer_encoding_and_content_length(true);
}
if (unknown_transfer_encoding) {
log_defects.set_unknown_transfer_encoding(true);
}
if (multiple_transfer_encoding_keys) {
log_defects.set_multiple_transfer_encoding_keys(true);
}
if (tab_or_cr_found_in_firstline) {
log_defects.set_tab_or_cr_found_in_firstline(true);
}
if (obs_text_found_in_header_name) {
log_defects.set_obs_text_found_in_header_name(true);
}
}
};
} // namespace quiche
#endif // QUICHE_BALSA_HTTP_PROTOCOL_DEFECTS_H_