aboutsummaryrefslogtreecommitdiff
path: root/src/libstore/filetransfer.hh
blob: afc7e7aa63bdda882a3ed467ee3b3788cceb6670 (plain)
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
125
126
127
128
129
130
131
132
133
134
135
#pragma once

#include "types.hh"
#include "hash.hh"
#include "config.hh"

#include <string>
#include <future>

namespace nix {

struct FileTransferSettings : Config
{
    Setting<bool> enableHttp2{this, true, "http2",
        "Whether to enable HTTP/2 support."};

    Setting<std::string> userAgentSuffix{this, "", "user-agent-suffix",
        "String appended to the user agent in HTTP requests."};

    Setting<size_t> httpConnections{
        this, 25, "http-connections",
        R"(
          The maximum number of parallel TCP connections used to fetch
          files from binary caches and by other downloads. It defaults
          to 25. 0 means no limit.
        )",
        {"binary-caches-parallel-connections"}};

    Setting<unsigned long> connectTimeout{
        this, 0, "connect-timeout",
        R"(
          The timeout (in seconds) for establishing connections in the
          binary cache substituter. It corresponds to `curl`’s
          `--connect-timeout` option.
        )"};

    Setting<unsigned long> stalledDownloadTimeout{
        this, 300, "stalled-download-timeout",
        R"(
          The timeout (in seconds) for receiving data from servers
          during download. Nix cancels idle downloads after this
          timeout's duration.
        )"};

    Setting<unsigned int> tries{this, 5, "download-attempts",
        "How often Nix will attempt to download a file before giving up."};
};

extern FileTransferSettings fileTransferSettings;

struct FileTransferRequest
{
    std::string uri;
    Headers headers;
    std::string expectedETag;
    bool verifyTLS = true;
    bool head = false;
    size_t tries = fileTransferSettings.tries;
    unsigned int baseRetryTimeMs = 250;
    ActivityId parentAct;
    bool decompress = true;
    std::shared_ptr<std::string> data;
    std::string mimeType;
    std::function<void(std::string_view data)> dataCallback;

    FileTransferRequest(const std::string & uri)
        : uri(uri), parentAct(getCurActivity()) { }

    std::string verb()
    {
        return data ? "upload" : "download";
    }
};

struct FileTransferResult
{
    bool cached = false;
    std::string etag;
    std::string effectiveUri;
    std::shared_ptr<std::string> data;
    uint64_t bodySize = 0;
};

class Store;

struct FileTransfer
{
    virtual ~FileTransfer() { }

    /* Enqueue a data transfer request, returning a future to the result of
       the download. The future may throw a FileTransferError
       exception. */
    virtual void enqueueFileTransfer(const FileTransferRequest & request,
        Callback<FileTransferResult> callback) = 0;

    std::future<FileTransferResult> enqueueFileTransfer(const FileTransferRequest & request);

    /* Synchronously download a file. */
    FileTransferResult download(const FileTransferRequest & request);

    /* Synchronously upload a file. */
    FileTransferResult upload(const FileTransferRequest & request);

    /* Download a file, writing its data to a sink. The sink will be
       invoked on the thread of the caller. */
    void download(FileTransferRequest && request, Sink & sink);

    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. */
ref<FileTransfer> makeFileTransfer();

class FileTransferError : public Error
{
public:
    FileTransfer::Error error;
    std::shared_ptr<string> response; // intentionally optional

    template<typename... Args>
    FileTransferError(FileTransfer::Error error, std::shared_ptr<string> response, const Args & ... args);

    virtual const char* sname() const override { return "FileTransferError"; }
};

bool isUri(const string & s);

/* Resolve deprecated 'channel:<foo>' URLs. */
std::string resolveUri(const std::string & uri);

}