1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
#pragma once
///@file
#include "lix/libutil/async-io.hh"
#include "lix/libutil/box_ptr.hh"
#include "lix/libutil/ref.hh"
#include "lix/libutil/logging.hh"
#include "lix/libutil/result.hh"
#include "lix/libutil/serialise.hh"
#include "lix/libutil/types.hh"
#include "lix/libutil/config.hh"
#include <kj/async.h>
#include <curl/curl.h>
#include <string>
#include <future>
namespace nix {
struct FileTransferSettings : Config
{
#include "lix/libstore/file-transfer-settings.gen.inc"
};
extern FileTransferSettings fileTransferSettings;
struct FileTransferResult
{
bool cached = false;
std::string etag;
std::string effectiveUri;
/* An "immutable" URL for this resource (i.e. one whose contents
will never change), as returned by the `Link: <url>;
rel="immutable"` header. */
std::optional<std::string> immutableUrl;
};
struct FileTransferOptions
{
Headers headers;
/**
* Function to perform any additional curl setup, e.g. auth method, key material.
* This is meant to be used by plugins which want to extend the initialization that Lix
* performs.
*/
std::function<void(CURL*)> extraSetup;
};
class Store;
struct FileTransfer
{
virtual ~FileTransfer() { }
/**
* Upload some data. May throw a FileTransferError exception.
*/
virtual kj::Promise<Result<void>> upload(
const std::string & uri,
std::string data,
FileTransferOptions options = {},
const Activity * context = nullptr
) = 0;
/**
* Checks whether the given URI exists. For historical reasons this function
* treats HTTP 403 responses like HTTP 404 responses and returns `false` for
* both. This was originally done to handle unlistable S3 buckets, which may
* return 403 (not 404) if the reuqested object doesn't exist in the bucket.
*
* ## Bugs
*
* S3 objects are downloaded completely to answer this request.
*/
virtual kj::Promise<Result<bool>> exists(
const std::string & uri,
FileTransferOptions options = {},
const Activity * context = nullptr
) = 0;
/**
* Download a file, returning its contents through a source. Will not return
* before the transfer has fully started, ensuring that any errors thrown by
* the setup phase (e.g. HTTP 404 or similar errors) are not postponed to be
* thrown by the returned source. The source will only throw errors detected
* during the transfer itself (decompression errors, connection drops, etc).
*/
virtual kj::Promise<Result<std::pair<FileTransferResult, box_ptr<AsyncInputStream>>>> download(
const std::string & uri,
FileTransferOptions options = {},
const Activity * context = nullptr
) = 0;
enum Error { NotFound, Forbidden, Misc, Transient, Interrupted };
};
/**
* @return a shared FileTransfer object.
*
* Using this object is preferred because it enables connection reuse
* and HTTP/2 multiplexing.
*/
ref<FileTransfer> getFileTransfer();
/**
* @return a new FileTransfer object
*
* Prefer getFileTransfer() to this; see its docs for why.
*/
ref<FileTransfer> makeFileTransfer(std::optional<unsigned int> baseRetryTimeMs = {});
class FileTransferError : public Error
{
public:
FileTransfer::Error error;
/// intentionally optional
std::optional<std::string> response;
template<typename... Args>
FileTransferError(FileTransfer::Error error, std::optional<std::string> response, const Args & ... args);
};
}
|