Add RestSslClient; add User-Agent header.
This commit is contained in:
@@ -160,6 +160,7 @@ if(WEBCC_BUILD_EXAMPLE)
|
||||
|
||||
if(WEBCC_ENABLE_SSL)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/example/http_ssl_client)
|
||||
add_subdirectory(${PROJECT_SOURCE_DIR}/example/rest_github_client)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ void Test(boost::asio::io_context& io_context) {
|
||||
|
||||
request->set_method(webcc::kHttpGet);
|
||||
request->set_url("/index.html");
|
||||
request->SetHost("localhost", "8000");
|
||||
request->UpdateStartLine();
|
||||
request->set_host("localhost", "8000");
|
||||
request->Make();
|
||||
|
||||
webcc::HttpAsyncClientPtr client(new webcc::HttpAsyncClient(io_context));
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@ void Test() {
|
||||
webcc::HttpRequest request;
|
||||
request.set_method(webcc::kHttpGet);
|
||||
request.set_url("/index.html");
|
||||
request.SetHost("localhost", "8000");
|
||||
request.UpdateStartLine();
|
||||
request.set_host("localhost", "8000");
|
||||
request.Make();
|
||||
|
||||
webcc::HttpClient client;
|
||||
if (client.Request(request)) {
|
||||
|
||||
@@ -7,10 +7,14 @@ void Test() {
|
||||
webcc::HttpRequest request;
|
||||
request.set_method(webcc::kHttpGet);
|
||||
request.set_url("/LICENSE_1_0.txt");
|
||||
request.SetHost("www.boost.org", "443");
|
||||
request.UpdateStartLine();
|
||||
|
||||
// Leave port to default value.
|
||||
request.set_host("www.boost.org");
|
||||
|
||||
request.Make();
|
||||
|
||||
webcc::HttpSslClient client;
|
||||
|
||||
if (client.Request(request)) {
|
||||
std::cout << client.response()->content() << std::endl;
|
||||
} else {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
add_executable(rest_github_client main.cc)
|
||||
|
||||
set(SSL_LIBS ${OPENSSL_LIBRARIES})
|
||||
if(WIN32)
|
||||
set(SSL_LIBS ${SSL_LIBS} crypt32)
|
||||
endif()
|
||||
|
||||
target_link_libraries(rest_github_client webcc ${Boost_LIBRARIES})
|
||||
target_link_libraries(rest_github_client "${CMAKE_THREAD_LIBS_INIT}")
|
||||
target_link_libraries(rest_github_client ${SSL_LIBS})
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "webcc/rest_ssl_client.h"
|
||||
#include "webcc/logger.h"
|
||||
|
||||
void Test() {
|
||||
webcc::RestSslClient client("api.github.com");
|
||||
|
||||
if (client.Get("/events")) {
|
||||
std::cout << client.response()->content() << std::endl;
|
||||
} else {
|
||||
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);
|
||||
|
||||
Test();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -9,6 +9,7 @@ endif()
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(HEADERS
|
||||
version.h
|
||||
globals.h
|
||||
http_async_client.h
|
||||
http_client.h
|
||||
@@ -23,6 +24,7 @@ set(HEADERS
|
||||
http_server.h
|
||||
logger.h
|
||||
queue.h
|
||||
basic_rest_client.h
|
||||
rest_async_client.h
|
||||
rest_client.h
|
||||
rest_request_handler.h
|
||||
@@ -48,7 +50,6 @@ set(SOURCES
|
||||
http_server.cc
|
||||
logger.cc
|
||||
rest_async_client.cc
|
||||
rest_client.cc
|
||||
rest_request_handler.cc
|
||||
rest_service_manager.cc
|
||||
rest_service.cc
|
||||
@@ -59,6 +60,7 @@ set(SOURCES
|
||||
if(WEBCC_ENABLE_SSL)
|
||||
set(HEADERS ${HEADERS}
|
||||
http_ssl_client.h
|
||||
rest_ssl_client.h
|
||||
)
|
||||
|
||||
set(SOURCES ${SOURCES}
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
#ifndef WEBCC_BASIC_REST_CLIENT_H_
|
||||
#define WEBCC_BASIC_REST_CLIENT_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <utility> // for move()
|
||||
|
||||
#include "webcc/globals.h"
|
||||
#include "webcc/http_request.h"
|
||||
#include "webcc/http_response.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
template <class HttpClientType>
|
||||
class BasicRestClient {
|
||||
public:
|
||||
// If |port| is empty, |host| will be checked to see if it contains port or
|
||||
// not (separated by ':').
|
||||
explicit BasicRestClient(const std::string& host,
|
||||
const std::string& port = "")
|
||||
: host_(host), port_(port) {
|
||||
if (port_.empty()) {
|
||||
std::size_t i = host_.find_last_of(':');
|
||||
if (i != std::string::npos) {
|
||||
port_ = host_.substr(i + 1);
|
||||
host_ = host_.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
~BasicRestClient() = default;
|
||||
|
||||
WEBCC_DELETE_COPY_ASSIGN(BasicRestClient);
|
||||
|
||||
void SetTimeout(int seconds) {
|
||||
http_client_.SetTimeout(seconds);
|
||||
}
|
||||
|
||||
// NOTE:
|
||||
// The return value of the following methods (Get, Post, etc.) only indicates
|
||||
// if the socket communication is successful or not. Check error() and
|
||||
// timed_out() for more information if it's failed. Check response_status()
|
||||
// instead for the HTTP status code.
|
||||
|
||||
// HTTP GET request.
|
||||
inline bool Get(const std::string& url) {
|
||||
return Request(kHttpGet, url, "");
|
||||
}
|
||||
|
||||
// HTTP POST request.
|
||||
inline bool Post(const std::string& url, std::string&& content) {
|
||||
return Request(kHttpPost, url, std::move(content));
|
||||
}
|
||||
|
||||
// HTTP PUT request.
|
||||
inline bool Put(const std::string& url, std::string&& content) {
|
||||
return Request(kHttpPut, url, std::move(content));
|
||||
}
|
||||
|
||||
// HTTP PATCH request.
|
||||
inline bool Patch(const std::string& url, std::string&& content) {
|
||||
return Request(kHttpPatch, url, std::move(content));
|
||||
}
|
||||
|
||||
// HTTP DELETE request.
|
||||
inline bool Delete(const std::string& url) {
|
||||
return Request(kHttpDelete, url, "");
|
||||
}
|
||||
|
||||
HttpResponsePtr response() const {
|
||||
return http_client_.response();
|
||||
}
|
||||
|
||||
int response_status() const {
|
||||
assert(response());
|
||||
return response()->status();
|
||||
}
|
||||
|
||||
const std::string& response_content() const {
|
||||
assert(response());
|
||||
return response()->content();
|
||||
}
|
||||
|
||||
bool timed_out() const {
|
||||
return http_client_.timed_out();
|
||||
}
|
||||
|
||||
Error error() const {
|
||||
return http_client_.error();
|
||||
}
|
||||
|
||||
private:
|
||||
bool Request(const std::string& method, const std::string& url,
|
||||
std::string&& content) {
|
||||
HttpRequest http_request;
|
||||
|
||||
http_request.set_method(method);
|
||||
http_request.set_url(url);
|
||||
http_request.set_host(host_, port_);
|
||||
|
||||
if (!content.empty()) {
|
||||
http_request.SetContent(std::move(content), true);
|
||||
http_request.SetContentType(kAppJsonUtf8);
|
||||
}
|
||||
|
||||
http_request.Make();
|
||||
|
||||
if (!http_client_.Request(http_request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string host_;
|
||||
std::string port_;
|
||||
|
||||
HttpClientType http_client_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_BASIC_REST_CLIENT_H_
|
||||
@@ -9,6 +9,7 @@ namespace webcc {
|
||||
const std::string kHost = "Host";
|
||||
const std::string kContentType = "Content-Type";
|
||||
const std::string kContentLength = "Content-Length";
|
||||
const std::string kUserAgent = "User-Agent";
|
||||
|
||||
const std::string kAppJsonUtf8 = "application/json; charset=utf-8";
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webcc/version.h"
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Macros
|
||||
|
||||
@@ -38,9 +40,11 @@ const std::size_t kInvalidLength = std::string::npos;
|
||||
// Default timeout for reading response.
|
||||
const int kMaxReadSeconds = 30;
|
||||
|
||||
// HTTP headers.
|
||||
extern const std::string kHost;
|
||||
extern const std::string kContentType;
|
||||
extern const std::string kContentLength;
|
||||
extern const std::string kUserAgent;
|
||||
|
||||
extern const std::string kAppJsonUtf8;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "webcc/http_client.h"
|
||||
|
||||
#include <algorithm> // for min
|
||||
#include <string>
|
||||
|
||||
#include "boost/asio/connect.hpp"
|
||||
|
||||
@@ -50,9 +50,9 @@ class HttpMessage {
|
||||
}
|
||||
}
|
||||
|
||||
// Set start line according to other informations.
|
||||
// Make the message (e.g., update start line).
|
||||
// Must be called before ToBuffers()!
|
||||
virtual void UpdateStartLine() = 0;
|
||||
virtual void Make() = 0;
|
||||
|
||||
// Convert the message into a vector of buffers. The buffers do not own the
|
||||
// underlying memory blocks, therefore the message object must remain valid
|
||||
|
||||
+9
-12
@@ -2,23 +2,20 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
void HttpRequest::SetHost(const std::string& host, const std::string& port) {
|
||||
host_ = host;
|
||||
port_ = port;
|
||||
|
||||
if (port.empty()) {
|
||||
SetHeader(kHost, host);
|
||||
} else {
|
||||
SetHeader(kHost, host + ":" + port);
|
||||
}
|
||||
}
|
||||
|
||||
void HttpRequest::UpdateStartLine() {
|
||||
void HttpRequest::Make() {
|
||||
start_line_ = method_;
|
||||
start_line_ += " ";
|
||||
start_line_ += url_;
|
||||
start_line_ += " HTTP/1.1";
|
||||
start_line_ += CRLF;
|
||||
|
||||
if (port_.empty()) {
|
||||
SetHeader(kHost, host_);
|
||||
} else {
|
||||
SetHeader(kHost, host_ + ":" + port_);
|
||||
}
|
||||
|
||||
SetHeader(kUserAgent, "Webcc/"WEBCC_VERSION);
|
||||
}
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
@@ -29,12 +29,15 @@ class HttpRequest : public HttpMessage {
|
||||
// Set host name and port number.
|
||||
// The |host| is a descriptive name (e.g., www.google.com) or a numeric IP
|
||||
// address (127.0.0.1).
|
||||
// The |port| is a numeric number (e.g., 9000), the default (80 for HTTP and
|
||||
// 443 for HTTPS) will be used if it's empty.
|
||||
void SetHost(const std::string& host, const std::string& port);
|
||||
// The |port| is a numeric number (e.g., 9000). The default value (80 for HTTP
|
||||
// or 443 for HTTPS) will be used to connect to server if it's empty.
|
||||
void set_host(const std::string& host, const std::string& port = "") {
|
||||
host_ = host;
|
||||
port_ = port;
|
||||
}
|
||||
|
||||
// Set start line according to HTTP method, URL, etc.
|
||||
void UpdateStartLine() override;
|
||||
// Compose start line, set Host header, etc.
|
||||
void Make() override;
|
||||
|
||||
private:
|
||||
// HTTP method.
|
||||
|
||||
@@ -55,7 +55,7 @@ const std::string& ToString(int status) {
|
||||
|
||||
} // namespace status_strings
|
||||
|
||||
void HttpResponse::UpdateStartLine() {
|
||||
void HttpResponse::Make() {
|
||||
start_line_ = status_strings::ToString(status_);
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ HttpResponse HttpResponse::Fault(HttpStatus::Enum status) {
|
||||
|
||||
HttpResponse response;
|
||||
response.set_status(status);
|
||||
response.UpdateStartLine();
|
||||
|
||||
response.Make();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ class HttpResponse : public HttpMessage {
|
||||
void set_status(int status) { status_ = status; }
|
||||
|
||||
// Set start line according to status code.
|
||||
void UpdateStartLine() override;
|
||||
void Make() override;
|
||||
|
||||
// Get a fault response when HTTP status is not OK.
|
||||
// TODO: Avoid copy.
|
||||
|
||||
@@ -40,7 +40,7 @@ void HttpSession::SetResponseContent(std::string&& content,
|
||||
|
||||
void HttpSession::SendResponse(HttpStatus::Enum status) {
|
||||
response_.set_status(status);
|
||||
response_.UpdateStartLine();
|
||||
response_.Make();
|
||||
DoWrite();
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
#include "boost/asio/read.hpp"
|
||||
#include "boost/asio/write.hpp"
|
||||
#include "boost/date_time/posix_time/posix_time.hpp"
|
||||
#include "boost/lambda/bind.hpp"
|
||||
#include "boost/lambda/lambda.hpp"
|
||||
|
||||
#include "webcc/logger.h"
|
||||
#include "webcc/utility.h"
|
||||
@@ -93,14 +91,6 @@ Error HttpSslClient::Connect(const HttpRequest& request) {
|
||||
|
||||
LOG_VERB("Socket connected.");
|
||||
|
||||
// The deadline actor may have had a chance to run and close our socket, even
|
||||
// though the connect operation notionally succeeded.
|
||||
if (stopped_) {
|
||||
// |timed_out_| should be true in this case.
|
||||
LOG_ERRO("Socket connect timed out.");
|
||||
return kEndpointConnectError;
|
||||
}
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// HTTP SSL (a.k.a., HTTPS) client session in synchronous mode.
|
||||
// A request will not return until the response is received or timeout occurs.
|
||||
// Don't use the same HttpClient object in multiple threads.
|
||||
class HttpSslClient {
|
||||
public:
|
||||
HttpSslClient();
|
||||
|
||||
@@ -16,14 +16,14 @@ void RestAsyncClient::Request(const std::string& method,
|
||||
|
||||
request->set_method(method);
|
||||
request->set_url(url);
|
||||
request->SetHost(host_, port_);
|
||||
request->set_host(host_, port_);
|
||||
|
||||
if (!content.empty()) {
|
||||
request->SetContent(std::move(content), true);
|
||||
request->SetContentType(kAppJsonUtf8);
|
||||
}
|
||||
|
||||
request->UpdateStartLine();
|
||||
request->Make();
|
||||
|
||||
HttpAsyncClientPtr http_client(new HttpAsyncClient(io_context_));
|
||||
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#include "webcc/rest_client.h"
|
||||
|
||||
#include "webcc/http_request.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
RestClient::RestClient(const std::string& host, const std::string& port)
|
||||
: host_(host), port_(port) {
|
||||
if (port_.empty()) {
|
||||
std::size_t i = host_.find_last_of(':');
|
||||
if (i != std::string::npos) {
|
||||
port_ = host_.substr(i + 1);
|
||||
host_ = host_.substr(0, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RestClient::Request(const std::string& method, const std::string& url,
|
||||
std::string&& content) {
|
||||
HttpRequest http_request;
|
||||
|
||||
http_request.set_method(method);
|
||||
http_request.set_url(url);
|
||||
http_request.SetHost(host_, port_);
|
||||
|
||||
if (!content.empty()) {
|
||||
http_request.SetContent(std::move(content), true);
|
||||
http_request.SetContentType(kAppJsonUtf8);
|
||||
}
|
||||
|
||||
http_request.UpdateStartLine();
|
||||
|
||||
if (!http_client_.Request(http_request)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace webcc
|
||||
+2
-82
@@ -1,92 +1,12 @@
|
||||
#ifndef WEBCC_REST_CLIENT_H_
|
||||
#define WEBCC_REST_CLIENT_H_
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <utility> // for move()
|
||||
|
||||
#include "webcc/globals.h"
|
||||
#include "webcc/basic_rest_client.h"
|
||||
#include "webcc/http_client.h"
|
||||
#include "webcc/http_response.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class RestClient {
|
||||
public:
|
||||
// If |port| is empty, |host| will be checked to see if it contains port or
|
||||
// not (separated by ':').
|
||||
explicit RestClient(const std::string& host, const std::string& port = "");
|
||||
|
||||
~RestClient() = default;
|
||||
|
||||
WEBCC_DELETE_COPY_ASSIGN(RestClient);
|
||||
|
||||
void SetTimeout(int seconds) {
|
||||
http_client_.SetTimeout(seconds);
|
||||
}
|
||||
|
||||
// NOTE:
|
||||
// The return value of the following methods (Get, Post, etc.) only indicates
|
||||
// if the socket communication is successful or not. Check error() and
|
||||
// timed_out() for more information if it's failed. Check response_status()
|
||||
// instead for the HTTP status code.
|
||||
|
||||
// HTTP GET request.
|
||||
inline bool Get(const std::string& url) {
|
||||
return Request(kHttpGet, url, "");
|
||||
}
|
||||
|
||||
// HTTP POST request.
|
||||
inline bool Post(const std::string& url, std::string&& content) {
|
||||
return Request(kHttpPost, url, std::move(content));
|
||||
}
|
||||
|
||||
// HTTP PUT request.
|
||||
inline bool Put(const std::string& url, std::string&& content) {
|
||||
return Request(kHttpPut, url, std::move(content));
|
||||
}
|
||||
|
||||
// HTTP PATCH request.
|
||||
inline bool Patch(const std::string& url, std::string&& content) {
|
||||
return Request(kHttpPatch, url, std::move(content));
|
||||
}
|
||||
|
||||
// HTTP DELETE request.
|
||||
inline bool Delete(const std::string& url) {
|
||||
return Request(kHttpDelete, url, "");
|
||||
}
|
||||
|
||||
HttpResponsePtr response() const {
|
||||
return http_client_.response();
|
||||
}
|
||||
|
||||
int response_status() const {
|
||||
assert(response());
|
||||
return response()->status();
|
||||
}
|
||||
|
||||
const std::string& response_content() const {
|
||||
assert(response());
|
||||
return response()->content();
|
||||
}
|
||||
|
||||
bool timed_out() const {
|
||||
return http_client_.timed_out();
|
||||
}
|
||||
|
||||
Error error() const {
|
||||
return http_client_.error();
|
||||
}
|
||||
|
||||
private:
|
||||
bool Request(const std::string& method, const std::string& url,
|
||||
std::string&& content);
|
||||
|
||||
std::string host_;
|
||||
std::string port_;
|
||||
|
||||
HttpClient http_client_;
|
||||
};
|
||||
typedef BasicRestClient<HttpClient> RestClient;
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#ifndef WEBCC_REST_SSL_CLIENT_H_
|
||||
#define WEBCC_REST_SSL_CLIENT_H_
|
||||
|
||||
#include "webcc/basic_rest_client.h"
|
||||
#include "webcc/http_ssl_client.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
typedef BasicRestClient<HttpSslClient> RestSslClient;
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_REST_SSL_CLIENT_H_
|
||||
@@ -66,9 +66,9 @@ void SoapAsyncClient::Request(const std::string& operation,
|
||||
http_request->SetContentType(kAppSoapXmlUtf8);
|
||||
}
|
||||
|
||||
http_request->SetHost(host_, port_);
|
||||
http_request->set_host(host_, port_);
|
||||
http_request->SetHeader(kSoapAction, operation);
|
||||
http_request->UpdateStartLine();
|
||||
http_request->Make();
|
||||
|
||||
HttpAsyncClientPtr http_client(new HttpAsyncClient(io_context_));
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ bool SoapClient::Request(const std::string& operation,
|
||||
http_request.SetContentType(kAppSoapXmlUtf8);
|
||||
}
|
||||
|
||||
http_request.SetHost(host_, port_);
|
||||
http_request.set_host(host_, port_);
|
||||
http_request.SetHeader(kSoapAction, operation);
|
||||
http_request.UpdateStartLine();
|
||||
http_request.Make();
|
||||
|
||||
if (!http_client_.Request(http_request)) {
|
||||
error_ = http_client_.error();
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef WEBCC_VERSION_H_
|
||||
#define WEBCC_VERSION_H_
|
||||
|
||||
#define WEBCC_VERSION "0.1.0"
|
||||
|
||||
#endif // WEBCC_VERSION_H_
|
||||
Reference in New Issue
Block a user