Add new balsa_frame microbenchmark This microbenchmark is very simple and tests the performance of parsing a chunked request with extensions with the strictest HttpValidationPolicy options available since they all add a bit of extra overhead. It also defines a nearly no-op visitor which should mimic the overhead required to invoke an integrators visitor implementation. A nearly identical test is added to balsa_frame_test.cc to test the correctness of the logic. All `_benchmark.cc` are already excluded by copybara rules. ``` Benchmarking blaze-out/k8-opt/bin/third_party/quiche/balsa/balsa_frame_benchmark Run on reubent3.cam (128 X 2695 MHz CPUs); 2026-02-11T17:21:00.272874364-05:00 CPU: AMD Rome (64 cores) dL1:32KB dL2:512KB dL3:256MB ***WARNING*** CPU scaling is enabled, the benchmark timings may be noisy, see http://go/benchmark#cpu-scaling Benchmark Time(ns) CPU(ns) Iterations ---------------------------------------------------------------------- BM_ProcessInputChunked 1703 1762 36579 5.334kB/s BM_ProcessInputChunked 1741 1629 31899 6.615kB/s BM_ProcessInputChunked 1721 1719 39511 5.061kB/s BM_ProcessInputChunked 1731 1718 39599 5.053kB/s BM_ProcessInputChunked 1689 1712 39726 5.053kB/s BM_ProcessInputChunked 1699 1642 31726 6.599kB/s BM_ProcessInputChunked 1686 1719 39580 5.053kB/s BM_ProcessInputChunked 1685 1711 39837 5.044kB/s BM_ProcessInputChunked 1693 1716 39636 5.053kB/s BM_ProcessInputChunked 1693 1710 39783 5.053kB/s BM_ProcessInputChunked 1711 1702 39922 5.060kB/s BM_ProcessInputChunked_mean 1704 1706 417798 5.315kB/s BM_ProcessInputChunked_stddev 17.9 33.2 417798 566.449B/s ``` Protected by adding google3 only performance test. PiperOrigin-RevId: 869351347
diff --git a/quiche/balsa/balsa_frame_test.cc b/quiche/balsa/balsa_frame_test.cc index 1ff0488..3bf7873 100644 --- a/quiche/balsa/balsa_frame_test.cc +++ b/quiche/balsa/balsa_frame_test.cc
@@ -5101,5 +5101,48 @@ EXPECT_EQ(BalsaFrameEnums::BALSA_NO_ERROR, balsa_frame_.ErrorCode()); } +TEST_F(HTTPBalsaFrameTest, MostRestrictiveTest) { + BalsaFrame balsa_frame; + BalsaHeaders headers; + balsa_frame.set_is_request(true); + balsa_frame.set_balsa_headers(&headers); + balsa_frame.set_http_validation_policy(kMostStrictHttpValidationPolicy); + + std::string message_headers = + "POST /search?q=benchy \t HTTP/1.1 \t \r\n" + "Transfer-Encoding: chunked\r\n" + "header_1: a\r\n" + "header_2: b\r\n" + "header_3: c\r\n" + "header_4: d\r\n" + "header_5: e\r\n" + "\r\n"; + std::string message_body = + "A;chunked_extension=\"foobar\"quote\"\"\r\n" + "0123456789\r\n" + "3f\r\n" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\r\n" + "2; chunked_extension=\"foobar\"quote\"\"\r\n" + "x \r\n" + "0; that's all folks\r\n"; + std::string trailer_data = + "a_trailer_key: and a trailer value\r\n" + "\r\n"; + + std::string message = + absl::StrCat(message_headers, message_body, trailer_data); + + size_t header_bytes_consumed = + balsa_frame.ProcessInput(message.data(), message.size()); + EXPECT_EQ(header_bytes_consumed, message_headers.size()); + + size_t body_bytes_consumed = balsa_frame.ProcessInput( + message.data() + message_headers.size(), message.size()); + EXPECT_EQ(body_bytes_consumed, message_body.size() + trailer_data.size()); + EXPECT_TRUE(balsa_frame.MessageFullyRead()); + EXPECT_FALSE(balsa_frame.Error()); + EXPECT_EQ(balsa_frame.ErrorCode(), BalsaFrameEnums::BALSA_NO_ERROR); +} + } // namespace } // namespace quiche::test
diff --git a/quiche/balsa/http_validation_policy.h b/quiche/balsa/http_validation_policy.h index fc5cd7e..a197071 100644 --- a/quiche/balsa/http_validation_policy.h +++ b/quiche/balsa/http_validation_policy.h
@@ -176,6 +176,29 @@ } }; +static constexpr HttpValidationPolicy kMostStrictHttpValidationPolicy = { + .disallow_header_continuation_lines = true, + .require_header_colon = true, + .disallow_multiple_content_length = true, + .disallow_transfer_encoding_with_content_length = true, + .validate_transfer_encoding = true, + .require_content_length_if_body_required = true, + .disallow_double_quote_in_header_name = true, + .disallow_invalid_header_characters_in_response = true, + .disallow_lone_cr_in_request_headers = true, + .disallow_lone_cr_in_chunk_extension = true, + .disallow_invalid_target_uris = true, + .sanitize_cr_tab_in_first_line = + quiche::HttpValidationPolicy::FirstLineValidationOption::SANITIZE, + .disallow_obs_text_in_field_names = true, + .disallow_lone_lf_in_chunk_extension = true, + .require_chunked_body_end_with_crlf_crlf = true, + .sanitize_firstline_spaces = + quiche::HttpValidationPolicy::FirstLineValidationOption::SANITIZE, + .sanitize_obs_fold_in_header_values = true, + .disallow_stray_data_after_chunk = true, + .disallow_invalid_request_methods = true}; + } // namespace quiche #endif // QUICHE_BALSA_HTTP_VALIDATION_POLICY_H_