Path: blob/main/contrib/llvm-project/llvm/lib/Debuginfod/HTTPClient.cpp
35233 views
//===-- llvm/Debuginfod/HTTPClient.cpp - HTTP client library ----*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7///8/// \file9/// This file defines the implementation of the HTTPClient library for issuing10/// HTTP requests and handling the responses.11///12//===----------------------------------------------------------------------===//1314#include "llvm/Debuginfod/HTTPClient.h"15#include "llvm/ADT/APInt.h"16#include "llvm/ADT/StringRef.h"17#include "llvm/Support/Errc.h"18#include "llvm/Support/Error.h"19#include "llvm/Support/MemoryBuffer.h"20#ifdef LLVM_ENABLE_CURL21#include <curl/curl.h>22#endif2324using namespace llvm;2526HTTPRequest::HTTPRequest(StringRef Url) { this->Url = Url.str(); }2728bool operator==(const HTTPRequest &A, const HTTPRequest &B) {29return A.Url == B.Url && A.Method == B.Method &&30A.FollowRedirects == B.FollowRedirects;31}3233HTTPResponseHandler::~HTTPResponseHandler() = default;3435bool HTTPClient::IsInitialized = false;3637class HTTPClientCleanup {38public:39~HTTPClientCleanup() { HTTPClient::cleanup(); }40};41static const HTTPClientCleanup Cleanup;4243#ifdef LLVM_ENABLE_CURL4445bool HTTPClient::isAvailable() { return true; }4647void HTTPClient::initialize() {48if (!IsInitialized) {49curl_global_init(CURL_GLOBAL_ALL);50IsInitialized = true;51}52}5354void HTTPClient::cleanup() {55if (IsInitialized) {56curl_global_cleanup();57IsInitialized = false;58}59}6061void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {62if (Timeout < std::chrono::milliseconds(0))63Timeout = std::chrono::milliseconds(0);64curl_easy_setopt(Curl, CURLOPT_TIMEOUT_MS, Timeout.count());65}6667/// CurlHTTPRequest and the curl{Header,Write}Function are implementation68/// details used to work with Curl. Curl makes callbacks with a single69/// customizable pointer parameter.70struct CurlHTTPRequest {71CurlHTTPRequest(HTTPResponseHandler &Handler) : Handler(Handler) {}72void storeError(Error Err) {73ErrorState = joinErrors(std::move(Err), std::move(ErrorState));74}75HTTPResponseHandler &Handler;76llvm::Error ErrorState = Error::success();77};7879static size_t curlWriteFunction(char *Contents, size_t Size, size_t NMemb,80CurlHTTPRequest *CurlRequest) {81Size *= NMemb;82if (Error Err =83CurlRequest->Handler.handleBodyChunk(StringRef(Contents, Size))) {84CurlRequest->storeError(std::move(Err));85return 0;86}87return Size;88}8990HTTPClient::HTTPClient() {91assert(IsInitialized &&92"Must call HTTPClient::initialize() at the beginning of main().");93if (Curl)94return;95Curl = curl_easy_init();96assert(Curl && "Curl could not be initialized");97// Set the callback hooks.98curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, curlWriteFunction);99// Detect supported compressed encodings and accept all.100curl_easy_setopt(Curl, CURLOPT_ACCEPT_ENCODING, "");101}102103HTTPClient::~HTTPClient() { curl_easy_cleanup(Curl); }104105Error HTTPClient::perform(const HTTPRequest &Request,106HTTPResponseHandler &Handler) {107if (Request.Method != HTTPMethod::GET)108return createStringError(errc::invalid_argument,109"Unsupported CURL request method.");110111SmallString<128> Url = Request.Url;112curl_easy_setopt(Curl, CURLOPT_URL, Url.c_str());113curl_easy_setopt(Curl, CURLOPT_FOLLOWLOCATION, Request.FollowRedirects);114115curl_slist *Headers = nullptr;116for (const std::string &Header : Request.Headers)117Headers = curl_slist_append(Headers, Header.c_str());118curl_easy_setopt(Curl, CURLOPT_HTTPHEADER, Headers);119120CurlHTTPRequest CurlRequest(Handler);121curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &CurlRequest);122CURLcode CurlRes = curl_easy_perform(Curl);123curl_slist_free_all(Headers);124if (CurlRes != CURLE_OK)125return joinErrors(std::move(CurlRequest.ErrorState),126createStringError(errc::io_error,127"curl_easy_perform() failed: %s\n",128curl_easy_strerror(CurlRes)));129return std::move(CurlRequest.ErrorState);130}131132unsigned HTTPClient::responseCode() {133long Code = 0;134curl_easy_getinfo(Curl, CURLINFO_RESPONSE_CODE, &Code);135return Code;136}137138#else139140HTTPClient::HTTPClient() = default;141142HTTPClient::~HTTPClient() = default;143144bool HTTPClient::isAvailable() { return false; }145146void HTTPClient::initialize() {}147148void HTTPClient::cleanup() {}149150void HTTPClient::setTimeout(std::chrono::milliseconds Timeout) {}151152Error HTTPClient::perform(const HTTPRequest &Request,153HTTPResponseHandler &Handler) {154llvm_unreachable("No HTTP Client implementation available.");155}156157unsigned HTTPClient::responseCode() {158llvm_unreachable("No HTTP Client implementation available.");159}160161#endif162163164