| // 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_POSTFIELDS, body.c_str())); |
| 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 |