#include "binary-cache-store.hh" #include "download.hh" #include "globals.hh" #include "nar-info-disk-cache.hh" namespace nix { MakeError(UploadToHTTP, Error); class HttpBinaryCacheStore : public BinaryCacheStore { private: Path cacheUri; public: HttpBinaryCacheStore( const Params & params, const Path & _cacheUri) : BinaryCacheStore(params) , cacheUri(_cacheUri) { if (cacheUri.back() == '/') cacheUri.pop_back(); diskCache = getNarInfoDiskCache(); } std::string getUri() override { return cacheUri; } void init() override { // FIXME: do this lazily? if (!diskCache->cacheExists(cacheUri, wantMassQuery_, priority)) { try { BinaryCacheStore::init(); } catch (UploadToHTTP &) { throw Error(format("'%s' does not appear to be a binary cache") % cacheUri); } diskCache->createCache(cacheUri, storeDir, wantMassQuery_, priority); } } protected: bool fileExists(const std::string & path) override { try { DownloadRequest request(cacheUri + "/" + path); request.head = true; request.tries = 5; getDownloader()->download(request); return true; } catch (DownloadError & e) { /* S3 buckets return 403 if a file doesn't exist and the bucket is unlistable, so treat 403 as 404. */ if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden) return false; throw; } } void upsertFile(const std::string & path, const std::string & data, const std::string & mimeType) override { throw UploadToHTTP("uploading to an HTTP binary cache is not supported"); } void getFile(const std::string & path, std::function)> success, std::function failure) override { DownloadRequest request(cacheUri + "/" + path); request.tries = 8; getDownloader()->enqueueDownload(request, [success](const DownloadResult & result) { success(result.data); }, [success, failure](std::exception_ptr exc) { try { std::rethrow_exception(exc); } catch (DownloadError & e) { if (e.error == Downloader::NotFound || e.error == Downloader::Forbidden) return success(0); failure(exc); } catch (...) { failure(exc); } }); } }; static RegisterStoreImplementation regStore([]( const std::string & uri, const Store::Params & params) -> std::shared_ptr { if (std::string(uri, 0, 7) != "http://" && std::string(uri, 0, 8) != "https://" && (getEnv("_NIX_FORCE_HTTP_BINARY_CACHE_STORE") != "1" || std::string(uri, 0, 7) != "file://") ) return 0; auto store = std::make_shared(params, uri); store->init(); return store; }); }