Range::bytes and ContentRange::bytes do unchecked u64 arithmetic on bounds
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Newbie friendliness
- 78/100
Research direction
Start with src/common/range.rs and src/common/content_range.rs at the reported arithmetic lines, then run the supplied reproducer in debug and release profiles. Done means empty or unrepresentable bounds return InvalidRange or InvalidContentRange rather than panic or emit wrapped HTTP ranges.
Written by the indexing model from the issue text.
Description
Range::bytes and ContentRange::bytes convert range bounds with unchecked u64 arithmetic. Debug builds panic with "attempt to subtract with overflow". Release builds wrap to u64::MAX and emit headers describing a 2^64-byte span, and empty ranges with a non-zero start emit bytes=N-(N-1) in both profiles.
Crate version: headers 0.4.1, no feature flags.
Reproducer
use headers::{ContentRange, Header, HeaderValue, Range};
fn encode<H: Header>(h: &H) -> String {
let mut values: Vec<HeaderValue> = Vec::new();
h.encode(&mut values);
values[0].to_str().unwrap().to_owned()
}
fn main() {
println!("{}", encode(&Range::bytes(0u64..0u64).unwrap()));
println!("{}", encode(&Range::bytes(3u64..3u64).unwrap()));
println!("{}", encode(&ContentRange::bytes(0u64..0u64, 500u64).unwrap()));
println!("{}", encode(&ContentRange::bytes(0u64.., 0u64).unwrap()));
println!("{}", encode(&ContentRange::bytes(3u64..3u64, 100u64).unwrap()));
}
Observed
cargo run --release prints:
bytes=0-18446744073709551615
bytes=3-2
bytes 0-18446744073709551615/500
bytes 0-18446744073709551615/0
bytes 3-2/100
cargo run in debug panics on the first call at src/common/range.rs:56, so the program prints nothing. Run on their own in a debug build, ContentRange::bytes(0u64..0u64, 500u64) panics at src/common/content_range.rs:66 and ContentRange::bytes(0u64.., 0u64) panics at src/common/content_range.rs:68.
Expected
All five calls should return Err(InvalidRange) or Err(InvalidContentRange). Both constructors return a Result so unrepresentable bounds can be rejected. RFC 7233 section 2.1 requires last-byte-pos >= first-byte-pos in a byte-range-spec, so bytes=3-2 is invalid. RFC 7233 section 4.2 adds last-byte-pos < complete-length, which rules out bytes 0-18446744073709551615/0.
Root cause
src/common/range.rs:56:format!("bytes={}-{}", start, end - 1)src/common/content_range.rs:66:Bound::Excluded(&e) => e - 1,src/common/content_range.rs:68:Some(max) => max - 1,src/common/content_range.rs:60:Bound::Excluded(&s) => s + 1,, the mirrored addition on an excluded start bound. Not exercised here.
Scope
Any empty half-open range N..N passed to either constructor. Any ContentRange::bytes call with an unbounded end and complete_length == 0. Those 0..0 and zero-length forms panic in debug and wrap in release. The non-zero empty forms are silent in both.
- Dominant language
- Rust
- Stars
- 200
- Forks
- 107
- PR merge metrics
- No merged PRs in 30d
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from hyperium/headers
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
-
Difficulty 4/5 3-5 days Newbie friendliness 48/100
-
Difficulty 5/5 Over a week Newbie friendliness 35/100
-
Link support Open
Difficulty 4/5 3-5 days Newbie friendliness 38/100
-
easy
Difficulty 2/5 1-3 hours Newbie friendliness 50/100
All issues in hyperium/headers
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
-
state:needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
zed-industries/zed#64680 · 2 comments ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
RustPython/RustPython#8802 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 75/100
TheLarkInn/aipm#2390 ·