19
19
#include " llvm/Support/Errc.h"
20
20
#include " llvm/Support/Error.h"
21
21
#include " llvm/Support/MemoryBuffer.h"
22
+ #ifdef LLVM_ENABLE_CURL
23
+ #include < curl/curl.h>
24
+ #endif
22
25
23
26
using namespace llvm ;
24
27
@@ -81,12 +84,120 @@ Expected<HTTPResponseBuffer> HTTPClient::get(StringRef Url) {
81
84
return perform (Request);
82
85
}
83
86
87
+ #ifdef LLVM_ENABLE_CURL
88
+
89
+ bool HTTPClient::isAvailable () { return true ; }
90
+
91
+ bool HTTPClient::IsInitialized = false ;
92
+
93
+ void HTTPClient::initialize () {
94
+ if (!IsInitialized) {
95
+ curl_global_init (CURL_GLOBAL_ALL);
96
+ IsInitialized = true ;
97
+ }
98
+ }
99
+
100
+ void HTTPClient::cleanup () {
101
+ if (IsInitialized) {
102
+ curl_global_cleanup ();
103
+ IsInitialized = false ;
104
+ }
105
+ }
106
+
107
+ void HTTPClient::setTimeout (std::chrono::milliseconds Timeout) {
108
+ if (Timeout < std::chrono::milliseconds (0 ))
109
+ Timeout = std::chrono::milliseconds (0 );
110
+ curl_easy_setopt (Curl, CURLOPT_TIMEOUT_MS, Timeout.count ());
111
+ }
112
+
113
+ // / CurlHTTPRequest and the curl{Header,Write}Function are implementation
114
+ // / details used to work with Curl. Curl makes callbacks with a single
115
+ // / customizable pointer parameter.
116
+ struct CurlHTTPRequest {
117
+ CurlHTTPRequest (HTTPResponseHandler &Handler) : Handler(Handler) {}
118
+ void storeError (Error Err) {
119
+ ErrorState = joinErrors (std::move (Err), std::move (ErrorState));
120
+ }
121
+ HTTPResponseHandler &Handler;
122
+ llvm::Error ErrorState = Error::success();
123
+ };
124
+
125
+ static size_t curlHeaderFunction (char *Contents, size_t Size, size_t NMemb,
126
+ CurlHTTPRequest *CurlRequest) {
127
+ assert (Size == 1 && " The Size passed by libCURL to CURLOPT_HEADERFUNCTION "
128
+ " should always be 1." );
129
+ if (Error Err =
130
+ CurlRequest->Handler .handleHeaderLine (StringRef (Contents, NMemb))) {
131
+ CurlRequest->storeError (std::move (Err));
132
+ return 0 ;
133
+ }
134
+ return NMemb;
135
+ }
136
+
137
+ static size_t curlWriteFunction (char *Contents, size_t Size, size_t NMemb,
138
+ CurlHTTPRequest *CurlRequest) {
139
+ Size *= NMemb;
140
+ if (Error Err =
141
+ CurlRequest->Handler .handleBodyChunk (StringRef (Contents, Size))) {
142
+ CurlRequest->storeError (std::move (Err));
143
+ return 0 ;
144
+ }
145
+ return Size;
146
+ }
147
+
148
+ HTTPClient::HTTPClient () {
149
+ assert (IsInitialized &&
150
+ " Must call HTTPClient::initialize() at the beginning of main()." );
151
+ if (Curl)
152
+ return ;
153
+ assert ((Curl = curl_easy_init ()) && " Curl could not be initialized." );
154
+ // Set the callback hooks.
155
+ curl_easy_setopt (Curl, CURLOPT_WRITEFUNCTION, curlWriteFunction);
156
+ curl_easy_setopt (Curl, CURLOPT_HEADERFUNCTION, curlHeaderFunction);
157
+ }
158
+
159
+ HTTPClient::~HTTPClient () { curl_easy_cleanup (Curl); }
160
+
161
+ Error HTTPClient::perform (const HTTPRequest &Request,
162
+ HTTPResponseHandler &Handler) {
163
+ if (Request.Method != HTTPMethod::GET)
164
+ return createStringError (errc::invalid_argument,
165
+ " Unsupported CURL request method." );
166
+
167
+ SmallString<128 > Url = Request.Url ;
168
+ curl_easy_setopt (Curl, CURLOPT_URL, Url.c_str ());
169
+ curl_easy_setopt (Curl, CURLOPT_FOLLOWLOCATION, Request.FollowRedirects );
170
+
171
+ CurlHTTPRequest CurlRequest (Handler);
172
+ curl_easy_setopt (Curl, CURLOPT_WRITEDATA, &CurlRequest);
173
+ curl_easy_setopt (Curl, CURLOPT_HEADERDATA, &CurlRequest);
174
+ CURLcode CurlRes = curl_easy_perform (Curl);
175
+ if (CurlRes != CURLE_OK)
176
+ return joinErrors (std::move (CurlRequest.ErrorState ),
177
+ createStringError (errc::io_error,
178
+ " curl_easy_perform() failed: %s\n " ,
179
+ curl_easy_strerror (CurlRes)));
180
+ if (CurlRequest.ErrorState )
181
+ return std::move (CurlRequest.ErrorState );
182
+
183
+ unsigned Code;
184
+ curl_easy_getinfo (Curl, CURLINFO_RESPONSE_CODE, &Code);
185
+ if (Error Err = Handler.handleStatusCode (Code))
186
+ return joinErrors (std::move (CurlRequest.ErrorState ), std::move (Err));
187
+
188
+ return std::move (CurlRequest.ErrorState );
189
+ }
190
+
191
+ #else
192
+
84
193
HTTPClient::HTTPClient () = default ;
85
194
86
195
HTTPClient::~HTTPClient () = default ;
87
196
88
197
bool HTTPClient::isAvailable () { return false ; }
89
198
199
+ void HTTPClient::initialize () {}
200
+
90
201
void HTTPClient::cleanup () {}
91
202
92
203
void HTTPClient::setTimeout (std::chrono::milliseconds Timeout) {}
@@ -95,3 +206,5 @@ Error HTTPClient::perform(const HTTPRequest &Request,
95
206
HTTPResponseHandler &Handler) {
96
207
llvm_unreachable (" No HTTP Client implementation available." );
97
208
}
209
+
210
+ #endif
0 commit comments