Add `num_bhttp_chunks` flag and remove `indeterminate_length` flag. If `num_bhttp_chunks` is not set or is set to -1, it will match the chunked flag mode. If `num_bhttp_chunks` is set to 0, the logic will use known-length BHTTP. If it is more than 0, then it will use indeterminate-length BHTTP and attempt to split the post data (if any) by `num_bhttp_chunks`. PiperOrigin-RevId: 897754014
diff --git a/quiche/quic/masque/masque_ohttp_client.cc b/quiche/quic/masque/masque_ohttp_client.cc index 540c7a7..6e8d5d2 100644 --- a/quiche/quic/masque/masque_ohttp_client.cc +++ b/quiche/quic/masque/masque_ohttp_client.cc
@@ -81,6 +81,24 @@ return absl::OkStatus(); } +absl::StatusOr<std::vector<absl::string_view>> SplitIntoChunks( + absl::string_view data, int num_chunks) { + if (num_chunks <= 0) { + return absl::InvalidArgumentError("num_chunks must be greater than 0"); + } + if (data.size() < num_chunks) { + return absl::InvalidArgumentError("data is smaller than num_chunks"); + } + std::vector<absl::string_view> chunks; + size_t offset = 0; + for (size_t i = 0; i < num_chunks; ++i) { + size_t end = (data.size() * (i + 1)) / num_chunks; + chunks.push_back(data.substr(offset, end - offset)); + offset = end; + } + return chunks; +} + } // namespace std::string MasqueOhttpClient::Config::PerRequestConfig::method() const { @@ -405,10 +423,11 @@ "Cannot send OHTTP request without OHTTP client"); } std::string encoded_data; - const bool use_indeterminate_length = - per_request_config.use_indeterminate_length().value_or( - per_request_config.use_chunked_ohttp()); - if (use_indeterminate_length) { + int num_bhttp_chunks = per_request_config.num_bhttp_chunks(); + if (num_bhttp_chunks < 0) { + num_bhttp_chunks = (per_request_config.use_chunked_ohttp() ? 1 : 0); + } + if (num_bhttp_chunks > 0) { BinaryHttpRequest::IndeterminateLengthEncoder encoder; QUICHE_ASSIGN_OR_RETURN(encoded_data, @@ -422,26 +441,17 @@ encoder.EncodeHeaders(absl::MakeSpan(headers))); encoded_data += encoded_headers; if (!post_data.empty()) { - absl::string_view body = post_data; - std::vector<absl::string_view> body_chunks; - if (body.size() > 1) { - // Intentionally split the data into two chunks to test body chunking. - body_chunks.push_back(body.substr(0, body.size() / 2)); - body_chunks.push_back(body.substr(body.size() / 2)); - } else { - body_chunks.push_back(body); - } + QUICHE_ASSIGN_OR_RETURN(std::vector<absl::string_view> body_chunks, + SplitIntoChunks(post_data, num_bhttp_chunks)); QUICHE_ASSIGN_OR_RETURN( std::string encoded_body, encoder.EncodeBodyChunks(absl::MakeSpan(body_chunks), /*body_chunks_done=*/false)); encoded_data += encoded_body; } - std::vector<absl::string_view> empty_body_chunks; QUICHE_ASSIGN_OR_RETURN( std::string encoded_final_chunk, - encoder.EncodeBodyChunks(absl::MakeSpan(empty_body_chunks), - /*body_chunks_done=*/true)); + encoder.EncodeBodyChunks({}, /*body_chunks_done=*/true)); encoded_data += encoded_final_chunk; std::vector<quiche::BinaryHttpMessage::FieldView> trailers; QUICHE_ASSIGN_OR_RETURN(std::string encoded_trailers,
diff --git a/quiche/quic/masque/masque_ohttp_client.h b/quiche/quic/masque/masque_ohttp_client.h index 6f4db6a..8a5c02b 100644 --- a/quiche/quic/masque/masque_ohttp_client.h +++ b/quiche/quic/masque/masque_ohttp_client.h
@@ -54,10 +54,7 @@ void SetUseChunkedOhttp(bool use_chunked_ohttp) { use_chunked_ohttp_ = use_chunked_ohttp; } - void SetUseIndeterminateLength( - std::optional<bool> use_indeterminate_length) { - use_indeterminate_length_ = use_indeterminate_length; - } + void SetNumBhttpChunks(int num_chunks) { num_bhttp_chunks_ = num_chunks; } void SetExpectedGatewayError(const std::string& expected_gateway_error) { expected_gateway_error_ = expected_gateway_error; } @@ -84,9 +81,7 @@ return outer_headers_; } bool use_chunked_ohttp() const { return use_chunked_ohttp_; } - std::optional<bool> use_indeterminate_length() const { - return use_indeterminate_length_; - } + int num_bhttp_chunks() const { return num_bhttp_chunks_; } std::optional<std::string> expected_gateway_error() const { return expected_gateway_error_; } @@ -107,7 +102,7 @@ std::vector<std::pair<std::string, std::string>> headers_; std::vector<std::pair<std::string, std::string>> outer_headers_; bool use_chunked_ohttp_ = false; - std::optional<bool> use_indeterminate_length_; + int num_bhttp_chunks_ = -1; std::optional<std::string> expected_gateway_error_; std::optional<uint16_t> expected_gateway_status_code_; std::optional<uint16_t> expected_encapsulated_status_code_;
diff --git a/quiche/quic/masque/masque_ohttp_client_bin.cc b/quiche/quic/masque/masque_ohttp_client_bin.cc index 13b9bbb..fab77ab 100644 --- a/quiche/quic/masque/masque_ohttp_client_bin.cc +++ b/quiche/quic/masque/masque_ohttp_client_bin.cc
@@ -32,12 +32,6 @@ DEFINE_QUICHE_COMMAND_LINE_FLAG(bool, chunked, false, "If true, use chunked OHTTP."); -DEFINE_QUICHE_COMMAND_LINE_FLAG(std::optional<bool>, indeterminate_length, - std::nullopt, - "If set, overrides whether to use the " - "indeterminate length binary HTTP encoding. If " - "unset, uses the value of --chunked."); - DEFINE_QUICHE_COMMAND_LINE_FLAG(int, address_family, 0, "IP address family to use. Must be 0, 4 or 6. " "Defaults to 0 which means any."); @@ -64,6 +58,12 @@ "--post_data or --post_data_file is set."); DEFINE_QUICHE_COMMAND_LINE_FLAG( + int, num_bhttp_chunks, -1, + "Number of indeterminate-length BHTTP chunks to split post data into. If " + "not set or if set to -1, it will match the chunked flag mode. If set to " + "0, the client will use known-length BHTTP."); + +DEFINE_QUICHE_COMMAND_LINE_FLAG( std::vector<std::string>, header, {}, "Adds a header field to the encapsulated binary request. Separate the " "header name and value with a colon. Can be specified multiple times."); @@ -122,8 +122,6 @@ quiche::GetQuicheCommandLineFlag(FLAGS_use_mtls_for_key_fetch); const bool use_chunked_ohttp = quiche::GetQuicheCommandLineFlag(FLAGS_chunked); - const std::optional<bool> indeterminate_length = - quiche::GetQuicheCommandLineFlag(FLAGS_indeterminate_length); const std::string client_cert_file = quiche::GetQuicheCommandLineFlag(FLAGS_client_cert_file); const std::string client_cert_key_file = @@ -156,6 +154,8 @@ } std::optional<std::string> method = quiche::GetQuicheCommandLineFlag(FLAGS_method); + const int num_bhttp_chunks = + quiche::GetQuicheCommandLineFlag(FLAGS_num_bhttp_chunks); std::vector<std::string> headers = quiche::GetQuicheCommandLineFlag(FLAGS_header); std::vector<std::string> key_fetch_headers = @@ -225,7 +225,7 @@ per_request_config.AddPrivateToken(generated_private_token)); } per_request_config.SetUseChunkedOhttp(use_chunked_ohttp); - per_request_config.SetUseIndeterminateLength(indeterminate_length); + per_request_config.SetNumBhttpChunks(num_bhttp_chunks); if (expect_gateway_error.has_value()) { per_request_config.SetExpectedGatewayError(*expect_gateway_error); }