LLVM  15.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 /// This file defines the implementation of the HTTPClient library for issuing
11 /// HTTP requests and handling the responses.
12 ///
13 //===----------------------------------------------------------------------===//
14 
16 #include "llvm/ADT/APInt.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Errc.h"
19 #include "llvm/Support/Error.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 
35 
36 bool HTTPClient::IsInitialized = false;
37 
39 public:
41 };
43 
44 #ifdef LLVM_ENABLE_CURL
45 
46 bool HTTPClient::isAvailable() { return true; }
47 
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 
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 }
101 
102 HTTPClient::~HTTPClient() { curl_easy_cleanup(Curl); }
103 
104 Error HTTPClient::perform(const HTTPRequest &Request,
105  HTTPResponseHandler &Handler) {
106  if (Request.Method != HTTPMethod::GET)
108  "Unsupported CURL request method.");
109 
110  SmallString<128> Url = Request.Url;
111  curl_easy_setopt(Curl, CURLOPT_URL, Url.c_str());
112  curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, Request.FollowRedirects);
113 
114  CurlHTTPRequest CurlRequest(Handler);
115  curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &CurlRequest);
116  CURLcode CurlRes = curl_easy_perform(Curl);
117  if (CurlRes != CURLE_OK)
118  return joinErrors(std::move(CurlRequest.ErrorState),
120  "curl_easy_perform() failed: %s\n",
121  curl_easy_strerror(CurlRes)));
122  return std::move(CurlRequest.ErrorState);
123 }
124 
125 unsigned HTTPClient::responseCode() {
126  long Code = 0;
127  curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Code);
128  return Code;
129 }
130 
131 #else
132 
133 HTTPClient::HTTPClient() = default;
134 
135 HTTPClient::~HTTPClient() = default;
136 
137 bool HTTPClient::isAvailable() { return false; }
138 
140 
142 
143 void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {}
144 
146  HTTPResponseHandler &Handler) {
147  llvm_unreachable("No HTTP Client implementation available.");
148 }
149 
151  llvm_unreachable("No HTTP Client implementation available.");
152 }
153 
154 #endif
llvm::Check::Size
@ Size
Definition: FileCheck.h:77
MemoryBuffer.h
llvm::errc::invalid_argument
@ invalid_argument
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
llvm::HTTPResponseHandler
A handler for state updates occurring while an HTTPRequest is performed.
Definition: HTTPClient.h:40
StringRef.h
llvm::HTTPClient::IsInitialized
static bool IsInitialized
Definition: HTTPClient.h:59
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:329
Error.h
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:139
HTTPClient.h
llvm::HTTPRequest::HTTPRequest
HTTPRequest(StringRef Url)
Definition: HTTPClient.cpp:27
llvm::HTTPClient::cleanup
static void cleanup()
Must be called at the end of a program, while it is a single thread.
Definition: HTTPClient.cpp:141
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:145
HTTPClientCleanup::~HTTPClientCleanup
~HTTPClientCleanup()
Definition: HTTPClient.cpp:40
llvm::SmallString< 128 >
llvm::HTTPResponseHandler::~HTTPResponseHandler
~HTTPResponseHandler()
llvm::SmallString::c_str
const char * c_str()
Definition: SmallString.h:263
llvm::HTTPRequest::Url
SmallString< 128 > Url
Definition: HTTPClient.h:29
llvm::HTTPClient::responseCode
unsigned responseCode()
Returns the last received response code or zero if none.
Definition: HTTPClient.cpp:150
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:426
HTTPClientCleanup
Definition: HTTPClient.cpp:38
llvm::HTTPClient::isAvailable
static bool isAvailable()
Returns true only if LLVM has been compiled with a working HTTPClient.
Definition: HTTPClient.cpp:137
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::HTTPClient::setTimeout
void setTimeout(std::chrono::milliseconds Timeout)
Sets the timeout for the entire request, in milliseconds.
Definition: HTTPClient.cpp:143
llvm::operator==
bool operator==(uint64_t V1, const APInt &V2)
Definition: APInt.h:1990
Cleanup
static const HTTPClientCleanup Cleanup
Definition: HTTPClient.cpp:42
llvm::HTTPRequest::FollowRedirects
bool FollowRedirects
Definition: HTTPClient.h:31
llvm::StringRef
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:58
llvm_unreachable
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Definition: ErrorHandling.h:143
llvm::HTTPRequest::Method
HTTPMethod Method
Definition: HTTPClient.h:30
llvm::createStringError
Error createStringError(std::error_code EC, char const *Fmt, const Ts &... Vals)
Create formatted StringError object.
Definition: Error.h:1239
llvm::HTTPRequest
A stateless description of an outbound HTTP request.
Definition: HTTPClient.h:28
llvm::Error
Lightweight error class with error context and mandatory checking.
Definition: Error.h:155
llvm::errc::io_error
@ io_error
llvm::SmallString::str
StringRef str() const
Explicit conversion to StringRef.
Definition: SmallString.h:260
llvm::HTTPClient::HTTPClient
HTTPClient()
llvm::HTTPMethod::GET
@ GET