apache / apache/arrow-rs-object-store

Errors on 200 Response for entire-object range request

Open Beginner friendly
#806 1 comment 0 reactions 0 assignees View on GitHub
bug
Dominant language
Rust
Stars
322
Forks
212
Avg merge
5d 2h
Merged PRs (30d)
10

Description

**Describe the bug**
When issuing a range request matching the entire content of an object_store, the object_store refuses an HTTP/200 response containing range headers.

Trace:
```
GET /data.bin HTTP/1.1
range: bytes=0-11
accept: */*
user-agent: object_store/0.14.1
host: 127.0.0.1:8000

HTTP/1.1 200 OK
content-length: 12
content-range: bytes 0-11/12
content-type: application/octet-stream
last-modified: Fri, 17 Jul 2026 08:44:44 GMT
etag: "2c6d9c:c:6a59eb7c:2f8f2e0c"
content-disposition: attachment; filename="data.bin"
accept-ranges: bytes
date: Fri, 17 Jul 2026 08:47:00 GMT
```

Relevant code section likely here:
https://github.com/apache/arrow-rs-object-store/blob/c7316d29face118e7409eead0cda098f38589428/src/http/client.rs#L404-L410

The request/response is legal as far as I can tell. Minor, the content-range in the response should be ignored per the RFC.

**To Reproduce**
This uses miniserve, which uses Actix under the hood.

```rust
//! HTTP store rejects a range request that covers the entire object when the
//! server (miniserve, or anything actix-files based) replies `200 OK` with the
//! full body instead of `206 Partial Content`.
//!
//! Setup:
//! mkdir -p /tmp/serve && printf 'hello world!' > /tmp/serve/data.bin
//! miniserve --interfaces 127.0.0.1 --port 8000 /tmp/serve &
use object_store::http::HttpBuilder;
use object_store::path::Path;
use object_store::{ClientOptions, GetOptions, GetRange, ObjectStore, ObjectStoreExt};

#[tokio::main]
async fn main() {
let store = HttpBuilder::new()
.with_url("http://127.0.0.1:8000")
.with_client_options(ClientOptions::new().with_allow_http(true))
.build()
.unwrap();
let path = Path::from("data.bin");

let size = store.head(&path).await.unwrap().size;
println!("object size: {size}");

for range in [0..size - 1, 0..size] {
let opts = GetOptions {
range: Some(GetRange::Bounded(range.clone())),
..Default::default()
};
match store.get_opts(&path, opts).await {
Ok(r) => println!("range {range:?} -> ok, {} bytes", r.bytes().await.unwrap().len()),
Err(e) => println!("range {range:?} -> ERROR: {e}"),
}
}
}
```
gives:
(a) on miniserve:
```
object size: 12
range 0..11 -> ok, 11 bytes
range 0..12 -> ERROR: Operation not supported: Range request not supported by data.bin
```
(b) on npx http-server:
```
object size: 12
range 0..11 -> ok, 11 bytes
range 0..12 -> ok, 12 bytes
```

**Expected behavior**
It should accept a 200 response on a full-object range request.

**Additional context**
Master issue ref:
https://github.com/pola-rs/polars/issues/28400

Per AI analysis:
server | partial 0-10 | full-file 0-11
-- | -- | --
nginx 1.24 | 206 | 206, Content-Range: bytes 0-11/12
node http-server (npm) | 206 | 206
miniserve / actix-files | 206 | 200 (+ stray Content-Range)
python3 -m http.server | 200 (no range support at all) | 200

Contributor guide

Open the contributing guide

Research direction

Start in src/http/client.rs around lines 404-410, where the HTTP response to a range request is validated. Run the provided Rust reproduction against miniserve and npx http-server to compare the responses. Done means a full-object range request with a legal 200 response succeeds while normal range handling remains intact.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
networking
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.