HTTP File upload fixes and tweaks

- Do not write the HTTP PUT response to cache which can potentially overflow the cache buffer as it is not consumed.
- VLOG(1) instead of LOG(ERROR) on HttpFile::Size() as it can be called during normal code execution.
- Add a command line flag `--user_agent` to allow users to specify their custom user agent string.

Fixes #939.
This commit is contained in:
Daniel Cantarín 2021-05-05 02:53:23 -03:00 committed by GitHub
parent 4528bdb330
commit 37b16b4091
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 5 deletions

View File

@ -16,6 +16,8 @@
#include "packager/base/strings/stringprintf.h" #include "packager/base/strings/stringprintf.h"
#include "packager/base/threading/worker_pool.h" #include "packager/base/threading/worker_pool.h"
DEFINE_string(user_agent, "",
"Set a custom User-Agent string for HTTP requests.");
DEFINE_string(ca_file, DEFINE_string(ca_file,
"", "",
"Absolute path to the Certificate Authority file for the " "Absolute path to the Certificate Authority file for the "
@ -45,8 +47,14 @@ constexpr const int kMinLogLevelForCurlDebugFunction = 2;
size_t CurlWriteCallback(char* buffer, size_t size, size_t nmemb, void* user) { size_t CurlWriteCallback(char* buffer, size_t size, size_t nmemb, void* user) {
IoCache* cache = reinterpret_cast<IoCache*>(user); IoCache* cache = reinterpret_cast<IoCache*>(user);
size_t length = cache->Write(buffer, size * nmemb); size_t length = size * nmemb;
if (cache) {
length = cache->Write(buffer, length);
VLOG(3) << "CurlWriteCallback length=" << length; VLOG(3) << "CurlWriteCallback length=" << length;
} else {
// For the case of HTTP Put, the returned data may not be consumed. Return
// the size of the data to avoid curl errors.
}
return length; return length;
} }
@ -159,6 +167,7 @@ HttpFile::HttpFile(HttpMethod method,
upload_cache_(FLAGS_io_cache_size), upload_cache_(FLAGS_io_cache_size),
curl_(curl_easy_init()), curl_(curl_easy_init()),
status_(Status::OK), status_(Status::OK),
user_agent_(FLAGS_user_agent),
task_exit_event_(base::WaitableEvent::ResetPolicy::MANUAL, task_exit_event_(base::WaitableEvent::ResetPolicy::MANUAL,
base::WaitableEvent::InitialState::NOT_SIGNALED) { base::WaitableEvent::InitialState::NOT_SIGNALED) {
static LibCurlInitializer lib_curl_initializer; static LibCurlInitializer lib_curl_initializer;
@ -236,7 +245,7 @@ int64_t HttpFile::Write(const void* buffer, uint64_t length) {
} }
int64_t HttpFile::Size() { int64_t HttpFile::Size() {
LOG(ERROR) << "HttpFile does not support Size()."; VLOG(1) << "HttpFile does not support Size().";
return -1; return -1;
} }
@ -279,12 +288,14 @@ void HttpFile::SetupRequest() {
} }
curl_easy_setopt(curl, CURLOPT_URL, url_.c_str()); curl_easy_setopt(curl, CURLOPT_URL, url_.c_str());
curl_easy_setopt(curl, CURLOPT_USERAGENT, kUserAgent); curl_easy_setopt(curl, CURLOPT_USERAGENT,
user_agent_.empty() ? kUserAgent : user_agent_.data());
curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_in_seconds_); curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout_in_seconds_);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L); curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlWriteCallback); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &CurlWriteCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &download_cache_); curl_easy_setopt(curl, CURLOPT_WRITEDATA,
method_ == HttpMethod::kPut ? nullptr : &download_cache_);
if (method_ != HttpMethod::kGet) { if (method_ != HttpMethod::kGet) {
curl_easy_setopt(curl, CURLOPT_READFUNCTION, &CurlReadCallback); curl_easy_setopt(curl, CURLOPT_READFUNCTION, &CurlReadCallback);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_cache_); curl_easy_setopt(curl, CURLOPT_READDATA, &upload_cache_);

View File

@ -83,6 +83,7 @@ class HttpFile : public File {
// The headers need to remain alive for the duration of the request. // The headers need to remain alive for the duration of the request.
std::unique_ptr<curl_slist, CurlDelete> request_headers_; std::unique_ptr<curl_slist, CurlDelete> request_headers_;
Status status_; Status status_;
std::string user_agent_;
// Signaled when the "curl easy perform" task completes. // Signaled when the "curl easy perform" task completes.
base::WaitableEvent task_exit_event_; base::WaitableEvent task_exit_event_;