diff --git a/CMakeLists.txt b/CMakeLists.txt index 8cbc60e..47f29a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -96,7 +96,7 @@ if(WEBCC_ENABLE_SSL) endif() include_directories( - # For including its own headers as "webcc/http_client.h". + # For including its own headers as "webcc/client.h". ${PROJECT_SOURCE_DIR} # For including config.h as "webcc/config.h". ${PROJECT_BINARY_DIR} @@ -109,8 +109,6 @@ if(WIN32) link_directories(${THIRD_PARTY_DIR}/win32/lib) endif() -# For including pugixml as "pugixml/pugixml.hpp" or gtest as -# "gtest/gtest.h". include_directories(${THIRD_PARTY_DIR}/src) # For using zlib on Windows. diff --git a/README.md b/README.md index e398e56..7db566b 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ A complete client example: ```cpp #include -#include "webcc/http_client_session.h" +#include "webcc/client_session.h" #include "webcc/logger.h" int main() { @@ -21,7 +21,7 @@ int main() { // Session provides convenient request APIs, stores request configurations // and manages persistent connenction. - webcc::HttpClientSession session; + webcc::ClientSession session; // Catch exceptions for error handling. try { @@ -41,11 +41,11 @@ int main() { The `Get()` method is nothing but a shortcut of `Request()`. Using `Request()` directly is more complicated: ```cpp -auto r = session.Request(webcc::HttpRequestBuilder{}.Get(). +auto r = session.Request(webcc::RequestBuilder{}.Get(). Url("http://httpbin.org/get") ()); ``` -As you can see, a helper class named `HttpRequestBuilder` is used to chain the parameters and finally build (don't miss the `()` operator) a request object. +As you can see, a helper class named `RequestBuilder` is used to chain the parameters and finally build (don't miss the `()` operator) a request object. Both the shortcut and `Request()` accept URL query parameters: @@ -53,7 +53,7 @@ Both the shortcut and `Request()` accept URL query parameters: // Query parameters are passed using a std::vector. session.Get("http://httpbin.org/get", { "key1", "value1", "key2", "value2" }); -session.Request(webcc::HttpRequestBuilder{}.Get(). +session.Request(webcc::RequestBuilder{}.Get(). Url("http://httpbin.org/get"). Query("key1", "value1"). Query("key2", "value2") @@ -66,7 +66,7 @@ session.Get("http://httpbin.org/get", {"key1", "value1", "key2", "value2"}, {"Accept", "application/json"}); // Also a std::vector -session.Request(webcc::HttpRequestBuilder{}.Get(). +session.Request(webcc::RequestBuilder{}.Get(). Url("http://httpbin.org/get"). Query("key1", "value1"). Query("key2", "value2"). diff --git a/autotest/CMakeLists.txt b/autotest/CMakeLists.txt index 781365c..dd17406 100644 --- a/autotest/CMakeLists.txt +++ b/autotest/CMakeLists.txt @@ -1,7 +1,7 @@ # Auto test set(AT_SRCS - http_client_autotest.cc + client_autotest.cc ) set(AT_TARGET_NAME webcc_autotest) diff --git a/autotest/http_client_autotest.cc b/autotest/client_autotest.cc similarity index 86% rename from autotest/http_client_autotest.cc rename to autotest/client_autotest.cc index 25f9428..70aec7a 100644 --- a/autotest/http_client_autotest.cc +++ b/autotest/client_autotest.cc @@ -3,7 +3,7 @@ #include "boost/algorithm/string.hpp" #include "json/json.h" -#include "webcc/http_client_session.h" +#include "webcc/client_session.h" #include "webcc/logger.h" // ----------------------------------------------------------------------------- @@ -36,7 +36,7 @@ static Json::Value StringToJson(const std::string& str) { // ----------------------------------------------------------------------------- -static void AssertGet(webcc::HttpResponsePtr r) { +static void AssertGet(webcc::ResponsePtr r) { Json::Value json = StringToJson(r->content()); Json::Value args = json["args"]; @@ -52,11 +52,11 @@ static void AssertGet(webcc::HttpResponsePtr r) { EXPECT_EQ("httpbin.org", headers["Host"].asString()); } -TEST(HttpClientTest, Get_RequestFunc) { - webcc::HttpClientSession session; +TEST(ClientTest, Get_RequestFunc) { + webcc::ClientSession session; try { - auto r = session.Request(webcc::HttpRequestBuilder{}.Get(). + auto r = session.Request(webcc::RequestBuilder{}.Get(). Url("http://httpbin.org/get"). Query("key1", "value1"). Query("key2", "value2"). @@ -70,8 +70,8 @@ TEST(HttpClientTest, Get_RequestFunc) { } } -TEST(HttpClientTest, Get_Shortcut) { - webcc::HttpClientSession session; +TEST(ClientTest, Get_Shortcut) { + webcc::ClientSession session; try { auto r = session.Get("http://httpbin.org/get", @@ -86,14 +86,14 @@ TEST(HttpClientTest, Get_Shortcut) { } #if WEBCC_ENABLE_SSL -TEST(HttpClientTest, Get_SSL) { - webcc::HttpClientSession session; +TEST(ClientTest, Get_SSL) { + webcc::ClientSession session; session.set_ssl_verify(kSslVerify); try { // HTTPS is auto-detected from the URL scheme. - auto r = session.Request(webcc::HttpRequestBuilder{}.Get(). + auto r = session.Request(webcc::RequestBuilder{}.Get(). Url("https://httpbin.org/get"). Query("key1", "value1"). Query("key2", "value2"). @@ -111,8 +111,8 @@ TEST(HttpClientTest, Get_SSL) { // ----------------------------------------------------------------------------- // Test Gzip compressed response. -TEST(HttpClientTest, Compression_Gzip) { - webcc::HttpClientSession session; +TEST(ClientTest, Compression_Gzip) { + webcc::ClientSession session; try { auto r = session.Get("http://httpbin.org/gzip"); @@ -127,8 +127,8 @@ TEST(HttpClientTest, Compression_Gzip) { } // Test Deflate compressed response. -TEST(HttpClientTest, Compression_Deflate) { - webcc::HttpClientSession session; +TEST(ClientTest, Compression_Deflate) { + webcc::ClientSession session; try { auto r = session.Get("http://httpbin.org/deflate"); @@ -157,8 +157,8 @@ TEST(HttpClientTest, Compression_Deflate) { // "https://www.google.com"; // "https://api.github.com/events"; // -TEST(HttpClientTest, KeepAlive) { - webcc::HttpClientSession session; +TEST(ClientTest, KeepAlive) { + webcc::ClientSession session; std::string url = "http://httpbin.org/get"; try { @@ -176,14 +176,14 @@ TEST(HttpClientTest, KeepAlive) { EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close")); // Close by using request builder. - r = session.Request(webcc::HttpRequestBuilder{}.Get(). + r = session.Request(webcc::RequestBuilder{}.Get(). Url(url).KeepAlive(false) ()); EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Close")); // Keep-Alive explicitly by using request builder. - r = session.Request(webcc::HttpRequestBuilder{}.Get(). + r = session.Request(webcc::RequestBuilder{}.Get(). Url(url).KeepAlive(true) ()); @@ -197,8 +197,8 @@ TEST(HttpClientTest, KeepAlive) { // ----------------------------------------------------------------------------- // Get a JPEG image. -TEST(HttpClientTest, GetImageJpeg) { - webcc::HttpClientSession session; +TEST(ClientTest, GetImageJpeg) { + webcc::ClientSession session; std::string url = "http://httpbin.org/get"; try { diff --git a/examples/client_basics.cc b/examples/client_basics.cc index 6438325..f2dcced 100644 --- a/examples/client_basics.cc +++ b/examples/client_basics.cc @@ -1,6 +1,6 @@ #include -#include "webcc/http_client_session.h" +#include "webcc/client_session.h" #include "webcc/logger.h" #if (defined(WIN32) || defined(_WIN64)) @@ -19,7 +19,7 @@ static void PrintSeparator() { int main() { WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - webcc::HttpClientSession session; + webcc::ClientSession session; session.set_ssl_verify(kSslVerify); @@ -27,7 +27,7 @@ int main() { PrintSeparator(); // Using request builder: - auto r = session.Request(webcc::HttpRequestBuilder{}.Get(). + auto r = session.Request(webcc::RequestBuilder{}.Get(). Url("http://httpbin.org/get"). Query("key1", "value1"). Query("key2", "value2"). diff --git a/examples/file_upload_client.cc b/examples/file_upload_client.cc index bca5212..819f1f2 100644 --- a/examples/file_upload_client.cc +++ b/examples/file_upload_client.cc @@ -2,7 +2,7 @@ #include "boost/filesystem.hpp" -#include "webcc/http_client_session.h" +#include "webcc/client_session.h" #include "webcc/logger.h" #if (defined(WIN32) || defined(_WIN64)) @@ -47,12 +47,12 @@ int main(int argc, char* argv[]) { return 1; } - webcc::HttpClientSession session; + webcc::ClientSession session; try { //auto r = session.PostFile(url, "file", upload_dir / "remember.txt"); - auto r = session.Request(webcc::HttpRequestBuilder{}.Post(). + auto r = session.Request(webcc::RequestBuilder{}.Post(). Url(url). File("file", upload_dir / "remember.txt"). Form("json", "{}", "application/json") diff --git a/examples/file_upload_server.cc b/examples/file_upload_server.cc index 525d7bf..1517439 100644 --- a/examples/file_upload_server.cc +++ b/examples/file_upload_server.cc @@ -20,9 +20,9 @@ public: } response->content = "OK"; - response->media_type = webcc::http::media_types::kTextPlain; + response->media_type = webcc::media_types::kTextPlain; response->charset = "utf-8"; - response->status = webcc::http::Status::kCreated; + response->status = webcc::Status::kCreated; } } }; diff --git a/examples/github_client.cc b/examples/github_client.cc index 5903c13..40bd0d0 100644 --- a/examples/github_client.cc +++ b/examples/github_client.cc @@ -2,7 +2,7 @@ #include "json/json.h" -#include "webcc/http_client_session.h" +#include "webcc/client_session.h" #include "webcc/logger.h" // ----------------------------------------------------------------------------- @@ -61,7 +61,7 @@ void PrettyPrintJsonString(const std::string& str) { // ----------------------------------------------------------------------------- // List public events. -void ListEvents(webcc::HttpClientSession& session) { +void ListEvents(webcc::ClientSession& session) { try { auto r = session.Get(kUrlRoot + "/events"); @@ -75,8 +75,7 @@ void ListEvents(webcc::HttpClientSession& session) { // List the followers of the given user. // Example: // ListUserFollowers(session, "") -void ListUserFollowers(webcc::HttpClientSession& session, - const std::string& user) { +void ListUserFollowers(webcc::ClientSession& session, const std::string& user) { try { auto r = session.Get(kUrlRoot + "/users/" + user + "/followers"); @@ -90,11 +89,11 @@ void ListUserFollowers(webcc::HttpClientSession& session, // List the followers of the current authorized user using Basic authorization. // E.g., list my own followers: // ListAuthUserFollowers(session, "sprinfall@gmail.com", ""); -void ListAuthUserFollowers(webcc::HttpClientSession& session, +void ListAuthUserFollowers(webcc::ClientSession& session, const std::string& login, const std::string& password) { try { - auto r = session.Request(webcc::HttpRequestBuilder{}.Get(). + auto r = session.Request(webcc::RequestBuilder{}.Get(). Url(kUrlRoot + "/user/followers"). AuthBasic(login, password) ()); @@ -106,8 +105,9 @@ void ListAuthUserFollowers(webcc::HttpClientSession& session, } } -void CreateAuthorization(webcc::HttpClientSession& session, - const std::string& auth) { +void CreateAuthorization(webcc::ClientSession& session, + const std::string& login, + const std::string& password) { try { std::string data = "{\n" @@ -115,8 +115,12 @@ void CreateAuthorization(webcc::HttpClientSession& session, " 'scopes': ['public_repo', 'repo', 'repo:status', 'user']\n" "}"; - auto r = session.Post(kUrlRoot + "/authorizations", std::move(data), true, - {"Authorization", auth}); + auto r = session.Request(webcc::RequestBuilder{}.Post(). + Url(kUrlRoot + "/authorizations"). + Data(std::move(data)). + Json(true). + AuthBasic(login, password) + ()); std::cout << r->content() << std::endl; @@ -130,7 +134,7 @@ void CreateAuthorization(webcc::HttpClientSession& session, int main() { WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - webcc::HttpClientSession session; + webcc::ClientSession session; session.set_ssl_verify(kSslVerify); diff --git a/examples/rest_book_client.cc b/examples/rest_book_client.cc index 2810694..17e6b6a 100644 --- a/examples/rest_book_client.cc +++ b/examples/rest_book_client.cc @@ -3,7 +3,7 @@ #include "json/json.h" -#include "webcc/http_client_session.h" +#include "webcc/client_session.h" #include "webcc/logger.h" #include "examples/common/book.h" @@ -21,7 +21,7 @@ class BookClientBase { public: - BookClientBase(webcc::HttpClientSession& session, const std::string& url) + BookClientBase(webcc::ClientSession& session, const std::string& url) : session_(session), url_(url) { } @@ -29,7 +29,7 @@ public: protected: // Check HTTP response status. - bool CheckStatus(webcc::HttpResponsePtr response, int expected_status) { + bool CheckStatus(webcc::ResponsePtr response, int expected_status) { int status = response->status(); if (status != expected_status) { LOG_ERRO("HTTP status error (actual: %d, expected: %d).", @@ -42,14 +42,14 @@ protected: protected: std::string url_; - webcc::HttpClientSession& session_; + webcc::ClientSession& session_; }; // ----------------------------------------------------------------------------- class BookListClient : public BookClientBase { public: - BookListClient(webcc::HttpClientSession& session, const std::string& url) + BookListClient(webcc::ClientSession& session, const std::string& url) : BookClientBase(session, url) { } @@ -57,7 +57,7 @@ public: try { auto r = session_.Get(url_ + "/books"); - if (!CheckStatus(r, webcc::http::Status::kOK)) { + if (!CheckStatus(r, webcc::Status::kOK)) { // Response HTTP status error. return false; } @@ -88,7 +88,7 @@ public: try { auto r = session_.Post(url_ + "/books", JsonToString(req_json), true); - if (!CheckStatus(r, webcc::http::Status::kCreated)) { + if (!CheckStatus(r, webcc::Status::kCreated)) { return false; } @@ -108,7 +108,7 @@ public: class BookDetailClient : public BookClientBase { public: - BookDetailClient(webcc::HttpClientSession& session, const std::string& url) + BookDetailClient(webcc::ClientSession& session, const std::string& url) : BookClientBase(session, url) { } @@ -116,7 +116,7 @@ public: try { auto r = session_.Get(url_ + "/books/" + id); - if (!CheckStatus(r, webcc::http::Status::kOK)) { + if (!CheckStatus(r, webcc::Status::kOK)) { return false; } @@ -137,7 +137,7 @@ public: try { auto r = session_.Put(url_ + "/books/" + id, JsonToString(json), true); - if (!CheckStatus(r, webcc::http::Status::kOK)) { + if (!CheckStatus(r, webcc::Status::kOK)) { return false; } @@ -153,7 +153,7 @@ public: try { auto r = session_.Delete(url_ + "/books/" + id); - if (!CheckStatus(r, webcc::http::Status::kOK)) { + if (!CheckStatus(r, webcc::Status::kOK)) { return false; } @@ -209,7 +209,7 @@ int main(int argc, char* argv[]) { WEBCC_LOG_INIT("", webcc::LOG_CONSOLE_FILE_OVERWRITE); // Share the same session. - webcc::HttpClientSession session; + webcc::ClientSession session; // Session-level settings. session.set_timeout(timeout); diff --git a/examples/rest_book_server.cc b/examples/rest_book_server.cc index 72f6bd3..701bee9 100644 --- a/examples/rest_book_server.cc +++ b/examples/rest_book_server.cc @@ -100,9 +100,9 @@ void BookListService::Get(const webcc::UrlQuery& /*query*/, // TODO: Simplify response->content = JsonToString(json); - response->media_type = webcc::http::media_types::kApplicationJson; + response->media_type = webcc::media_types::kApplicationJson; response->charset = "utf-8"; - response->status = webcc::http::Status::kOK; + response->status = webcc::Status::kOK; } void BookListService::Post(const std::string& request_content, @@ -117,12 +117,12 @@ void BookListService::Post(const std::string& request_content, json["id"] = id; response->content = JsonToString(json); - response->media_type = webcc::http::media_types::kApplicationJson; + response->media_type = webcc::media_types::kApplicationJson; response->charset = "utf-8"; - response->status = webcc::http::Status::kCreated; + response->status = webcc::Status::kCreated; } else { // Invalid JSON - response->status = webcc::http::Status::kBadRequest; + response->status = webcc::Status::kBadRequest; } } @@ -136,7 +136,7 @@ void BookDetailService::Get(const webcc::UrlMatches& url_matches, if (url_matches.size() != 1) { // Using kNotFound means the resource specified by the URL cannot be found. // kBadRequest could be another choice. - response->status = webcc::http::Status::kNotFound; + response->status = webcc::Status::kNotFound; return; } @@ -144,14 +144,14 @@ void BookDetailService::Get(const webcc::UrlMatches& url_matches, const Book& book = g_book_store.GetBook(book_id); if (book.IsNull()) { - response->status = webcc::http::Status::kNotFound; + response->status = webcc::Status::kNotFound; return; } response->content = BookToJsonString(book); - response->media_type = webcc::http::media_types::kApplicationJson; + response->media_type = webcc::media_types::kApplicationJson; response->charset = "utf-8"; - response->status = webcc::http::Status::kOK; + response->status = webcc::Status::kOK; } void BookDetailService::Put(const webcc::UrlMatches& url_matches, @@ -160,7 +160,7 @@ void BookDetailService::Put(const webcc::UrlMatches& url_matches, Sleep(sleep_seconds_); if (url_matches.size() != 1) { - response->status = webcc::http::Status::kNotFound; + response->status = webcc::Status::kNotFound; return; } @@ -168,14 +168,14 @@ void BookDetailService::Put(const webcc::UrlMatches& url_matches, Book book; if (!JsonStringToBook(request_content, &book)) { - response->status = webcc::http::Status::kBadRequest; + response->status = webcc::Status::kBadRequest; return; } book.id = book_id; g_book_store.UpdateBook(book); - response->status = webcc::http::Status::kOK; + response->status = webcc::Status::kOK; } void BookDetailService::Delete(const webcc::UrlMatches& url_matches, @@ -183,18 +183,18 @@ void BookDetailService::Delete(const webcc::UrlMatches& url_matches, Sleep(sleep_seconds_); if (url_matches.size() != 1) { - response->status = webcc::http::Status::kNotFound; + response->status = webcc::Status::kNotFound; return; } const std::string& book_id = url_matches[0]; if (!g_book_store.DeleteBook(book_id)) { - response->status = webcc::http::Status::kNotFound; + response->status = webcc::Status::kNotFound; return; } - response->status = webcc::http::Status::kOK; + response->status = webcc::Status::kOK; } // ----------------------------------------------------------------------------- diff --git a/unittest/CMakeLists.txt b/unittest/CMakeLists.txt index ae48d83..9525efe 100644 --- a/unittest/CMakeLists.txt +++ b/unittest/CMakeLists.txt @@ -2,7 +2,7 @@ set(UT_SRCS base64_unittest.cc - http_parser_unittest.cc + parser_unittest.cc rest_service_manager_unittest.cc url_unittest.cc ) diff --git a/unittest/http_parser_unittest.cc b/unittest/parser_unittest.cc similarity index 92% rename from unittest/http_parser_unittest.cc rename to unittest/parser_unittest.cc index 8b90913..329fb20 100644 --- a/unittest/http_parser_unittest.cc +++ b/unittest/parser_unittest.cc @@ -1,9 +1,9 @@ #include "gtest/gtest.h" -#include "webcc/http_request.h" -#include "webcc/http_request_parser.h" -#include "webcc/http_response.h" -#include "webcc/http_response_parser.h" +#include "webcc/request.h" +#include "webcc/request_parser.h" +#include "webcc/response.h" +#include "webcc/response_parser.h" #include @@ -35,8 +35,8 @@ protected: std::string payload_; - webcc::HttpRequest request_; - webcc::HttpRequestParser parser_; + webcc::Request request_; + webcc::RequestParser parser_; }; TEST_F(GetRequestParserTest, ParseFullDataOnce) { @@ -121,8 +121,8 @@ protected: std::string payload_; std::string data_; - webcc::HttpRequest request_; - webcc::HttpRequestParser parser_; + webcc::Request request_; + webcc::RequestParser parser_; }; TEST_F(PostRequestParserTest, ParseFullDataOnce) { diff --git a/unittest/rest_service_manager_unittest.cc b/unittest/rest_service_manager_unittest.cc index 37d4e82..f863e78 100644 --- a/unittest/rest_service_manager_unittest.cc +++ b/unittest/rest_service_manager_unittest.cc @@ -8,7 +8,7 @@ class MyRestService : public webcc::RestService { public: void Handle(const webcc::RestRequest& request, webcc::RestResponse* response) final { - response->status = webcc::http::Status::kOK; + response->status = webcc::Status::kOK; } }; diff --git a/webcc/base64.cc b/webcc/base64.cc index f5db115..93060eb 100644 --- a/webcc/base64.cc +++ b/webcc/base64.cc @@ -116,7 +116,7 @@ std::size_t Encode(const void* src, std::size_t len, void* dst) { return out - static_cast(dst); } -typedef std::pair SizePair; +using SizePair = std::pair; SizePair Decode(const char* src, std::size_t len, void* dst) { auto in = reinterpret_cast(src); @@ -161,21 +161,22 @@ SizePair Decode(const char* src, std::size_t len, void* dst) { } // namespace base64 -std::string Base64Encode(const std::uint8_t* data, std::size_t len) { +std::string Base64Encode(const std::uint8_t* data, std::size_t length) { std::string dst; - dst.resize(base64::EncodedSize(len)); - dst.resize(base64::Encode(data, len, &dst[0])); + dst.resize(base64::EncodedSize(length)); + dst.resize(base64::Encode(data, length, &dst[0])); return dst; } -std::string Base64Encode(const std::string& s) { - return Base64Encode(reinterpret_cast(s.data()), s.size()); +std::string Base64Encode(const std::string& input) { + return Base64Encode(reinterpret_cast(input.data()), + input.size()); } -std::string Base64Decode(const std::string& data) { +std::string Base64Decode(const std::string& input) { std::string dst; - dst.resize(base64::DecodedSize(data.size())); - auto result = base64::Decode(data.data(), data.size(), &dst[0]); + dst.resize(base64::DecodedSize(input.size())); + auto result = base64::Decode(input.data(), input.size(), &dst[0]); dst.resize(result.first); return dst; } diff --git a/webcc/base64.h b/webcc/base64.h index 1733a85..2e178a0 100644 --- a/webcc/base64.h +++ b/webcc/base64.h @@ -6,11 +6,11 @@ namespace webcc { -std::string Base64Encode(const std::uint8_t* data, std::size_t len); +std::string Base64Encode(const std::uint8_t* data, std::size_t length); std::string Base64Encode(const std::string& input); -std::string Base64Decode(const std::string& data); +std::string Base64Decode(const std::string& input); } // namespace webcc diff --git a/webcc/http_client.cc b/webcc/client.cc similarity index 87% rename from webcc/http_client.cc rename to webcc/client.cc index b377ad2..7f5939f 100644 --- a/webcc/http_client.cc +++ b/webcc/client.cc @@ -1,4 +1,4 @@ -#include "webcc/http_client.h" +#include "webcc/client.h" #include "boost/date_time/posix_time/posix_time.hpp" @@ -9,7 +9,7 @@ using boost::asio::ip::tcp; namespace webcc { -HttpClient::HttpClient() +Client::Client() : timer_(io_context_), ssl_verify_(true), buffer_size_(kBufferSize), @@ -20,10 +20,10 @@ HttpClient::HttpClient() error_(kNoError) { } -bool HttpClient::Request(HttpRequestPtr request, bool connect) { +bool Client::Request(RequestPtr request, bool connect) { io_context_.restart(); - response_.reset(new HttpResponse{}); + response_.reset(new Response{}); response_parser_.Init(response_.get()); closed_ = false; @@ -54,7 +54,7 @@ bool HttpClient::Request(HttpRequestPtr request, bool connect) { return true; } -void HttpClient::Close() { +void Client::Close() { if (closed_) { return; } @@ -71,23 +71,22 @@ void HttpClient::Close() { } } -Error HttpClient::Connect(HttpRequestPtr request) { +Error Client::Connect(RequestPtr request) { if (request->url().scheme() == "https") { #if WEBCC_ENABLE_SSL - socket_.reset(new HttpSslSocket{ io_context_, ssl_verify_ }); + socket_.reset(new SslSocket{ io_context_, ssl_verify_ }); return DoConnect(request, kPort443); #else LOG_ERRO("SSL/HTTPS support is not enabled."); return kSchemaError; #endif // WEBCC_ENABLE_SSL } else { - socket_.reset(new HttpSocket{ io_context_ }); + socket_.reset(new Socket{ io_context_ }); return DoConnect(request, kPort80); } } -Error HttpClient::DoConnect(HttpRequestPtr request, - const std::string& default_port) { +Error Client::DoConnect(RequestPtr request, const std::string& default_port) { tcp::resolver resolver(io_context_); std::string port = request->port(default_port); @@ -118,7 +117,7 @@ Error HttpClient::DoConnect(HttpRequestPtr request, return kNoError; } -Error HttpClient::WriteReqeust(HttpRequestPtr request) { +Error Client::WriteReqeust(RequestPtr request) { LOG_VERB("HTTP request:\n%s", request->Dump(4, "> ").c_str()); // NOTE: @@ -142,7 +141,7 @@ Error HttpClient::WriteReqeust(HttpRequestPtr request) { return kNoError; } -Error HttpClient::ReadResponse() { +Error Client::ReadResponse() { LOG_VERB("Read response (timeout: %ds)...", timeout_); timer_.expires_from_now(boost::posix_time::seconds(timeout_)); @@ -158,7 +157,7 @@ Error HttpClient::ReadResponse() { return error; } -void HttpClient::DoReadResponse(Error* error) { +void Client::DoReadResponse(Error* error) { boost::system::error_code ec = boost::asio::error::would_block; auto handler = [this, &ec, error](boost::system::error_code inner_ec, @@ -218,13 +217,12 @@ void HttpClient::DoReadResponse(Error* error) { } while (ec == boost::asio::error::would_block); } -void HttpClient::DoWaitTimer() { +void Client::DoWaitTimer() { LOG_VERB("Wait timer asynchronously."); - timer_.async_wait( - std::bind(&HttpClient::OnTimer, this, std::placeholders::_1)); + timer_.async_wait(std::bind(&Client::OnTimer, this, std::placeholders::_1)); } -void HttpClient::OnTimer(boost::system::error_code ec) { +void Client::OnTimer(boost::system::error_code ec) { LOG_VERB("On deadline timer."); // timer_.cancel() was called. @@ -252,7 +250,7 @@ void HttpClient::OnTimer(boost::system::error_code ec) { DoWaitTimer(); } -void HttpClient::CancelTimer() { +void Client::CancelTimer() { if (timer_canceled_) { return; } diff --git a/webcc/http_client.h b/webcc/client.h similarity index 69% rename from webcc/http_client.h rename to webcc/client.h index e52b5c5..7e7ec6c 100644 --- a/webcc/http_client.h +++ b/webcc/client.h @@ -1,5 +1,5 @@ -#ifndef WEBCC_HTTP_CLIENT_H_ -#define WEBCC_HTTP_CLIENT_H_ +#ifndef WEBCC_CLIENT_H_ +#define WEBCC_CLIENT_H_ #include #include @@ -11,28 +11,28 @@ #include "boost/asio/ip/tcp.hpp" #include "webcc/globals.h" -#include "webcc/http_request.h" -#include "webcc/http_response.h" -#include "webcc/http_response_parser.h" -#include "webcc/http_socket.h" +#include "webcc/request.h" +#include "webcc/response.h" +#include "webcc/response_parser.h" +#include "webcc/socket.h" namespace webcc { -class HttpClient; -typedef std::shared_ptr HttpClientPtr; +class Client; +using ClientPtr = std::shared_ptr; // Synchronous HTTP & HTTPS client. // In synchronous mode, a request won't return until the response is received // or timeout occurs. // Please don't use the same client object in multiple threads. -class HttpClient { +class Client { public: - HttpClient(); + Client(); - virtual ~HttpClient() = default; + virtual ~Client() = default; - HttpClient(const HttpClient&) = delete; - HttpClient& operator=(const HttpClient&) = delete; + Client(const Client&) = delete; + Client& operator=(const Client&) = delete; void set_ssl_verify(bool ssl_verify) { ssl_verify_ = ssl_verify; @@ -52,12 +52,12 @@ public: } // Connect to server, send request, wait until response is received. - bool Request(HttpRequestPtr request, bool connect = true); + bool Request(RequestPtr request, bool connect = true); // Close the socket. void Close(); - HttpResponsePtr response() const { return response_; } + ResponsePtr response() const { return response_; } bool closed() const { return closed_; } @@ -66,11 +66,11 @@ public: Error error() const { return error_; } private: - Error Connect(HttpRequestPtr request); + Error Connect(RequestPtr request); - Error DoConnect(HttpRequestPtr request, const std::string& default_port); + Error DoConnect(RequestPtr request, const std::string& default_port); - Error WriteReqeust(HttpRequestPtr request); + Error WriteReqeust(RequestPtr request); Error ReadResponse(); @@ -86,10 +86,10 @@ private: boost::asio::io_context io_context_; // Socket connection. - std::unique_ptr socket_; + std::unique_ptr socket_; - HttpResponsePtr response_; - HttpResponseParser response_parser_; + ResponsePtr response_; + ResponseParser response_parser_; // Timer for the timeout control. boost::asio::deadline_timer timer_; @@ -122,4 +122,4 @@ private: } // namespace webcc -#endif // WEBCC_HTTP_CLIENT_H_ +#endif // WEBCC_CLIENT_H_ diff --git a/webcc/http_client_pool.cc b/webcc/client_pool.cc similarity index 71% rename from webcc/http_client_pool.cc rename to webcc/client_pool.cc index 07df165..90e3c2f 100644 --- a/webcc/http_client_pool.cc +++ b/webcc/client_pool.cc @@ -1,10 +1,10 @@ -#include "webcc/http_client_pool.h" +#include "webcc/client_pool.h" #include "webcc/logger.h" namespace webcc { -HttpClientPool::~HttpClientPool() { +ClientPool::~ClientPool() { if (!clients_.empty()) { LOG_INFO("Close socket for all (%u) connections in the pool.", clients_.size()); @@ -15,24 +15,24 @@ HttpClientPool::~HttpClientPool() { } } -HttpClientPtr HttpClientPool::Get(const Key& key) const { +ClientPtr ClientPool::Get(const Key& key) const { auto it = clients_.find(key); if (it != clients_.end()) { return it->second; } else { - return HttpClientPtr{}; + return ClientPtr{}; } } -void HttpClientPool::Add(const Key& key, HttpClientPtr client) { +void ClientPool::Add(const Key& key, ClientPtr client) { clients_[key] = client; LOG_INFO("Added connection to pool (%s, %s, %s).", key.scheme.c_str(), key.host.c_str(), key.port.c_str()); } -void HttpClientPool::Remove(const Key& key) { +void ClientPool::Remove(const Key& key) { clients_.erase(key); LOG_INFO("Removed connection from pool (%s, %s, %s).", diff --git a/webcc/http_client_pool.h b/webcc/client_pool.h similarity index 70% rename from webcc/http_client_pool.h rename to webcc/client_pool.h index 99ef36b..0ccd55a 100644 --- a/webcc/http_client_pool.h +++ b/webcc/client_pool.h @@ -1,16 +1,16 @@ -#ifndef WEBCC_HTTP_CLIENT_POOL_H_ -#define WEBCC_HTTP_CLIENT_POOL_H_ +#ifndef WEBCC_CLIENT_POOL_H_ +#define WEBCC_CLIENT_POOL_H_ #include #include -#include "webcc/http_client.h" +#include "webcc/client.h" #include "webcc/url.h" namespace webcc { // Connection pool for keep-alive connections. -class HttpClientPool { +class ClientPool { public: struct Key { std::string scheme; @@ -42,20 +42,20 @@ public: }; public: - HttpClientPool() = default; + ClientPool() = default; - ~HttpClientPool(); + ~ClientPool(); - HttpClientPtr Get(const Key& key) const; + ClientPtr Get(const Key& key) const; - void Add(const Key& key, HttpClientPtr client); + void Add(const Key& key, ClientPtr client); void Remove(const Key& key); private: - std::map clients_; + std::map clients_; }; } // namespace webcc -#endif // WEBCC_HTTP_CLIENT_POOL_H_ +#endif // WEBCC_CLIENT_POOL_H_ diff --git a/webcc/http_client_session.cc b/webcc/client_session.cc similarity index 63% rename from webcc/http_client_session.cc rename to webcc/client_session.cc index 16831ac..0e3bf2b 100644 --- a/webcc/http_client_session.cc +++ b/webcc/client_session.cc @@ -1,4 +1,4 @@ -#include "webcc/http_client_session.h" +#include "webcc/client_session.h" #include "webcc/base64.h" #include "webcc/logger.h" @@ -6,26 +6,26 @@ namespace webcc { -HttpClientSession::HttpClientSession() { +ClientSession::ClientSession() { InitHeaders(); } -void HttpClientSession::Auth(const std::string& type, - const std::string& credentials) { - headers_.Set(http::headers::kAuthorization, type + " " + credentials); +void ClientSession::Auth(const std::string& type, + const std::string& credentials) { + headers_.Set(headers::kAuthorization, type + " " + credentials); } -void HttpClientSession::AuthBasic(const std::string& login, - const std::string& password) { +void ClientSession::AuthBasic(const std::string& login, + const std::string& password) { auto credentials = Base64Encode(login + ":" + password); return Auth("Basic", credentials); } -void HttpClientSession::AuthToken(const std::string& token) { +void ClientSession::AuthToken(const std::string& token) { return Auth("Token", token); } -HttpResponsePtr HttpClientSession::Request(HttpRequestPtr request) { +ResponsePtr ClientSession::Request(RequestPtr request) { assert(request); for (const auto& h : headers_.data()) { @@ -35,7 +35,7 @@ HttpResponsePtr HttpClientSession::Request(HttpRequestPtr request) { } if (!content_type_.empty() && - !request->HasHeader(http::headers::kContentType)) { + !request->HasHeader(headers::kContentType)) { request->SetContentType(content_type_, charset_); } @@ -45,7 +45,7 @@ HttpResponsePtr HttpClientSession::Request(HttpRequestPtr request) { } static void SetHeaders(const std::vector& headers, - HttpRequestBuilder* builder) { + RequestBuilder* builder) { assert(headers.size() % 2 == 0); for (std::size_t i = 1; i < headers.size(); i += 2) { @@ -53,10 +53,10 @@ static void SetHeaders(const std::vector& headers, } } -HttpResponsePtr HttpClientSession::Get( - const std::string& url, const std::vector& parameters, - const std::vector& headers) { - HttpRequestBuilder builder; +ResponsePtr ClientSession::Get(const std::string& url, + const std::vector& parameters, + const std::vector& headers) { + RequestBuilder builder; builder.Get().Url(url); assert(parameters.size() % 2 == 0); @@ -69,10 +69,10 @@ HttpResponsePtr HttpClientSession::Get( return Request(builder()); } -HttpResponsePtr HttpClientSession::Post( - const std::string& url, std::string&& data, bool json, - const std::vector& headers) { - HttpRequestBuilder builder; +ResponsePtr ClientSession::Post(const std::string& url, std::string&& data, + bool json, + const std::vector& headers) { + RequestBuilder builder; builder.Post().Url(url); SetHeaders(headers, &builder); @@ -83,10 +83,10 @@ HttpResponsePtr HttpClientSession::Post( return Request(builder()); } -HttpResponsePtr HttpClientSession::Put( - const std::string& url, std::string&& data, bool json, - const std::vector& headers) { - HttpRequestBuilder builder; +ResponsePtr ClientSession::Put(const std::string& url, std::string&& data, + bool json, + const std::vector& headers) { + RequestBuilder builder; builder.Put().Url(url); SetHeaders(headers, &builder); @@ -97,9 +97,9 @@ HttpResponsePtr HttpClientSession::Put( return Request(builder()); } -HttpResponsePtr HttpClientSession::Delete( - const std::string& url, const std::vector& headers) { - HttpRequestBuilder builder; +ResponsePtr ClientSession::Delete(const std::string& url, + const std::vector& headers) { + RequestBuilder builder; builder.Delete().Url(url); SetHeaders(headers, &builder); @@ -107,10 +107,10 @@ HttpResponsePtr HttpClientSession::Delete( return Request(builder()); } -HttpResponsePtr HttpClientSession::Patch( - const std::string& url, std::string&& data, bool json, - const std::vector& headers) { - HttpRequestBuilder builder; +ResponsePtr ClientSession::Patch(const std::string& url, std::string&& data, + bool json, + const std::vector& headers) { + RequestBuilder builder; builder.Patch().Url(url); SetHeaders(headers, &builder); @@ -121,10 +121,10 @@ HttpResponsePtr HttpClientSession::Patch( return Request(builder()); } -HttpResponsePtr HttpClientSession::PostFile( - const std::string& url, const std::string& name, const Path& path, - const std::vector& headers) { - HttpRequestBuilder builder; +ResponsePtr ClientSession::PostFile(const std::string& url, + const std::string& name, const Path& path, + const std::vector& headers) { + RequestBuilder builder; builder.Post().Url(url); SetHeaders(headers, &builder); @@ -134,12 +134,12 @@ HttpResponsePtr HttpClientSession::PostFile( return Request(builder()); } -HttpResponsePtr HttpClientSession::PostFiles( - const std::string& url, const std::map& paths, - const std::vector& headers) { +ResponsePtr ClientSession::PostFiles(const std::string& url, + const std::map& paths, + const std::vector& headers) { assert(!paths.empty()); - HttpRequestBuilder builder; + RequestBuilder builder; builder.Post().Url(url); SetHeaders(headers, &builder); @@ -151,10 +151,10 @@ HttpResponsePtr HttpClientSession::PostFiles( return Request(builder()); } -void HttpClientSession::InitHeaders() { - using namespace http::headers; +void ClientSession::InitHeaders() { + using namespace headers; - headers_.Set(kUserAgent, http::UserAgent()); + headers_.Set(kUserAgent, UserAgent()); // Content-Encoding Tokens: // (https://en.wikipedia.org/wiki/HTTP_compression) @@ -184,15 +184,15 @@ void HttpClientSession::InitHeaders() { headers_.Set(kConnection, "Keep-Alive"); } -HttpResponsePtr HttpClientSession::Send(HttpRequestPtr request) { - const HttpClientPool::Key key{request->url()}; +ResponsePtr ClientSession::Send(RequestPtr request) { + const ClientPool::Key key{request->url()}; // Reuse a pooled connection. bool reuse = false; - HttpClientPtr client = pool_.Get(key); + ClientPtr client = pool_.Get(key); if (!client) { - client.reset(new HttpClient{}); + client.reset(new Client{}); reuse = false; } else { LOG_VERB("Reuse an existing connection."); diff --git a/webcc/http_client_session.h b/webcc/client_session.h similarity index 56% rename from webcc/http_client_session.h rename to webcc/client_session.h index 8c33640..b8b6fcd 100644 --- a/webcc/http_client_session.h +++ b/webcc/client_session.h @@ -1,24 +1,23 @@ -#ifndef WEBCC_HTTP_CLIENT_SESSION_H_ -#define WEBCC_HTTP_CLIENT_SESSION_H_ +#ifndef WEBCC_CLIENT_SESSION_H_ +#define WEBCC_CLIENT_SESSION_H_ #include #include -#include "webcc/http_client_pool.h" -#include "webcc/http_request_builder.h" -#include "webcc/http_response.h" +#include "webcc/client_pool.h" +#include "webcc/request_builder.h" +#include "webcc/response.h" namespace webcc { // HTTP requests session providing connection-pooling, configuration and more. -// NOTE: // A session shouldn't be shared by multiple threads. Please create a new // session for each thread instead. -class HttpClientSession { +class ClientSession { public: - HttpClientSession(); + ClientSession(); - ~HttpClientSession() = default; + ~ClientSession() = default; void set_ssl_verify(bool ssl_verify) { ssl_verify_ = ssl_verify; @@ -56,44 +55,44 @@ public: void AuthToken(const std::string& token); // Send a request. - // Please use HttpRequestBuilder to build the request. - HttpResponsePtr Request(HttpRequestPtr request); + // Please use RequestBuilder to build the request. + ResponsePtr Request(RequestPtr request); // Shortcut for GET request. - HttpResponsePtr Get(const std::string& url, - const std::vector& parameters = {}, - const std::vector& headers = {}); + ResponsePtr Get(const std::string& url, + const std::vector& parameters = {}, + const std::vector& headers = {}); // Shortcut for POST request. - HttpResponsePtr Post(const std::string& url, std::string&& data, bool json, - const std::vector& headers = {}); + ResponsePtr Post(const std::string& url, std::string&& data, bool json, + const std::vector& headers = {}); // Shortcut for PUT request. - HttpResponsePtr Put(const std::string& url, std::string&& data, bool json, - const std::vector& headers = {}); + ResponsePtr Put(const std::string& url, std::string&& data, bool json, + const std::vector& headers = {}); // Shortcut for DELETE request. - HttpResponsePtr Delete(const std::string& url, - const std::vector& headers = {}); + ResponsePtr Delete(const std::string& url, + const std::vector& headers = {}); // Shortcut for PATCH request. - HttpResponsePtr Patch(const std::string& url, std::string&& data, bool json, - const std::vector& headers = {}); + ResponsePtr Patch(const std::string& url, std::string&& data, bool json, + const std::vector& headers = {}); // Post a file. - HttpResponsePtr PostFile(const std::string& url, const std::string& name, - const Path& path, - const std::vector& headers = {}); + ResponsePtr PostFile(const std::string& url, const std::string& name, + const Path& path, + const std::vector& headers = {}); // Post multiple files. - HttpResponsePtr PostFiles(const std::string& url, - const std::map& paths, - const std::vector& headers = {}); + ResponsePtr PostFiles(const std::string& url, + const std::map& paths, + const std::vector& headers = {}); private: void InitHeaders(); - HttpResponsePtr Send(HttpRequestPtr request); + ResponsePtr Send(RequestPtr request); private: // E.g., "application/json". @@ -103,7 +102,7 @@ private: std::string charset_; // Additional headers for each request. - HttpHeaders headers_; + Headers headers_; // Verify the certificate of the peer or not. bool ssl_verify_ = true; @@ -116,9 +115,9 @@ private: int timeout_ = 0; // Connection pool for keep-alive. - HttpClientPool pool_; + ClientPool pool_; }; } // namespace webcc -#endif // WEBCC_HTTP_CLIENT_SESSION_H_ +#endif // WEBCC_CLIENT_SESSION_H_ diff --git a/webcc/common.cc b/webcc/common.cc index 7b8df2d..31544a4 100644 --- a/webcc/common.cc +++ b/webcc/common.cc @@ -56,7 +56,7 @@ bool ReadFile(const Path& path, std::string* output) { // ----------------------------------------------------------------------------- -void HttpHeaders::Set(const std::string& key, const std::string& value) { +void Headers::Set(const std::string& key, const std::string& value) { auto it = Find(key); if (it != headers_.end()) { it->second = value; @@ -65,7 +65,7 @@ void HttpHeaders::Set(const std::string& key, const std::string& value) { } } -void HttpHeaders::Set(std::string&& key, std::string&& value) { +void Headers::Set(std::string&& key, std::string&& value) { auto it = Find(key); if (it != headers_.end()) { it->second = std::move(value); @@ -74,13 +74,13 @@ void HttpHeaders::Set(std::string&& key, std::string&& value) { } } -bool HttpHeaders::Has(const std::string& key) const { - return const_cast(this)->Find(key) != headers_.end(); +bool Headers::Has(const std::string& key) const { + return const_cast(this)->Find(key) != headers_.end(); } -const std::string& HttpHeaders::Get(const std::string& key, +const std::string& Headers::Get(const std::string& key, bool* existed) const { - auto it = const_cast(this)->Find(key); + auto it = const_cast(this)->Find(key); if (existed != nullptr) { *existed = (it != headers_.end()); @@ -94,7 +94,7 @@ const std::string& HttpHeaders::Get(const std::string& key, return s_no_value; } -std::vector::iterator HttpHeaders::Find(const std::string& key) { +std::vector
::iterator Headers::Find(const std::string& key) { auto it = headers_.begin(); for (; it != headers_.end(); ++it) { if (boost::iequals(it->first, key)) { @@ -225,7 +225,7 @@ FormPart::FormPart(const std::string& name, const Path& path, // Determine media type from file extension. if (media_type_.empty()) { std::string extension = path.extension().string(); - media_type_ = http::media_types::FromExtension(extension, false); + media_type_ = media_types::FromExtension(extension, false); } } @@ -244,7 +244,7 @@ void FormPart::Prepare(Payload* payload) { using boost::asio::buffer; - for (const HttpHeader& h : headers_.data()) { + for (const Header& h : headers_.data()) { payload->push_back(buffer(h.first)); payload->push_back(buffer(misc_strings::HEADER_SEPARATOR)); payload->push_back(buffer(h.second)); @@ -270,12 +270,12 @@ void FormPart::SetHeaders() { if (!file_name_.empty()) { content_disposition.append("; filename=\"" + file_name_ + "\""); } - headers_.Set(http::headers::kContentDisposition, content_disposition); + headers_.Set(headers::kContentDisposition, content_disposition); // Header: Content-Type if (!media_type_.empty()) { - headers_.Set(http::headers::kContentType, media_type_); + headers_.Set(headers::kContentType, media_type_); } } diff --git a/webcc/common.h b/webcc/common.h index 411d374..be7352f 100644 --- a/webcc/common.h +++ b/webcc/common.h @@ -30,9 +30,9 @@ bool ReadFile(const Path& path, std::string* output); // ----------------------------------------------------------------------------- -typedef std::pair HttpHeader; +using Header = std::pair; -class HttpHeaders { +class Headers { public: std::size_t size() const { return headers_.size(); @@ -42,7 +42,7 @@ public: return headers_.empty(); } - const std::vector& data() const { + const std::vector
& data() const { return headers_; } @@ -53,7 +53,7 @@ public: bool Has(const std::string& key) const; // Get header by index. - const HttpHeader& Get(std::size_t index) const { + const Header& Get(std::size_t index) const { assert(index < size()); return headers_[index]; } @@ -68,9 +68,9 @@ public: } private: - std::vector::iterator Find(const std::string& key); + std::vector
::iterator Find(const std::string& key); - std::vector headers_; + std::vector
headers_; }; // ----------------------------------------------------------------------------- @@ -261,7 +261,7 @@ private: // Headers generated from the above properties. // Only Used to prepare payload. - HttpHeaders headers_; + Headers headers_; std::string data_; }; diff --git a/webcc/http_connection.cc b/webcc/connection.cc similarity index 71% rename from webcc/http_connection.cc rename to webcc/connection.cc index e8604d6..4e5fa65 100644 --- a/webcc/http_connection.cc +++ b/webcc/connection.cc @@ -1,32 +1,32 @@ -#include "webcc/http_connection.h" +#include "webcc/connection.h" #include // for move() #include "boost/asio/write.hpp" -#include "webcc/http_connection_pool.h" -#include "webcc/http_request_handler.h" +#include "webcc/connection_pool.h" #include "webcc/logger.h" +#include "webcc/request_handler.h" using boost::asio::ip::tcp; namespace webcc { -HttpConnection::HttpConnection(tcp::socket socket, HttpConnectionPool* pool, - HttpRequestHandler* handler) +Connection::Connection(tcp::socket socket, ConnectionPool* pool, + RequestHandler* handler) : socket_(std::move(socket)), pool_(pool), buffer_(kBufferSize), request_handler_(handler) { } -void HttpConnection::Start() { - request_.reset(new HttpRequest{}); +void Connection::Start() { + request_.reset(new Request{}); request_parser_.Init(request_.get()); DoRead(); } -void HttpConnection::Close() { +void Connection::Close() { LOG_INFO("Close socket..."); boost::system::error_code ec; @@ -36,15 +36,15 @@ void HttpConnection::Close() { } } -void HttpConnection::SendResponse(HttpResponsePtr response) { +void Connection::SendResponse(ResponsePtr response) { assert(response); response_ = response; if (request_->IsConnectionKeepAlive()) { - response_->SetHeader(http::headers::kConnection, "Keep-Alive"); + response_->SetHeader(headers::kConnection, "Keep-Alive"); } else { - response_->SetHeader(http::headers::kConnection, "Close"); + response_->SetHeader(headers::kConnection, "Close"); } response_->Prepare(); @@ -52,18 +52,18 @@ void HttpConnection::SendResponse(HttpResponsePtr response) { DoWrite(); } -void HttpConnection::SendResponse(http::Status status) { - SendResponse(std::make_shared(status)); +void Connection::SendResponse(Status status) { + SendResponse(std::make_shared(status)); } -void HttpConnection::DoRead() { +void Connection::DoRead() { socket_.async_read_some(boost::asio::buffer(buffer_), - std::bind(&HttpConnection::OnRead, shared_from_this(), + std::bind(&Connection::OnRead, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } -void HttpConnection::OnRead(boost::system::error_code ec, std::size_t length) { +void Connection::OnRead(boost::system::error_code ec, std::size_t length) { if (ec) { LOG_ERRO("Socket read error (%s).", ec.message().c_str()); if (ec != boost::asio::error::operation_aborted) { @@ -75,7 +75,7 @@ void HttpConnection::OnRead(boost::system::error_code ec, std::size_t length) { if (!request_parser_.Parse(buffer_.data(), length)) { // Bad request. LOG_ERRO("Failed to parse HTTP request."); - SendResponse(http::Status::kBadRequest); + SendResponse(Status::kBadRequest); return; } @@ -92,11 +92,11 @@ void HttpConnection::OnRead(boost::system::error_code ec, std::size_t length) { request_handler_->Enqueue(shared_from_this()); } -void HttpConnection::DoWrite() { +void Connection::DoWrite() { LOG_VERB("HTTP response:\n%s", response_->Dump(4, "> ").c_str()); boost::asio::async_write(socket_, response_->payload(), - std::bind(&HttpConnection::OnWrite, shared_from_this(), + std::bind(&Connection::OnWrite, shared_from_this(), std::placeholders::_1, std::placeholders::_2)); } @@ -105,7 +105,7 @@ void HttpConnection::DoWrite() { // This write handler will be called from main thread (the thread calling // io_context.run), even though AsyncWrite() is invoked by worker threads. // This is ensured by Asio. -void HttpConnection::OnWrite(boost::system::error_code ec, std::size_t length) { +void Connection::OnWrite(boost::system::error_code ec, std::size_t length) { if (ec) { LOG_ERRO("Socket write error (%s).", ec.message().c_str()); @@ -128,7 +128,7 @@ void HttpConnection::OnWrite(boost::system::error_code ec, std::size_t length) { // Socket close VS. shutdown: // https://stackoverflow.com/questions/4160347/close-vs-shutdown-socket -void HttpConnection::Shutdown() { +void Connection::Shutdown() { LOG_INFO("Shutdown socket..."); // Initiate graceful connection closure. diff --git a/webcc/connection.h b/webcc/connection.h new file mode 100644 index 0000000..480bb1d --- /dev/null +++ b/webcc/connection.h @@ -0,0 +1,82 @@ +#ifndef WEBCC_CONNECTION_H_ +#define WEBCC_CONNECTION_H_ + +#include +#include +#include + +#include "boost/asio/ip/tcp.hpp" // for ip::tcp::socket + +#include "webcc/globals.h" +#include "webcc/request.h" +#include "webcc/request_parser.h" +#include "webcc/response.h" + +namespace webcc { + +class Connection; +class ConnectionPool; +class RequestHandler; + +using ConnectionPtr = std::shared_ptr; + +class Connection : public std::enable_shared_from_this { +public: + Connection(boost::asio::ip::tcp::socket socket, ConnectionPool* pool, + RequestHandler* handler); + + ~Connection() = default; + + Connection(const Connection&) = delete; + Connection& operator=(const Connection&) = delete; + + RequestPtr request() const { + return request_; + } + + // Start to read and process the client request. + void Start(); + + // Close the socket. + void Close(); + + // Send response to client. + void SendResponse(ResponsePtr response); + + void SendResponse(Status status); + +private: + void DoRead(); + void OnRead(boost::system::error_code ec, std::size_t length); + + void DoWrite(); + void OnWrite(boost::system::error_code ec, std::size_t length); + + // Shutdown the socket. + void Shutdown(); + + // Socket for the connection. + boost::asio::ip::tcp::socket socket_; + + // The pool for this connection. + ConnectionPool* pool_; + + // Buffer for incoming data. + std::vector buffer_; + + // The handler used to process the incoming request. + RequestHandler* request_handler_; + + // The incoming request. + RequestPtr request_; + + // The parser for the incoming request. + RequestParser request_parser_; + + // The response to be sent back to the client. + ResponsePtr response_; +}; + +} // namespace webcc + +#endif // WEBCC_CONNECTION_H_ diff --git a/webcc/http_connection_pool.cc b/webcc/connection_pool.cc similarity index 62% rename from webcc/http_connection_pool.cc rename to webcc/connection_pool.cc index e19bca9..dc0595b 100644 --- a/webcc/http_connection_pool.cc +++ b/webcc/connection_pool.cc @@ -1,25 +1,25 @@ -#include "webcc/http_connection_pool.h" +#include "webcc/connection_pool.h" #include "webcc/logger.h" namespace webcc { -HttpConnectionPool::HttpConnectionPool() { +ConnectionPool::ConnectionPool() { } -void HttpConnectionPool::Start(HttpConnectionPtr c) { +void ConnectionPool::Start(ConnectionPtr c) { LOG_VERB("Starting connection..."); connections_.insert(c); c->Start(); } -void HttpConnectionPool::Close(HttpConnectionPtr c) { +void ConnectionPool::Close(ConnectionPtr c) { LOG_VERB("Closing connection..."); connections_.erase(c); c->Close(); } -void HttpConnectionPool::CloseAll() { +void ConnectionPool::CloseAll() { LOG_VERB("Closing all (%u) connections...", connections_.size()); for (auto& c : connections_) { c->Close(); diff --git a/webcc/connection_pool.h b/webcc/connection_pool.h new file mode 100644 index 0000000..c35cc7a --- /dev/null +++ b/webcc/connection_pool.h @@ -0,0 +1,33 @@ +#ifndef WEBCC_CONNECTION_POOL_H_ +#define WEBCC_CONNECTION_POOL_H_ + +#include + +#include "webcc/connection.h" + +namespace webcc { + +class ConnectionPool { +public: + ConnectionPool(const ConnectionPool&) = delete; + ConnectionPool& operator=(const ConnectionPool&) = delete; + + ConnectionPool(); + + // Add a connection to the pool and start it. + void Start(ConnectionPtr c); + + // Close a connection. + void Close(ConnectionPtr c); + + // Close all connections. + void CloseAll(); + +private: + /// The managed connections. + std::set connections_; +}; + +} // namespace webcc + +#endif // WEBCC_CONNECTION_POOL_H_ diff --git a/webcc/globals.cc b/webcc/globals.cc index ff0e4b7..dd33279 100644 --- a/webcc/globals.cc +++ b/webcc/globals.cc @@ -8,8 +8,6 @@ namespace webcc { // ----------------------------------------------------------------------------- -namespace http { - const std::string& UserAgent() { static std::string s_user_agent = std::string("Webcc/") + WEBCC_VERSION; return s_user_agent; @@ -52,8 +50,6 @@ std::string FromExtension(const std::string& extension, } // namespace media_types -} // namespace http - // ----------------------------------------------------------------------------- const char* DescribeError(Error error) { diff --git a/webcc/globals.h b/webcc/globals.h index 4b602a9..9e43866 100644 --- a/webcc/globals.h +++ b/webcc/globals.h @@ -68,8 +68,6 @@ const std::size_t kGzipThreshold = 1400; // ----------------------------------------------------------------------------- -namespace http { - namespace methods { // HTTP methods (verbs) in string. @@ -156,8 +154,6 @@ enum class ContentEncoding { // Return default user agent for HTTP headers. const std::string& UserAgent(); -} // namespace http - // ----------------------------------------------------------------------------- // Client side error codes. diff --git a/webcc/http_connection.h b/webcc/http_connection.h deleted file mode 100644 index 0d4cdb3..0000000 --- a/webcc/http_connection.h +++ /dev/null @@ -1,82 +0,0 @@ -#ifndef WEBCC_HTTP_CONNECTION_H_ -#define WEBCC_HTTP_CONNECTION_H_ - -#include -#include -#include - -#include "boost/asio/ip/tcp.hpp" // for ip::tcp::socket - -#include "webcc/globals.h" -#include "webcc/http_request.h" -#include "webcc/http_request_parser.h" -#include "webcc/http_response.h" - -namespace webcc { - -class HttpConnection; -class HttpConnectionPool; -class HttpRequestHandler; - -typedef std::shared_ptr HttpConnectionPtr; - -class HttpConnection : public std::enable_shared_from_this { -public: - HttpConnection(boost::asio::ip::tcp::socket socket, HttpConnectionPool* pool, - HttpRequestHandler* handler); - - ~HttpConnection() = default; - - HttpConnection(const HttpConnection&) = delete; - HttpConnection& operator=(const HttpConnection&) = delete; - - HttpRequestPtr request() const { - return request_; - } - - // Start to read and process the client request. - void Start(); - - // Close the socket. - void Close(); - - // Send response to client. - void SendResponse(HttpResponsePtr response); - - void SendResponse(http::Status status); - -private: - void DoRead(); - void OnRead(boost::system::error_code ec, std::size_t length); - - void DoWrite(); - void OnWrite(boost::system::error_code ec, std::size_t length); - - // Shutdown the socket. - void Shutdown(); - - // Socket for the connection. - boost::asio::ip::tcp::socket socket_; - - // The pool for this connection. - HttpConnectionPool* pool_; - - // Buffer for incoming data. - std::vector buffer_; - - // The handler used to process the incoming request. - HttpRequestHandler* request_handler_; - - // The incoming request. - HttpRequestPtr request_; - - // The parser for the incoming request. - HttpRequestParser request_parser_; - - // The response to be sent back to the client. - HttpResponsePtr response_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_CONNECTION_H_ diff --git a/webcc/http_connection_pool.h b/webcc/http_connection_pool.h deleted file mode 100644 index 5f89e66..0000000 --- a/webcc/http_connection_pool.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef WEBCC_HTTP_CONNECTION_POOL_H_ -#define WEBCC_HTTP_CONNECTION_POOL_H_ - -#include - -#include "webcc/http_connection.h" - -namespace webcc { - -class HttpConnectionPool { -public: - HttpConnectionPool(const HttpConnectionPool&) = delete; - HttpConnectionPool& operator=(const HttpConnectionPool&) = delete; - - HttpConnectionPool(); - - // Add a connection to the pool and start it. - void Start(HttpConnectionPtr c); - - // Close a connection. - void Close(HttpConnectionPtr c); - - // Close all connections. - void CloseAll(); - -private: - /// The managed connections. - std::set connections_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_CONNECTION_POOL_H_ diff --git a/webcc/http_request_builder.cc b/webcc/http_request_builder.cc deleted file mode 100644 index 042f6b3..0000000 --- a/webcc/http_request_builder.cc +++ /dev/null @@ -1,92 +0,0 @@ -#include "webcc/http_request_builder.h" - -#include "webcc/base64.h" -#include "webcc/logger.h" -#include "webcc/utility.h" -#include "webcc/zlib_wrapper.h" - -namespace webcc { - -HttpRequestPtr HttpRequestBuilder::Build() { - assert(parameters_.size() % 2 == 0); - assert(headers_.size() % 2 == 0); - - auto request = std::make_shared(method_, url_); - - for (std::size_t i = 1; i < parameters_.size(); i += 2) { - request->AddQuery(parameters_[i - 1], parameters_[i]); - } - - for (std::size_t i = 1; i < headers_.size(); i += 2) { - request->SetHeader(std::move(headers_[i - 1]), std::move(headers_[i])); - } - - // No keep-alive? - if (!keep_alive_) { - request->SetHeader(http::headers::kConnection, "Close"); - } - - if (!data_.empty()) { - SetContent(request, std::move(data_)); - - // TODO: Request-level charset. - if (json_) { - request->SetContentType(http::media_types::kApplicationJson, ""); - } - } else if (!form_parts_.empty()) { - request->set_form_parts(std::move(form_parts_)); - } - - return request; -} - -HttpRequestBuilder& HttpRequestBuilder::File(const std::string& name, - const Path& path, - const std::string& mime_type) { - assert(!name.empty()); - form_parts_.push_back(FormPart{ name, path, mime_type }); - return *this; -} - -HttpRequestBuilder& HttpRequestBuilder::Form(const std::string& name, - std::string&& data, - const std::string& mime_type) { - assert(!name.empty()); - form_parts_.push_back(FormPart{ name, std::move(data), mime_type }); - return *this; -} - -HttpRequestBuilder& HttpRequestBuilder::Auth(const std::string& type, - const std::string& credentials) { - headers_.push_back(http::headers::kAuthorization); - headers_.push_back(type + " " + credentials); - return *this; -} - -HttpRequestBuilder& HttpRequestBuilder::AuthBasic(const std::string& login, - const std::string& password) { - auto credentials = Base64Encode(login + ":" + password); - return Auth("Basic", credentials); -} - -HttpRequestBuilder& HttpRequestBuilder::AuthToken(const std::string& token) { - return Auth("Token", token); -} - -void HttpRequestBuilder::SetContent(HttpRequestPtr request, - std::string&& data) { - if (gzip_ && data.size() > kGzipThreshold) { - std::string compressed; - if (Compress(data, &compressed)) { - request->SetContent(std::move(compressed), true); - request->SetHeader(http::headers::kContentEncoding, "gzip"); - return; - } - - LOG_WARN("Cannot compress the content data!"); - } - - request->SetContent(std::move(data), true); -} - -} // namespace webcc diff --git a/webcc/http_request_builder.h b/webcc/http_request_builder.h deleted file mode 100644 index 4702c70..0000000 --- a/webcc/http_request_builder.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef WEBCC_HTTP_REQUEST_BUILDER_H_ -#define WEBCC_HTTP_REQUEST_BUILDER_H_ - -#include -#include - -#include "webcc/http_request.h" - -namespace webcc { - -class HttpRequestBuilder { -public: - explicit HttpRequestBuilder(const std::string& method = "") - : method_(method) { - } - - ~HttpRequestBuilder() = default; - - HttpRequestBuilder(const HttpRequestBuilder&) = delete; - HttpRequestBuilder& operator=(const HttpRequestBuilder&) = delete; - - // Build the request. - HttpRequestPtr Build(); - - HttpRequestPtr operator()() { - return Build(); - } - - HttpRequestBuilder& Get() { return Method(http::methods::kGet); } - HttpRequestBuilder& Head() { return Method(http::methods::kHead); } - HttpRequestBuilder& Post() { return Method(http::methods::kPost); } - HttpRequestBuilder& Put() { return Method(http::methods::kPut); } - HttpRequestBuilder& Delete() { return Method(http::methods::kDelete); } - HttpRequestBuilder& Patch() { return Method(http::methods::kPatch); } - - // NOTE: - // The naming convention doesn't follow Google C++ Style for - // consistency and simplicity. - - HttpRequestBuilder& Method(const std::string& method) { - method_ = method; - return *this; - } - - HttpRequestBuilder& Url(const std::string& url) { - url_ = url; - return *this; - } - - HttpRequestBuilder& Query(const std::string& key, - const std::string& value) { - parameters_.push_back(key); - parameters_.push_back(value); - return *this; - } - - HttpRequestBuilder& Data(const std::string& data) { - data_ = data; - return *this; - } - - HttpRequestBuilder& Data(std::string&& data) { - data_ = std::move(data); - return *this; - } - - HttpRequestBuilder& Json(bool json = true) { - json_ = json; - return *this; - } - - // Upload a file. - HttpRequestBuilder& File(const std::string& name, const Path& path, - const std::string& mime_type = ""); - - HttpRequestBuilder& Form(FormPart&& part) { - form_parts_.push_back(std::move(part)); - return *this; - } - - HttpRequestBuilder& Form(const std::string& name, std::string&& data, - const std::string& mime_type = ""); - - HttpRequestBuilder& Gzip(bool gzip = true) { - gzip_ = gzip; - return *this; - } - - HttpRequestBuilder& Header(const std::string& key, - const std::string& value) { - headers_.push_back(key); - headers_.push_back(value); - return *this; - } - - HttpRequestBuilder& KeepAlive(bool keep_alive = true) { - keep_alive_ = keep_alive; - return *this; - } - - HttpRequestBuilder& Auth(const std::string& type, - const std::string& credentials); - - HttpRequestBuilder& AuthBasic(const std::string& login, - const std::string& password); - - HttpRequestBuilder& AuthToken(const std::string& token); - -private: - void SetContent(HttpRequestPtr request, std::string&& data); - -private: - std::string method_; - - std::string url_; - - // URL query parameters. - std::vector parameters_; - - // Data to send in the body of the request. - std::string data_; - - // Is the data to send a JSON string? - bool json_ = false; - - // Files to upload for a POST request. - std::vector form_parts_; - - // Compress the request content. - // NOTE: Most servers don't support compressed requests. - // Even the requests module from Python doesn't have a built-in support. - // See: https://github.com/kennethreitz/requests/issues/1753 - bool gzip_ = false; - - // Additional request headers. - std::vector headers_; - - // Persistent connection. - bool keep_alive_ = true; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_REQUEST_BUILDER_H_ diff --git a/webcc/http_request_handler.h b/webcc/http_request_handler.h deleted file mode 100644 index 732feb6..0000000 --- a/webcc/http_request_handler.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef WEBCC_HTTP_REQUEST_HANDLER_H_ -#define WEBCC_HTTP_REQUEST_HANDLER_H_ - -#include -#include -#include - -#include "webcc/http_connection.h" -#include "webcc/queue.h" - -namespace webcc { - -class HttpRequest; -class HttpResponse; - -// The common handler for all incoming requests. -class HttpRequestHandler { -public: - HttpRequestHandler() = default; - virtual ~HttpRequestHandler() = default; - - HttpRequestHandler(const HttpRequestHandler&) = delete; - HttpRequestHandler& operator=(const HttpRequestHandler&) = delete; - - // Put the connection into the queue. - void Enqueue(HttpConnectionPtr connection); - - // Start worker threads. - void Start(std::size_t count); - - // Clear pending connections from the queue and stop worker threads. - void Stop(); - -private: - void WorkerRoutine(); - - // Called by the worker routine. - virtual void HandleConnection(HttpConnectionPtr connection) = 0; - -private: - Queue queue_; - - std::vector workers_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_REQUEST_HANDLER_H_ diff --git a/webcc/http_response.h b/webcc/http_response.h deleted file mode 100644 index aafbba7..0000000 --- a/webcc/http_response.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef WEBCC_HTTP_RESPONSE_H_ -#define WEBCC_HTTP_RESPONSE_H_ - -#include -#include - -#include "webcc/http_message.h" - -namespace webcc { - -class HttpResponse; -typedef std::shared_ptr HttpResponsePtr; - -class HttpResponse : public HttpMessage { -public: - explicit HttpResponse(http::Status status = http::Status::kOK) - : status_(status) { - } - - ~HttpResponse() override = default; - - int status() const { - return status_; - } - - void set_status(int status) { - status_ = status; - } - - // Set start line according to status code. - void Prepare() final; - -private: - int status_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_RESPONSE_H_ diff --git a/webcc/http_response_parser.h b/webcc/http_response_parser.h deleted file mode 100644 index d03eec0..0000000 --- a/webcc/http_response_parser.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef WEBCC_HTTP_RESPONSE_PARSER_H_ -#define WEBCC_HTTP_RESPONSE_PARSER_H_ - -#include - -#include "webcc/http_parser.h" - -namespace webcc { - -class HttpResponse; - -class HttpResponseParser : public HttpParser { -public: - explicit HttpResponseParser(HttpResponse* response = nullptr); - - ~HttpResponseParser() override = default; - - void Init(HttpResponse* response); - -private: - // Parse HTTP start line; E.g., "HTTP/1.1 200 OK". - bool ParseStartLine(const std::string& line) final; - - // The result response message. - HttpResponse* response_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_RESPONSE_PARSER_H_ diff --git a/webcc/logger.cc b/webcc/logger.cc index 2a3ed67..3cb96e4 100644 --- a/webcc/logger.cc +++ b/webcc/logger.cc @@ -214,15 +214,17 @@ void LogInit(const std::string& dir, int modes) { } static std::string GetTimestamp() { - auto now = std::chrono::system_clock::now(); - std::time_t t = std::chrono::system_clock::to_time_t(now); + using system_clock = std::chrono::system_clock; + using milliseconds = std::chrono::milliseconds; + + auto now = system_clock::now(); + std::time_t t = system_clock::to_time_t(now); std::stringstream ss; ss << std::put_time(std::localtime(&t), "%Y-%m-%d %H:%M:%S"); - std::chrono::milliseconds milli_seconds = - std::chrono::duration_cast( - now.time_since_epoch()); + milliseconds milli_seconds = + std::chrono::duration_cast(now.time_since_epoch()); std::string micro_seconds_str = std::to_string(milli_seconds.count() % 1000); while (micro_seconds_str.size() < 3) { micro_seconds_str = "0" + micro_seconds_str; @@ -233,7 +235,7 @@ static std::string GetTimestamp() { return ss.str(); } -void LogWrite(int level, const char* file, int line, const char* format, ...) { +void Log(int level, const char* file, int line, const char* format, ...) { assert(format != nullptr); std::string timestamp = GetTimestamp(); diff --git a/webcc/logger.h b/webcc/logger.h index 709a5a2..8e8a534 100644 --- a/webcc/logger.h +++ b/webcc/logger.h @@ -41,7 +41,7 @@ const int LOG_FILE_OVERWRITE = LOG_FILE | LOG_OVERWRITE; // If |dir| is empty, log file will be generated in current directory. void LogInit(const std::string& dir, int modes); -void LogWrite(int level, const char* file, int line, const char* format, ...); +void Log(int level, const char* file, int line, const char* format, ...); } // namespace webcc @@ -58,35 +58,35 @@ void LogWrite(int level, const char* file, int line, const char* format, ...); #if WEBCC_LOG_LEVEL <= WEBCC_VERB #define LOG_VERB(format, ...) \ - webcc::LogWrite(WEBCC_VERB, __FILENAME__, __LINE__, format, ##__VA_ARGS__); + webcc::Log(WEBCC_VERB, __FILENAME__, __LINE__, format, ##__VA_ARGS__); #else #define LOG_VERB(format, ...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_INFO #define LOG_INFO(format, ...) \ - webcc::LogWrite(WEBCC_INFO, __FILENAME__, __LINE__, format, ##__VA_ARGS__); + webcc::Log(WEBCC_INFO, __FILENAME__, __LINE__, format, ##__VA_ARGS__); #else #define LOG_INFO(format, ...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_WARN #define LOG_WARN(format, ...) \ - webcc::LogWrite(WEBCC_WARN, __FILENAME__, __LINE__, format, ##__VA_ARGS__); + webcc::Log(WEBCC_WARN, __FILENAME__, __LINE__, format, ##__VA_ARGS__); #else #define LOG_WARN(format, ...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_ERRO #define LOG_ERRO(format, ...) \ - webcc::LogWrite(WEBCC_ERRO, __FILENAME__, __LINE__, format, ##__VA_ARGS__); + webcc::Log(WEBCC_ERRO, __FILENAME__, __LINE__, format, ##__VA_ARGS__); #else #define LOG_ERRO(format, ...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_FATA #define LOG_FATA(format, ...) \ - webcc::LogWrite(WEBCC_FATA, __FILENAME__, __LINE__, format, ##__VA_ARGS__); + webcc::Log(WEBCC_FATA, __FILENAME__, __LINE__, format, ##__VA_ARGS__); #else #define LOG_FATA(format, ...) #endif @@ -98,35 +98,35 @@ void LogWrite(int level, const char* file, int line, const char* format, ...); #if WEBCC_LOG_LEVEL <= WEBCC_VERB #define LOG_VERB(format, args...) \ - webcc::LogWrite(WEBCC_VERB, __FILENAME__, __LINE__, format, ##args); + webcc::Log(WEBCC_VERB, __FILENAME__, __LINE__, format, ##args); #else #define LOG_VERB(format, args...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_INFO #define LOG_INFO(format, args...) \ - webcc::LogWrite(WEBCC_INFO, __FILENAME__, __LINE__, format, ##args); + webcc::Log(WEBCC_INFO, __FILENAME__, __LINE__, format, ##args); #else #define LOG_INFO(format, args...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_WARN #define LOG_WARN(format, args...) \ - webcc::LogWrite(WEBCC_WARN, __FILENAME__, __LINE__, format, ##args); + webcc::Log(WEBCC_WARN, __FILENAME__, __LINE__, format, ##args); #else #define LOG_WARN(format, args...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_ERRO #define LOG_ERRO(format, args...) \ - webcc::LogWrite(WEBCC_ERRO, __FILENAME__, __LINE__, format, ##args); + webcc::Log(WEBCC_ERRO, __FILENAME__, __LINE__, format, ##args); #else #define LOG_ERRO(format, args...) #endif #if WEBCC_LOG_LEVEL <= WEBCC_FATA #define LOG_FATA(format, args...) \ - webcc::LogWrite(WEBCC_FATA, __FILENAME__, __LINE__, format, ##args); + webcc::Log(WEBCC_FATA, __FILENAME__, __LINE__, format, ##args); #else #define LOG_FATA(format, args...) #endif diff --git a/webcc/http_message.cc b/webcc/message.cc similarity index 71% rename from webcc/http_message.cc rename to webcc/message.cc index 2071055..9a9d0d8 100644 --- a/webcc/http_message.cc +++ b/webcc/message.cc @@ -1,5 +1,7 @@ -#include "webcc/http_message.h" +#include "webcc/message.h" +#include +#include // for put_time #include #include "boost/algorithm/string.hpp" @@ -22,15 +24,15 @@ const char CRLF[] = { '\r', '\n' }; // ----------------------------------------------------------------------------- -std::ostream& operator<<(std::ostream& os, const HttpMessage& message) { +std::ostream& operator<<(std::ostream& os, const Message& message) { message.Dump(os); return os; } // ----------------------------------------------------------------------------- -bool HttpMessage::IsConnectionKeepAlive() const { - using http::headers::kConnection; +bool Message::IsConnectionKeepAlive() const { + using headers::kConnection; bool existed = false; const std::string& connection = GetHeader(kConnection, &existed); @@ -47,29 +49,29 @@ bool HttpMessage::IsConnectionKeepAlive() const { return false; } -http::ContentEncoding HttpMessage::GetContentEncoding() const { - using http::headers::kContentEncoding; +ContentEncoding Message::GetContentEncoding() const { + using headers::kContentEncoding; const std::string& encoding = GetHeader(kContentEncoding); if (encoding == "gzip") { - return http::ContentEncoding::kGzip; + return ContentEncoding::kGzip; } if (encoding == "deflate") { - return http::ContentEncoding::kDeflate; + return ContentEncoding::kDeflate; } - return http::ContentEncoding::kUnknown; + return ContentEncoding::kUnknown; } -bool HttpMessage::AcceptEncodingGzip() const { - using http::headers::kAcceptEncoding; +bool Message::AcceptEncodingGzip() const { + using headers::kAcceptEncoding; return GetHeader(kAcceptEncoding).find("gzip") != std::string::npos; } // See: https://tools.ietf.org/html/rfc7231#section-3.1.1.1 -void HttpMessage::SetContentType(const std::string& media_type, - const std::string& charset) { - using http::headers::kContentType; +void Message::SetContentType(const std::string& media_type, + const std::string& charset) { + using headers::kContentType; if (charset.empty()) { SetHeader(kContentType, media_type); @@ -78,14 +80,14 @@ void HttpMessage::SetContentType(const std::string& media_type, } } -void HttpMessage::SetContent(std::string&& content, bool set_length) { +void Message::SetContent(std::string&& content, bool set_length) { content_ = std::move(content); if (set_length) { SetContentLength(content_.size()); } } -void HttpMessage::Prepare() { +void Message::Prepare() { assert(!start_line_.empty()); using boost::asio::buffer; @@ -95,7 +97,7 @@ void HttpMessage::Prepare() { payload_.push_back(buffer(start_line_)); payload_.push_back(buffer(misc_strings::CRLF)); - for (const HttpHeader& h : headers_.data()) { + for (const Header& h : headers_.data()) { payload_.push_back(buffer(h.first)); payload_.push_back(buffer(misc_strings::HEADER_SEPARATOR)); payload_.push_back(buffer(h.second)); @@ -109,20 +111,20 @@ void HttpMessage::Prepare() { } } -void HttpMessage::CopyPayload(std::ostream& os) const { +void Message::CopyPayload(std::ostream& os) const { for (const boost::asio::const_buffer& b : payload_) { os.write(static_cast(b.data()), b.size()); } } -void HttpMessage::CopyPayload(std::string* str) const { +void Message::CopyPayload(std::string* str) const { std::stringstream ss; CopyPayload(ss); *str = ss.str(); } -void HttpMessage::Dump(std::ostream& os, std::size_t indent, - const std::string& prefix) const { +void Message::Dump(std::ostream& os, std::size_t indent, + const std::string& prefix) const { std::string indent_str; if (indent > 0) { indent_str.append(indent, ' '); @@ -131,7 +133,7 @@ void HttpMessage::Dump(std::ostream& os, std::size_t indent, os << indent_str << start_line_ << std::endl; - for (const HttpHeader& h : headers_.data()) { + for (const Header& h : headers_.data()) { os << indent_str << h.first << ": " << h.second << std::endl; } @@ -172,11 +174,18 @@ void HttpMessage::Dump(std::ostream& os, std::size_t indent, } } -std::string HttpMessage::Dump(std::size_t indent, - const std::string& prefix) const { +std::string Message::Dump(std::size_t indent, + const std::string& prefix) const { std::stringstream ss; Dump(ss, indent, prefix); return ss.str(); } +std::string Message::GetTimestamp() { + std::time_t t = std::time(nullptr); + std::stringstream ss; + ss << std::put_time(std::gmtime(&t), "%a, %d %b %Y %H:%M:%S") << " GMT"; + return ss.str(); +} + } // namespace webcc diff --git a/webcc/http_message.h b/webcc/message.h similarity index 78% rename from webcc/http_message.h rename to webcc/message.h index ddc6d8c..2325c5b 100644 --- a/webcc/http_message.h +++ b/webcc/message.h @@ -1,5 +1,5 @@ -#ifndef WEBCC_HTTP_MESSAGE_H_ -#define WEBCC_HTTP_MESSAGE_H_ +#ifndef WEBCC_MESSAGE_H_ +#define WEBCC_MESSAGE_H_ #include #include @@ -11,16 +11,16 @@ namespace webcc { -class HttpMessage; -std::ostream& operator<<(std::ostream& os, const HttpMessage& message); +class Message; +std::ostream& operator<<(std::ostream& os, const Message& message); // Base class for HTTP request and response messages. -class HttpMessage { +class Message { public: - HttpMessage() : content_length_(kInvalidLength) { + Message() : content_length_(kInvalidLength) { } - virtual ~HttpMessage() = default; + virtual ~Message() = default; const std::string& start_line() const { return start_line_; @@ -40,7 +40,7 @@ public: bool IsConnectionKeepAlive() const; - void SetHeader(HttpHeader&& header) { + void SetHeader(Header&& header) { headers_.Set(std::move(header.first), std::move(header.second)); } @@ -57,7 +57,7 @@ public: return headers_.Has(key); } - http::ContentEncoding GetContentEncoding() const; + ContentEncoding GetContentEncoding() const; // Return true if header Accept-Encoding contains "gzip". bool AcceptEncodingGzip() const; @@ -72,7 +72,7 @@ public: } void SetContentType(const std::string& content_type) { - SetHeader(http::headers::kContentType, content_type); + SetHeader(headers::kContentType, content_type); } // Example: SetContentType("application/json", "utf-8") @@ -105,9 +105,14 @@ public: protected: void SetContentLength(std::size_t content_length) { content_length_ = content_length; - SetHeader(http::headers::kContentLength, std::to_string(content_length)); + SetHeader(headers::kContentLength, std::to_string(content_length)); } + // Get the timestamp for HTTP Date header field. + // E.g., Wed, 21 Oct 2015 07:28:00 GMT + // See: https://tools.ietf.org/html/rfc7231#section-7.1.1.2 + std::string GetTimestamp(); + protected: std::string start_line_; @@ -117,7 +122,7 @@ protected: std::size_t content_length_; - HttpHeaders headers_; + Headers headers_; // NOTE: The payload itself doesn't hold the memory! Payload payload_; @@ -125,4 +130,4 @@ protected: } // namespace webcc -#endif // WEBCC_HTTP_MESSAGE_H_ +#endif // WEBCC_MESSAGE_H_ diff --git a/webcc/http_parser.cc b/webcc/parser.cc similarity index 84% rename from webcc/http_parser.cc rename to webcc/parser.cc index 49c01c6..b0f37e0 100644 --- a/webcc/http_parser.cc +++ b/webcc/parser.cc @@ -1,9 +1,9 @@ -#include "webcc/http_parser.h" +#include "webcc/parser.h" #include "boost/algorithm/string.hpp" -#include "webcc/http_message.h" #include "webcc/logger.h" +#include "webcc/message.h" #include "webcc/utility.h" #include "webcc/zlib_wrapper.h" @@ -26,7 +26,7 @@ bool StringToSizeT(const std::string& str, int base, std::size_t* output) { // ----------------------------------------------------------------------------- -HttpParser::HttpParser(HttpMessage* message) +Parser::Parser(Message* message) : message_(message), content_length_(kInvalidLength), start_line_parsed_(false), @@ -37,12 +37,12 @@ HttpParser::HttpParser(HttpMessage* message) finished_(false) { } -void HttpParser::Init(HttpMessage* message) { +void Parser::Init(Message* message) { Reset(); message_ = message; } -bool HttpParser::Parse(const char* data, std::size_t length) { +bool Parser::Parse(const char* data, std::size_t length) { if (header_ended_) { return ParseContent(data, length); } @@ -64,7 +64,7 @@ bool HttpParser::Parse(const char* data, std::size_t length) { } } -void HttpParser::Reset() { +void Parser::Reset() { pending_data_.clear(); content_.clear(); @@ -77,7 +77,7 @@ void HttpParser::Reset() { finished_ = false; } -bool HttpParser::ParseHeaders() { +bool Parser::ParseHeaders() { std::size_t off = 0; while (true) { @@ -113,8 +113,7 @@ bool HttpParser::ParseHeaders() { return true; } -bool HttpParser::GetNextLine(std::size_t off, std::string* line, - bool erase) { +bool Parser::GetNextLine(std::size_t off, std::string* line, bool erase) { std::size_t pos = pending_data_.find(kCRLF, off); if (pos == std::string::npos) { @@ -134,15 +133,15 @@ bool HttpParser::GetNextLine(std::size_t off, std::string* line, return true; } -bool HttpParser::ParseHeaderLine(const std::string& line) { - HttpHeader header; +bool Parser::ParseHeaderLine(const std::string& line) { + Header header; if (!Split2(line, ':', &header.first, &header.second)) { return false; } do { if (!chunked_ && !content_length_parsed_) { - if (boost::iequals(header.first, http::headers::kContentLength)) { + if (boost::iequals(header.first, headers::kContentLength)) { content_length_parsed_ = true; if (!StringToSizeT(header.second, 10, &content_length_)) { @@ -166,7 +165,7 @@ bool HttpParser::ParseHeaderLine(const std::string& line) { // TODO: Replace `!chunked_` with . if (!chunked_ && !content_length_parsed_) { - if (boost::iequals(header.first, http::headers::kTransferEncoding)) { + if (boost::iequals(header.first, headers::kTransferEncoding)) { if (header.second == "chunked") { // The content is chunked. chunked_ = true; @@ -178,7 +177,7 @@ bool HttpParser::ParseHeaderLine(const std::string& line) { } while (false); // Parse Content-Type. - if (boost::iequals(header.first, http::headers::kContentType)) { + if (boost::iequals(header.first, headers::kContentType)) { ContentType content_type(header.second); if (!content_type.Valid()) { LOG_ERRO("Invalid content-type header: %s", header.second.c_str()); @@ -192,7 +191,7 @@ bool HttpParser::ParseHeaderLine(const std::string& line) { return true; } -bool HttpParser::ParseContent(const char* data, std::size_t length) { +bool Parser::ParseContent(const char* data, std::size_t length) { if (chunked_) { return ParseChunkedContent(data, length); } else { @@ -200,7 +199,7 @@ bool HttpParser::ParseContent(const char* data, std::size_t length) { } } -bool HttpParser::ParseFixedContent(const char* data, std::size_t length) { +bool Parser::ParseFixedContent(const char* data, std::size_t length) { if (!content_length_parsed_) { // No Content-Length, no content. Finish(); @@ -229,7 +228,7 @@ bool HttpParser::ParseFixedContent(const char* data, std::size_t length) { return true; } -bool HttpParser::ParseChunkedContent(const char* data, std::size_t length) { +bool Parser::ParseChunkedContent(const char* data, std::size_t length) { // Append the new data to the pending data. // NOTE: It's more difficult to avoid this than fixed-length content. pending_data_.append(data, length); @@ -285,7 +284,7 @@ bool HttpParser::ParseChunkedContent(const char* data, std::size_t length) { return true; } -bool HttpParser::ParseChunkSize() { +bool Parser::ParseChunkSize() { LOG_VERB("Parse chunk size."); std::string line; @@ -312,7 +311,7 @@ bool HttpParser::ParseChunkSize() { return true; } -bool HttpParser::Finish() { +bool Parser::Finish() { finished_ = true; if (content_.empty()) { @@ -336,21 +335,21 @@ bool HttpParser::Finish() { return true; } -void HttpParser::AppendContent(const char* data, std::size_t count) { +void Parser::AppendContent(const char* data, std::size_t count) { content_.append(data, count); } -void HttpParser::AppendContent(const std::string& data) { +void Parser::AppendContent(const std::string& data) { content_.append(data); } -bool HttpParser::IsContentFull() const { +bool Parser::IsContentFull() const { return content_length_ != kInvalidLength && content_length_ <= content_.length(); } -bool HttpParser::IsContentCompressed() const { - return message_->GetContentEncoding() != http::ContentEncoding::kUnknown; +bool Parser::IsContentCompressed() const { + return message_->GetContentEncoding() != ContentEncoding::kUnknown; } } // namespace webcc diff --git a/webcc/http_parser.h b/webcc/parser.h similarity index 83% rename from webcc/http_parser.h rename to webcc/parser.h index 7605adf..1b524e2 100644 --- a/webcc/http_parser.h +++ b/webcc/parser.h @@ -1,5 +1,5 @@ -#ifndef WEBCC_HTTP_PARSER_H_ -#define WEBCC_HTTP_PARSER_H_ +#ifndef WEBCC_PARSER_H_ +#define WEBCC_PARSER_H_ #include @@ -8,19 +8,19 @@ namespace webcc { -class HttpMessage; +class Message; // HTTP request and response parser. -class HttpParser { +class Parser { public: - explicit HttpParser(HttpMessage* message); + explicit Parser(Message* message); - virtual ~HttpParser() = default; + virtual ~Parser() = default; - HttpParser(const HttpParser&) = delete; - HttpParser& operator=(const HttpParser&) = delete; + Parser(const Parser&) = delete; + Parser& operator=(const Parser&) = delete; - void Init(HttpMessage* message); + void Init(Message* message); bool finished() const { return finished_; } @@ -66,7 +66,7 @@ protected: protected: // The result HTTP message. - HttpMessage* message_; + Message* message_; // Data waiting to be parsed. std::string pending_data_; @@ -84,4 +84,4 @@ protected: } // namespace webcc -#endif // WEBCC_HTTP_PARSER_H_ +#endif // WEBCC_PARSER_H_ diff --git a/webcc/http_request.cc b/webcc/request.cc similarity index 88% rename from webcc/http_request.cc rename to webcc/request.cc index 29f050e..3f0d305 100644 --- a/webcc/http_request.cc +++ b/webcc/request.cc @@ -1,4 +1,4 @@ -#include "webcc/http_request.h" +#include "webcc/request.h" #include "webcc/logger.h" #include "webcc/utility.h" @@ -18,17 +18,17 @@ const char DOUBLE_DASHES[] = { '-', '-' }; // ----------------------------------------------------------------------------- -void HttpRequest::Prepare() { +void Request::Prepare() { CreateStartLine(); if (url_.port().empty()) { - SetHeader(http::headers::kHost, url_.host()); + SetHeader(headers::kHost, url_.host()); } else { - SetHeader(http::headers::kHost, url_.host() + ":" + url_.port()); + SetHeader(headers::kHost, url_.host() + ":" + url_.port()); } if (form_parts_.empty()) { - HttpMessage::Prepare(); + Message::Prepare(); return; } @@ -69,13 +69,13 @@ void HttpRequest::Prepare() { SetContentLength(content_length); // Prepare start line and headers. - HttpMessage::Prepare(); + Message::Prepare(); // Append payload of content data. payload_.insert(payload_.end(), data_payload.begin(), data_payload.end()); } -void HttpRequest::CreateStartLine() { +void Request::CreateStartLine() { if (!start_line_.empty()) { return; } diff --git a/webcc/http_request.h b/webcc/request.h similarity index 77% rename from webcc/http_request.h rename to webcc/request.h index 725bbc0..d1cbf9a 100644 --- a/webcc/http_request.h +++ b/webcc/request.h @@ -1,27 +1,27 @@ -#ifndef WEBCC_HTTP_REQUEST_H_ -#define WEBCC_HTTP_REQUEST_H_ +#ifndef WEBCC_REQUEST_H_ +#define WEBCC_REQUEST_H_ #include #include #include -#include "webcc/http_message.h" +#include "webcc/message.h" #include "webcc/url.h" namespace webcc { -class HttpRequest; -typedef std::shared_ptr HttpRequestPtr; +class Request; +using RequestPtr = std::shared_ptr; -class HttpRequest : public HttpMessage { +class Request : public Message { public: - HttpRequest() = default; + Request() = default; - HttpRequest(const std::string& method, const std::string& url) + Request(const std::string& method, const std::string& url) : method_(method), url_(url) { } - ~HttpRequest() override = default; + ~Request() override = default; const std::string& method() const { return method_; @@ -86,4 +86,4 @@ private: } // namespace webcc -#endif // WEBCC_HTTP_REQUEST_H_ +#endif // WEBCC_REQUEST_H_ diff --git a/webcc/request_builder.cc b/webcc/request_builder.cc new file mode 100644 index 0000000..f6453ce --- /dev/null +++ b/webcc/request_builder.cc @@ -0,0 +1,91 @@ +#include "webcc/request_builder.h" + +#include "webcc/base64.h" +#include "webcc/logger.h" +#include "webcc/utility.h" +#include "webcc/zlib_wrapper.h" + +namespace webcc { + +RequestPtr RequestBuilder::Build() { + assert(parameters_.size() % 2 == 0); + assert(headers_.size() % 2 == 0); + + auto request = std::make_shared(method_, url_); + + for (std::size_t i = 1; i < parameters_.size(); i += 2) { + request->AddQuery(parameters_[i - 1], parameters_[i]); + } + + for (std::size_t i = 1; i < headers_.size(); i += 2) { + request->SetHeader(std::move(headers_[i - 1]), std::move(headers_[i])); + } + + // No keep-alive? + if (!keep_alive_) { + request->SetHeader(headers::kConnection, "Close"); + } + + if (!data_.empty()) { + SetContent(request, std::move(data_)); + + // TODO: Request-level charset. + if (json_) { + request->SetContentType(media_types::kApplicationJson, ""); + } + } else if (!form_parts_.empty()) { + request->set_form_parts(std::move(form_parts_)); + } + + return request; +} + +RequestBuilder& RequestBuilder::File(const std::string& name, + const Path& path, + const std::string& media_type) { + assert(!name.empty()); + form_parts_.push_back(FormPart{ name, path, media_type }); + return *this; +} + +RequestBuilder& RequestBuilder::Form(const std::string& name, + std::string&& data, + const std::string& media_type) { + assert(!name.empty()); + form_parts_.push_back(FormPart{ name, std::move(data), media_type }); + return *this; +} + +RequestBuilder& RequestBuilder::Auth(const std::string& type, + const std::string& credentials) { + headers_.push_back(headers::kAuthorization); + headers_.push_back(type + " " + credentials); + return *this; +} + +RequestBuilder& RequestBuilder::AuthBasic(const std::string& login, + const std::string& password) { + auto credentials = Base64Encode(login + ":" + password); + return Auth("Basic", credentials); +} + +RequestBuilder& RequestBuilder::AuthToken(const std::string& token) { + return Auth("Token", token); +} + +void RequestBuilder::SetContent(RequestPtr request, std::string&& data) { + if (gzip_ && data.size() > kGzipThreshold) { + std::string compressed; + if (Compress(data, &compressed)) { + request->SetContent(std::move(compressed), true); + request->SetHeader(headers::kContentEncoding, "gzip"); + return; + } + + LOG_WARN("Cannot compress the content data!"); + } + + request->SetContent(std::move(data), true); +} + +} // namespace webcc diff --git a/webcc/request_builder.h b/webcc/request_builder.h new file mode 100644 index 0000000..faaa30e --- /dev/null +++ b/webcc/request_builder.h @@ -0,0 +1,141 @@ +#ifndef WEBCC_REQUEST_BUILDER_H_ +#define WEBCC_REQUEST_BUILDER_H_ + +#include +#include + +#include "webcc/request.h" + +namespace webcc { + +class RequestBuilder { +public: + explicit RequestBuilder(const std::string& method = "") + : method_(method) { + } + + ~RequestBuilder() = default; + + RequestBuilder(const RequestBuilder&) = delete; + RequestBuilder& operator=(const RequestBuilder&) = delete; + + // Build the request. + RequestPtr Build(); + + RequestPtr operator()() { + return Build(); + } + + RequestBuilder& Get() { return Method(methods::kGet); } + RequestBuilder& Head() { return Method(methods::kHead); } + RequestBuilder& Post() { return Method(methods::kPost); } + RequestBuilder& Put() { return Method(methods::kPut); } + RequestBuilder& Delete() { return Method(methods::kDelete); } + RequestBuilder& Patch() { return Method(methods::kPatch); } + + // NOTE: + // The naming convention doesn't follow Google C++ Style for + // consistency and simplicity. + + RequestBuilder& Method(const std::string& method) { + method_ = method; + return *this; + } + + RequestBuilder& Url(const std::string& url) { + url_ = url; + return *this; + } + + RequestBuilder& Query(const std::string& key, const std::string& value) { + parameters_.push_back(key); + parameters_.push_back(value); + return *this; + } + + RequestBuilder& Data(const std::string& data) { + data_ = data; + return *this; + } + + RequestBuilder& Data(std::string&& data) { + data_ = std::move(data); + return *this; + } + + RequestBuilder& Json(bool json = true) { + json_ = json; + return *this; + } + + // Upload a file. + RequestBuilder& File(const std::string& name, const Path& path, + const std::string& media_type = ""); + + RequestBuilder& Form(FormPart&& part) { + form_parts_.push_back(std::move(part)); + return *this; + } + + RequestBuilder& Form(const std::string& name, std::string&& data, + const std::string& media_type = ""); + + RequestBuilder& Gzip(bool gzip = true) { + gzip_ = gzip; + return *this; + } + + RequestBuilder& Header(const std::string& key, const std::string& value) { + headers_.push_back(key); + headers_.push_back(value); + return *this; + } + + RequestBuilder& KeepAlive(bool keep_alive = true) { + keep_alive_ = keep_alive; + return *this; + } + + RequestBuilder& Auth(const std::string& type, const std::string& credentials); + + RequestBuilder& AuthBasic(const std::string& login, + const std::string& password); + + RequestBuilder& AuthToken(const std::string& token); + +private: + void SetContent(RequestPtr request, std::string&& data); + +private: + std::string method_; + + std::string url_; + + // URL query parameters. + std::vector parameters_; + + // Data to send in the body of the request. + std::string data_; + + // Is the data to send a JSON string? + bool json_ = false; + + // Files to upload for a POST request. + std::vector form_parts_; + + // Compress the request content. + // NOTE: Most servers don't support compressed requests. + // Even the requests module from Python doesn't have a built-in support. + // See: https://github.com/kennethreitz/requests/issues/1753 + bool gzip_ = false; + + // Additional request headers. + std::vector headers_; + + // Persistent connection. + bool keep_alive_ = true; +}; + +} // namespace webcc + +#endif // WEBCC_REQUEST_BUILDER_H_ diff --git a/webcc/http_request_handler.cc b/webcc/request_handler.cc similarity index 58% rename from webcc/http_request_handler.cc rename to webcc/request_handler.cc index 2a6640f..e26e088 100644 --- a/webcc/http_request_handler.cc +++ b/webcc/request_handler.cc @@ -1,36 +1,36 @@ -#include "webcc/http_request_handler.h" +#include "webcc/request_handler.h" #include #include "webcc/globals.h" -#include "webcc/http_request.h" -#include "webcc/http_response.h" +#include "webcc/request.h" +#include "webcc/response.h" #include "webcc/logger.h" namespace webcc { -void HttpRequestHandler::Enqueue(HttpConnectionPtr connection) { +void RequestHandler::Enqueue(ConnectionPtr connection) { queue_.Push(connection); } -void HttpRequestHandler::Start(std::size_t count) { +void RequestHandler::Start(std::size_t count) { assert(count > 0 && workers_.size() == 0); for (std::size_t i = 0; i < count; ++i) { - workers_.emplace_back(std::bind(&HttpRequestHandler::WorkerRoutine, this)); + workers_.emplace_back(std::bind(&RequestHandler::WorkerRoutine, this)); } } -void HttpRequestHandler::Stop() { +void RequestHandler::Stop() { LOG_INFO("Stopping workers..."); // Clear pending connections. - // The connections will be closed later (see HttpServer::DoAwaitStop). + // The connections will be closed later (see Server::DoAwaitStop). LOG_INFO("Clear pending connections..."); queue_.Clear(); // Enqueue a null connection to trigger the first worker to stop. - queue_.Push(HttpConnectionPtr()); + queue_.Push(ConnectionPtr()); for (auto& worker : workers_) { if (worker.joinable()) { @@ -41,17 +41,17 @@ void HttpRequestHandler::Stop() { LOG_INFO("All workers have been stopped."); } -void HttpRequestHandler::WorkerRoutine() { +void RequestHandler::WorkerRoutine() { LOG_INFO("Worker is running."); for (;;) { - HttpConnectionPtr connection = queue_.PopOrWait(); + ConnectionPtr connection = queue_.PopOrWait(); if (!connection) { LOG_INFO("Worker is going to stop."); // For stopping next worker. - queue_.Push(HttpConnectionPtr()); + queue_.Push(ConnectionPtr()); // Stop the worker. break; diff --git a/webcc/request_handler.h b/webcc/request_handler.h new file mode 100644 index 0000000..f409489 --- /dev/null +++ b/webcc/request_handler.h @@ -0,0 +1,48 @@ +#ifndef WEBCC_REQUEST_HANDLER_H_ +#define WEBCC_REQUEST_HANDLER_H_ + +#include +#include +#include + +#include "webcc/connection.h" +#include "webcc/queue.h" + +namespace webcc { + +class Request; +class Response; + +// The common handler for all incoming requests. +class RequestHandler { +public: + RequestHandler() = default; + virtual ~RequestHandler() = default; + + RequestHandler(const RequestHandler&) = delete; + RequestHandler& operator=(const RequestHandler&) = delete; + + // Put the connection into the queue. + void Enqueue(ConnectionPtr connection); + + // Start worker threads. + void Start(std::size_t count); + + // Clear pending connections from the queue and stop worker threads. + void Stop(); + +private: + void WorkerRoutine(); + + // Called by the worker routine. + virtual void HandleConnection(ConnectionPtr connection) = 0; + +private: + Queue queue_; + + std::vector workers_; +}; + +} // namespace webcc + +#endif // WEBCC_REQUEST_HANDLER_H_ diff --git a/webcc/http_request_parser.cc b/webcc/request_parser.cc similarity index 86% rename from webcc/http_request_parser.cc rename to webcc/request_parser.cc index 046731f..2d2a239 100644 --- a/webcc/http_request_parser.cc +++ b/webcc/request_parser.cc @@ -1,24 +1,24 @@ -#include "webcc/http_request_parser.h" +#include "webcc/request_parser.h" #include #include "boost/algorithm/string.hpp" -#include "webcc/http_request.h" +#include "webcc/request.h" #include "webcc/logger.h" namespace webcc { -HttpRequestParser::HttpRequestParser(HttpRequest* request) - : HttpParser(request), request_(request) { +RequestParser::RequestParser(Request* request) + : Parser(request), request_(request) { } -void HttpRequestParser::Init(HttpRequest* request) { - HttpParser::Init(request); +void RequestParser::Init(Request* request) { + Parser::Init(request); request_ = request; } -bool HttpRequestParser::ParseStartLine(const std::string& line) { +bool RequestParser::ParseStartLine(const std::string& line) { std::vector strs; boost::split(strs, line, boost::is_any_of(" "), boost::token_compress_on); @@ -34,7 +34,7 @@ bool HttpRequestParser::ParseStartLine(const std::string& line) { return true; } -bool HttpRequestParser::ParseContent(const char* data, std::size_t length) { +bool RequestParser::ParseContent(const char* data, std::size_t length) { if (chunked_) { return ParseChunkedContent(data, length); } else { @@ -46,7 +46,7 @@ bool HttpRequestParser::ParseContent(const char* data, std::size_t length) { } } -bool HttpRequestParser::ParseMultipartContent(const char* data, +bool RequestParser::ParseMultipartContent(const char* data, std::size_t length) { // Append the new data to the pending data. // NOTE: It's more difficult to avoid this than normal fixed-length content. @@ -139,7 +139,7 @@ bool HttpRequestParser::ParseMultipartContent(const char* data, return true; } -bool HttpRequestParser::ParsePartHeaders(bool* need_more_data) { +bool RequestParser::ParsePartHeaders(bool* need_more_data) { std::size_t off = 0; while (true) { @@ -157,7 +157,7 @@ bool HttpRequestParser::ParsePartHeaders(bool* need_more_data) { break; } - HttpHeader header; + Header header; if (!Split2(line, ':', &header.first, &header.second)) { LOG_ERRO("Invalid part header line: %s", line.c_str()); return false; @@ -167,7 +167,7 @@ bool HttpRequestParser::ParsePartHeaders(bool* need_more_data) { header.second.c_str()); // Parse Content-Disposition. - if (boost::iequals(header.first, http::headers::kContentDisposition)) { + if (boost::iequals(header.first, headers::kContentDisposition)) { ContentDisposition content_disposition(header.second); if (!content_disposition.valid()) { LOG_ERRO("Invalid content-disposition header: %s", @@ -189,7 +189,7 @@ bool HttpRequestParser::ParsePartHeaders(bool* need_more_data) { return true; } -bool HttpRequestParser::GetNextBoundaryLine(std::size_t* b_off, +bool RequestParser::GetNextBoundaryLine(std::size_t* b_off, std::size_t* b_count, bool* ended) { std::size_t off = 0; @@ -228,14 +228,14 @@ bool HttpRequestParser::GetNextBoundaryLine(std::size_t* b_off, return false; } -bool HttpRequestParser::IsBoundary(const std::string& line) const { +bool RequestParser::IsBoundary(const std::string& line) const { if (line == "--" + request_->content_type().boundary()) { return true; } return false; } -bool HttpRequestParser::IsBoundaryEnd(const std::string& line) const { +bool RequestParser::IsBoundaryEnd(const std::string& line) const { if (line == "--" + request_->content_type().boundary() + "--") { return true; } diff --git a/webcc/http_request_parser.h b/webcc/request_parser.h similarity index 67% rename from webcc/http_request_parser.h rename to webcc/request_parser.h index b2390df..29ed745 100644 --- a/webcc/http_request_parser.h +++ b/webcc/request_parser.h @@ -1,21 +1,21 @@ -#ifndef WEBCC_HTTP_REQUEST_PARSER_H_ -#define WEBCC_HTTP_REQUEST_PARSER_H_ +#ifndef WEBCC_REQUEST_PARSER_H_ +#define WEBCC_REQUEST_PARSER_H_ #include -#include "webcc/http_parser.h" +#include "webcc/parser.h" namespace webcc { -class HttpRequest; +class Request; -class HttpRequestParser : public HttpParser { +class RequestParser : public Parser { public: - explicit HttpRequestParser(HttpRequest* request = nullptr); + explicit RequestParser(Request* request = nullptr); - ~HttpRequestParser() override = default; + ~RequestParser() override = default; - void Init(HttpRequest* request); + void Init(Request* request); private: bool ParseStartLine(const std::string& line) final; @@ -33,7 +33,7 @@ private: bool IsBoundaryEnd(const std::string& line) const; private: - HttpRequest* request_; + Request* request_; enum Step { kStart, @@ -48,4 +48,4 @@ private: } // namespace webcc -#endif // WEBCC_HTTP_REQUEST_PARSER_H_ +#endif // WEBCC_REQUEST_PARSER_H_ diff --git a/webcc/http_response.cc b/webcc/response.cc similarity index 68% rename from webcc/http_response.cc rename to webcc/response.cc index dbc1739..aa247a7 100644 --- a/webcc/http_response.cc +++ b/webcc/response.cc @@ -1,4 +1,4 @@ -#include "webcc/http_response.h" +#include "webcc/response.h" #include "webcc/utility.h" @@ -20,34 +20,34 @@ const std::string SERVICE_UNAVAILABLE = "HTTP/1.1 503 Service Unavailable"; const std::string& ToString(int status) { switch (status) { - case http::Status::kOK: + case Status::kOK: return OK; - case http::Status::kCreated: + case Status::kCreated: return CREATED; - case http::Status::kAccepted: + case Status::kAccepted: return ACCEPTED; - case http::Status::kNoContent: + case Status::kNoContent: return NO_CONTENT; - case http::Status::kNotModified: + case Status::kNotModified: return NOT_MODIFIED; - case http::Status::kBadRequest: + case Status::kBadRequest: return BAD_REQUEST; - case http::Status::kNotFound: + case Status::kNotFound: return NOT_FOUND; - case http::Status::kInternalServerError: + case Status::kInternalServerError: return INTERNAL_SERVER_ERROR; - case http::Status::kNotImplemented: + case Status::kNotImplemented: return NOT_IMPLEMENTED; - case http::Status::kServiceUnavailable: + case Status::kServiceUnavailable: return SERVICE_UNAVAILABLE; default: @@ -57,15 +57,15 @@ const std::string& ToString(int status) { } // namespace status_strings -void HttpResponse::Prepare() { +void Response::Prepare() { if (start_line_.empty()) { start_line_ = status_strings::ToString(status_); } - SetHeader(http::headers::kServer, http::UserAgent()); - SetHeader(http::headers::kDate, GetHttpDateTimestamp()); + SetHeader(headers::kServer, UserAgent()); + SetHeader(headers::kDate, GetTimestamp()); - HttpMessage::Prepare(); + Message::Prepare(); } } // namespace webcc diff --git a/webcc/response.h b/webcc/response.h new file mode 100644 index 0000000..9b4345e --- /dev/null +++ b/webcc/response.h @@ -0,0 +1,39 @@ +#ifndef WEBCC_RESPONSE_H_ +#define WEBCC_RESPONSE_H_ + +#include +#include + +#include "webcc/message.h" + +namespace webcc { + +class Response; +using ResponsePtr = std::shared_ptr; + +class Response : public Message { +public: + explicit Response(Status status = Status::kOK) + : status_(status) { + } + + ~Response() override = default; + + int status() const { + return status_; + } + + void set_status(int status) { + status_ = status; + } + + // Set start line according to status code. + void Prepare() final; + +private: + int status_; +}; + +} // namespace webcc + +#endif // WEBCC_RESPONSE_H_ diff --git a/webcc/http_response_parser.cc b/webcc/response_parser.cc similarity index 64% rename from webcc/http_response_parser.cc rename to webcc/response_parser.cc index c9f94fd..31246a6 100644 --- a/webcc/http_response_parser.cc +++ b/webcc/response_parser.cc @@ -1,22 +1,22 @@ -#include "webcc/http_response_parser.h" +#include "webcc/response_parser.h" #include "boost/algorithm/string.hpp" -#include "webcc/http_response.h" +#include "webcc/response.h" #include "webcc/logger.h" namespace webcc { -HttpResponseParser::HttpResponseParser(HttpResponse* response) - : HttpParser(response), response_(response) { +ResponseParser::ResponseParser(Response* response) + : Parser(response), response_(response) { } -void HttpResponseParser::Init(HttpResponse* response) { - HttpParser::Init(response); +void ResponseParser::Init(Response* response) { + Parser::Init(response); response_ = response; } -bool HttpResponseParser::ParseStartLine(const std::string& line) { +bool ResponseParser::ParseStartLine(const std::string& line) { std::vector parts; boost::split(parts, line, boost::is_any_of(" "), boost::token_compress_on); diff --git a/webcc/response_parser.h b/webcc/response_parser.h new file mode 100644 index 0000000..83717f5 --- /dev/null +++ b/webcc/response_parser.h @@ -0,0 +1,30 @@ +#ifndef WEBCC_RESPONSE_PARSER_H_ +#define WEBCC_RESPONSE_PARSER_H_ + +#include + +#include "webcc/parser.h" + +namespace webcc { + +class Response; + +class ResponseParser : public Parser { +public: + explicit ResponseParser(Response* response = nullptr); + + ~ResponseParser() override = default; + + void Init(Response* response); + +private: + // Parse HTTP start line; E.g., "HTTP/1.1 200 OK". + bool ParseStartLine(const std::string& line) final; + + // The result response message. + Response* response_; +}; + +} // namespace webcc + +#endif // WEBCC_RESPONSE_PARSER_H_ diff --git a/webcc/rest_request_handler.cc b/webcc/rest_request_handler.cc index a1581f5..7ad1804 100644 --- a/webcc/rest_request_handler.cc +++ b/webcc/rest_request_handler.cc @@ -14,8 +14,8 @@ bool RestRequestHandler::Bind(RestServicePtr service, const std::string& url, return service_manager_.AddService(service, url, is_regex); } -void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) { - HttpRequestPtr http_request = connection->request(); +void RestRequestHandler::HandleConnection(ConnectionPtr connection) { + RequestPtr http_request = connection->request(); assert(http_request); const Url& url = http_request->url(); @@ -28,14 +28,14 @@ void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) { if (!service) { LOG_WARN("No service matches the URL path: %s", url.path().c_str()); - connection->SendResponse(http::Status::kNotFound); + connection->SendResponse(Status::kNotFound); return; } RestResponse rest_response; service->Handle(rest_request, &rest_response); - auto http_response = std::make_shared(rest_response.status); + auto http_response = std::make_shared(rest_response.status); if (!rest_response.content.empty()) { if (!rest_response.media_type.empty()) { @@ -48,7 +48,7 @@ void RestRequestHandler::HandleConnection(HttpConnectionPtr connection) { http_request->AcceptEncodingGzip()) { std::string compressed; if (Compress(rest_response.content, &compressed)) { - http_response->SetHeader(http::headers::kContentEncoding, "gzip"); + http_response->SetHeader(headers::kContentEncoding, "gzip"); http_response->SetContent(std::move(compressed), true); } } else { diff --git a/webcc/rest_request_handler.h b/webcc/rest_request_handler.h index f07afc6..1854e11 100644 --- a/webcc/rest_request_handler.h +++ b/webcc/rest_request_handler.h @@ -5,12 +5,12 @@ #include -#include "webcc/http_request_handler.h" +#include "webcc/request_handler.h" #include "webcc/rest_service_manager.h" namespace webcc { -class RestRequestHandler : public HttpRequestHandler { +class RestRequestHandler : public RequestHandler { public: RestRequestHandler() = default; @@ -19,7 +19,7 @@ public: bool Bind(RestServicePtr service, const std::string& url, bool is_regex); private: - void HandleConnection(HttpConnectionPtr connection) final; + void HandleConnection(ConnectionPtr connection) final; private: RestServiceManager service_manager_; diff --git a/webcc/rest_server.h b/webcc/rest_server.h index 330cfb2..3111d85 100644 --- a/webcc/rest_server.h +++ b/webcc/rest_server.h @@ -5,16 +5,16 @@ #include -#include "webcc/http_server.h" +#include "webcc/server.h" #include "webcc/rest_request_handler.h" #include "webcc/rest_service.h" namespace webcc { -class RestServer : public HttpServer { +class RestServer : public Server { public: RestServer(std::uint16_t port, std::size_t workers) - : HttpServer(port, workers) { + : Server(port, workers) { } ~RestServer() override = default; @@ -32,7 +32,7 @@ public: } private: - HttpRequestHandler* GetRequestHandler() final { + RequestHandler* GetRequestHandler() final { return &request_handler_; } diff --git a/webcc/rest_service.cc b/webcc/rest_service.cc index 4ec0086..09199f8 100644 --- a/webcc/rest_service.cc +++ b/webcc/rest_service.cc @@ -10,10 +10,10 @@ void RestListService::Handle(const RestRequest& request, RestResponse* response) { const std::string& method = request.http->method(); - if (method == http::methods::kGet) { + if (method == methods::kGet) { Get(UrlQuery(request.http->url().query()), response); - } else if (method == http::methods::kPost) { + } else if (method == methods::kPost) { Post(request.http->content(), response); } else { @@ -27,16 +27,16 @@ void RestDetailService::Handle(const RestRequest& request, RestResponse* response) { const std::string& method = request.http->method(); - if (method == http::methods::kGet) { + if (method == methods::kGet) { Get(request.url_matches, UrlQuery(request.http->url().query()), response); - } else if (method == http::methods::kPut) { + } else if (method == methods::kPut) { Put(request.url_matches, request.http->content(), response); - } else if (method == http::methods::kPatch) { + } else if (method == methods::kPatch) { Patch(request.url_matches, request.http->content(), response); - } else if (method == http::methods::kDelete) { + } else if (method == methods::kDelete) { Delete(request.url_matches, response); } else { diff --git a/webcc/rest_service.h b/webcc/rest_service.h index bf04233..5160cbf 100644 --- a/webcc/rest_service.h +++ b/webcc/rest_service.h @@ -14,7 +14,7 @@ #include #include "webcc/globals.h" -#include "webcc/http_request.h" +#include "webcc/request.h" #include "webcc/url.h" namespace webcc { @@ -22,18 +22,18 @@ namespace webcc { // ----------------------------------------------------------------------------- // Regex sub-matches of the URL. -typedef std::vector UrlMatches; +using UrlMatches = std::vector; struct RestRequest { // Original HTTP request. - HttpRequestPtr http; + RequestPtr http; // Regex sub-matches of the URL (usually resource ID's). UrlMatches url_matches; }; struct RestResponse { - http::Status status; + Status status; std::string content; @@ -52,7 +52,7 @@ public: virtual void Handle(const RestRequest& request, RestResponse* response) = 0; }; -typedef std::shared_ptr RestServicePtr; +using RestServicePtr = std::shared_ptr; // ----------------------------------------------------------------------------- diff --git a/webcc/http_server.cc b/webcc/server.cc similarity index 90% rename from webcc/http_server.cc rename to webcc/server.cc index d708aed..00e79a0 100644 --- a/webcc/http_server.cc +++ b/webcc/server.cc @@ -1,9 +1,9 @@ -#include "webcc/http_server.h" +#include "webcc/server.h" #include #include -#include "webcc/http_request_handler.h" +#include "webcc/request_handler.h" #include "webcc/logger.h" #include "webcc/utility.h" @@ -11,7 +11,7 @@ using tcp = boost::asio::ip::tcp; namespace webcc { -HttpServer::HttpServer(std::uint16_t port, std::size_t workers) +Server::Server(std::uint16_t port, std::size_t workers) : acceptor_(io_context_), signals_(io_context_), workers_(workers) { RegisterSignals(); @@ -50,7 +50,7 @@ HttpServer::HttpServer(std::uint16_t port, std::size_t workers) } } -void HttpServer::Run() { +void Server::Run() { assert(GetRequestHandler() != nullptr); if (!acceptor_.is_open()) { @@ -74,7 +74,7 @@ void HttpServer::Run() { io_context_.run(); } -void HttpServer::RegisterSignals() { +void Server::RegisterSignals() { signals_.add(SIGINT); // Ctrl+C signals_.add(SIGTERM); @@ -83,7 +83,7 @@ void HttpServer::RegisterSignals() { #endif } -void HttpServer::DoAccept() { +void Server::DoAccept() { acceptor_.async_accept( [this](boost::system::error_code ec, tcp::socket socket) { // Check whether the server was stopped by a signal before this @@ -95,7 +95,7 @@ void HttpServer::DoAccept() { if (!ec) { LOG_INFO("Accepted a connection."); - auto connection = std::make_shared( + auto connection = std::make_shared( std::move(socket), &pool_, GetRequestHandler()); pool_.Start(connection); @@ -105,7 +105,7 @@ void HttpServer::DoAccept() { }); } -void HttpServer::DoAwaitStop() { +void Server::DoAwaitStop() { signals_.async_wait( [this](boost::system::error_code, int signo) { // The server is stopped by canceling all outstanding asynchronous diff --git a/webcc/http_server.h b/webcc/server.h similarity index 69% rename from webcc/http_server.h rename to webcc/server.h index 48580d5..1170333 100644 --- a/webcc/http_server.h +++ b/webcc/server.h @@ -1,5 +1,5 @@ -#ifndef WEBCC_HTTP_SERVER_H_ -#define WEBCC_HTTP_SERVER_H_ +#ifndef WEBCC_SERVER_H_ +#define WEBCC_SERVER_H_ #include @@ -8,23 +8,23 @@ #include "boost/asio/signal_set.hpp" #include "webcc/globals.h" -#include "webcc/http_connection.h" -#include "webcc/http_connection_pool.h" +#include "webcc/connection.h" +#include "webcc/connection_pool.h" namespace webcc { -class HttpRequestHandler; +class RequestHandler; // HTTP server accepts TCP connections from TCP clients. // NOTE: Only support IPv4. -class HttpServer { +class Server { public: - HttpServer(std::uint16_t port, std::size_t workers); + Server(std::uint16_t port, std::size_t workers); - virtual ~HttpServer() = default; + virtual ~Server() = default; - HttpServer(const HttpServer&) = delete; - HttpServer& operator=(const HttpServer&) = delete; + Server(const Server&) = delete; + Server& operator=(const Server&) = delete; // Run the server's io_service loop. void Run(); @@ -40,7 +40,7 @@ private: void DoAwaitStop(); // Get the handler for incoming requests. - virtual HttpRequestHandler* GetRequestHandler() = 0; + virtual RequestHandler* GetRequestHandler() = 0; // The io_context used to perform asynchronous operations. boost::asio::io_context io_context_; @@ -49,7 +49,7 @@ private: boost::asio::ip::tcp::acceptor acceptor_; // The connection pool which owns all live connections. - HttpConnectionPool pool_; + ConnectionPool pool_; // The signal_set is used to register for process termination notifications. boost::asio::signal_set signals_; @@ -60,4 +60,4 @@ private: } // namespace webcc -#endif // WEBCC_HTTP_SERVER_H_ +#endif // WEBCC_SERVER_H_ diff --git a/webcc/http_socket.cc b/webcc/socket.cc similarity index 66% rename from webcc/http_socket.cc rename to webcc/socket.cc index db417ff..493c100 100644 --- a/webcc/http_socket.cc +++ b/webcc/socket.cc @@ -1,4 +1,4 @@ -#include "webcc/http_socket.h" +#include "webcc/socket.h" #include "boost/asio/connect.hpp" #include "boost/asio/read.hpp" @@ -10,26 +10,26 @@ namespace webcc { // ----------------------------------------------------------------------------- -HttpSocket::HttpSocket(boost::asio::io_context& io_context) +Socket::Socket(boost::asio::io_context& io_context) : socket_(io_context) { } -void HttpSocket::Connect(const std::string& /*host*/, +void Socket::Connect(const std::string& /*host*/, const Endpoints& endpoints, boost::system::error_code* ec) { boost::asio::connect(socket_, endpoints, *ec); } -void HttpSocket::Write(const HttpRequest& request, +void Socket::Write(const Request& request, boost::system::error_code* ec) { boost::asio::write(socket_, request.payload(), *ec); } -void HttpSocket::AsyncReadSome(ReadHandler&& handler, std::vector* buffer) { +void Socket::AsyncReadSome(ReadHandler&& handler, std::vector* buffer) { socket_.async_read_some(boost::asio::buffer(*buffer), std::move(handler)); } -void HttpSocket::Close(boost::system::error_code* ec) { +void Socket::Close(boost::system::error_code* ec) { socket_.close(*ec); } @@ -39,8 +39,7 @@ void HttpSocket::Close(boost::system::error_code* ec) { namespace ssl = boost::asio::ssl; -HttpSslSocket::HttpSslSocket(boost::asio::io_context& io_context, - bool ssl_verify) +SslSocket::SslSocket(boost::asio::io_context& io_context, bool ssl_verify) : ssl_context_(ssl::context::sslv23), ssl_socket_(io_context, ssl_context_), ssl_verify_(ssl_verify) { @@ -48,9 +47,8 @@ HttpSslSocket::HttpSslSocket(boost::asio::io_context& io_context, ssl_context_.set_default_verify_paths(); } -void HttpSslSocket::Connect(const std::string& host, - const Endpoints& endpoints, - boost::system::error_code* ec) { +void SslSocket::Connect(const std::string& host, const Endpoints& endpoints, + boost::system::error_code* ec) { boost::asio::connect(ssl_socket_.lowest_layer(), endpoints, *ec); if (*ec) { @@ -60,21 +58,21 @@ void HttpSslSocket::Connect(const std::string& host, Handshake(host, ec); } -void HttpSslSocket::Write(const HttpRequest& request, - boost::system::error_code* ec) { +void SslSocket::Write(const Request& request, boost::system::error_code* ec) { boost::asio::write(ssl_socket_, request.payload(), *ec); } -void HttpSslSocket::AsyncReadSome(ReadHandler&& handler, std::vector* buffer) { +void SslSocket::AsyncReadSome(ReadHandler&& handler, + std::vector* buffer) { ssl_socket_.async_read_some(boost::asio::buffer(*buffer), std::move(handler)); } -void HttpSslSocket::Close(boost::system::error_code* ec) { +void SslSocket::Close(boost::system::error_code* ec) { ssl_socket_.lowest_layer().close(*ec); } -void HttpSslSocket::Handshake(const std::string& host, - boost::system::error_code* ec) { +void SslSocket::Handshake(const std::string& host, + boost::system::error_code* ec) { if (ssl_verify_) { ssl_socket_.set_verify_mode(ssl::verify_peer); } else { diff --git a/webcc/http_socket.h b/webcc/socket.h similarity index 72% rename from webcc/http_socket.h rename to webcc/socket.h index ef9ce05..da80cd7 100644 --- a/webcc/http_socket.h +++ b/webcc/socket.h @@ -1,12 +1,12 @@ -#ifndef WEBCC_HTTP_SOCKET_H_ -#define WEBCC_HTTP_SOCKET_H_ +#ifndef WEBCC_SOCKET_H_ +#define WEBCC_SOCKET_H_ #include #include "boost/asio/ip/tcp.hpp" #include "webcc/config.h" -#include "webcc/http_request.h" +#include "webcc/request.h" #if WEBCC_ENABLE_SSL #include "boost/asio/ssl.hpp" @@ -16,21 +16,21 @@ namespace webcc { // ----------------------------------------------------------------------------- -class HttpSocketBase { +class SocketBase { public: - virtual ~HttpSocketBase() = default; + virtual ~SocketBase() = default; - typedef boost::asio::ip::tcp::resolver::results_type Endpoints; + using Endpoints = boost::asio::ip::tcp::resolver::results_type; - typedef std::function - ReadHandler; + using ReadHandler = + std::function; // TODO: Remove |host| virtual void Connect(const std::string& host, const Endpoints& endpoints, boost::system::error_code* ec) = 0; - virtual void Write(const HttpRequest& request, + virtual void Write(const Request& request, boost::system::error_code* ec) = 0; virtual void AsyncReadSome(ReadHandler&& handler, @@ -41,15 +41,15 @@ public: // ----------------------------------------------------------------------------- -class HttpSocket : public HttpSocketBase { +class Socket : public SocketBase { public: - explicit HttpSocket(boost::asio::io_context& io_context); + explicit Socket(boost::asio::io_context& io_context); void Connect(const std::string& host, const Endpoints& endpoints, boost::system::error_code* ec) final; - void Write(const HttpRequest& request, + void Write(const Request& request, boost::system::error_code* ec) final; void AsyncReadSome(ReadHandler&& handler, std::vector* buffer) final; @@ -64,16 +64,16 @@ private: #if WEBCC_ENABLE_SSL -class HttpSslSocket : public HttpSocketBase { +class SslSocket : public SocketBase { public: - explicit HttpSslSocket(boost::asio::io_context& io_context, - bool ssl_verify = true); + explicit SslSocket(boost::asio::io_context& io_context, + bool ssl_verify = true); void Connect(const std::string& host, const Endpoints& endpoints, boost::system::error_code* ec) final; - void Write(const HttpRequest& request, + void Write(const Request& request, boost::system::error_code* ec) final; void AsyncReadSome(ReadHandler&& handler, std::vector* buffer) final; @@ -95,4 +95,4 @@ private: } // namespace webcc -#endif // WEBCC_HTTP_SOCKET_H_ +#endif // WEBCC_SOCKET_H_ diff --git a/webcc/url.h b/webcc/url.h index f7bc80f..310b11d 100644 --- a/webcc/url.h +++ b/webcc/url.h @@ -16,8 +16,8 @@ namespace webcc { // URL query parameters. class UrlQuery { public: - typedef std::pair Parameter; - typedef std::vector Parameters; + using Parameter = std::pair; + using Parameters = std::vector; UrlQuery() = default; @@ -47,7 +47,7 @@ public: std::string ToString() const; private: - typedef Parameters::const_iterator ConstIterator; + using ConstIterator = Parameters::const_iterator; ConstIterator Find(const std::string& key) const; Parameters parameters_; diff --git a/webcc/utility.cc b/webcc/utility.cc index 75b65bd..99580d6 100644 --- a/webcc/utility.cc +++ b/webcc/utility.cc @@ -1,52 +1,12 @@ #include "webcc/utility.h" -#include -#include -#include // for put_time -#include #include #include "boost/uuid/random_generator.hpp" #include "boost/uuid/uuid_io.hpp" -#include "webcc/logger.h" - -using tcp = boost::asio::ip::tcp; - namespace webcc { -void PrintEndpoint(std::ostream& ostream, const TcpEndpoint& endpoint) { - ostream << endpoint; - if (endpoint.protocol() == tcp::v4()) { - ostream << ", v4"; - } else if (endpoint.protocol() == tcp::v6()) { - ostream << ", v6"; - } -} - -void PrintEndpoints(std::ostream& ostream, const TcpEndpoints& endpoints) { - ostream << "Endpoints: " << endpoints.size() << std::endl; - tcp::resolver::results_type::iterator it = endpoints.begin(); - for (; it != endpoints.end(); ++it) { - ostream << " - "; - PrintEndpoint(ostream, it->endpoint()); - ostream << std::endl; - } -} - -std::string EndpointToString(const TcpEndpoint& endpoint) { - std::stringstream ss; - PrintEndpoint(ss, endpoint); - return ss.str(); -} - -std::string GetHttpDateTimestamp() { - std::time_t t = std::time(nullptr); - std::stringstream ss; - ss << std::put_time(std::gmtime(&t), "%a, %d %b %Y %H:%M:%S") << " GMT"; - return ss.str(); -} - std::string RandomUuid() { boost::uuids::uuid u = boost::uuids::random_generator()(); std::stringstream ss; diff --git a/webcc/utility.h b/webcc/utility.h index bb91b32..4adca9e 100644 --- a/webcc/utility.h +++ b/webcc/utility.h @@ -4,19 +4,8 @@ #include #include -#include "boost/asio/ip/tcp.hpp" - namespace webcc { -typedef boost::asio::ip::tcp::endpoint TcpEndpoint; -typedef boost::asio::ip::tcp::resolver::results_type TcpEndpoints; - -void PrintEndpoint(std::ostream& ostream, const TcpEndpoint& endpoint); - -void PrintEndpoints(std::ostream& ostream, const TcpEndpoints& endpoints); - -std::string EndpointToString(const TcpEndpoint& endpoint); - // Get the timestamp for HTTP Date header field. // E.g., Wed, 21 Oct 2015 07:28:00 GMT // See: https://tools.ietf.org/html/rfc7231#section-7.1.1.2