From acd5d28fb14cf5980bd1dd70a49931df4f60e0e9 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Mon, 16 Jan 2023 15:08:25 -0600 Subject: [PATCH] fix: handle webseed servers that do not serve partial content (#4601) Fixes #4595. --- libtransmission/web.cc | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/libtransmission/web.cc b/libtransmission/web.cc index 4f2c5f05c..88daa9ef8 100644 --- a/libtransmission/web.cc +++ b/libtransmission/web.cc @@ -431,6 +431,31 @@ public: auto* task = static_cast(vtask); TR_ASSERT(std::this_thread::get_id() == task->impl.curl_thread->get_id()); + if (auto const range = task->range(); range) + { + // https://curl.se/libcurl/c/CURLINFO_RESPONSE_CODE.html + // "The stored value will be zero if no server response code has been received" + static auto constexpr NoResponseCode = 0L; + static auto constexpr PartialContentResponseCode = 206L; + + // Test for webservers that don't support partial-content, see GH #4595 + auto code = long{}; + (void)curl_easy_getinfo(task->easy(), CURLINFO_RESPONSE_CODE, &code); + if (code != NoResponseCode && code != PartialContentResponseCode) + { + tr_logAddWarn(fmt::format( + _("Couldn't fetch '{url}': expected HTTP response code {expected_code}, got {actual_code}"), + fmt::arg("url", task->url()), + fmt::arg("expected_code", PartialContentResponseCode), + fmt::arg("actual_code", code))); + + // Tell curl to error out. Returning anything that's not + // `bytes_used` signals an error and causes the transfer + // to be aborted w/CURLE_WRITE_ERROR. + return bytes_used + 1; + } + } + if (auto const& tag = task->speedLimitTag(); tag) { // If this is more bandwidth than is allocated for this tag, @@ -530,7 +555,7 @@ public: (void)curl_easy_setopt(e, CURLOPT_URL, task.url().c_str()); (void)curl_easy_setopt(e, CURLOPT_VERBOSE, curl_verbose ? 1L : 0L); (void)curl_easy_setopt(e, CURLOPT_WRITEDATA, &task); - (void)curl_easy_setopt(e, CURLOPT_WRITEFUNCTION, onDataReceived); + (void)curl_easy_setopt(e, CURLOPT_WRITEFUNCTION, &tr_web::Impl::onDataReceived); (void)curl_easy_setopt(e, CURLOPT_MAXREDIRS, MaxRedirects); if (auto const addrstr = task.publicAddress(); addrstr)