Skip to content

avformat/libcurl: streams with unknown total size (Content-Range: bytes X-Y/*) end with a 416 error instead of EOF #75

Description

@ronag

Summary

6be7932 (avformat/libcurl: also continue sending requests on unknown size) treats resources of unknown size as infinite "at least until we see a 416 Range Not Satisfiable". But nothing handles that 416. on_done() keeps issuing follow-up requests while file_end < 0. The follow-up issued after the true end gets a 416, which header_callback() treats as an ordinary HTTP error. So after the whole resource has been delivered correctly, the read returns AVERROR_HTTP_RANGE_NOT_SATISFIABLE instead of EOF. If reconnect_on_http_error contains 4xx or 416, it instead retries the 416 with backoff until max_retries runs out.

This is the libcurl counterpart of #46 (http.c).

Location

  • Continuation on unknown size:
    if (code == CURLE_OK && c->stream_ok) {
    int64_t file_end = c->content_size > 0 ? c->content_size - 1 : -1;
    if (c->end_off > 0)
    file_end = FFMIN(file_end, c->end_off - 1);
    if (c->seekable && c->request_end >= 0 &&
    (c->request_end < file_end || file_end < 0))
    {
    c->is_initial = 0;
    start_request(c);
    return;
    }
  • Error branch in header_callback():
    } else {
    c->loop->num_errors++;
    c->stream_ok = 0;
    if (!c->status) {
    if (http_error_is_recoverable(c, status))
    c->status = AVERROR(EAGAIN);
    else
    c->status = ff_http_averror(status, AVERROR(EIO));
    }
    curl_off_t retry_after = 0;
    curl_easy_getinfo(c->easy, CURLINFO_RETRY_AFTER, &retry_after);
    c->retry_after = retry_after;
    }

Reproduction

Server replies 206 with Content-Range: bytes 0-1048575/* (harness from #71):

$ t libcurl:http://127.0.0.1:18080/unknown --readall
size: -78 seekable: 1
readall: total=1048576 last=-909194488 (Server returned 416 Range Not Satisfiable) pb->error=-909194488 eof=1

All 1048576 bytes are delivered, and then the stream ends in an error rather than EOF.

Suggested fix

In header_callback(), when a follow-up request gets a 416 and content_size is unknown (probed, request_start equals the bytes delivered so far), set status = AVERROR_EOF and learn content_size = request_start. Exclude this case from the reconnect_on_http_error matching. Doing the same for a seek past the (unknown) end also covers the unknown-size variant of #74.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingfork-regressionRegression introduced by a fork-specific commitlibcurllibcurl-based HTTP(S) protocol (libavformat/libcurl.c)prio:low

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions