algesten / ureq

A simple, safe HTTP client
Apache License 2.0
1.72k stars 177 forks source link

3.0.0-rc2 panics on src/run.rs:429:13 with assertion failed: input_used == n #879

Open AndrejsK opened 10 hours ago

AndrejsK commented 10 hours ago

I hit this assertion by posting a random 150k file with ascii letters and numbers: random150k.txt

Full reproduction here: AndrejsK/ureq3-panic-repro

Reproducible with 3.0.0-rc2 on Linux with only default features on debug build:

fn main() {
    let file = std::fs::File::open("./random150k.txt")
        .expect("This repro should be run from the cargo project's root folder");
    ureq::post("https://posttestserver.dev/p/ecsiyilyv3x54kkw/post")
        .content_type("application/octet-stream")
        .send(file)
        .expect("should panic before here");
}

Backtrace:

$ RUST_BACKTRACE=1 cargo r
    Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.02s
     Running `/home/user/.cargo/target/debug/ureq3-panic-repro`
thread 'main' panicked at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/run.rs:429:13:
assertion failed: input_used == n
stack backtrace:
   0: rust_begin_unwind
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/std/src/panicking.rs:662:5
   1: core::panicking::panic_fmt
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/panicking.rs:74:14
   2: core::panicking::panic
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/panicking.rs:148:5
   3: ureq::run::send_body
             at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/run.rs:429:13
   4: ureq::run::flow_run
             at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/run.rs:144:46
   5: ureq::run::run
             at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/run.rs:61:15
   6: ureq::middleware::MiddlewareNext::handle
             at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/middleware.rs:209:13
   7: ureq::agent::Agent::run_via_middleware
             at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/agent.rs:204:9
   8: ureq::request::do_call
             at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/request.rs:427:20
   9: ureq::request::RequestBuilder<ureq::request::WithBody>::send
             at /home/user/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ureq-3.0.0-rc2/src/request.rs:308:9
  10: ureq3_panic_repro::main
             at ./src/main.rs:4:5
  11: core::ops::function::FnOnce::call_once
             at /rustc/f6e511eec7342f59a25f7c0534f1dbea00d01b14/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
algesten commented 9 hours ago

Excellent! Thanks!

algesten commented 3 hours ago

I found the problem. Or rather a combo of problem.

  1. This is too naive

https://github.com/algesten/ureq-proto/blob/main/src/body.rs#L155-L166

We end up in a situation where we think we can write another chunk, but can't because the overhead of the chunk is more than the hardcoded 5.

The solve will be to calculate the exact amount we can fit including overhead into the remaining output. However it is maybe a secondary problem. Because:

  1. The overhead calculation is wrong

https://github.com/algesten/ureq/blob/main/src/run.rs#L419

We do not write the entire output in one big chunk, but rather have a default max chunk in ureq-proto which will cause n-loops x overhead. This means the exact overhead calculation is totally off.