LLVM  14.0.0git
HTTPClient.cpp
Go to the documentation of this file.
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 ///
11 /// This file defines the methods of the HTTPRequest, HTTPClient, and
12 /// BufferedHTTPResponseHandler classes.
13 ///
14 //===----------------------------------------------------------------------===//
15 
17 #include "llvm/ADT/APInt.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Errc.h"
20 #include "llvm/Support/Error.h"
22 #ifdef LLVM_ENABLE_CURL
23 #include <curl/curl.h>
24 #endif
25 
26 using namespace llvm;
27 
28 HTTPRequest::HTTPRequest(StringRef Url) { this->Url = Url.str(); }
29 
30 bool operator==(const HTTPRequest &A, const HTTPRequest &B) {
31  return A.Url == B.Url && A.Method == B.Method &&
32  A.FollowRedirects == B.FollowRedirects;
33 }
34 
36 
37 static inline bool parseContentLengthHeader(StringRef LineRef,
38  size_t &ContentLength) {
39  // Content-Length is a mandatory header, and the only one we handle.
40  return LineRef.consume_front("Content-Length: ") &&
41  to_integer(LineRef.trim(), ContentLength, 10);
42 }
43 
45  if (ResponseBuffer.Body)
46  return Error::success();
47 
48  size_t ContentLength;
49  if (parseContentLengthHeader(HeaderLine, ContentLength))
52 
53  return Error::success();
54 }
55 
57  if (!ResponseBuffer.Body)
59  "Unallocated response buffer. HTTP Body data "
60  "received before Content-Length header.");
61  if (Offset + BodyChunk.size() > ResponseBuffer.Body->getBufferSize())
63  "Content size exceeds buffer size.");
64  memcpy(ResponseBuffer.Body->getBufferStart() + Offset, BodyChunk.data(),
65  BodyChunk.size());
66  Offset += BodyChunk.size();
67  return Error::success();
68 }
69 
71  ResponseBuffer.Code = Code;
72  return Error::success();
73 }
74 
75 bool HTTPClient::IsInitialized = false;
76 
78 public:
80 };
82 
85  if (Error Err = perform(Request, Handler))
86  return std::move(Err);
87  return std::move(Handler.ResponseBuffer);
88 }
89 
91  HTTPRequest Request(Url);
92  return perform(Request);
93 }
94 
95 #ifdef LLVM_ENABLE_CURL
96 
97 bool HTTPClient::isAvailable() { return true; }
98 
100  if (!IsInitialized) {
101  curl_global_init(CURL_GLOBAL_ALL);
102  IsInitialized = true;
103  }
104 }
105 
106 void HTTPClient::cleanup() {
107  if (IsInitialized) {
108  curl_global_cleanup();
109  IsInitialized = false;
110  }
111 }
112 
113 void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {
114  if (Timeout < std::chrono::milliseconds(0))
115  Timeout = std::chrono::milliseconds(0);
116  curl_easy_setopt(Curl, CURLOPT_TIMEOUT_MS, Timeout.count());
117 }
118 
119 /// CurlHTTPRequest and the curl{Header,Write}Function are implementation
120 /// details used to work with Curl. Curl makes callbacks with a single
121 /// customizable pointer parameter.
122 struct CurlHTTPRequest {
123  CurlHTTPRequest(HTTPResponseHandler &Handler) : Handler(Handler) {}
124  void storeError(Error Err) {
125  ErrorState = joinErrors(std::move(Err), std::move(ErrorState));
126  }
127  HTTPResponseHandler &Handler;
128  llvm::Error ErrorState = Error::success();
129 };
130 
131 static size_t curlHeaderFunction(char *Contents, size_t Size, size_t NMemb,
132  CurlHTTPRequest *CurlRequest) {
133  assert(Size == 1 && "The Size passed by libCURL to CURLOPT_HEADERFUNCTION "
134  "should always be 1.");
135  if (Error Err =
136  CurlRequest->Handler.handleHeaderLine(StringRef(Contents, NMemb))) {
137  CurlRequest->storeError(std::move(Err));
138  return 0;
139  }
140  return NMemb;
141 }
142 
143 static size_t curlWriteFunction(char *Contents, size_t Size, size_t NMemb,
144  CurlHTTPRequest *CurlRequest) {
145  Size *= NMemb;
146  if (Error Err =
147  CurlRequest->Handler.handleBodyChunk(StringRef(Contents, Size))) {
148  CurlRequest->storeError(std::move(Err));
149  return 0;
150  }
151  return Size;
152 }
153 
156  "Must call HTTPClient::initialize() at the beginning of main().");
157  if (Curl)
158  return;
159  assert((Curl = curl_easy_init()) && "Curl could not be initialized.");
160  // Set the callback hooks.
161  curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, curlWriteFunction);
162  curl_easy_setopt(Curl, CURLOPT_HEADERFUNCTION, curlHeaderFunction);
163 }
164 
165 HTTPClient::~HTTPClient() { curl_easy_cleanup(Curl); }
166 
167 Error HTTPClient::perform(const HTTPRequest &Request,
168  HTTPResponseHandler &Handler) {
169  if (Request.Method != HTTPMethod::GET)
171  "Unsupported CURL request method.");
172 
173  SmallString<128> Url = Request.Url;
174  curl_easy_setopt(Curl, CURLOPT_URL, Url.c_str());
175  curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, Request.FollowRedirects);
176 
177  CurlHTTPRequest CurlRequest(Handler);
178  curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &CurlRequest);
179  curl_easy_setopt(Curl, CURLOPT_HEADERDATA, &CurlRequest);
180  CURLcode CurlRes = curl_easy_perform(Curl);
181  if (CurlRes != CURLE_OK)
182  return joinErrors(std::move(CurlRequest.ErrorState),
184  "curl_easy_perform() failed: %s\n",
185  curl_easy_strerror(CurlRes)));
186  if (CurlRequest.ErrorState)
187  return std::move(CurlRequest.ErrorState);
188 
189  unsigned Code;
190  curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Code);
191  if (Error Err = Handler.handleStatusCode(Code))
192  return joinErrors(std::move(CurlRequest.ErrorState), std::move(Err));
193 
194  return std::move(CurlRequest.ErrorState);
195 }
196 
197 #else
198 
199 HTTPClient::HTTPClient() = default;
200 
201 HTTPClient::~HTTPClient() = default;
202 
203 bool HTTPClient::isAvailable() { return false; }
204 
206 
208 
209 void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {}
210 
212  HTTPResponseHandler &Handler) {
213  llvm_unreachable("No HTTP Client implementation available.");
214 }
215 
216 #endif
llvm::Check::Size
@ Size
Definition: FileCheck.h:73
MemoryBuffer.h
llvm::errc::invalid_argument
@ invalid_argument
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AllocatorList.h:23
llvm::HTTPResponseHandler
A handler for state updates occurring while an HTTPRequest is performed.
Definition: HTTPClient.h:39
StringRef.h
llvm::HTTPClient::IsInitialized
static bool IsInitialized
Definition: HTTPClient.h:88
llvm::tgtok::Code
@ Code
Definition: TGLexer.h:50
llvm::HTTPClient::~HTTPClient
~HTTPClient()
llvm::Error::success
static ErrorSuccess success()
Create a success value.
Definition: Error.h:331
Error.h
llvm::StringRef::consume_front
bool consume_front(StringRef Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition: StringRef.h:681
parseContentLengthHeader
static bool parseContentLengthHeader(StringRef LineRef, size_t &ContentLength)
Definition: HTTPClient.cpp:37
llvm::BufferedHTTPResponseHandler
A simple handler which writes returned data to an HTTPResponseBuffer.
Definition: HTTPClient.h:63
APInt.h
Errc.h
llvm::HTTPClient::initialize
static void initialize()
Must be called at the beginning of a program, while it is a single thread.
Definition: HTTPClient.cpp:205
llvm::BufferedHTTPResponseHandler::handleHeaderLine
Error handleHeaderLine(StringRef HeaderLine) override
These callbacks store the body and status code in an HTTPResponseBuffer allocated based on Content-Le...
Definition: HTTPClient.cpp:44
HTTPClient.h
llvm::Expected
Tagged union holding either a T or a Error.
Definition: APFloat.h:42
llvm::BufferedHTTPResponseHandler::ResponseBuffer
HTTPResponseBuffer ResponseBuffer
Stores the data received from the HTTP server.
Definition: HTTPClient.h:68
llvm::HTTPRequest::HTTPRequest
HTTPRequest(StringRef Url)
Definition: HTTPClient.cpp:28
llvm::HTTPClient::cleanup
static void cleanup()
Must be called at the end of a program, while it is a single thread.
Definition: HTTPClient.cpp:207
B
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
llvm::HTTPClient::perform
Error perform(const HTTPRequest &Request, HTTPResponseHandler &Handler)
Performs the Request, passing response data to the Handler.
Definition: HTTPClient.cpp:211
llvm::BufferedHTTPResponseHandler::handleStatusCode
Error handleStatusCode(unsigned Code) override
Processes the HTTP response status code.
Definition: HTTPClient.cpp:70
HTTPClientCleanup::~HTTPClientCleanup
~HTTPClientCleanup()
Definition: HTTPClient.cpp:79
llvm::SmallString< 128 >
llvm::HTTPResponseHandler::~HTTPResponseHandler
~HTTPResponseHandler()
llvm::StringRef::trim
LLVM_NODISCARD StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
Definition: StringRef.h:869
llvm::SmallString::c_str
const char * c_str()
Definition: SmallString.h:262
llvm::HTTPResponseBuffer::Body
std::unique_ptr< WritableMemoryBuffer > Body
Definition: HTTPClient.h:57
llvm::HTTPRequest::Url
SmallString< 128 > Url
Definition: HTTPClient.h:28
llvm::BufferedHTTPResponseHandler::handleBodyChunk
Error handleBodyChunk(StringRef BodyChunk) override
Processes an additional chunk of bytes of the HTTP response body.
Definition: HTTPClient.cpp:56
move
compiles ldr LCPI1_0 ldr ldr mov lsr tst moveq r1 ldr LCPI1_1 and r0 bx lr It would be better to do something like to fold the shift into the conditional move
Definition: README.txt:546
llvm::joinErrors
Error joinErrors(Error E1, Error E2)
Concatenate errors.
Definition: Error.h:428
HTTPClientCleanup
Definition: HTTPClient.cpp:77
llvm::HTTPClient::isAvailable
static bool isAvailable()
Returns true only if LLVM has been compiled with a working HTTPClient.
Definition: HTTPClient.cpp:203
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::WritableMemoryBuffer::getNewUninitMemBuffer
static std::unique_ptr< WritableMemoryBuffer > getNewUninitMemBuffer(size_t Size, const Twine &BufferName="")
Allocate a new MemoryBuffer of the specified size that is not initialized.
Definition: MemoryBuffer.cpp:280
llvm::HTTPClient::setTimeout
void setTimeout(std::chrono::milliseconds Timeout)
Sets the timeout for the entire request, in milliseconds.
Definition: HTTPClient.cpp:209
memcpy
<%struct.s * > cast struct s *S to sbyte *< sbyte * > sbyte uint cast struct s *agg result to sbyte *< sbyte * > sbyte uint cast struct s *memtmp to sbyte *< sbyte * > sbyte uint ret void llc ends up issuing two memcpy or custom lower memcpy(of small size) to be ldmia/stmia. I think option 2 is better but the current register allocator cannot allocate a chunk of registers at a time. A feasible temporary solution is to use specific physical registers at the lowering time for small(<
llvm::operator==
bool operator==(uint64_t V1, const APInt &V2)
Definition: APInt.h:1986
Cleanup
static const HTTPClientCleanup Cleanup
Definition: HTTPClient.cpp:81
llvm::HTTPRequest::FollowRedirects
bool FollowRedirects
Definition: HTTPClient.h:30
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:57
llvm::HTTPResponseBuffer::Code
unsigned Code
Definition: HTTPClient.h:56
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:134
llvm::HTTPRequest::Method
HTTPMethod Method
Definition: HTTPClient.h:29
llvm::HTTPClient::get
Expected< HTTPResponseBuffer > get(StringRef Url)
Performs an HTTPRequest with the default configuration to make a GET request to the given Url.
Definition: HTTPClient.cpp:90
llvm::StringRef::size
constexpr LLVM_NODISCARD size_t size() const
size - Get the string size.
Definition: StringRef.h:156
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1241
llvm::HTTPRequest
A stateless description of an outbound HTTP request.
Definition: HTTPClient.h:27
llvm::HTTPResponseHandler::handleStatusCode
virtual Error handleStatusCode(unsigned Code)=0
Processes the HTTP response status code.
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
llvm::errc::io_error
@ io_error
llvm::SmallString::str
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:259
llvm::HTTPClient::HTTPClient
HTTPClient()
llvm::StringRef::data
const LLVM_NODISCARD char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:148
llvm::HTTPMethod::GET
@ GET