blob: ac93465d63bfac3714da39af47496621cc50eea5 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include "util/clearcut/curl_handle.h"
namespace cobalt {
namespace util {
namespace clearcut {
CurlHandle::CurlHandle() {
handle_ = curl_easy_init();
if (handle_ == nullptr) {
throw Status(StatusCode::INTERNAL, "curl_easy_init() returned nullptr");
}
}
CurlHandle::~CurlHandle() {
if (handle_ != nullptr) {
curl_easy_cleanup(handle_);
handle_ = nullptr;
}
}
StatusOr<std::unique_ptr<CurlHandle>> CurlHandle::Init() {
try {
std::unique_ptr<CurlHandle> handle(new CurlHandle());
RETURN_IF_ERROR(handle->Setopt(CURLOPT_ERRORBUFFER, handle->errbuf_));
RETURN_IF_ERROR(handle->Setopt(CURLOPT_WRITEDATA, &handle->response_body_));
RETURN_IF_ERROR(
handle->Setopt(CURLOPT_WRITEFUNCTION, CurlHandle::WriteResponseData));
return handle;
} catch (Status s) {
return s;
}
}
size_t CurlHandle::WriteResponseData(char *ptr, size_t size, size_t nmemb,
void *userdata) {
(reinterpret_cast<std::string *>(userdata))
->append(reinterpret_cast<char *>(ptr), size * nmemb);
return size * nmemb;
}
template <class Param>
Status CurlHandle::Setopt(CURLoption option, Param parameter) {
auto res = curl_easy_setopt(handle_, option, parameter);
if (res != CURLE_OK) {
return CURLCodeToStatus(res);
}
return Status::OK;
}
Status CurlHandle::SetHeaders(
const std::map<std::string, std::string> &headers) {
if (!headers.empty()) {
struct curl_slist *header_list = nullptr;
for (const auto &header : headers) {
std::string header_str = header.first + ": " + header.second;
if (header.second == "") {
header_str = header.first + ";";
}
header_list = curl_slist_append(header_list, header_str.c_str());
}
return Setopt(CURLOPT_HTTPHEADER, header_list);
}
return Status::OK;
}
Status CurlHandle::SetTimeout(int64_t timeout_ms) {
if (timeout_ms > 0) {
return Setopt(CURLOPT_TIMEOUT_MS, timeout_ms);
}
return Status::OK;
}
Status CurlHandle::CURLCodeToStatus(CURLcode code) {
std::string details = "";
if (strlen(errbuf_) != 0) {
details = errbuf_;
}
return Status(StatusCode::INTERNAL, curl_easy_strerror(code), details);
}
StatusOr<HTTPResponse> CurlHandle::Post(std::string url, std::string body) {
RETURN_IF_ERROR(Setopt(CURLOPT_URL, url.c_str()));
RETURN_IF_ERROR(Setopt(CURLOPT_POSTFIELDSIZE, body.size()));
RETURN_IF_ERROR(Setopt(CURLOPT_POSTFIELDS, body.data()));
auto result = curl_easy_perform(handle_);
switch (result) {
case CURLE_OK:
int64_t response_code;
curl_easy_getinfo(handle_, CURLINFO_RESPONSE_CODE, &response_code);
return HTTPResponse(response_body_, Status::OK, response_code);
case CURLE_OPERATION_TIMEDOUT:
return Status(StatusCode::DEADLINE_EXCEEDED, "Post request timed out.");
default:
return CURLCodeToStatus(result);
}
}
} // namespace clearcut
} // namespace util
} // namespace cobalt