Add RestSslClient; add User-Agent header.

master
Chunting Gu 7 years ago
parent b02ea902c9
commit d159ce46bf

@ -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

@ -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

@ -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_
Loading…
Cancel
Save