HttpBinaryCacheStore: Support upsertFile with PUT.

Some servers, such as Artifactory, allow uploading with PUT and BASIC
auth. This allows nix copy to work to upload binaries to those
servers.

Worked on together with @adelbertc
This commit is contained in:
Shea Levy 2018-01-26 11:12:30 -08:00
parent e09161d05c
commit 1d5d277ac7
No known key found for this signature in database
GPG key ID: 5C0BD6957D86FE27
3 changed files with 38 additions and 4 deletions

View file

@ -22,6 +22,7 @@
#include <thread> #include <thread>
#include <cmath> #include <cmath>
#include <random> #include <random>
#include <algorithm>
using namespace std::string_literals; using namespace std::string_literals;
@ -91,6 +92,8 @@ struct CurlDownloader : public Downloader
{ {
if (!request.expectedETag.empty()) if (!request.expectedETag.empty())
requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + request.expectedETag).c_str()); requestHeaders = curl_slist_append(requestHeaders, ("If-None-Match: " + request.expectedETag).c_str());
if (!request.mimeType.empty())
requestHeaders = curl_slist_append(requestHeaders, ("Content-Type: " + request.mimeType).c_str());
} }
~DownloadItem() ~DownloadItem()
@ -185,6 +188,22 @@ struct CurlDownloader : public Downloader
return 0; return 0;
} }
size_t readOffset = 0;
int readCallback(char *buffer, size_t size, size_t nitems)
{
if (readOffset == request.data->length())
return 0;
auto count = std::min(size * nitems, request.data->length() - readOffset);
memcpy(buffer, request.data->data() + readOffset, count);
readOffset += count;
return count;
}
static int readCallbackWrapper(char *buffer, size_t size, size_t nitems, void * userp)
{
return ((DownloadItem *) userp)->readCallback(buffer, size, nitems);
}
long lowSpeedTimeout = 300; long lowSpeedTimeout = 300;
void init() void init()
@ -225,6 +244,13 @@ struct CurlDownloader : public Downloader
if (request.head) if (request.head)
curl_easy_setopt(req, CURLOPT_NOBODY, 1); curl_easy_setopt(req, CURLOPT_NOBODY, 1);
if (request.data) {
curl_easy_setopt(req, CURLOPT_UPLOAD, 1L);
curl_easy_setopt(req, CURLOPT_READFUNCTION, readCallbackWrapper);
curl_easy_setopt(req, CURLOPT_READDATA, this);
curl_easy_setopt(req, CURLOPT_INFILESIZE_LARGE, (curl_off_t) request.data->length());
}
if (request.verifyTLS) { if (request.verifyTLS) {
if (settings.caFile != "") if (settings.caFile != "")
curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str()); curl_easy_setopt(req, CURLOPT_CAINFO, settings.caFile.c_str());
@ -265,7 +291,7 @@ struct CurlDownloader : public Downloader
} }
if (code == CURLE_OK && if (code == CURLE_OK &&
(httpStatus == 200 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */)) (httpStatus == 200 || httpStatus == 201 || httpStatus == 204 || httpStatus == 304 || httpStatus == 226 /* FTP */ || httpStatus == 0 /* other protocol */))
{ {
result.cached = httpStatus == 304; result.cached = httpStatus == 304;
done = true; done = true;

View file

@ -18,9 +18,11 @@ struct DownloadRequest
unsigned int baseRetryTimeMs = 250; unsigned int baseRetryTimeMs = 250;
ActivityId parentAct; ActivityId parentAct;
bool decompress = true; bool decompress = true;
std::shared_ptr<std::string> data;
std::string mimeType;
DownloadRequest(const std::string & uri) DownloadRequest(const std::string & uri, std::shared_ptr<std::string> data = nullptr, std::string mimeType = "")
: uri(uri), parentAct(curActivity) { } : uri(uri), parentAct(curActivity), data(std::move(data)), mimeType(std::move(mimeType)) { }
}; };
struct DownloadResult struct DownloadResult

View file

@ -67,7 +67,13 @@ protected:
const std::string & data, const std::string & data,
const std::string & mimeType) override const std::string & mimeType) override
{ {
throw UploadToHTTP("uploading to an HTTP binary cache is not supported"); auto data_ = std::make_shared<string>(data);
auto req = DownloadRequest(cacheUri + "/" + path, data_, mimeType);
try {
getDownloader()->download(req);
} catch (DownloadError & e) {
throw UploadToHTTP(format("uploading to HTTP binary cache at %1% not supported: %2%") % cacheUri % e.msg());
}
} }
void getFile(const std::string & path, void getFile(const std::string & path,