Allow selecting the binary HTTP encoding in OHTTP test client

PiperOrigin-RevId: 865532368
diff --git a/quiche/quic/masque/masque_ohttp_client.cc b/quiche/quic/masque/masque_ohttp_client.cc
index 574f9d8..8bd965e 100644
--- a/quiche/quic/masque/masque_ohttp_client.cc
+++ b/quiche/quic/masque/masque_ohttp_client.cc
@@ -344,21 +344,14 @@
     return absl::InternalError(
         "Cannot send OHTTP request without OHTTP client");
   }
-  if (pending_request.per_request_config.use_chunked_ohttp()) {
-    pending_request.chunk_handler = std::make_unique<ChunkHandler>();
-    absl::StatusOr<ChunkedObliviousHttpClient> chunked_client =
-        ChunkedObliviousHttpClient::Create(ohttp_client_->GetPublicKey(),
-                                           ohttp_client_->GetKeyConfig(),
-                                           pending_request.chunk_handler.get());
-    if (!chunked_client.ok()) {
-      return absl::InternalError(
-          absl::StrCat("Failed to create chunked OHTTP client: ",
-                       chunked_client.status().message()));
-    }
-
+  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) {
     BinaryHttpRequest::IndeterminateLengthEncoder encoder;
 
-    QUICHE_ASSIGN_OR_RETURN(std::string encoded_data,
+    QUICHE_ASSIGN_OR_RETURN(encoded_data,
                             encoder.EncodeControlData(control_data));
     std::vector<quiche::BinaryHttpMessage::FieldView> headers;
     if (!formatted_token.empty()) {
@@ -393,40 +386,39 @@
     QUICHE_ASSIGN_OR_RETURN(std::string encoded_trailers,
                             encoder.EncodeTrailers(absl::MakeSpan(trailers)));
     encoded_data += encoded_trailers;
-
-    // Intentionally split the data into two chunks to test encryption chunking.
-    QUICHE_ASSIGN_OR_RETURN(encrypted_data,
-                            chunked_client->EncryptRequestChunk(
-                                absl::string_view(encoded_data).substr(0, 1),
-                                /*is_final_chunk=*/false));
-    QUICHE_ASSIGN_OR_RETURN(std::string encrypted_data2,
-                            chunked_client->EncryptRequestChunk(
-                                absl::string_view(encoded_data).substr(1),
-                                /*is_final_chunk=*/true));
-    encrypted_data += encrypted_data2;
-
-    pending_request.chunk_handler->SetChunkedClient(std::move(*chunked_client));
   } else {
     BinaryHttpRequest binary_request(control_data);
     binary_request.set_body(post_data);
     if (!formatted_token.empty()) {
       binary_request.AddHeaderField({"authorization", formatted_token});
     }
-    absl::StatusOr<std::string> encoded_request = binary_request.Serialize();
-    if (!encoded_request.ok()) {
-      return absl::InternalError(
-          absl::StrCat("Failed to serialize OHTTP request: ",
-                       encoded_request.status().message()));
-    }
-    absl::StatusOr<ObliviousHttpRequest> ohttp_request =
-        ohttp_client_->CreateObliviousHttpRequest(*encoded_request);
-    if (!ohttp_request.ok()) {
-      return absl::InternalError(
-          absl::StrCat("Failed to create OHTTP request: ",
-                       ohttp_request.status().message()));
-    }
-    encrypted_data = ohttp_request->EncapsulateAndSerialize();
-    pending_request.context.emplace(std::move(*ohttp_request).ReleaseContext());
+    QUICHE_ASSIGN_OR_RETURN(encoded_data, binary_request.Serialize());
+  }
+  if (pending_request.per_request_config.use_chunked_ohttp()) {
+    pending_request.chunk_handler = std::make_unique<ChunkHandler>();
+    QUICHE_ASSIGN_OR_RETURN(
+        ChunkedObliviousHttpClient chunked_client,
+        ChunkedObliviousHttpClient::Create(
+            ohttp_client_->GetPublicKey(), ohttp_client_->GetKeyConfig(),
+            pending_request.chunk_handler.get()));
+    // Intentionally split the data into two chunks to test encryption chunking.
+    QUICHE_ASSIGN_OR_RETURN(encrypted_data,
+                            chunked_client.EncryptRequestChunk(
+                                absl::string_view(encoded_data).substr(0, 1),
+                                /*is_final_chunk=*/false));
+    QUICHE_ASSIGN_OR_RETURN(std::string encrypted_data2,
+                            chunked_client.EncryptRequestChunk(
+                                absl::string_view(encoded_data).substr(1),
+                                /*is_final_chunk=*/true));
+    encrypted_data += encrypted_data2;
+
+    pending_request.chunk_handler->SetChunkedClient(std::move(chunked_client));
+  } else {
+    QUICHE_ASSIGN_OR_RETURN(
+        ObliviousHttpRequest ohttp_request,
+        ohttp_client_->CreateObliviousHttpRequest(encoded_data));
+    encrypted_data = ohttp_request.EncapsulateAndSerialize();
+    pending_request.context.emplace(std::move(ohttp_request).ReleaseContext());
   }
   Message request;
   request.headers[":method"] = "POST";
diff --git a/quiche/quic/masque/masque_ohttp_client.h b/quiche/quic/masque/masque_ohttp_client.h
index 6d188ff..7645421 100644
--- a/quiche/quic/masque/masque_ohttp_client.h
+++ b/quiche/quic/masque/masque_ohttp_client.h
@@ -49,6 +49,10 @@
       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 SetExpectedGatewayError(const std::string& expected_gateway_error) {
         expected_gateway_error_ = expected_gateway_error;
       }
@@ -71,6 +75,9 @@
       std::string post_data() const { return post_data_; }
       std::string private_token() const { return private_token_; }
       bool use_chunked_ohttp() const { return use_chunked_ohttp_; }
+      std::optional<bool> use_indeterminate_length() const {
+        return use_indeterminate_length_;
+      }
       std::optional<std::string> expected_gateway_error() const {
         return expected_gateway_error_;
       }
@@ -89,6 +96,7 @@
       std::string post_data_;
       std::string private_token_;
       bool use_chunked_ohttp_ = false;
+      std::optional<bool> use_indeterminate_length_;
       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 77d5f79..8e7979b 100644
--- a/quiche/quic/masque/masque_ohttp_client_bin.cc
+++ b/quiche/quic/masque/masque_ohttp_client_bin.cc
@@ -31,6 +31,12 @@
 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.");
@@ -87,6 +93,8 @@
       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 =
@@ -137,6 +145,7 @@
     MasqueOhttpClient::Config::PerRequestConfig per_request_config(urls[i]);
     per_request_config.SetPostData(post_data);
     per_request_config.SetUseChunkedOhttp(use_chunked_ohttp);
+    per_request_config.SetUseIndeterminateLength(indeterminate_length);
     per_request_config.SetPrivateToken(private_token);
     if (expect_gateway_error.has_value()) {
       per_request_config.SetExpectedGatewayError(*expect_gateway_error);