Skip to content

cat with a timeout can truncate responses #127

@mrd0ll4r

Description

@mrd0ll4r

Hello,

the IPFS API for cat returns a chunked, streaming response, but still accepts the timeout parameter. If that is specified, responses may be truncated if the timeout is reached. The API then appends an HTTP trailer named X-Stream-Error to the response. Currently, this crate swallows that error, which truncates file responses (and potentially appends the trailer as garbage at the end).

Example API call:

$ curl --raw -v -X POST "http://127.0.0.1:5001/api/v0/cat?arg=/ipfs/f01701220d45cdd10be2505683ab3d9dbcb0ea6429b61debfede8d23f10a8531a27383bd5&timeout=30s" --output tmp
*   Trying 127.0.0.1:5001...
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0* Connected to 127.0.0.1 (127.0.0.1) port 5001 (#0)
> POST /api/v0/cat?arg=/ipfs/f01701220d45cdd10be2505683ab3d9dbcb0ea6429b61debfede8d23f10a8531a27383bd5&timeout=30s HTTP/1.1
> Host: 127.0.0.1:5001
> User-Agent: curl/7.81.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Access-Control-Allow-Headers: X-Stream-Output, X-Chunked-Output, X-Content-Length
< Access-Control-Expose-Headers: X-Stream-Output, X-Chunked-Output, X-Content-Length
< Content-Type: text/plain
< Server: kubo/0.18.1
< Trailer: X-Stream-Error
< Vary: Origin
< X-Content-Length: 1388014004
< X-Stream-Output: 1
< Date: Tue, 07 Feb 2023 17:30:35 GMT
< Transfer-Encoding: chunked
<
{ [4104 bytes data]
100  250M    0  250M    0     0  8533k      0 --:--:--  0:00:30 --:--:-- 9370k
* Connection #0 to host 127.0.0.1 left intact
$ tail tmp
<binary garbage>
0
X-Stream-Error: context deadline exceeded

I'm using the hyper client with a global timeout configured. I then call it like so:

client
        .cat(c)
        .map_ok(|chunk| chunk.to_vec())
        .try_concat()
        .await
        .map_err(|err| anyhow!("{}", err))

If the timeout occurs before streaming starts, the server responds with 500, which is correctly picked up.
However, if the timeout occurs after streaming has started, no error is returned and you end up with a partial file.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions