diff --git a/CMakeLists.txt b/CMakeLists.txt index a570bda..8d460a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.20) -project(libprozilla VERSION 1.2.0 LANGUAGES C) +project(libprozilla VERSION 1.2.1 LANGUAGES C) include(CTest) diff --git a/src/curl-retr.c b/src/curl-retr.c index 78c1ae2..93682a4 100644 --- a/src/curl-retr.c +++ b/src/curl-retr.c @@ -12,7 +12,9 @@ typedef struct { CURL *curl; int write_failed; int require_partial_response; + int range_complete; size_t bytes_written; + off_t expected_bytes; } curl_write_context; static CURLcode configure_curl(CURL *curl, connection_t *connection) @@ -122,6 +124,20 @@ static size_t curl_write(void *data, size_t size, size_t count, void *opaque) if (size != 0 && count > SIZE_MAX / size) return 0; bytes = size * count; + if (ctx->expected_bytes > 0) + { + off_t remaining = ctx->expected_bytes - (off_t) ctx->bytes_written; + if (remaining <= 0) + { + ctx->range_complete = 1; + return 0; + } + if ((uintmax_t) bytes > (uintmax_t) remaining) + { + bytes = (size_t) remaining; + ctx->range_complete = 1; + } + } if (ctx->require_partial_response) { curl_easy_getinfo(ctx->curl, CURLINFO_RESPONSE_CODE, &response); @@ -139,6 +155,8 @@ static size_t curl_write(void *data, size_t size, size_t count, void *opaque) ctx->bytes_written += bytes; connection_calc_ratebps(ctx->connection); connection_throttle_bps(ctx->connection); + if (ctx->range_complete) + return 0; return bytes; } @@ -146,7 +164,7 @@ static uerr_t curl_get_file(connection_t *connection) { CURL *curl = curl_easy_init(); CURLcode result; - curl_write_context ctx = { connection, curl, 0, 0, 0 }; + curl_write_context ctx = { connection, curl, 0, 0, 0, 0, 0 }; char range[96]; long response = 0; @@ -161,6 +179,8 @@ static uerr_t curl_get_file(connection_t *connection) (intmax_t) connection->remote_startpos, (intmax_t) (connection->remote_endpos - 1)); curl_easy_setopt(curl, CURLOPT_RANGE, range); + ctx.expected_bytes = + connection->remote_endpos - connection->remote_startpos; if (connection->u.proto == URLHTTP || connection->u.proto == URLHTTPS) ctx.require_partial_response = 1; @@ -181,7 +201,9 @@ static uerr_t curl_get_file(connection_t *connection) && (off_t) ctx.bytes_written != connection->remote_endpos - connection->remote_startpos) return READERR; - if (result == CURLE_OK && response < 400) + if ((ctx.expected_bytes > 0 + && (off_t) ctx.bytes_written == ctx.expected_bytes) + || ((result == CURLE_OK || ctx.range_complete) && response < 400)) { connection_change_status(connection, COMPLETED); return HOK;