Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/Debuginfod/HTTPClient.cpp
35233 views
1
//===-- llvm/Debuginfod/HTTPClient.cpp - HTTP client library ----*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// This file defines the implementation of the HTTPClient library for issuing
11
/// HTTP requests and handling the responses.
12
///
13
//===----------------------------------------------------------------------===//
14
15
#include "llvm/Debuginfod/HTTPClient.h"
16
#include "llvm/ADT/APInt.h"
17
#include "llvm/ADT/StringRef.h"
18
#include "llvm/Support/Errc.h"
19
#include "llvm/Support/Error.h"
20
#include "llvm/Support/MemoryBuffer.h"
21
#ifdef LLVM_ENABLE_CURL
22
#include <curl/curl.h>
23
#endif
24
25
using namespace llvm;
26
27
HTTPRequest::HTTPRequest(StringRef Url) { this->Url = Url.str(); }
28
29
bool operator==(const HTTPRequest &A, const HTTPRequest &B) {
30
return A.Url == B.Url && A.Method == B.Method &&
31
A.FollowRedirects == B.FollowRedirects;
32
}
33
34
HTTPResponseHandler::~HTTPResponseHandler() = default;
35
36
bool HTTPClient::IsInitialized = false;
37
38
class HTTPClientCleanup {
39
public:
40
~HTTPClientCleanup() { HTTPClient::cleanup(); }
41
};
42
static const HTTPClientCleanup Cleanup;
43
44
#ifdef LLVM_ENABLE_CURL
45
46
bool HTTPClient::isAvailable() { return true; }
47
48
void HTTPClient::initialize() {
49
if (!IsInitialized) {
50
curl_global_init(CURL_GLOBAL_ALL);
51
IsInitialized = true;
52
}
53
}
54
55
void HTTPClient::cleanup() {
56
if (IsInitialized) {
57
curl_global_cleanup();
58
IsInitialized = false;
59
}
60
}
61
62
void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {
63
if (Timeout < std::chrono::milliseconds(0))
64
Timeout = std::chrono::milliseconds(0);
65
curl_easy_setopt(Curl, CURLOPT_TIMEOUT_MS, Timeout.count());
66
}
67
68
/// CurlHTTPRequest and the curl{Header,Write}Function are implementation
69
/// details used to work with Curl. Curl makes callbacks with a single
70
/// customizable pointer parameter.
71
struct CurlHTTPRequest {
72
CurlHTTPRequest(HTTPResponseHandler &Handler) : Handler(Handler) {}
73
void storeError(Error Err) {
74
ErrorState = joinErrors(std::move(Err), std::move(ErrorState));
75
}
76
HTTPResponseHandler &Handler;
77
llvm::Error ErrorState = Error::success();
78
};
79
80
static size_t curlWriteFunction(char *Contents, size_t Size, size_t NMemb,
81
CurlHTTPRequest *CurlRequest) {
82
Size *= NMemb;
83
if (Error Err =
84
CurlRequest->Handler.handleBodyChunk(StringRef(Contents, Size))) {
85
CurlRequest->storeError(std::move(Err));
86
return 0;
87
}
88
return Size;
89
}
90
91
HTTPClient::HTTPClient() {
92
assert(IsInitialized &&
93
"Must call HTTPClient::initialize() at the beginning of main().");
94
if (Curl)
95
return;
96
Curl = curl_easy_init();
97
assert(Curl && "Curl could not be initialized");
98
// Set the callback hooks.
99
curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, curlWriteFunction);
100
// Detect supported compressed encodings and accept all.
101
curl_easy_setopt(Curl, CURLOPT_ACCEPT_ENCODING, "");
102
}
103
104
HTTPClient::~HTTPClient() { curl_easy_cleanup(Curl); }
105
106
Error HTTPClient::perform(const HTTPRequest &Request,
107
HTTPResponseHandler &Handler) {
108
if (Request.Method != HTTPMethod::GET)
109
return createStringError(errc::invalid_argument,
110
"Unsupported CURL request method.");
111
112
SmallString<128> Url = Request.Url;
113
curl_easy_setopt(Curl, CURLOPT_URL, Url.c_str());
114
curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, Request.FollowRedirects);
115
116
curl_slist *Headers = nullptr;
117
for (const std::string &Header : Request.Headers)
118
Headers = curl_slist_append(Headers, Header.c_str());
119
curl_easy_setopt(Curl, CURLOPT_HTTPHEADER, Headers);
120
121
CurlHTTPRequest CurlRequest(Handler);
122
curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &CurlRequest);
123
CURLcode CurlRes = curl_easy_perform(Curl);
124
curl_slist_free_all(Headers);
125
if (CurlRes != CURLE_OK)
126
return joinErrors(std::move(CurlRequest.ErrorState),
127
createStringError(errc::io_error,
128
"curl_easy_perform() failed: %s\n",
129
curl_easy_strerror(CurlRes)));
130
return std::move(CurlRequest.ErrorState);
131
}
132
133
unsigned HTTPClient::responseCode() {
134
long Code = 0;
135
curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Code);
136
return Code;
137
}
138
139
#else
140
141
HTTPClient::HTTPClient() = default;
142
143
HTTPClient::~HTTPClient() = default;
144
145
bool HTTPClient::isAvailable() { return false; }
146
147
void HTTPClient::initialize() {}
148
149
void HTTPClient::cleanup() {}
150
151
void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {}
152
153
Error HTTPClient::perform(const HTTPRequest &Request,
154
HTTPResponseHandler &Handler) {
155
llvm_unreachable("No HTTP Client implementation available.");
156
}
157
158
unsigned HTTPClient::responseCode() {
159
llvm_unreachable("No HTTP Client implementation available.");
160
}
161
162
#endif
163
164