diff --git a/src/libstore/filetransfer.cc b/src/libstore/filetransfer.cc index 5746c32a3..2c39c6adf 100644 --- a/src/libstore/filetransfer.cc +++ b/src/libstore/filetransfer.cc @@ -116,6 +116,26 @@ struct curlFileTransfer : public FileTransfer for (auto it = request.headers.begin(); it != request.headers.end(); ++it){ requestHeaders = curl_slist_append(requestHeaders, fmt("%s: %s", it->first, it->second).c_str()); } + + for (auto &[host, prog] : fileTransferSettings.preHTTPRequestHooks.get()) + { + if (hasPrefix(request.uri, fmt("https://%s/", host)) || hasPrefix(request.uri, fmt("http://%s/", host))) + { + auto verb = request.data ? "upload" : "download"; + debug("pre-http-request-hooks: '%s' for '%s' (%d)", prog, request.uri, verb); + auto lines = runProgram(prog, false, Strings({ request.uri, verb })); + auto lastPos = std::string::size_type{0}; + for (auto nlPos = lines.find('\n'); nlPos != std::string::npos; nlPos = lines.find('\n', lastPos)) + { + auto line = lines.substr(lastPos, nlPos - lastPos); + lastPos = nlPos + 1; + auto hn = line.substr(0, line.find(':')); + debug("add header: '%s: *****' to '%s' (%d)", hn, request.uri, verb); + requestHeaders = curl_slist_append(requestHeaders, line.c_str()); + } + break; + } + } } ~TransferItem() diff --git a/src/libstore/filetransfer.hh b/src/libstore/filetransfer.hh index 40e7cf52c..3b4c83c2a 100644 --- a/src/libstore/filetransfer.hh +++ b/src/libstore/filetransfer.hh @@ -26,6 +26,35 @@ struct FileTransferSettings : Config )", {"binary-caches-parallel-connections"}}; + Setting preHTTPRequestHooks{this, {}, "pre-http-request-hooks", + R"( + Optional. A whitespace-separated list of tuples (`host=`) where + the program can set extra URL-specific HTTP headers. This is used for URLs + that can't be accessed publically. + + The hook is passed wth the resource URL and the verb (`upload` or `download`). + It can then add https headers to the HTTP request by send them to stdout. + + When using the nix-daemon, the daemon executes the hook as `root`. + If the nix-daemon is not involved, the hook runs as the user + executing the nix-build. + + Example: + `#!/usr/bin/env bash + + source /my/lib.sh + + url=$1 + verb=$2 + + host=$(parse_host ${url}) + token=$(get_cached_CF_token_for ${url} ${verb}) + + echo Cookie: CF_Authorization=${token}; Domain=${host}; Secure; HttpOnly + echo Origin: ${host} + `. + )"}; + Setting connectTimeout{ this, 0, "connect-timeout", R"(