Initial client API V2
parent
b38b7e6d38
commit
9b8304f06c
@ -1,29 +1,49 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "webcc/http_client.h"
|
||||
#include "webcc/http_client_session.h" // TEST
|
||||
#include "webcc/logger.h"
|
||||
|
||||
static void PrintError(const webcc::HttpClient& client) {
|
||||
std::cout << webcc::DescribeError(client.error());
|
||||
if (client.timed_out()) {
|
||||
std::cout << " (timed out)";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
int main() {
|
||||
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
||||
|
||||
auto request = webcc::HttpRequest::New(webcc::kHttpGet, "/get",
|
||||
"httpbin.org");
|
||||
using namespace webcc;
|
||||
|
||||
HttpResponsePtr r;
|
||||
|
||||
HttpClientSession session;
|
||||
|
||||
#if 0
|
||||
r = session.Request(HttpRequestArgs("GET")
|
||||
.url("http://httpbin.org/get") // Moved
|
||||
.parameters({ "key1", "value1", "key2", "value2" }) // Moved
|
||||
.headers({ "Accept", "application/json" }) // Moved
|
||||
.buffer_size(1000));
|
||||
|
||||
std::cout << r->content() << std::endl;
|
||||
|
||||
// If you want to create the args object firstly, there'll be an extra call
|
||||
// to its move constructor.
|
||||
// - constructor: HttpRequestArgs("GET")
|
||||
// - move constructor: auto args = ...
|
||||
auto args = HttpRequestArgs("GET")
|
||||
.url("http://httpbin.org/get")
|
||||
.parameters({ "key1", "value1", "key2", "value2" })
|
||||
.headers({ "Accept", "application/json" })
|
||||
.buffer_size(1000);
|
||||
|
||||
r = session.Request(std::move(args));
|
||||
|
||||
r = session.Get("http://httpbin.org/get",
|
||||
{ "key1", "value1", "key2", "value2" },
|
||||
{ "Accept", "application/json" },
|
||||
HttpRequestArgs().buffer_size(1000));
|
||||
#endif
|
||||
|
||||
webcc::HttpClient client;
|
||||
r = session.Post("http://httpbin.org/post", "{ 'key': 'value' }", true,
|
||||
{ "Accept", "application/json" },
|
||||
HttpRequestArgs().buffer_size(1000));
|
||||
|
||||
if (client.Request(*request)) {
|
||||
std::cout << client.response_content() << std::endl;
|
||||
} else {
|
||||
PrintError(client);
|
||||
}
|
||||
std::cout << r->content() << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -0,0 +1,80 @@
|
||||
#include "webcc/http_client_session.h"
|
||||
|
||||
#include "webcc/http_client.h"
|
||||
#include "webcc/http_request.h"
|
||||
#include "webcc/url.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
HttpClientSession::HttpClientSession() {
|
||||
InitHeaders();
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClientSession::Request(HttpRequestArgs&& args) {
|
||||
assert(args.parameters_.size() % 2 == 0);
|
||||
assert(args.headers_.size() % 2 == 0);
|
||||
|
||||
HttpRequest request(args.method_, args.url_, args.parameters_);
|
||||
|
||||
if (!args.data_.empty()) {
|
||||
request.SetContent(std::move(args.data_), true);
|
||||
|
||||
// TODO: charset/encoding
|
||||
if (args.json_) {
|
||||
request.SetContentType(http::media_types::kApplicationJson, "");
|
||||
}
|
||||
}
|
||||
|
||||
// Apply the session-level headers.
|
||||
for (const HttpHeader& h : headers_.data()) {
|
||||
request.SetHeader(h.first, h.second);
|
||||
}
|
||||
|
||||
// Apply the request-level headers.
|
||||
// This will overwrite the session-level headers.
|
||||
for (std::size_t i = 1; i < args.headers_.size(); i += 2) {
|
||||
request.SetHeader(std::move(args.headers_[i - 1]),
|
||||
std::move(args.headers_[i]));
|
||||
}
|
||||
|
||||
request.Prepare();
|
||||
|
||||
HttpClient client;
|
||||
if (!client.Request(request, args.buffer_size_)) {
|
||||
return HttpResponsePtr{};
|
||||
}
|
||||
|
||||
return client.response();
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClientSession::Get(const std::string& url,
|
||||
std::vector<std::string>&& parameters,
|
||||
std::vector<std::string>&& headers,
|
||||
HttpRequestArgs&& args) {
|
||||
return Request(args.method(http::kGet).url(url)
|
||||
.parameters(std::move(parameters))
|
||||
.headers(std::move(headers)));
|
||||
}
|
||||
|
||||
HttpResponsePtr HttpClientSession::Post(const std::string& url,
|
||||
std::string&& data, bool json,
|
||||
std::vector<std::string>&& headers,
|
||||
HttpRequestArgs&& args) {
|
||||
return Request(args.method(http::kPost).url(url).data(std::move(data))
|
||||
.json(json).headers(std::move(headers)));
|
||||
}
|
||||
|
||||
void HttpClientSession::InitHeaders() {
|
||||
// NOTE: C++11 requires a space between literal and string macro.
|
||||
headers_.Add(http::headers::kUserAgent, USER_AGENT);
|
||||
|
||||
// TODO: Support gzip, deflate
|
||||
headers_.Add(http::headers::kAcceptEncoding, "identity");
|
||||
|
||||
headers_.Add(http::headers::kAccept, "*/*");
|
||||
|
||||
// TODO: Support Keep-Alive connection.
|
||||
//headers_.Add(http::headers::kConnection, "close");
|
||||
}
|
||||
|
||||
} // namespace webcc
|
@ -0,0 +1,43 @@
|
||||
#ifndef WEBCC_HTTP_CLIENT_SESSION_H_
|
||||
#define WEBCC_HTTP_CLIENT_SESSION_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/http_request_args.h"
|
||||
#include "webcc/http_response.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpClientSession {
|
||||
public:
|
||||
HttpClientSession();
|
||||
|
||||
~HttpClientSession() = default;
|
||||
|
||||
void AddHeader(const std::string& key, const std::string& value) {
|
||||
headers_.Add(key, value);
|
||||
}
|
||||
|
||||
HttpResponsePtr Request(HttpRequestArgs&& args);
|
||||
|
||||
HttpResponsePtr Get(const std::string& url,
|
||||
std::vector<std::string>&& parameters = {},
|
||||
std::vector<std::string>&& headers = {},
|
||||
HttpRequestArgs&& args = HttpRequestArgs());
|
||||
|
||||
HttpResponsePtr Post(const std::string& url,
|
||||
std::string&& data, bool json,
|
||||
std::vector<std::string>&& headers = {},
|
||||
HttpRequestArgs&& args = HttpRequestArgs());
|
||||
|
||||
private:
|
||||
void InitHeaders();
|
||||
|
||||
// Headers to be sent on each request sent from this session.
|
||||
HttpHeaderDict headers_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_CLIENT_SESSION_H_
|
@ -0,0 +1,140 @@
|
||||
#ifndef WEBCC_HTTP_REQUEST_ARGS_H_
|
||||
#define WEBCC_HTTP_REQUEST_ARGS_H_
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/globals.h"
|
||||
#include "webcc/logger.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpClientSession;
|
||||
|
||||
// Args maker for HttpClientSession.
|
||||
// Use method chaining to simulate Named Parameters.
|
||||
class HttpRequestArgs {
|
||||
public:
|
||||
explicit HttpRequestArgs(const std::string& method = "")
|
||||
: method_(method), json_(false), buffer_size_(0) {
|
||||
LOG_VERB("HttpRequestArgs()");
|
||||
}
|
||||
|
||||
HttpRequestArgs(const HttpRequestArgs&) = default;
|
||||
HttpRequestArgs& operator=(const HttpRequestArgs&) = default;
|
||||
|
||||
#if WEBCC_DEFAULT_MOVE_COPY_ASSIGN
|
||||
|
||||
HttpRequestArgs(HttpRequestArgs&&) = default;
|
||||
HttpRequestArgs& operator=(HttpRequestArgs&&) = default;
|
||||
|
||||
#else
|
||||
|
||||
HttpRequestArgs(HttpRequestArgs&& rhs)
|
||||
: method_(std::move(rhs.method_)),
|
||||
url_(std::move(rhs.url_)),
|
||||
parameters_(std::move(rhs.parameters_)),
|
||||
data_(std::move(rhs.data_)),
|
||||
json_(rhs.json_),
|
||||
headers_(std::move(rhs.headers_)),
|
||||
buffer_size_(rhs.buffer_size_) {
|
||||
LOG_VERB("HttpRequestArgs(&&)");
|
||||
}
|
||||
|
||||
HttpRequestArgs& operator=(HttpRequestArgs&& rhs) {
|
||||
if (&rhs != this) {
|
||||
method_ = std::move(rhs.method_);
|
||||
url_ = std::move(rhs.url_);
|
||||
parameters_ = std::move(rhs.parameters_);
|
||||
data_ = std::move(rhs.data_);
|
||||
json_ = rhs.json_;
|
||||
headers_ = std::move(rhs.headers_);
|
||||
buffer_size_ = buffer_size_;
|
||||
}
|
||||
LOG_VERB("HttpRequestArgs& operator=(&&)");
|
||||
return *this;
|
||||
}
|
||||
|
||||
#endif // WEBCC_DEFAULT_MOVE_COPY_ASSIGN
|
||||
|
||||
HttpRequestArgs&& method(const std::string& method) {
|
||||
method_ = method;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& url(const std::string& url) {
|
||||
url_ = url;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& url(std::string&& url) {
|
||||
url_ = std::move(url);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& parameters(const std::vector<std::string>& parameters) {
|
||||
parameters_ = parameters;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& parameters(std::vector<std::string>&& parameters) {
|
||||
parameters_ = std::move(parameters);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& data(const std::string& data) {
|
||||
data_ = data;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& data(std::string&& data) {
|
||||
data_ = std::move(data);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& json(bool json = true) {
|
||||
json_ = json;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& headers(const std::vector<std::string>& headers) {
|
||||
headers_ = headers;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& headers(std::vector<std::string>&& headers) {
|
||||
headers_ = std::move(headers);
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
HttpRequestArgs&& buffer_size(std::size_t buffer_size) {
|
||||
buffer_size_ = buffer_size;
|
||||
return std::move(*this);
|
||||
}
|
||||
|
||||
private:
|
||||
friend class HttpClientSession;
|
||||
|
||||
std::string method_;
|
||||
|
||||
std::string url_;
|
||||
|
||||
std::vector<std::string> parameters_;
|
||||
|
||||
// Data to send in the body of the request.
|
||||
std::string data_;
|
||||
|
||||
// Is the data to send a JSON string?
|
||||
bool json_;
|
||||
|
||||
std::vector<std::string> headers_;
|
||||
|
||||
// Size of the buffer to read response.
|
||||
// Leave it to 0 for using default value.
|
||||
std::size_t buffer_size_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_REQUEST_ARGS_H_
|
Loading…
Reference in New Issue