brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.9 KiB · 4cca250 Raw
163 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file defines the implementation of the HTTPClient library for issuing11/// 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_CURL22#include <curl/curl.h>23#endif24 25using namespace llvm;26 27HTTPRequest::HTTPRequest(StringRef Url) { this->Url = Url.str(); }28 29bool operator==(const HTTPRequest &A, const HTTPRequest &B) {30  return A.Url == B.Url && A.Method == B.Method &&31         A.FollowRedirects == B.FollowRedirects;32}33 34HTTPResponseHandler::~HTTPResponseHandler() = default;35 36bool HTTPClient::IsInitialized = false;37 38class HTTPClientCleanup {39public:40  ~HTTPClientCleanup() { HTTPClient::cleanup(); }41};42static const HTTPClientCleanup Cleanup;43 44#ifdef LLVM_ENABLE_CURL45 46bool HTTPClient::isAvailable() { return true; }47 48void HTTPClient::initialize() {49  if (!IsInitialized) {50    curl_global_init(CURL_GLOBAL_ALL);51    IsInitialized = true;52  }53}54 55void HTTPClient::cleanup() {56  if (IsInitialized) {57    curl_global_cleanup();58    IsInitialized = false;59  }60}61 62void 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 implementation69/// details used to work with Curl. Curl makes callbacks with a single70/// customizable pointer parameter.71struct 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 80static 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 91HTTPClient::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 104HTTPClient::~HTTPClient() { curl_easy_cleanup(Curl); }105 106Error 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 133unsigned HTTPClient::responseCode() {134  long Code = 0;135  curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Code);136  return Code;137}138 139#else140 141HTTPClient::HTTPClient() = default;142 143HTTPClient::~HTTPClient() = default;144 145bool HTTPClient::isAvailable() { return false; }146 147void HTTPClient::initialize() {}148 149void HTTPClient::cleanup() {}150 151void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {}152 153Error HTTPClient::perform(const HTTPRequest &Request,154                          HTTPResponseHandler &Handler) {155  llvm_unreachable("No HTTP Client implementation available.");156}157 158unsigned HTTPClient::responseCode() {159  llvm_unreachable("No HTTP Client implementation available.");160}161 162#endif163