Skip to content

fix(http_request): read the response body only up to the cap - #92

Merged
M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/http-request-bounded-body
Oct 23, 2026
Merged

M3gA-Mind merged 2 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/http-request-bounded-body

Conversation

@M3gA-Mind

Copy link
Copy Markdown
Collaborator

Summary

http_request read the whole response body with response.text() and only then cut it to max_response_size. A large body was buffered in full before the cap applied. A body that never ends (a stream, or a hostile server) kept the call waiting until the request timeout, and memory grew with every byte received.

The body is now read in chunks with response.chunk() and reading stops after max_response_size + 1 bytes. The extra byte tells "over the cap" apart from "exactly at the cap". The bytes are decoded as lossy UTF-8, the same decoding text() did since the charset feature is off. The result then goes through the existing byte-safe truncate_response. The reader is a small helper in network/gate.rs (read_body_capped), so the other network tools can use it later.

web_fetch is not changed here: it needs a decision on its download ceiling first.

Related issue

None.

API or behavior changes

http_request now reads no more than max_response_size + 1 bytes of a response body. The output it returns is the same as before: the body truncated to the cap, plus the existing truncation marker. An endless or very large body now returns right away and no longer waits for the request timeout.

Validation

Commands actually run, with their outcome:

  • cargo fmt --all -- --check: rustfmt --edition 2024 on the touched files only.
  • N/A: cargo clippy --all-targets --all-features -- -D warnings was left to CI.
  • N/A: cargo build --all-targets --all-features was left to CI.
  • N/A: cargo test --all-features was left to CI. Only these tests ran locally:
    • an_endless_body_is_read_only_up_to_the_cap before the fix failed (the body read did not stop at the cap: Elapsed(()) after 5 s); after the fix it passed;
    • the existing truncate_response_* tests passed.

Tests

network/http_request_tests.rs::an_endless_body_is_read_only_up_to_the_cap: a local server sends x bytes without stopping, against a 1000-byte cap. The response must come back within 5 s, carry the truncation marker, and hold no more than 1000 bytes of body.

Documentation

Not needed: max_response_size is already documented as the response-size limit.

Checklist

  • The change is focused on one logical change
  • No new #[allow(...)], #[ignore], or relaxed lints
  • No secrets, tokens, or .env contents in the diff or the description

@tinysweeper

tinysweeper Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Tiny Sweeper review

Reviewed head: 7a1b471eaa3e17511f57abd3f17404883aec37aa

Verdict: Ready for maintainer review · Priority: none
Coverage: Reviewed 3 of 3 files.
Pull request purpose (title): fix(http_request): r…

Diagnostics and supporting details

Full summary

Pull request purpose (title): fix(http_request): read the response body only up to the cap. The pull request titled `fix(http_request): read the response body only up to the cap` changes `http_request` so the response body is no longer buffered in full via `response.text()` before truncation. A new helper `read_body_capped` in `network/gate.rs` reads at most `max_response_size + 1` bytes, distinguishing "over the cap" from "exactly at the cap", and the bytes are decoded with lossy UTF-8 before going through the existing `truncate_response`. An endless or very large body now returns promptly instead of waiting for the request timeout, and memory no longer grows with every received byte. This revision reworks the regression test's server loop and result handling (hoisting the 65536-byte chunk allocation and asserting on `output.is_ok()` before unwrapping). No push-delta comparison is available.

Review snapshot

Change surface Files Review signal Count
Production 2 Active findings 0
Tests 1 Noted findings 0
Documentation 0 Resolved findings 0
Configuration 0 Pending checks/questions 0

Completeness: Complete
Test assessment: No supported feature-to-test mapping was available; this does not mean tests are absent or passed.

Features

  • Added — `read_body_capped` capped body reader: Provides a reusable async helper on the network gate that reads at most `cap + 1` bytes of a response body in chunks, letting callers distinguish an over-cap body from one exactly at the cap without reading the remainder; returns the transport error if a chunk fails to arrive. (crates/tinytools-std/src/network/gate.rs pub(crate) fn host_of(url: &str) -> String {)
  • Modified — `http_request` body read bounded by cap: `http_request` now reads the body through `read_body_capped(response, self.max_response_size)` instead of `response.text()`, so an endless or very large body returns quickly rather than waiting for the request timeout and memory is bounded by the cap rather than growing with every received byte. The lossy UTF-8 decoding preserves the prior output semantics and the result still flows through `truncate_response`. (crates/tinytools-std/src/network/http_request.rs impl HttpRequestTool {)

Tests

No supported feature-to-test mapping was produced. Test execution is not inferred.

Findings

No active actionable findings.

Before merge

None.

Agent review details

critique

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The critique lane answered with zero findings, noting the new test sets up a never-ending loopback server and asserts the body read stops at the cap rather than hanging, matching `read_body_capped`'s contract.
  • Lane summary: The new test sets up a never-ending local server and asserts the body read stops at the cap rather than hanging, which matches read_body_capped's contract and the marker emitted by format_response. It is deterministic, loopback-only, and uses pinned_to_local as the existing tests do; I found no defect to report. _The code index is behind this pull request (indexed at `28ea0933b938`), so retrieved context may be out of date._

security

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The security lane answered with zero findings, checking the constructors and helpers the test calls, its deterministic loopback-only I/O, the 5-second timeout guard, and the truncation-marker and no-1001-x assertions.
  • Lane summary: This adds a single tokio test that spins up a loopback server which streams an endless body, then checks that `execute_request`/`format_response` on `HttpRequestTool` truncate the read at the configured cap rather than reading to EOF. I checked the constructors and helpers it calls (`HttpRequestTool::new`, `TestNetGate::supervised`, `pinned_to_local`, `execute_request`, `format_response`) and they line up with the argument shapes used; the test is deterministic, uses only loopback I/O, has a 5-second timeout guard, and asserts the truncation marker plus that no run of >1000 'x' survives. I see no security or correctness defect introduced by the test, and no repository rule it breaks. _The code index is behind this pull request (indexed at `28ea0933b938`), so retrieved context may be out of date._

tests

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Lane summary: The chained commits add a bounded body read plus a test that an endless response stops at the cap; earlier commits added `read_body_capped` with no test of its own, but this test exercises the truncation path end to end (body over the 1000-byte cap produces the truncation marker and no run of 1001 body bytes), and `truncate_response_caps_bytes_not_chars` still covers the byte-boundary cut. I did not find a defect in the changed test or the cap logic; the one thing worth noting is that `read_body_capped`'s `cap + 1` overflow guard and the exact-cap boundary are not separately pinned, but both are exercised through this test's path only partially. _The code index is behind this pull request (indexed at `28ea0933b938`), so retrieved context may be out of date._

commits

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The commits lane answered that it found no sensitive content in committed files.
  • Lane summary: No sensitive content in committed files. _The code index is behind this pull request (indexed at `28ea0933b938`), so retrieved context may be out of date._

description

  • Conclusion: Success
  • Scope reviewed: all assigned evidence
  • Positive: The description lane answered that the revision adds the regression test for the bounded body read, that the helpers exist with the signatures used, and that the assertions match the described behaviour.
  • Lane summary: This revision adds the regression test for the bounded body read introduced in the previous commit: a local server that streams forever, asserted to return within 5s, carry the truncation marker, and hold no more than the cap. The test's helpers (`TestNetGate::supervised`, `pinned_to_local`, `HttpRequestTool::new`, `execute_request`, `format_response`) all exist with the signatures used, and the assertions match the described behaviour, so the new coverage is sound. _The code index is behind this pull request (indexed at `28ea0933b938`), so retrieved context may be out of date._
Evidence and run details
  • Models: ladder/vectors-oai3, deepseek-v4.1-flash
  • Spend: $0.000452
  • Tokens: 229276 input · 4630 output · 24064 cached · 230 embedding
  • Updated: 2026-10-22T23:28:22Z
Head State Pass summary
7932245ed50d ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-22T23:01:19Z)
7a1b471eaa3e ready for maintainer review 0 active finding(s), 0 resolved finding(s) (at 2026-10-22T23:28:22Z)

tinysweeper 0.1.2

@coderabbitai

coderabbitai Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 939cfab5-1c2b-4d19-8ec6-22cf4ca123cb
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@tinysweeper tinysweeper Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tinysweeper found nothing blocking. Approving.

Diagnostics

Total spend: $0.0009

@M3gA-Mind
M3gA-Mind merged commit ec4b804 into tinyhumansai:main Oct 23, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant