Large chunked OHTTP request fix (#36766)

The RFC suggests a maximum chunk size of 16,384 bytes. If a request is made with
a plaintext length that is greater than the limit, split it up into 15kb chunks and
encrypt them individually.
This commit is contained in:
Darnell Andries
2026-05-27 20:53:03 +01:00
committed by GitHub
parent 9189d8eb56
commit b9b4c5d9e6
2 changed files with 32 additions and 8 deletions
@@ -11,6 +11,10 @@
namespace oblivious_http {
namespace {
constexpr size_t kMaxEncryptChunkSize = 16384;
} // namespace
ObliviousHttpChunkProcessor::ObliviousHttpChunkProcessor(
mojo::PendingRemote<network::mojom::ObliviousHttpChunkClient>
chunk_client_remote,
@@ -55,12 +59,19 @@ ObliviousHttpChunkProcessor::Create(
std::optional<std::string> ObliviousHttpChunkProcessor::EncryptRequest(
std::string_view plaintext) {
CHECK(ohttp_client_);
auto result =
ohttp_client_->EncryptRequestChunk(plaintext, /*is_final_chunk=*/true);
if (!result.ok()) {
return std::nullopt;
std::string result;
for (size_t offset = 0; offset < plaintext.size();
offset += kMaxEncryptChunkSize) {
const bool is_final = offset + kMaxEncryptChunkSize >= plaintext.size();
const auto chunk = plaintext.substr(offset, kMaxEncryptChunkSize);
auto encrypted = ohttp_client_->EncryptRequestChunk(chunk, is_final);
if (!encrypted.ok()) {
return std::nullopt;
}
result += std::move(*encrypted);
}
return std::move(*result);
return result;
}
void ObliviousHttpChunkProcessor::OnDataReceived(std::string_view data,
@@ -161,12 +161,13 @@ class ObliviousHttpChunkProcessorTest
return result;
}
void EncryptRequestAndGatewayDecrypt() {
auto encrypted_request = processor_->EncryptRequest(kTestRequestBody);
void EncryptRequestAndGatewayDecrypt(
std::string_view request_body = kTestRequestBody) {
auto encrypted_request = processor_->EncryptRequest(request_body);
ASSERT_TRUE(encrypted_request.has_value());
ASSERT_TRUE(
gateway_->DecryptRequest(*encrypted_request, /*end_stream=*/true).ok());
EXPECT_EQ(kTestRequestBody, received_client_request_body_);
EXPECT_EQ(request_body, received_client_request_body_);
}
// Drives a full round-trip: encrypts kTestRequestBody, feeds the simulated
@@ -233,6 +234,18 @@ TEST_F(ObliviousHttpChunkProcessorTest,
EncryptRequestAndGatewayDecrypt();
}
TEST_F(ObliviousHttpChunkProcessorTest,
EncryptRequest_LargeRequest_GatewayDecryptsCorrectly) {
constexpr std::string_view kAlphabet = "abcdefghijklmnopqrstuvwxyz";
constexpr size_t kLargeRequestSize = 50000;
std::string large_request;
large_request.reserve(kLargeRequestSize);
while (large_request.size() < kLargeRequestSize) {
large_request += kAlphabet;
}
EncryptRequestAndGatewayDecrypt(large_request);
}
TEST_F(ObliviousHttpChunkProcessorTest,
RoundTrip_BodyChunksDeliveredToChunkClient) {
auto future = RunRoundTrip("hello chunked", net::HTTP_OK,