23#ifdef LLVM_ENABLE_CURL
35 return A.Url ==
B.Url &&
A.Method ==
B.Method &&
36 A.FollowRedirects ==
B.FollowRedirects;
49#ifdef LLVM_ENABLE_CURL
55 curl_global_init(CURL_GLOBAL_ALL);
62 curl_global_cleanup();
68 if (
Timeout < std::chrono::milliseconds(0))
69 Timeout = std::chrono::milliseconds(0);
70 curl_easy_setopt(Handle, CURLOPT_TIMEOUT_MS,
Timeout.count());
76struct CurlHTTPRequest {
77 CurlHTTPRequest(HTTPResponseHandler &Handler) : Handler(Handler) {}
78 void storeError(
Error Err) {
79 ErrorState =
joinErrors(std::move(Err), std::move(ErrorState));
81 HTTPResponseHandler &Handler;
85static size_t curlWriteFunction(
char *Contents,
size_t Size,
size_t NMemb,
86 CurlHTTPRequest *CurlRequest) {
89 CurlRequest->Handler.handleBodyChunk(
StringRef(Contents,
Size))) {
90 CurlRequest->storeError(std::move(Err));
98 "Must call HTTPClient::initialize() at the beginning of main().");
101 Handle = curl_easy_init();
102 assert(Handle &&
"Curl could not be initialized");
104 curl_easy_setopt(Handle, CURLOPT_WRITEFUNCTION, curlWriteFunction);
106 curl_easy_setopt(Handle, CURLOPT_ACCEPT_ENCODING,
"");
115 "Unsupported CURL request method.");
117 SmallString<128> Url = Request.
Url;
118 curl_easy_setopt(Handle, CURLOPT_URL, Url.
c_str());
119 curl_easy_setopt(Handle, CURLOPT_FOLLOWLOCATION, Request.
FollowRedirects);
121 curl_slist *Headers =
nullptr;
122 for (
const std::string &Header : Request.
Headers)
123 Headers = curl_slist_append(Headers, Header.c_str());
124 curl_easy_setopt(Handle, CURLOPT_HTTPHEADER, Headers);
126 CurlHTTPRequest CurlRequest(Handler);
127 curl_easy_setopt(Handle, CURLOPT_WRITEDATA, &CurlRequest);
128 CURLcode CurlRes = curl_easy_perform(Handle);
129 curl_slist_free_all(Headers);
130 if (CurlRes != CURLE_OK)
131 return joinErrors(std::move(CurlRequest.ErrorState),
133 "curl_easy_perform() failed: %s\n",
134 curl_easy_strerror(CurlRes)));
135 return std::move(CurlRequest.ErrorState);
140 curl_easy_getinfo(Handle, CURLINFO_RESPONSE_CODE, &Code);
149#pragma comment(lib, "winhttp.lib")
153struct WinHTTPSession {
154 HINTERNET SessionHandle =
nullptr;
155 HINTERNET ConnectHandle =
nullptr;
156 HINTERNET RequestHandle =
nullptr;
157 DWORD ResponseCode = 0;
161 WinHttpCloseHandle(RequestHandle);
163 WinHttpCloseHandle(ConnectHandle);
165 WinHttpCloseHandle(SessionHandle);
169bool parseURL(
StringRef Url, std::wstring &Host, std::wstring &Path,
170 INTERNET_PORT &Port,
bool &Secure) {
182 size_t SlashPos = Url.
find(
'/');
188 size_t ColonPos = HostPort.
find(
':');
199 Port =
static_cast<INTERNET_PORT
>(std::stoi(PortStr.
str()));
201 Port = Secure ? INTERNET_DEFAULT_HTTPS_PORT : INTERNET_DEFAULT_HTTP_PORT;
228 WinHTTPSession *Session =
static_cast<WinHTTPSession *
>(Handle);
229 if (Session && Session->SessionHandle) {
231 WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_CONNECT_TIMEOUT,
232 &TimeoutMs,
sizeof(TimeoutMs));
233 WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_RECEIVE_TIMEOUT,
234 &TimeoutMs,
sizeof(TimeoutMs));
235 WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_SEND_TIMEOUT,
236 &TimeoutMs,
sizeof(TimeoutMs));
244 "Only GET requests are supported.");
245 for (
const std::string &Header : Request.
Headers)
246 if (Header.find(
"\r") != std::string::npos ||
247 Header.find(
"\n") != std::string::npos) {
249 "Unsafe request can lead to header injection.");
252 WinHTTPSession *Session =
static_cast<WinHTTPSession *
>(Handle);
255 std::wstring Host,
Path;
256 INTERNET_PORT Port = 0;
258 if (!parseURL(Request.
Url, Host, Path, Port, Secure))
260 "Invalid URL: " + Request.
Url);
263 Session->SessionHandle =
264 WinHttpOpen(L
"LLVM-HTTPClient/1.0", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY,
265 WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
266 if (!Session->SessionHandle)
270 DWORD SecureProtocols =
271 WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_2 | WINHTTP_FLAG_SECURE_PROTOCOL_TLS1_3;
272 if (!WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_SECURE_PROTOCOLS,
273 &SecureProtocols,
sizeof(SecureProtocols)))
277 DWORD EnableHttp2 = WINHTTP_PROTOCOL_FLAG_HTTP2;
278 WinHttpSetOption(Session->SessionHandle, WINHTTP_OPTION_ENABLE_HTTP_PROTOCOL,
279 &EnableHttp2,
sizeof(EnableHttp2));
282 Session->ConnectHandle =
283 WinHttpConnect(Session->SessionHandle, Host.c_str(), Port, 0);
284 if (!Session->ConnectHandle) {
286 "Failed to connect to host: " + Request.
Url);
292 Flags |= WINHTTP_FLAG_SECURE;
294 Session->RequestHandle = WinHttpOpenRequest(
295 Session->ConnectHandle, L
"GET",
Path.c_str(),
nullptr, WINHTTP_NO_REFERER,
296 WINHTTP_DEFAULT_ACCEPT_TYPES, Flags);
297 if (!Session->RequestHandle)
301 DWORD EnableRevocationChecks = WINHTTP_ENABLE_SSL_REVOCATION;
302 if (!WinHttpSetOption(Session->RequestHandle, WINHTTP_OPTION_ENABLE_FEATURE,
303 &EnableRevocationChecks,
304 sizeof(EnableRevocationChecks)))
306 "Failed to enable certificate revocation checks");
310 DWORD SecurityFlags = 0;
311 if (!WinHttpSetOption(Session->RequestHandle, WINHTTP_OPTION_SECURITY_FLAGS,
312 &SecurityFlags,
sizeof(SecurityFlags)))
314 "Failed to enforce security flags");
317 for (
const std::string &Header : Request.
Headers) {
318 std::wstring WideHeader;
321 WinHttpAddRequestHeaders(Session->RequestHandle, WideHeader.c_str(),
322 static_cast<DWORD>(WideHeader.length()),
323 WINHTTP_ADDREQ_FLAG_ADD);
327 if (!WinHttpSendRequest(Session->RequestHandle, WINHTTP_NO_ADDITIONAL_HEADERS,
328 0,
nullptr, 0, 0, 0))
332 if (!WinHttpReceiveResponse(Session->RequestHandle,
nullptr))
337 if (!WinHttpQueryHeaders(Session->RequestHandle,
338 WINHTTP_QUERY_STATUS_CODE |
339 WINHTTP_QUERY_FLAG_NUMBER,
340 WINHTTP_HEADER_NAME_BY_INDEX, &Session->ResponseCode,
342 Session->ResponseCode = 0;
345 DWORD BytesAvailable = 0;
346 while (WinHttpQueryDataAvailable(Session->RequestHandle, &BytesAvailable)) {
347 if (BytesAvailable == 0)
350 std::vector<char> Buffer(BytesAvailable);
352 if (!WinHttpReadData(Session->RequestHandle, Buffer.data(), BytesAvailable,
367 WinHTTPSession *Session =
static_cast<WinHTTPSession *
>(Handle);
368 return Session ? Session->ResponseCode : 0;
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file implements a class to represent arbitrary precision integral constant values and operations...
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
ManagedStatic< HTTPClientCleanup > Cleanup
This file contains the declarations of the HTTPClient library for issuing HTTP requests and handling ...
Lightweight error class with error context and mandatory checking.
static ErrorSuccess success()
Create a success value.
static bool isAvailable()
Returns true only if LLVM has been compiled with a working HTTPClient.
static bool IsInitialized
unsigned responseCode()
Returns the last received response code or zero if none.
static void initialize()
Must be called at the beginning of a program, while it is a single thread.
Error perform(const HTTPRequest &Request, HTTPResponseHandler &Handler)
Performs the Request, passing response data to the Handler.
void setTimeout(std::chrono::milliseconds Timeout)
Sets the timeout for the entire request, in milliseconds.
static void cleanup()
Must be called at the end of a program, while it is a single thread.
A handler for state updates occurring while an HTTPRequest is performed.
virtual Error handleBodyChunk(StringRef BodyChunk)=0
Processes an additional chunk of bytes of the HTTP response body.
ManagedStatic - This transparently changes the behavior of global statics to be lazily constructed on...
StringRef - Represent a constant reference to a string, i.e.
static constexpr size_t npos
std::string str() const
str - Get the contents as an std::string.
constexpr StringRef substr(size_t Start, size_t N=npos) const
Return a reference to the substring from [Start, Start + N).
bool starts_with(StringRef Prefix) const
Check if this string starts with the given Prefix.
StringRef drop_front(size_t N=1) const
Return a StringRef equal to 'this' but with the first N elements dropped.
size_t find(char C, size_t From=0) const
Search for the first character C in the string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
NodeAddr< CodeNode * > Code
This is an optimization pass for GlobalISel generic memory operations.
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
bool operator==(const AddressRangeValuePair &LHS, const AddressRangeValuePair &RHS)
Error joinErrors(Error E1, Error E2)
Concatenate errors.
@ Timeout
Reached timeout while waiting for the owner to release the lock.
LLVM_ABI bool ConvertUTF8toWide(unsigned WideCharWidth, llvm::StringRef Source, char *&ResultPtr, const UTF8 *&ErrorPtr)
Convert an UTF8 StringRef to UTF8, UTF16, or UTF32 depending on WideCharWidth.
A stateless description of an outbound HTTP request.
SmallVector< std::string, 0 > Headers
HTTPRequest(StringRef Url)