blob: 63eb5e664c66e2b158bd7aa1349a78f9ea51184e [file] [log] [blame]
// Copyright 2019 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.
#ifndef SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_CURL_H_
#define SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_CURL_H_
#include <curl/curl.h>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
namespace zxdb {
namespace {
class CurlFDWatcher;
} // namespace
class Curl {
public:
class Error {
public:
explicit Error(CURLcode code) : code_(code) {}
Error& operator=(CURLcode code) {
code_ = code;
return *this;
}
bool operator==(const Error& other) { return other.code_ == code_; }
operator CURLcode() { return code_; }
operator bool() { return code_ != CURLE_OK; }
std::string ToString() { return curl_easy_strerror(code_); }
private:
CURLcode code_;
};
// Callback when we receive data from libcurl. The return value should be the
// number of bytes successfully processed (i.e. if we are passing this data
// to the write() syscall and it returns a short bytes written count, we
// should as well).
using DataCallback = std::function<size_t(const std::string&)>;
Curl();
~Curl();
Curl(Curl&) = delete;
Curl(Curl&& other) = delete;
static std::shared_ptr<Curl> MakeShared();
Error SetURL(const std::string& url) {
return Error(curl_easy_setopt(curl_, CURLOPT_URL, url.c_str()));
}
const std::string& post_data() { return post_data_; }
void set_post_data(const std::string& data) { post_data_ = data; }
void set_post_data(const std::map<std::string, std::string>& items);
std::vector<std::string>& headers() { return headers_; }
bool& get_body() { return get_body_; }
void set_data_callback(DataCallback handler) { data_callback_ = std::move(handler); }
void set_header_callback(DataCallback handler) { header_callback_ = std::move(handler); }
// Believe it or not this takes a curl handle, so it can't be static.
std::string Escape(const std::string& input);
// Run the curl request synchronously.
Error Perform();
// Run the curl request asynchronously. Invoke the callback when done.
void Perform(std::function<void(Curl*, Error)> cb);
// Get the response code from the request. Undefined if the request hasn't
// run.
long ResponseCode();
private:
friend class CurlFDWatcher;
friend size_t DoHeaderCallback(char* data, size_t size, size_t nitems, void* curl);
friend size_t DoDataCallback(char* data, size_t size, size_t nitems, void* curl);
static CURLM* multi_handle;
static void InitMulti();
void FreeSList();
void PrepareToPerform();
// Effectively a count of the number of Curl objects outstanding. When it
// first becomes nonzero we run curl_global_init() and when it becomes zero
// again we run curl_global_cleanup().
static size_t global_init;
CURL* curl_ = nullptr;
struct curl_slist* slist_ = nullptr;
bool get_body_ = true;
std::string post_data_;
std::weak_ptr<Curl> weak_self_ref_;
std::shared_ptr<Curl> self_ref_;
std::vector<std::string> headers_;
std::function<void(Curl*, Error)> multi_cb_ = nullptr;
DataCallback header_callback_ = [](const std::string& data) { return data.size(); };
DataCallback data_callback_ = [](const std::string& data) { return data.size(); };
};
} // namespace zxdb
#endif // SRC_DEVELOPER_DEBUG_ZXDB_CLIENT_CURL_H_