diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b1742c..3d7faa7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -118,48 +118,17 @@ endif() add_subdirectory(webcc) if(WEBCC_ENABLE_EXAMPLES) - # Common libraries to link for examples. - set(EXAMPLE_COMMON_LIBS webcc ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} - "${CMAKE_THREAD_LIBS_INIT}") - if(WIN32) - set(EXAMPLE_COMMON_LIBS ${EXAMPLE_COMMON_LIBS} crypt32) - endif() - if(UNIX) - # Add `-ldl` for Linux to avoid "undefined reference to `dlopen'". - set(EXAMPLE_COMMON_LIBS ${EXAMPLE_COMMON_LIBS} ${CMAKE_DL_LIBS}) - endif() - - add_subdirectory(example/http_client) - # add_subdirectory(example/http_async_client) - if(WEBCC_ENABLE_REST) # For including jsoncpp as "json/json.h". include_directories(${THIRD_PARTY_DIR}/src/jsoncpp) # REST examples need jsoncpp to parse and create JSON. add_subdirectory(${THIRD_PARTY_DIR}/src/jsoncpp) - - add_subdirectory(example/rest_book_server) - # add_subdirectory(example/rest_book_client) - # add_subdirectory(example/rest_book_async_client) endif() - if(WEBCC_ENABLE_SOAP) - add_subdirectory(example/soap_calc_server) - add_subdirectory(example/soap_calc_client) - add_subdirectory(example/soap_calc_client_parasoft) - add_subdirectory(example/soap_book_server) - add_subdirectory(example/soap_book_client) - endif() - - add_subdirectory(example/http_ssl_client) - # add_subdirectory(example/http_ssl_async_client) - - if(WEBCC_ENABLE_REST) - # add_subdirectory(example/github_rest_client) - endif() + add_subdirectory(example) endif() if(WEBCC_ENABLE_UNITTEST) - add_subdirectory(third_party/src/gtest) + add_subdirectory(${THIRD_PARTY_DIR}/src/gtest) add_subdirectory(unittest) endif() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..dc827a6 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,33 @@ +# Examples + +# Common libraries to link for examples. +set(EXAMPLE_COMMON_LIBS webcc ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES} + "${CMAKE_THREAD_LIBS_INIT}") +if(WIN32) + set(EXAMPLE_COMMON_LIBS ${EXAMPLE_COMMON_LIBS} crypt32) +endif() + +if(UNIX) + # Add `-ldl` for Linux to avoid "undefined reference to `dlopen'". + set(EXAMPLE_COMMON_LIBS ${EXAMPLE_COMMON_LIBS} ${CMAKE_DL_LIBS}) +endif() + +add_subdirectory(http_client) + +if(WEBCC_ENABLE_REST) + add_subdirectory(rest_book_server) + # add_subdirectory(rest_book_client) + add_subdirectory(github_client) +endif() + +if(WEBCC_ENABLE_SOAP) + add_subdirectory(soap_calc_server) + add_subdirectory(soap_book_server) + add_subdirectory(soap_book_client) +endif() + +add_executable(soap_calc_client soap_calc_client.cc) +add_executable(soap_calc_client_parasoft soap_calc_client_parasoft.cc) + +target_link_libraries(soap_calc_client ${EXAMPLE_COMMON_LIBS} pugixml) +target_link_libraries(soap_calc_client_parasoft ${EXAMPLE_COMMON_LIBS} pugixml) diff --git a/example/HttpBin.md b/example/HttpBin.md deleted file mode 100644 index 766bdfe..0000000 --- a/example/HttpBin.md +++ /dev/null @@ -1,36 +0,0 @@ -HttpBin (http://httpbin.org/) client example. - -You request to different endpoints, and it returns information about what was in the request. - -E.g., request: -```plain -GET /get HTTP/1.1 -Host: httpbin.org:80 -User-Agent: Webcc/0.1.0 - -``` - -Response: -```plain -HTTP/1.1 200 OK -Connection: keep-alive -Server: gunicorn/19.9.0 -Content-Type: application/json -Content-Length: 191 -Access-Control-Allow-Origin: * -Access-Control-Allow-Credentials: true -Via: 1.1 vegur - -{ - "args": {}, - "headers": { - "Connection": "close", - "Host": "httpbin.org", - "User-Agent": "Webcc/0.1.0" - }, - "origin": "198.55.94.81", - "url": "http://httpbin.org/get" -} -``` - -As you can see, the request information is returned in JSON format. diff --git a/example/common/book.h b/example/common/book.h index 8d47da9..f17b886 100644 --- a/example/common/book.h +++ b/example/common/book.h @@ -20,7 +20,7 @@ std::ostream& operator<<(std::ostream& os, const Book& book); extern const Book kNullBook; class BookStore { - public: +public: const std::list& books() const { return books_; } const Book& GetBook(const std::string& id) const; @@ -33,7 +33,7 @@ class BookStore { bool DeleteBook(const std::string& id); - private: +private: std::list::const_iterator FindBook(const std::string& id) const; std::list::iterator FindBook(const std::string& id); diff --git a/example/github_client/CMakeLists.txt b/example/github_client/CMakeLists.txt new file mode 100644 index 0000000..2384bca --- /dev/null +++ b/example/github_client/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(github_client main.cc) +target_link_libraries(github_client ${EXAMPLE_COMMON_LIBS} jsoncpp) diff --git a/example/github_rest_client/main.cc b/example/github_client/main.cc similarity index 55% rename from example/github_rest_client/main.cc rename to example/github_client/main.cc index 975bf9e..834c3c7 100644 --- a/example/github_rest_client/main.cc +++ b/example/github_client/main.cc @@ -3,8 +3,8 @@ #include "json/json.h" +#include "webcc/http_client_session.h" #include "webcc/logger.h" -#include "webcc/rest_ssl_client.h" // ----------------------------------------------------------------------------- @@ -19,7 +19,7 @@ bool kSslVerify = false; bool kSslVerify = true; #endif -const std::string kGithubHost = "api.github.com"; +const std::size_t kBufferSize = 1500; // ----------------------------------------------------------------------------- @@ -57,43 +57,48 @@ static void PrettyPrintJsonString(const std::string& str) { #define PRINT_JSON_STRING(str) #endif // PRINT_RESPONSE -static void PrintError(const webcc::RestSslClient& client) { - std::cout << webcc::DescribeError(client.error()); - if (client.timed_out()) { - std::cout << " (timed out)"; - } - std::cout << std::endl; -} - -// ----------------------------------------------------------------------------- - -// List public events. -static void ListEvents(webcc::RestSslClient& client) { - if (client.Get("/events")) { - PRINT_JSON_STRING(client.response_content()); - } else { - PrintError(client); - } -} - -// List the followers of the given user. -static void ListUserFollowers(webcc::RestSslClient& client, - const std::string& user) { - if (client.Get("/users/" + user + "/followers")) { - PRINT_JSON_STRING(client.response_content()); - } else { - PrintError(client); - } -} +//static void PrintError(const webcc::RestSslClient& client) { +// std::cout << webcc::DescribeError(client.error()); +// if (client.timed_out()) { +// std::cout << " (timed out)"; +// } +// std::cout << std::endl; +//} +// +//// ----------------------------------------------------------------------------- +// +//// List public events. +//static void ListEvents(webcc::RestSslClient& client) { +// if (client.Get("/events")) { +// PRINT_JSON_STRING(client.response_content()); +// } else { +// PrintError(client); +// } +//} +// +//// List the followers of the given user. +//static void ListUserFollowers(webcc::RestSslClient& client, +// const std::string& user) { +// if (client.Get("/users/" + user + "/followers")) { +// PRINT_JSON_STRING(client.response_content()); +// } else { +// PrintError(client); +// } +//} // List the followers of the current authorized user. // Header syntax: Authorization: -static void ListAuthorizedUserFollowers(webcc::RestSslClient& client, +static void ListAuthorizedUserFollowers(webcc::HttpClientSession& session, const std::string& auth) { - if (client.Get("/user/followers", { { "Authorization", auth } })) { - PRINT_JSON_STRING(client.response_content()); + auto r = session.Request(webcc::HttpRequestArgs("GET"). + url("https://api.github.com/user/followers"). + headers({ { "Authorization", auth } }). + ssl_verify(kSslVerify).buffer_size(kBufferSize)); + + if (r) { + PRINT_JSON_STRING(r->content()); } else { - PrintError(client); + //PrintError(client); } } @@ -102,10 +107,10 @@ static void ListAuthorizedUserFollowers(webcc::RestSslClient& client, int main() { WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - webcc::RestSslClient client(kGithubHost, "", kSslVerify, {}, 1500); + webcc::HttpClientSession session; //ListAuthorizedUserFollowers(client, "Basic c3ByaW5mYWxsQGdtYWlsLmNvbTpYaWFvTHVhbjFA"); - ListAuthorizedUserFollowers(client, "Token 1d42e2cce49929f2d24b1b6e96260003e5b3e1b0"); + ListAuthorizedUserFollowers(session, "Token 1d42e2cce49929f2d24b1b6e96260003e5b3e1b0"); return 0; } diff --git a/example/github_rest_client/CMakeLists.txt b/example/github_rest_client/CMakeLists.txt deleted file mode 100644 index 837856a..0000000 --- a/example/github_rest_client/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_executable(github_rest_client main.cc) -target_link_libraries(github_rest_client ${EXAMPLE_COMMON_LIBS} jsoncpp) diff --git a/example/http_async_client/CMakeLists.txt b/example/http_async_client/CMakeLists.txt deleted file mode 100644 index 819bd02..0000000 --- a/example/http_async_client/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -add_executable(http_async_client main.cc) - -target_link_libraries(http_async_client webcc ${Boost_LIBRARIES}) -target_link_libraries(http_async_client "${CMAKE_THREAD_LIBS_INIT}") diff --git a/example/http_async_client/main.cc b/example/http_async_client/main.cc deleted file mode 100644 index f2555f0..0000000 --- a/example/http_async_client/main.cc +++ /dev/null @@ -1,47 +0,0 @@ -#include - -#include "boost/asio/io_context.hpp" - -#include "webcc/http_async_client.h" -#include "webcc/logger.h" - -// TODO: The program blocks during read response. -// Only HttpBin.org has this issue. - -static void Test(boost::asio::io_context& io_context) { - auto request = webcc::HttpRequest::New(webcc::kHttpGet, "/get", - "httpbin.org"); - - auto client = webcc::HttpAsyncClient::New(io_context); - - client->SetTimeout(3); - - // Response callback. - auto callback = [](webcc::HttpResponsePtr response, webcc::Error error, - bool timed_out) { - if (error == webcc::kNoError) { - std::cout << response->content() << std::endl; - } else { - std::cout << DescribeError(error); - if (timed_out) { - std::cout << " (timed out)"; - } - std::cout << std::endl; - } - }; - - client->Request(request, callback); -} - -int main() { - WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - - boost::asio::io_context io_context; - - //Test(io_context); - Test(io_context); - - io_context.run(); - - return 0; -} diff --git a/example/http_client/main.cc b/example/http_client/main.cc index 4ab2310..f7b96d0 100644 --- a/example/http_client/main.cc +++ b/example/http_client/main.cc @@ -3,6 +3,14 @@ #include "webcc/http_client_session.h" #include "webcc/logger.h" +void GetBoostOrgLicense(webcc::HttpClientSession& session) { + auto r = session.Get("https://www.boost.org/LICENSE_1_0.txt"); + + if (r) { + std::cout << r->content() << std::endl; + } +} + int main() { WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); @@ -29,21 +37,21 @@ int main() { // - constructor: HttpRequestArgs{ "GET" } // - move constructor: auto args = ... - auto args = HttpRequestArgs{"GET"}. - url("http://httpbin.org/get"). - parameters({ "key1", "value1", "key2", "value2" }). - headers({ "Accept", "application/json" }). - buffer_size(1000); + //auto args = HttpRequestArgs{"GET"}. + // url("http://httpbin.org/get"). + // parameters({ "key1", "value1", "key2", "value2" }). + // headers({ "Accept", "application/json" }). + // buffer_size(1000); - r = session.Request(std::move(args)); + //r = session.Request(std::move(args)); // --------------------------------------------------------------------------- // Use pre-defined wrappers. - r = session.Get("http://httpbin.org/get", - { "key1", "value1", "key2", "value2" }, - { "Accept", "application/json" }, - HttpRequestArgs{}.buffer_size(1000)); + //r = session.Get("http://httpbin.org/get", + // { "key1", "value1", "key2", "value2" }, + // { "Accept", "application/json" }, + // HttpRequestArgs{}.buffer_size(1000)); // --------------------------------------------------------------------------- // HTTPS is auto-detected from the URL schema. @@ -56,5 +64,7 @@ int main() { std::cout << r->content() << std::endl; } + GetBoostOrgLicense(session); + return 0; } diff --git a/example/http_ssl_async_client/CMakeLists.txt b/example/http_ssl_async_client/CMakeLists.txt deleted file mode 100644 index e85b0e7..0000000 --- a/example/http_ssl_async_client/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -add_executable(http_ssl_async_client main.cc) - -# TODO -set(SSL_LIBS ${OPENSSL_LIBRARIES}) -if(WIN32) - set(SSL_LIBS ${SSL_LIBS} crypt32) -endif() - -target_link_libraries(http_ssl_async_client webcc ${Boost_LIBRARIES}) -target_link_libraries(http_ssl_async_client "${CMAKE_THREAD_LIBS_INIT}") -target_link_libraries(http_ssl_async_client ${SSL_LIBS}) diff --git a/example/http_ssl_async_client/main.cc b/example/http_ssl_async_client/main.cc deleted file mode 100644 index 55b8d6c..0000000 --- a/example/http_ssl_async_client/main.cc +++ /dev/null @@ -1,56 +0,0 @@ -#include - -#include "boost/asio/io_context.hpp" - -#include "webcc/http_ssl_async_client.h" -#include "webcc/logger.h" - -int main(int argc, char* argv[]) { - std::string host; - std::string url; - - if (argc != 3) { - host = "www.boost.org"; - url = "/LICENSE_1_0.txt"; - } else { - host = argv[1]; - url = argv[2]; - } - - std::cout << "Host: " << host << std::endl; - std::cout << "URL: " << url << std::endl; - std::cout << std::endl; - - WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - - boost::asio::io_context io_context; - - // Leave port to default value. - auto request = webcc::HttpRequest::New(webcc::kHttpGet, url, host); - - // Verify the certificate of the peer or not. - // See HttpSslClient::Request() for more details. - bool ssl_verify = false; - - auto client = webcc::HttpSslAsyncClient::New(io_context, 2000, ssl_verify); - - // Response callback. - auto callback = [](webcc::HttpResponsePtr response, webcc::Error error, - bool timed_out) { - if (error == webcc::kNoError) { - std::cout << response->content() << std::endl; - } else { - std::cout << DescribeError(error); - if (timed_out) { - std::cout << " (timed out)"; - } - std::cout << std::endl; - } - }; - - client->Request(request, callback); - - io_context.run(); - - return 0; -} diff --git a/example/http_ssl_client/CMakeLists.txt b/example/http_ssl_client/CMakeLists.txt deleted file mode 100644 index 5b78664..0000000 --- a/example/http_ssl_client/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_executable(http_ssl_client main.cc) -target_link_libraries(http_ssl_client ${EXAMPLE_COMMON_LIBS}) diff --git a/example/http_ssl_client/main.cc b/example/http_ssl_client/main.cc deleted file mode 100644 index 63762b8..0000000 --- a/example/http_ssl_client/main.cc +++ /dev/null @@ -1,42 +0,0 @@ -#include - -#include "webcc/http_ssl_client.h" -#include "webcc/logger.h" - -int main(int argc, char* argv[]) { - std::string url; - - if (argc != 3) { - url = "www.boost.org/LICENSE_1_0.txt"; - } else { - url = argv[1]; - } - - std::cout << "URL: " << url << std::endl; - std::cout << std::endl; - - WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - - // Leave port to default value. - webcc::HttpRequest request(webcc::http::kGet, url); - - request.Prepare(); - - // Verify the certificate of the peer or not. - // See HttpSslClient::Request() for more details. - bool ssl_verify = false; - - webcc::HttpSslClient client(ssl_verify, 2000); - - if (client.Request(request)) { - //std::cout << client.response()->content() << std::endl; - } else { - std::cout << webcc::DescribeError(client.error()); - if (client.timed_out()) { - std::cout << " (timed out)"; - } - std::cout << std::endl; - } - - return 0; -} diff --git a/example/rest_book_async_client/CMakeLists.txt b/example/rest_book_async_client/CMakeLists.txt deleted file mode 100644 index 5aea03a..0000000 --- a/example/rest_book_async_client/CMakeLists.txt +++ /dev/null @@ -1,13 +0,0 @@ -set(TARGET_NAME rest_book_async_client) - -set(SRCS - ../common/book.cc - ../common/book.h - ../common/book_json.cc - ../common/book_json.h - main.cc) - -add_executable(${TARGET_NAME} ${SRCS}) - -target_link_libraries(${TARGET_NAME} webcc jsoncpp ${Boost_LIBRARIES}) -target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") diff --git a/example/rest_book_async_client/main.cc b/example/rest_book_async_client/main.cc deleted file mode 100644 index 9bb1e45..0000000 --- a/example/rest_book_async_client/main.cc +++ /dev/null @@ -1,194 +0,0 @@ -#include - -#include "json/json.h" - -#include "webcc/logger.h" -#include "webcc/rest_async_client.h" - -#include "example/common/book.h" -#include "example/common/book_json.h" - -// ----------------------------------------------------------------------------- - -class BookClientBase { - public: - BookClientBase(boost::asio::io_context& io_context, - const std::string& host, const std::string& port, - int timeout_seconds) - : rest_client_(io_context, host, port) { - rest_client_.SetTimeout(timeout_seconds); - } - - virtual ~BookClientBase() = default; - - protected: - void PrintSeparateLine() { - std::cout << "--------------------------------"; - std::cout << "--------------------------------"; - std::cout << std::endl; - } - - // Generic response handler for RestAsyncClient APIs. - void GenericHandler(std::function rsp_callback, - webcc::HttpResponsePtr response, - webcc::Error error, - bool timed_out) { - if (error != webcc::kNoError) { - std::cout << webcc::DescribeError(error); - if (timed_out) { - std::cout << " (timed out)"; - } - std::cout << std::endl; - } else { - // Call the response callback on success. - rsp_callback(response); - } - } - - webcc::RestAsyncClient rest_client_; -}; - -// ----------------------------------------------------------------------------- - -class BookListClient : public BookClientBase { - public: - BookListClient(boost::asio::io_context& io_context, - const std::string& host, const std::string& port, - int timeout_seconds) - : BookClientBase(io_context, host, port, timeout_seconds) { - } - - void ListBooks(webcc::HttpResponseCallback callback) { - std::cout << "ListBooks" << std::endl; - - rest_client_.Get("/books", callback); - } - - void CreateBook(const std::string& title, double price, - std::function id_callback) { - std::cout << "CreateBook: " << title << " " << price << std::endl; - - Json::Value json(Json::objectValue); - json["title"] = title; - json["price"] = price; - - auto rsp_callback = [id_callback](webcc::HttpResponsePtr response) { - Json::Value rsp_json = StringToJson(response->content()); - id_callback(rsp_json["id"].asString()); - }; - - rest_client_.Post("/books", JsonToString(json), - std::bind(&BookListClient::GenericHandler, this, - rsp_callback, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3)); - } -}; - -// ----------------------------------------------------------------------------- - -class BookDetailClient : public BookClientBase { - public: - BookDetailClient(boost::asio::io_context& io_context, - const std::string& host, const std::string& port, - int timeout_seconds) - : BookClientBase(io_context, host, port, timeout_seconds) { - } - - void GetBook(const std::string& id, webcc::HttpResponseCallback callback) { - std::cout << "GetBook: " << id << std::endl; - - auto rsp_callback = [](webcc::HttpResponsePtr response) { - Json::Value rsp_json = StringToJson(response->content()); - - //id_callback(rsp_json["id"].asString()); - }; - - rest_client_.Get("/books/" + id, callback); - } - - void UpdateBook(const std::string& id, - const std::string& title, - double price, - webcc::HttpResponseCallback callback) { - std::cout << "UpdateBook: " << id << " " << title << " " << price - << std::endl; - - // NOTE: ID is already in the URL. - Json::Value json(Json::objectValue); - json["title"] = title; - json["price"] = price; - - rest_client_.Put("/books/" + id, JsonToString(json), callback); - } - - void DeleteBook(const std::string& id, webcc::HttpResponseCallback callback) { - std::cout << "DeleteBook: " << id << std::endl; - - rest_client_.Delete("/books/" + id, callback); - } -}; - -// ----------------------------------------------------------------------------- - -void Help(const char* argv0) { - std::cout << "Usage: " << argv0 << " [timeout]" << std::endl; - std::cout << " E.g.," << std::endl; - std::cout << " " << argv0 << " localhost 8080" << std::endl; - std::cout << " " << argv0 << " localhost 8080 2" << std::endl; -} - -int main(int argc, char* argv[]) { - if (argc < 3) { - Help(argv[0]); - return 1; - } - - WEBCC_LOG_INIT("", webcc::LOG_CONSOLE); - - std::string host = argv[1]; - std::string port = argv[2]; - - int timeout_seconds = -1; - if (argc > 3) { - timeout_seconds = std::atoi(argv[3]); - } - - boost::asio::io_context io_context; - - BookListClient list_client(io_context, host, port, timeout_seconds); - BookDetailClient detail_client(io_context, host, port, timeout_seconds); - - // Response handler. - auto handler = [](webcc::HttpResponsePtr response, webcc::Error error, - bool timed_out) { - if (error == webcc::kNoError) { - std::cout << response->content() << std::endl; - } else { - std::cout << webcc::DescribeError(error); - if (timed_out) { - std::cout << " (timed out)"; - } - std::cout << std::endl; - } - }; - - list_client.ListBooks(handler); - - list_client.CreateBook("1984", 12.3, [](std::string id) { - std::cout << "ID: " << id << std::endl; - }); - - //detail_client.GetBook("1", handler); - //detail_client.UpdateBook("1", "1Q84", 32.1, handler); - //detail_client.GetBook("1", handler); - //detail_client.DeleteBook("1", handler); - - //list_client.ListBooks(handler); - - io_context.run(); - - - return 0; -} diff --git a/example/rest_book_client/CMakeLists.txt b/example/rest_book_client/CMakeLists.txt index b934029..4df2c68 100644 --- a/example/rest_book_client/CMakeLists.txt +++ b/example/rest_book_client/CMakeLists.txt @@ -9,8 +9,7 @@ set(SRCS add_executable(${TARGET_NAME} ${SRCS}) -target_link_libraries(${TARGET_NAME} webcc jsoncpp ${Boost_LIBRARIES}) -target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") +target_link_libraries(${TARGET_NAME} ${EXAMPLE_COMMON_LIBS} jsoncpp) # Install VLD DLLs to build dir so that the example can be launched from # inside VS. diff --git a/example/rest_book_client/main.cc b/example/rest_book_client/main.cc index 5bf0c5c..d50569f 100644 --- a/example/rest_book_client/main.cc +++ b/example/rest_book_client/main.cc @@ -20,7 +20,7 @@ // ----------------------------------------------------------------------------- class BookClientBase { - public: +public: BookClientBase(const std::string& host, const std::string& port, int timeout_seconds) : host_(host), port_(port) { @@ -29,7 +29,7 @@ class BookClientBase { virtual ~BookClientBase() = default; - protected: +public: // Helper function to make a request. webcc::HttpRequestPtr MakeRequest(const std::string& method, const std::string& url, @@ -71,7 +71,7 @@ class BookClientBase { // ----------------------------------------------------------------------------- class BookListClient : public BookClientBase { - public: +public: BookListClient(const std::string& host, const std::string& port, int timeout_seconds) : BookClientBase(host, port, timeout_seconds) { @@ -131,7 +131,7 @@ class BookListClient : public BookClientBase { // ----------------------------------------------------------------------------- class BookDetailClient : public BookClientBase { - public: +public: BookDetailClient(const std::string& host, const std::string& port, int timeout_seconds) : BookClientBase(host, port, timeout_seconds) { diff --git a/example/rest_book_server/services.h b/example/rest_book_server/services.h index 026e254..f710483 100644 --- a/example/rest_book_server/services.h +++ b/example/rest_book_server/services.h @@ -9,12 +9,12 @@ // ----------------------------------------------------------------------------- class BookListService : public webcc::RestListService { - public: +public: explicit BookListService(int sleep_seconds) : sleep_seconds_(sleep_seconds) { } - protected: +public: // Get a list of books based on query parameters. void Get(const webcc::UrlQuery& query, webcc::RestResponse* response) final; @@ -22,7 +22,7 @@ class BookListService : public webcc::RestListService { void Post(const std::string& request_content, webcc::RestResponse* response) final; - private: +private: // Sleep some seconds before send back the response. // For testing timeout control in client side. int sleep_seconds_; @@ -33,12 +33,12 @@ class BookListService : public webcc::RestListService { // The URL is like '/books/{BookID}', and the 'url_sub_matches' parameter // contains the matched book ID. class BookDetailService : public webcc::RestDetailService { - public: +public: explicit BookDetailService(int sleep_seconds) : sleep_seconds_(sleep_seconds) { } - protected: +public: // Get the detailed information of a book. void Get(const webcc::UrlSubMatches& url_sub_matches, const webcc::UrlQuery& query, @@ -53,7 +53,7 @@ class BookDetailService : public webcc::RestDetailService { void Delete(const webcc::UrlSubMatches& url_sub_matches, webcc::RestResponse* response) final; - private: +private: // Sleep some seconds before send back the response. // For testing timeout control in client side. int sleep_seconds_; diff --git a/example/soap_book_client/CMakeLists.txt b/example/soap_book_client/CMakeLists.txt index 8d30720..81ebbaf 100644 --- a/example/soap_book_client/CMakeLists.txt +++ b/example/soap_book_client/CMakeLists.txt @@ -11,8 +11,7 @@ set(SRCS add_executable(${TARGET_NAME} ${SRCS}) -target_link_libraries(${TARGET_NAME} webcc pugixml ${Boost_LIBRARIES}) -target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") +target_link_libraries(${TARGET_NAME} ${EXAMPLE_COMMON_LIBS} pugixml) # Install VLD DLLs to build dir so that the example can be launched from # inside VS. diff --git a/example/soap_book_client/book_client.h b/example/soap_book_client/book_client.h index 92da8b5..734136a 100644 --- a/example/soap_book_client/book_client.h +++ b/example/soap_book_client/book_client.h @@ -10,7 +10,7 @@ #include "example/common/book.h" class BookClient { - public: +public: BookClient(const std::string& host, const std::string& port); int code() const { return code_; } @@ -28,7 +28,7 @@ class BookClient { // Delete a book by ID. bool DeleteBook(const std::string& id); - private: +private: // Call with 0 parameter. bool Call0(const std::string& operation, std::string* result_str); diff --git a/example/soap_book_server/book_service.h b/example/soap_book_server/book_service.h index b4f3ac7..2c0e133 100644 --- a/example/soap_book_server/book_service.h +++ b/example/soap_book_server/book_service.h @@ -4,11 +4,11 @@ #include "webcc/soap_service.h" class BookService : public webcc::SoapService { - public: +public: bool Handle(const webcc::SoapRequest& soap_request, webcc::SoapResponse* soap_response) override; - private: +private: bool CreateBook(const webcc::SoapRequest& soap_request, webcc::SoapResponse* soap_response); diff --git a/example/soap_calc_client/main.cc b/example/soap_calc_client.cc similarity index 99% rename from example/soap_calc_client/main.cc rename to example/soap_calc_client.cc index 70f0df5..283999e 100644 --- a/example/soap_calc_client/main.cc +++ b/example/soap_calc_client.cc @@ -8,7 +8,7 @@ static const std::string kResultName = "Result"; class CalcClient { - public: +public: CalcClient(const std::string& host, const std::string& port) : soap_client_(host, port) { soap_client_.SetTimeout(5); @@ -44,7 +44,7 @@ class CalcClient { return Calc("unknown", "x", "y", x, y, result); } - private: +private: bool Calc(const std::string& operation, const std::string& x_name, const std::string& y_name, double x, double y, diff --git a/example/soap_calc_client/CMakeLists.txt b/example/soap_calc_client/CMakeLists.txt deleted file mode 100644 index 2cfb33d..0000000 --- a/example/soap_calc_client/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(TARGET_NAME soap_calc_client) - -add_executable(${TARGET_NAME} main.cc) - -target_link_libraries(${TARGET_NAME} webcc pugixml ${Boost_LIBRARIES}) -target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") diff --git a/example/soap_calc_client_parasoft/main.cc b/example/soap_calc_client_parasoft.cc similarity index 99% rename from example/soap_calc_client_parasoft/main.cc rename to example/soap_calc_client_parasoft.cc index 055d3b9..46ec010 100644 --- a/example/soap_calc_client_parasoft/main.cc +++ b/example/soap_calc_client_parasoft.cc @@ -8,7 +8,7 @@ static const std::string kResultName = "Result"; class CalcClient { - public: +public: // NOTE: Parasoft's calculator service uses SOAP V1.1. CalcClient(const std::string& host, const std::string& port) : soap_client_(host, port, webcc::kSoapV11) { @@ -45,7 +45,7 @@ class CalcClient { return Calc("unknown", "x", "y", x, y, result); } - private: +private: bool Calc(const std::string& operation, const std::string& x_name, const std::string& y_name, double x, double y, diff --git a/example/soap_calc_client_parasoft/CMakeLists.txt b/example/soap_calc_client_parasoft/CMakeLists.txt deleted file mode 100644 index 27fd017..0000000 --- a/example/soap_calc_client_parasoft/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(TARGET_NAME soap_calc_client_parasoft) - -add_executable(${TARGET_NAME} main.cc) - -target_link_libraries(${TARGET_NAME} webcc pugixml ${Boost_LIBRARIES}) -target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") diff --git a/example/soap_calc_client_parasoft/calculator.wsdl b/example/soap_calc_client_parasoft/calculator.wsdl deleted file mode 100644 index 23ad1ec..0000000 --- a/example/soap_calc_client_parasoft/calculator.wsdl +++ /dev/null @@ -1,250 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - instance of class webtool.soap.examples.calculator.Calculator - - - - - diff --git a/example/soap_calc_server/calc_service.h b/example/soap_calc_server/calc_service.h index 2d767e3..4fcf0bf 100644 --- a/example/soap_calc_server/calc_service.h +++ b/example/soap_calc_server/calc_service.h @@ -4,7 +4,7 @@ #include "webcc/soap_service.h" class CalcService : public webcc::SoapService { - public: +public: CalcService() = default; ~CalcService() override = default; diff --git a/third_party/src/jsoncpp/json/json.h b/third_party/src/jsoncpp/json/json.h index 7314f7d..2eb484d 100644 --- a/third_party/src/jsoncpp/json/json.h +++ b/third_party/src/jsoncpp/json/json.h @@ -693,7 +693,7 @@ private: #endif #ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION class CZString { - public: +public: enum DuplicationPolicy { noDuplication = 0, duplicate, @@ -720,7 +720,7 @@ private: unsigned length() const; bool isStaticString() const; - private: + private: void swap(CZString& other); struct StringStorage { @@ -1548,14 +1548,14 @@ private: }; class Token { - public: +public: TokenType type_; Location start_; Location end_; }; class ErrorInfo { - public: +public: Token token_; JSONCPP_STRING message_; Location extra_; @@ -1646,7 +1646,7 @@ public: Value* root, JSONCPP_STRING* errs) = 0; class JSON_API Factory { - public: +public: virtual ~Factory() {} /** \brief Allocate a CharReader via operator new(). * \throw std::exception if something goes wrong (e.g. invalid settings) @@ -1853,7 +1853,7 @@ public: /** \brief A simple abstract factory. */ class JSON_API Factory { - public: +public: virtual ~Factory(); /** \brief Allocate a CharReader via operator new(). * \throw std::exception if something goes wrong (e.g. invalid settings) diff --git a/third_party/src/jsoncpp/jsoncpp.cpp b/third_party/src/jsoncpp/jsoncpp.cpp index 81c0c69..d650b94 100644 --- a/third_party/src/jsoncpp/jsoncpp.cpp +++ b/third_party/src/jsoncpp/jsoncpp.cpp @@ -1191,14 +1191,14 @@ private: }; class Token { - public: +public: TokenType type_; Location start_; Location end_; }; class ErrorInfo { - public: +public: Token token_; JSONCPP_STRING message_; Location extra_; diff --git a/unittest/rest_service_manager_test.cc b/unittest/rest_service_manager_test.cc index 14a3917..a02324d 100644 --- a/unittest/rest_service_manager_test.cc +++ b/unittest/rest_service_manager_test.cc @@ -5,7 +5,7 @@ // ----------------------------------------------------------------------------- class TestRestService : public webcc::RestService { - public: +public: void Handle(const webcc::RestRequest& request, webcc::RestResponse* response) final { response->status = webcc::http::Status::kOK; @@ -37,6 +37,23 @@ TEST(RestServiceManager, URL_RegexBasic) { EXPECT_FALSE(!!service); } +TEST(RestServiceManager, URL_Temp) { + webcc::RestServiceManager service_manager; + + service_manager.AddService(std::make_shared(), + "/instance/([\\w.]+)", true); + + std::vector sub_matches; + + std::string url = "/instance/123.45-+6aaa"; + webcc::RestServicePtr service = service_manager.GetService(url, &sub_matches); + + EXPECT_TRUE(!!service); + + EXPECT_EQ(1, sub_matches.size()); + EXPECT_EQ("123.45-6aaa", sub_matches[0]); +} + TEST(RestServiceManager, URL_RegexMultiple) { webcc::RestServiceManager service_manager; diff --git a/webcc/CMakeLists.txt b/webcc/CMakeLists.txt index 2b6c1db..e479ce9 100644 --- a/webcc/CMakeLists.txt +++ b/webcc/CMakeLists.txt @@ -15,8 +15,6 @@ include(GNUInstallDirs) set(HEADERS globals.h - # http_async_client_base.h - # http_async_client.h http_client_base.h http_client.h http_client_session.h @@ -31,7 +29,6 @@ set(HEADERS http_response_parser.h http_server.h http_ssl_client.h - # http_ssl_async_client.h queue.h url.h utility.h @@ -40,8 +37,6 @@ set(HEADERS set(SOURCES globals.cc - # http_async_client_base.cc - # http_async_client.cc http_client_base.cc http_client.cc http_client_session.cc @@ -55,7 +50,6 @@ set(SOURCES http_response_parser.cc http_server.cc http_ssl_client.cc - # http_ssl_async_client.cc logger.cc url.cc utility.cc @@ -63,16 +57,12 @@ set(SOURCES if(WEBCC_ENABLE_REST) set(REST_HEADERS - # rest_async_client.h - # rest_client.h rest_request_handler.h rest_server.h rest_service.h rest_service_manager.h ) set(REST_SOURCES - # rest_async_client.cc - # rest_client.cc rest_request_handler.cc rest_service_manager.cc rest_service.cc @@ -84,7 +74,6 @@ endif() if(WEBCC_ENABLE_SOAP) set(SOAP_HEADERS - # soap_async_client.h soap_client.h soap_globals.h soap_message.h @@ -98,7 +87,6 @@ if(WEBCC_ENABLE_SOAP) ) set(SOAP_SOURCES - # soap_async_client.cc soap_client.cc soap_globals.cc soap_message.cc diff --git a/webcc/http_async_client.cc b/webcc/http_async_client.cc deleted file mode 100644 index 06b3d7f..0000000 --- a/webcc/http_async_client.cc +++ /dev/null @@ -1,35 +0,0 @@ -#include "webcc/http_async_client.h" - -#include "boost/asio/connect.hpp" -#include "boost/asio/read.hpp" -#include "boost/asio/write.hpp" - -#include "webcc/logger.h" -#include "webcc/utility.h" - -namespace webcc { - -HttpAsyncClient::HttpAsyncClient(boost::asio::io_context& io_context, - std::size_t buffer_size) - : HttpAsyncClientBase(io_context, buffer_size), - socket_(io_context) { -} - -void HttpAsyncClient::SocketAsyncConnect(const Endpoints& endpoints, - ConnectHandler&& handler) { - boost::asio::async_connect(socket_, endpoints, std::move(handler)); -} - -void HttpAsyncClient::SocketAsyncWrite(WriteHandler&& handler) { - boost::asio::async_write(socket_, request_->ToBuffers(), std::move(handler)); -} - -void HttpAsyncClient::SocketAsyncReadSome(ReadHandler&& handler) { - socket_.async_read_some(boost::asio::buffer(buffer_), std::move(handler)); -} - -void HttpAsyncClient::SocketClose(boost::system::error_code* ec) { - socket_.close(*ec); -} - -} // namespace webcc diff --git a/webcc/http_async_client.h b/webcc/http_async_client.h deleted file mode 100644 index b927e3c..0000000 --- a/webcc/http_async_client.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef WEBCC_HTTP_ASYNC_CLIENT_H_ -#define WEBCC_HTTP_ASYNC_CLIENT_H_ - -#include "webcc/http_async_client_base.h" - -namespace webcc { - -class HttpAsyncClient; -typedef std::shared_ptr HttpAsyncClientPtr; - -// HTTP asynchronous client. -class HttpAsyncClient : public HttpAsyncClientBase { - public: - ~HttpAsyncClient() = default; - - // Forbid to create HttpAsyncClient in stack since it's derived from - // std::shared_from_this. - static HttpAsyncClientPtr New(boost::asio::io_context& io_context, - std::size_t buffer_size = 0) { - return HttpAsyncClientPtr{ - new HttpAsyncClient(io_context, buffer_size) - }; - } - - private: - explicit HttpAsyncClient(boost::asio::io_context& io_context, - std::size_t buffer_size = 0); - - void Resolve() final { - DoResolve(kHttpPort); - } - - void OnConnected() final { - DoWrite(); - } - - void SocketAsyncConnect(const Endpoints& endpoints, - ConnectHandler&& handler) final; - - void SocketAsyncWrite(WriteHandler&& handler) final; - - void SocketAsyncReadSome(ReadHandler&& handler) final; - - void SocketClose(boost::system::error_code* ec) final; - - tcp::socket socket_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_ASYNC_CLIENT_H_ diff --git a/webcc/http_async_client_base.cc b/webcc/http_async_client_base.cc deleted file mode 100644 index 3ffc677..0000000 --- a/webcc/http_async_client_base.cc +++ /dev/null @@ -1,236 +0,0 @@ -#include "webcc/http_async_client_base.h" - -#include "boost/asio/connect.hpp" -#include "boost/asio/read.hpp" -#include "boost/asio/write.hpp" - -#include "webcc/logger.h" -#include "webcc/utility.h" - -namespace webcc { - -HttpAsyncClientBase::HttpAsyncClientBase(boost::asio::io_context& io_context, - std::size_t buffer_size) - : resolver_(io_context), - buffer_(buffer_size == 0 ? kBufferSize : buffer_size), - deadline_(io_context), - timeout_seconds_(kMaxReadSeconds), - stopped_(false), - timed_out_(false) { -} - -void HttpAsyncClientBase::SetTimeout(int seconds) { - if (seconds > 0) { - timeout_seconds_ = seconds; - } -} - -void HttpAsyncClientBase::Request(std::shared_ptr request, - HttpResponseCallback response_callback) { - assert(request); - assert(response_callback); - - response_.reset(new HttpResponse()); - response_parser_.reset(new HttpResponseParser(response_.get())); - - stopped_ = false; - timed_out_ = false; - - LOG_VERB("HTTP request:\n%s", request->Dump(4, "> ").c_str()); - - request_ = request; - response_callback_ = response_callback; - - DoResolve(kHttpSslPort); -} - -void HttpAsyncClientBase::Stop() { - LOG_INFO("The user asks to cancel the request."); - - DoStop(); -} - -void HttpAsyncClientBase::DoResolve(const std::string& default_port) { - auto handler = std::bind(&HttpAsyncClientBase::OnResolve, shared_from_this(), - std::placeholders::_1, std::placeholders::_2); - - resolver_.async_resolve(tcp::v4(), request_->host(), - request_->port(default_port), handler); -} - -void HttpAsyncClientBase::OnResolve(boost::system::error_code ec, - tcp::resolver::results_type endpoints) { - if (ec) { - LOG_ERRO("Host resolve error (%s): %s, %s.", ec.message().c_str(), - request_->host().c_str(), request_->port().c_str()); - - response_callback_(response_, kHostResolveError, timed_out_); - } else { - LOG_VERB("Host resolved."); - - DoConnect(endpoints); - } -} - -void HttpAsyncClientBase::DoConnect(const Endpoints& endpoints) { - auto handler = std::bind(&HttpAsyncClientBase::OnConnect, - shared_from_this(), - std::placeholders::_1, std::placeholders::_2); - - SocketAsyncConnect(endpoints, std::move(handler)); -} - -void HttpAsyncClientBase::OnConnect(boost::system::error_code ec, - tcp::endpoint endpoint) { - if (ec) { - LOG_ERRO("Socket connect error (%s).", ec.message().c_str()); - DoStop(); - response_callback_(response_, kEndpointConnectError, timed_out_); - return; - } - - LOG_VERB("Socket connected."); - - // Even though the connect operation notionally succeeded, the user could - // have stopped the operation by calling Stop(). And if we started the - // deadline timer, it could also be stopped due to timeout. - if (stopped_) { - // TODO: Use some other error. - response_callback_(response_, kEndpointConnectError, timed_out_); - return; - } - - // Connection established. - OnConnected(); -} - -void HttpAsyncClientBase::DoWrite() { - // NOTE: - // It doesn't make much sense to set a timeout for socket write. - // I find that it's almost impossible to simulate a situation in the server - // side to test this timeout. - - SocketAsyncWrite(std::bind(&HttpAsyncClientBase::OnWrite, shared_from_this(), - std::placeholders::_1, std::placeholders::_2)); -} - -void HttpAsyncClientBase::OnWrite(boost::system::error_code ec, - std::size_t /*length*/) { - if (stopped_) { - // TODO: Use some other error. - response_callback_(response_, kSocketWriteError, timed_out_); - return; - } - - if (ec) { - LOG_ERRO("Socket write error (%s).", ec.message().c_str()); - DoStop(); - response_callback_(response_, kSocketWriteError, timed_out_); - } else { - LOG_INFO("Request sent."); - LOG_VERB("Read response (timeout: %ds)...", timeout_seconds_); - - deadline_.expires_from_now(boost::posix_time::seconds(timeout_seconds_)); - DoWaitDeadline(); - - DoRead(); - } -} - -void HttpAsyncClientBase::DoRead() { - auto handler = std::bind(&HttpAsyncClientBase::OnRead, shared_from_this(), - std::placeholders::_1, std::placeholders::_2); - SocketAsyncReadSome(std::move(handler)); -} - -void HttpAsyncClientBase::OnRead(boost::system::error_code ec, - std::size_t length) { - LOG_VERB("Socket async read handler."); - - if (ec || length == 0) { - DoStop(); - LOG_ERRO("Socket read error (%s).", ec.message().c_str()); - response_callback_(response_, kSocketReadError, timed_out_); - return; - } - - LOG_INFO("Read data, length: %u.", length); - - // Parse the response piece just read. - // If the content has been fully received, |finished()| will be true. - if (!response_parser_->Parse(buffer_.data(), length)) { - DoStop(); - LOG_ERRO("Failed to parse HTTP response."); - response_callback_(response_, kHttpError, timed_out_); - return; - } - - if (response_parser_->finished()) { - DoStop(); - - LOG_INFO("Finished to read and parse HTTP response."); - LOG_VERB("HTTP response:\n%s", response_->Dump(4, "> ").c_str()); - - response_callback_(response_, kNoError, timed_out_); - return; - } - - if (!stopped_) { - DoRead(); - } -} - -void HttpAsyncClientBase::DoWaitDeadline() { - deadline_.async_wait(std::bind(&HttpAsyncClientBase::OnDeadline, - shared_from_this(), std::placeholders::_1)); -} - -void HttpAsyncClientBase::OnDeadline(boost::system::error_code ec) { - if (stopped_) { - return; - } - - LOG_VERB("OnDeadline."); - - // NOTE: Can't check this: - // if (ec == boost::asio::error::operation_aborted) { - // LOG_VERB("Deadline timer canceled."); - // return; - // } - - if (deadline_.expires_at() <= - boost::asio::deadline_timer::traits_type::now()) { - // The deadline has passed. - // The socket is closed so that any outstanding asynchronous operations - // are canceled. - LOG_WARN("HTTP client timed out."); - timed_out_ = true; - Stop(); - return; - } - - // Put the actor back to sleep. - DoWaitDeadline(); -} - -void HttpAsyncClientBase::DoStop() { - if (stopped_) { - return; - } - - stopped_ = true; - - LOG_INFO("Close socket..."); - - boost::system::error_code ec; - SocketClose(&ec); - - if (ec) { - LOG_ERRO("Socket close error (%s).", ec.message().c_str()); - } - - LOG_INFO("Cancel deadline timer..."); - deadline_.cancel(); -} - -} // namespace webcc diff --git a/webcc/http_async_client_base.h b/webcc/http_async_client_base.h deleted file mode 100644 index c69b3cf..0000000 --- a/webcc/http_async_client_base.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef WEBCC_HTTP_ASYNC_CLIENT_BASE_H_ -#define WEBCC_HTTP_ASYNC_CLIENT_BASE_H_ - -#include -#include -#include - -#include "boost/asio/deadline_timer.hpp" -#include "boost/asio/io_context.hpp" -#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" - -namespace webcc { - -// Response callback. -typedef std::function HttpResponseCallback; - -// HTTP client session in asynchronous mode. -// A request will return without waiting for the response, the callback handler -// will be invoked when the response is received or timeout occurs. -// Don't use the same HttpAsyncClient object in multiple threads. -class HttpAsyncClientBase - : public std::enable_shared_from_this { - public: - // The |buffer_size| is the bytes of the buffer for reading response. - // 0 means default value (e.g., 1024) will be used. - explicit HttpAsyncClientBase(boost::asio::io_context& io_context, - std::size_t buffer_size = 0); - - virtual ~HttpAsyncClientBase() = default; - - WEBCC_DELETE_COPY_ASSIGN(HttpAsyncClientBase); - - // Set the timeout seconds for reading response. - // The |seconds| is only effective when greater than 0. - void SetTimeout(int seconds); - - // Asynchronously connect to the server, send the request, read the response, - // and call the |response_callback| when all these finish. - void Request(HttpRequestPtr request, HttpResponseCallback response_callback); - - // Called by the user to cancel the request. - void Stop(); - - protected: - using tcp = boost::asio::ip::tcp; - - typedef tcp::resolver::results_type Endpoints; - - typedef std::function - ReadHandler; - - typedef std::function - ConnectHandler; - - typedef std::function - WriteHandler; - - // To enable_shared_from_this for both parent and derived. - // See https://stackoverflow.com/q/657155/6825348 - template - std::shared_ptr shared_from_base() { - return std::static_pointer_cast(shared_from_this()); - } - - protected: - virtual void Resolve() = 0; - - void DoResolve(const std::string& default_port); - void OnResolve(boost::system::error_code ec, - tcp::resolver::results_type results); - - void DoConnect(const Endpoints& endpoints); - void OnConnect(boost::system::error_code ec, tcp::endpoint endpoint); - - virtual void OnConnected() = 0; - - void DoWrite(); - void OnWrite(boost::system::error_code ec, std::size_t length); - - void DoRead(); - void OnRead(boost::system::error_code ec, std::size_t length); - - void DoWaitDeadline(); - void OnDeadline(boost::system::error_code ec); - - // Terminate all the actors to shut down the connection. - void DoStop(); - - virtual void SocketAsyncConnect(const Endpoints& endpoints, - ConnectHandler&& handler) = 0; - - virtual void SocketAsyncWrite(WriteHandler&& handler) = 0; - - virtual void SocketAsyncReadSome(ReadHandler&& handler) = 0; - - virtual void SocketClose(boost::system::error_code* ec) = 0; - - tcp::resolver resolver_; - - HttpRequestPtr request_; - - std::vector buffer_; - - HttpResponsePtr response_; - std::unique_ptr response_parser_; - HttpResponseCallback response_callback_; - - // Timer for the timeout control. - boost::asio::deadline_timer deadline_; - - // Maximum seconds to wait before the client cancels the operation. - // Only for receiving response from server. - int timeout_seconds_; - - // Request stopped due to timeout or socket error. - bool stopped_; - - // If the error was caused by timeout or not. - // Will be passed to the response handler/callback. - bool timed_out_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_ASYNC_CLIENT_BASE_H_ diff --git a/webcc/http_client.h b/webcc/http_client.h index 55eea20..b2fa253 100644 --- a/webcc/http_client.h +++ b/webcc/http_client.h @@ -7,12 +7,12 @@ namespace webcc { // HTTP synchronous client. class HttpClient : public HttpClientBase { - public: +public: explicit HttpClient(std::size_t buffer_size = 0); ~HttpClient() = default; - private: +private: Error Connect(const HttpRequest& request) final { return DoConnect(request, kPort80); } diff --git a/webcc/http_client_base.h b/webcc/http_client_base.h index 3ce4cbc..eb6157f 100644 --- a/webcc/http_client_base.h +++ b/webcc/http_client_base.h @@ -22,7 +22,7 @@ namespace webcc { // or timeout occurs. // Please don't use the same client object in multiple threads. class HttpClientBase { - public: +public: // The |buffer_size| is the bytes of the buffer for reading response. // 0 means default value (e.g., 1024) will be used. explicit HttpClientBase(std::size_t buffer_size = 0); @@ -56,7 +56,7 @@ class HttpClientBase { Error error() const { return error_; } - protected: +public: typedef boost::asio::ip::tcp::resolver::results_type Endpoints; typedef std::function diff --git a/webcc/http_client_session.cc b/webcc/http_client_session.cc index afa0622..3d35f5a 100644 --- a/webcc/http_client_session.cc +++ b/webcc/http_client_session.cc @@ -14,14 +14,20 @@ HttpResponsePtr HttpClientSession::Request(HttpRequestArgs&& args) { assert(args.parameters_.size() % 2 == 0); assert(args.headers_.size() % 2 == 0); - HttpRequest request{ args.method_, args.url_, args.parameters_ }; + HttpRequest request{ args.method_, args.url_ }; + + for (std::size_t i = 1; i < args.parameters_.size(); i += 2) { + request.AddParameter(args.parameters_[i - 1], args.parameters_[i]); + } if (!args.data_.empty()) { request.SetContent(std::move(args.data_), true); - // TODO: charset/encoding + // TODO: Request-level charset. if (args.json_) { - request.SetContentType(http::media_types::kApplicationJson, ""); + request.SetContentType(http::media_types::kApplicationJson, charset_); + } else if (!content_type_.empty()) { + request.SetContentType(content_type_, charset_); } } diff --git a/webcc/http_client_session.h b/webcc/http_client_session.h index 4df7142..c48c2b2 100644 --- a/webcc/http_client_session.h +++ b/webcc/http_client_session.h @@ -15,6 +15,14 @@ public: ~HttpClientSession() = default; + void set_content_type(const std::string& content_type) { + content_type_ = content_type; + } + + void set_charset(const std::string& charset) { + charset_ = charset; + } + void AddHeader(const std::string& key, const std::string& value) { headers_.Add(key, value); } @@ -34,7 +42,13 @@ public: private: void InitHeaders(); - // Headers to be sent on each request sent from this session. + // E.g., "application/json". + std::string content_type_; + + // E.g., "utf-8". + std::string charset_; + + // Headers for each request sent from this session. HttpHeaderDict headers_; }; diff --git a/webcc/http_message.cc b/webcc/http_message.cc index 6e51409..fada240 100644 --- a/webcc/http_message.cc +++ b/webcc/http_message.cc @@ -73,12 +73,6 @@ void HttpMessage::SetContent(std::string&& content, bool set_length) { } } -void HttpMessage::SetContentInAppJsonUtf8(std::string&& content, - bool set_length) { - SetContent(std::move(content), set_length); - SetContentType(http::media_types::kApplicationJson, http::charsets::kUtf8); -} - // ATTENTION: The buffers don't hold the memory! std::vector HttpMessage::ToBuffers() const { assert(!start_line_.empty()); diff --git a/webcc/http_message.h b/webcc/http_message.h index 7ebecdc..8c442c9 100644 --- a/webcc/http_message.h +++ b/webcc/http_message.h @@ -88,8 +88,6 @@ public: // TODO: Remove parameter |set_length|. void SetContent(std::string&& content, bool set_length); - void SetContentInAppJsonUtf8(std::string&& content, bool set_length); - // Make the message (e.g., update start line). // Must be called before ToBuffers()! virtual bool Prepare() = 0; diff --git a/webcc/http_parser.h b/webcc/http_parser.h index 9cb4791..5a9f34e 100644 --- a/webcc/http_parser.h +++ b/webcc/http_parser.h @@ -11,7 +11,7 @@ class HttpMessage; // HttpParser parses HTTP request and response. class HttpParser { - public: +public: explicit HttpParser(HttpMessage* message); virtual ~HttpParser() = default; @@ -24,7 +24,7 @@ class HttpParser { bool Parse(const char* data, std::size_t length); - protected: +public: // Parse headers from pending data. // Return false only on syntax errors. bool ParseHeaders(); diff --git a/webcc/http_request.cc b/webcc/http_request.cc index a6f2cb5..6a6b363 100644 --- a/webcc/http_request.cc +++ b/webcc/http_request.cc @@ -4,16 +4,6 @@ namespace webcc { -HttpRequest::HttpRequest(const std::string& method, - const std::string& url, - const std::vector& parameters) - : method_(method), url_(url) { - assert(parameters.size() % 2 == 0); - for (std::size_t i = 1; i < parameters.size(); i += 2) { - url_.AddParameter(parameters[i - 1], parameters[i]); - } -} - bool HttpRequest::Prepare() { if (url_.host().empty()) { LOG_ERRO("Invalid request: host is missing."); @@ -41,17 +31,4 @@ bool HttpRequest::Prepare() { return true; } -HttpRequestPtr HttpRequest::New(const std::string& method, - const std::string& url, - const std::vector& parameters, - bool prepare) { - HttpRequestPtr request{ new HttpRequest{ method, url, parameters } }; - - if (prepare) { - request->Prepare(); - } - - return request; -} - } // namespace webcc diff --git a/webcc/http_request.h b/webcc/http_request.h index ed26010..38874be 100644 --- a/webcc/http_request.h +++ b/webcc/http_request.h @@ -11,7 +11,6 @@ namespace webcc { class HttpRequest; -class HttpRequestParser; typedef std::shared_ptr HttpRequestPtr; @@ -19,13 +18,25 @@ class HttpRequest : public HttpMessage { public: HttpRequest() = default; - // TODO: Move parameters - HttpRequest(const std::string& method, - const std::string& url, - const std::vector& parameters = {}); + HttpRequest(const std::string& method, const std::string& url) + : method_(method), url_(url) { + } ~HttpRequest() override = default; + void set_method(const std::string& method) { + method_ = method; + } + + void set_url(const std::string& url) { + url_.Init(url); + } + + // Add URL query parameter. + void AddParameter(const std::string& key, const std::string& value) { + url_.AddParameter(key, value); + } + const std::string& method() const { return method_; } @@ -46,36 +57,11 @@ public: return port().empty() ? default_port : port(); } - // Shortcut to set `Accept` header. - void Accept(const std::string& media_type) { - SetHeader(http::headers::kAccept, media_type); - } - - // Shortcut to set `Accept` header. - void AcceptAppJson() { - SetHeader(http::headers::kAccept, http::media_types::kApplicationJson); - } - // Prepare payload. // Compose start line, set Host header, etc. bool Prepare() override; - // TODO: Re-place - static HttpRequestPtr New(const std::string& method, - const std::string& url, - const std::vector& parameters = {}, - bool prepare = true); - private: - friend class HttpRequestParser; - - void set_method(const std::string& method) { - method_ = method; - } - void set_url(const std::string& url) { - url_.Init(url); - } - std::string method_; Url url_; }; diff --git a/webcc/http_request_parser.cc b/webcc/http_request_parser.cc index 828836c..75de792 100644 --- a/webcc/http_request_parser.cc +++ b/webcc/http_request_parser.cc @@ -19,8 +19,8 @@ bool HttpRequestParser::ParseStartLine(const std::string& line) { return false; } - request_->set_method(strs[0]); - request_->set_url(strs[1]); + request_->set_method(std::move(strs[0])); + request_->set_url(std::move(strs[1])); // HTTP version is ignored. diff --git a/webcc/http_request_parser.h b/webcc/http_request_parser.h index 8cbb7cb..f584c14 100644 --- a/webcc/http_request_parser.h +++ b/webcc/http_request_parser.h @@ -10,12 +10,12 @@ namespace webcc { class HttpRequest; class HttpRequestParser : public HttpParser { - public: +public: explicit HttpRequestParser(HttpRequest* request); ~HttpRequestParser() override = default; - private: +private: bool ParseStartLine(const std::string& line) override; HttpRequest* request_; diff --git a/webcc/http_response.h b/webcc/http_response.h index bedc717..e46321d 100644 --- a/webcc/http_response.h +++ b/webcc/http_response.h @@ -9,7 +9,7 @@ namespace webcc { class HttpResponse : public HttpMessage { - public: +public: HttpResponse() : status_(http::Status::kOK) {} ~HttpResponse() override = default; @@ -25,7 +25,7 @@ class HttpResponse : public HttpMessage { // TODO: Avoid copy. static HttpResponse Fault(http::Status status); - private: +private: int status_; }; diff --git a/webcc/http_response_parser.h b/webcc/http_response_parser.h index a2d3a79..6d7be71 100644 --- a/webcc/http_response_parser.h +++ b/webcc/http_response_parser.h @@ -10,12 +10,12 @@ namespace webcc { class HttpResponse; class HttpResponseParser : public HttpParser { - public: +public: explicit HttpResponseParser(HttpResponse* response); ~HttpResponseParser() override = default; - private: +private: // Parse HTTP start line; E.g., "HTTP/1.1 200 OK". bool ParseStartLine(const std::string& line) override; diff --git a/webcc/http_server.h b/webcc/http_server.h index 2285d72..8d6fa12 100644 --- a/webcc/http_server.h +++ b/webcc/http_server.h @@ -17,7 +17,7 @@ class HttpRequestHandler; // HTTP server accepts TCP connections from TCP clients. // NOTE: Only support IPv4. class HttpServer { - public: +public: HttpServer(std::uint16_t port, std::size_t workers); virtual ~HttpServer() = default; @@ -27,7 +27,7 @@ class HttpServer { // Run the server's io_service loop. void Run(); - private: +private: // Register to handle the signals that indicate when the server should exit. void RegisterSignals(); diff --git a/webcc/http_ssl_async_client.cc b/webcc/http_ssl_async_client.cc deleted file mode 100644 index 2bfc3fb..0000000 --- a/webcc/http_ssl_async_client.cc +++ /dev/null @@ -1,71 +0,0 @@ -#include "webcc/http_ssl_async_client.h" - -#include "boost/asio/connect.hpp" - -#include "webcc/logger.h" - -using tcp = boost::asio::ip::tcp; -namespace ssl = boost::asio::ssl; - -namespace webcc { - -HttpSslAsyncClient::HttpSslAsyncClient(boost::asio::io_context& io_context, - std::size_t buffer_size, - bool ssl_verify) - : HttpAsyncClientBase(io_context, buffer_size), - ssl_context_(ssl::context::sslv23), - ssl_socket_(io_context, ssl_context_), - ssl_verify_(ssl_verify) { - // Use the default paths for finding CA certificates. - ssl_context_.set_default_verify_paths(); -} - -void HttpSslAsyncClient::Resolve() { - DoResolve(kHttpSslPort); -} - -void HttpSslAsyncClient::DoHandshake() { - if (ssl_verify_) { - ssl_socket_.set_verify_mode(ssl::verify_peer); - } else { - ssl_socket_.set_verify_mode(ssl::verify_none); - } - - ssl_socket_.set_verify_callback(ssl::rfc2818_verification(request_->host())); - - ssl_socket_.async_handshake(ssl::stream_base::client, - std::bind(&HttpSslAsyncClient::OnHandshake, - shared_from_this(), - std::placeholders::_1)); -} - -void HttpSslAsyncClient::OnHandshake(boost::system::error_code ec) { - if (ec) { - LOG_ERRO("Handshake error (%s).", ec.message().c_str()); - response_callback_(response_, kHandshakeError, false); - return; - } - - DoWrite(); -} - -void HttpSslAsyncClient::SocketAsyncConnect(const Endpoints& endpoints, - ConnectHandler&& handler) { - boost::asio::async_connect(ssl_socket_.lowest_layer(), endpoints, - std::move(handler)); -} - -void HttpSslAsyncClient::SocketAsyncWrite(WriteHandler&& handler) { - boost::asio::async_write(ssl_socket_, request_->ToBuffers(), - std::move(handler)); -} - -void HttpSslAsyncClient::SocketAsyncReadSome(ReadHandler&& handler) { - ssl_socket_.async_read_some(boost::asio::buffer(buffer_), std::move(handler)); -} - -void HttpSslAsyncClient::SocketClose(boost::system::error_code* ec) { - ssl_socket_.lowest_layer().close(*ec); -} - -} // namespace webcc diff --git a/webcc/http_ssl_async_client.h b/webcc/http_ssl_async_client.h deleted file mode 100644 index 1ded014..0000000 --- a/webcc/http_ssl_async_client.h +++ /dev/null @@ -1,69 +0,0 @@ -#ifndef WEBCC_HTTP_SSL_ASYNC_CLIENT_H_ -#define WEBCC_HTTP_SSL_ASYNC_CLIENT_H_ - -#include "webcc/http_async_client_base.h" - -#include "boost/asio/ssl.hpp" - -namespace webcc { - -class HttpSslAsyncClient; -typedef std::shared_ptr HttpSslAsyncClientPtr; - -// HTTP SSL (a.k.a., HTTPS) asynchronous client. -class HttpSslAsyncClient : public HttpAsyncClientBase { - public: - ~HttpSslAsyncClient() = default; - - // Forbid to create HttpSslAsyncClient in stack since it's derived from - // std::shared_from_this. - static HttpSslAsyncClientPtr New(boost::asio::io_context& io_context, - std::size_t buffer_size = 0, - bool ssl_verify = true) { - return HttpSslAsyncClientPtr{ - new HttpSslAsyncClient(io_context, buffer_size, ssl_verify) - }; - } - - // See https://stackoverflow.com/q/657155/6825348 - std::shared_ptr shared_from_this() { - return shared_from_base(); - } - - private: - // SSL verification (|ssl_verify|) needs CA certificates to be found - // in the default verify paths of OpenSSL. On Windows, it means you need to - // set environment variable SSL_CERT_FILE properly. - explicit HttpSslAsyncClient(boost::asio::io_context& io_context, - std::size_t buffer_size = 0, - bool ssl_verify = true); - - void Resolve() final; - - // Override to do handshake after connected. - void OnConnected() final { - DoHandshake(); - } - - void DoHandshake(); - void OnHandshake(boost::system::error_code ec); - - void SocketAsyncConnect(const Endpoints& endpoints, - ConnectHandler&& handler) final; - - void SocketAsyncWrite(WriteHandler&& handler) final; - - void SocketAsyncReadSome(ReadHandler&& handler) final; - - void SocketClose(boost::system::error_code* ec) final; - - boost::asio::ssl::context ssl_context_; - boost::asio::ssl::stream ssl_socket_; - - // Verify the certificate of the peer (remote server) or not. - bool ssl_verify_; -}; - -} // namespace webcc - -#endif // WEBCC_HTTP_SSL_ASYNC_CLIENT_H_ diff --git a/webcc/http_ssl_client.h b/webcc/http_ssl_client.h index 8b70f91..890368e 100644 --- a/webcc/http_ssl_client.h +++ b/webcc/http_ssl_client.h @@ -9,7 +9,7 @@ namespace webcc { // HTTP SSL (a.k.a., HTTPS) synchronous client. class HttpSslClient : public HttpClientBase { - public: +public: // SSL verification (|ssl_verify|) needs CA certificates to be found // in the default verify paths of OpenSSL. On Windows, it means you need to // set environment variable SSL_CERT_FILE properly. @@ -17,7 +17,7 @@ class HttpSslClient : public HttpClientBase { ~HttpSslClient() = default; - private: +private: Error Handshake(const std::string& host); // Override to do handshake after connected. diff --git a/webcc/queue.h b/webcc/queue.h index 59d503e..3e51174 100644 --- a/webcc/queue.h +++ b/webcc/queue.h @@ -12,7 +12,7 @@ namespace webcc { template class Queue { - public: +public: Queue() = default; Queue(const Queue&) = delete; @@ -49,7 +49,7 @@ class Queue { not_empty_cv_.notify_one(); } - private: +private: std::list message_list_; std::mutex mutex_; std::condition_variable not_empty_cv_; diff --git a/webcc/rest_async_client.cc b/webcc/rest_async_client.cc deleted file mode 100644 index 302e78e..0000000 --- a/webcc/rest_async_client.cc +++ /dev/null @@ -1,38 +0,0 @@ -#include "webcc/rest_async_client.h" - -namespace webcc { - -RestAsyncClient::RestAsyncClient(boost::asio::io_context& io_context, - const std::string& host, - const std::string& port, - std::size_t buffer_size) - : io_context_(io_context), - host_(host), port_(port), - timeout_seconds_(0), - buffer_size_(buffer_size) { -} - -void RestAsyncClient::Request(const std::string& method, - const std::string& url, - std::string&& content, - HttpResponseCallback callback) { - HttpRequestPtr http_request(new HttpRequest(method, url, host_, port_)); - - if (!content.empty()) { - http_request->SetContent(std::move(content), true); - http_request->SetContentType(http::media_types::kApplicationJson, - http::charsets::kUtf8); - } - - http_request->Prepare(); - - auto http_async_client = HttpAsyncClient::New(io_context_, buffer_size_); - - if (timeout_seconds_ > 0) { - http_async_client->SetTimeout(timeout_seconds_); - } - - http_async_client->Request(http_request, callback); -} - -} // namespace webcc diff --git a/webcc/rest_async_client.h b/webcc/rest_async_client.h deleted file mode 100644 index 7eb1701..0000000 --- a/webcc/rest_async_client.h +++ /dev/null @@ -1,61 +0,0 @@ -#ifndef WEBCC_REST_ASYNC_CLIENT_H_ -#define WEBCC_REST_ASYNC_CLIENT_H_ - -#include -#include // for move() - -#include "webcc/http_async_client.h" - -namespace webcc { - -class RestAsyncClient { - public: - RestAsyncClient(boost::asio::io_context& io_context, - const std::string& host, const std::string& port, - std::size_t buffer_size = 0); - - void SetTimeout(int seconds) { - timeout_seconds_ = seconds; - } - - void Get(const std::string& url, HttpResponseCallback callback) { - Request(kHttpGet, url, "", callback); - } - - void Post(const std::string& url, std::string&& content, - HttpResponseCallback callback) { - Request(kHttpPost, url, std::move(content), callback); - } - - void Put(const std::string& url, std::string&& content, - HttpResponseCallback callback) { - Request(kHttpPut, url, std::move(content), callback); - } - - void Patch(const std::string& url, std::string&& content, - HttpResponseCallback callback) { - Request(kHttpPatch, url, std::move(content), callback); - } - - void Delete(const std::string& url, HttpResponseCallback callback) { - Request(kHttpDelete, url, "", callback); - } - - private: - void Request(const std::string& method, const std::string& url, - std::string&& content, HttpResponseCallback callback); - - boost::asio::io_context& io_context_; - - std::string host_; - std::string port_; - - // Timeout in seconds; only effective when > 0. - int timeout_seconds_; - - std::size_t buffer_size_; -}; - -} // namespace webcc - -#endif // WEBCC_REST_ASYNC_CLIENT_H_ diff --git a/webcc/rest_client.cc b/webcc/rest_client.cc deleted file mode 100644 index 0188f0d..0000000 --- a/webcc/rest_client.cc +++ /dev/null @@ -1,34 +0,0 @@ -#include "webcc/rest_client.h" -#include "webcc/utility.h" - -namespace webcc { - -RestClient::RestClient(const std::string& host, const std::string& port, - std::size_t buffer_size) - : host_(host), port_(port), http_client_(buffer_size) { - AdjustHostPort(host_, port_); -} - -bool RestClient::Request(const std::string& method, const std::string& url, - std::string&& content, std::size_t buffer_size) { - HttpRequest http_request(method, url, host_, port_); - - http_request.SetHeader(http::headers::kAccept, - http::media_types::kApplicationJson); - - if (!content.empty()) { - http_request.SetContent(std::move(content), true); - http_request.SetContentType(http::media_types::kApplicationJson, - http::charsets::kUtf8); - } - - http_request.Prepare(); - - if (!http_client_.Request(http_request, buffer_size)) { - return false; - } - - return true; -} - -} // namespace webcc diff --git a/webcc/rest_client.h b/webcc/rest_client.h deleted file mode 100644 index f06128c..0000000 --- a/webcc/rest_client.h +++ /dev/null @@ -1,94 +0,0 @@ -#ifndef WEBCC_REST_CLIENT_H_ -#define WEBCC_REST_CLIENT_H_ - -#include -#include -#include // for move() - -#include "webcc/globals.h" -#include "webcc/http_client.h" -#include "webcc/http_request.h" -#include "webcc/http_response.h" - -namespace webcc { - -class RestClient { - public: - // If |port| is empty, |host| will be checked to see if it contains port or - // not (separated by ':'). - explicit RestClient(const std::string& host, - const std::string& port = "", - std::size_t buffer_size = 0); - - ~RestClient() = default; - - WEBCC_DELETE_COPY_ASSIGN(RestClient); - - void SetTimeout(int seconds) { - http_client_.SetTimeout(seconds); - } - - // NOTE: - // The return value of the following methods (Get, Post, etc.) only indicates - // if the socket communication is successful or not. Check error() and - // timed_out() for more information if it's failed. Check response_status() - // instead for the HTTP status code. - - inline bool Get(const std::string& url, std::size_t buffer_size = 0) { - return Request("GET", url, "", buffer_size); - } - - inline bool Post(const std::string& url, std::string&& content, - std::size_t buffer_size = 0) { - return Request("POST", url, std::move(content), buffer_size); - } - - inline bool Put(const std::string& url, std::string&& content, - std::size_t buffer_size = 0) { - return Request("PUT", url, std::move(content), buffer_size); - } - - inline bool Patch(const std::string& url, std::string&& content, - std::size_t buffer_size = 0) { - return Request("PATCH", url, std::move(content), buffer_size); - } - - inline bool Delete(const std::string& url, std::size_t buffer_size = 0) { - return Request(kHttpDelete, url, "", buffer_size); - } - - HttpResponsePtr response() const { - return http_client_.response(); - } - - int response_status() const { - assert(response()); - return response()->status(); - } - - const std::string& response_content() const { - assert(response()); - return response()->content(); - } - - bool timed_out() const { - return http_client_.timed_out(); - } - - Error error() const { - return http_client_.error(); - } - - private: - bool Request(const std::string& method, const std::string& url, - std::string&& content, std::size_t buffer_size); - - std::string host_; - std::string port_; - - HttpClient http_client_; -}; - -} // namespace webcc - -#endif // WEBCC_REST_CLIENT_H_ diff --git a/webcc/rest_server.h b/webcc/rest_server.h index d1c5bcf..0a55d89 100644 --- a/webcc/rest_server.h +++ b/webcc/rest_server.h @@ -12,7 +12,7 @@ namespace webcc { class RestServer : public HttpServer { - public: +public: RestServer(std::uint16_t port, std::size_t workers) : HttpServer(port, workers) { } @@ -31,7 +31,7 @@ class RestServer : public HttpServer { return request_handler_.Bind(service, url, is_regex); } - private: +private: HttpRequestHandler* GetRequestHandler() override { return &request_handler_; } diff --git a/webcc/rest_service.h b/webcc/rest_service.h index 7a276e3..ac8adc0 100644 --- a/webcc/rest_service.h +++ b/webcc/rest_service.h @@ -46,7 +46,7 @@ struct RestResponse { // Base class for your REST service. class RestService { - public: +public: virtual ~RestService() = default; // Handle REST request, output response. @@ -58,10 +58,10 @@ typedef std::shared_ptr RestServicePtr; // ----------------------------------------------------------------------------- class RestListService : public RestService { - public: +public: void Handle(const RestRequest& request, RestResponse* response) final; - protected: +public: RestListService() = default; virtual void Get(const UrlQuery& query, RestResponse* response) { @@ -75,10 +75,10 @@ class RestListService : public RestService { // ----------------------------------------------------------------------------- class RestDetailService : public RestService { - public: +public: void Handle(const RestRequest& request, RestResponse* response) final; - protected: +public: virtual void Get(const UrlSubMatches& url_sub_matches, const UrlQuery& query, RestResponse* response) { diff --git a/webcc/rest_service_manager.h b/webcc/rest_service_manager.h index fabcedd..d758264 100644 --- a/webcc/rest_service_manager.h +++ b/webcc/rest_service_manager.h @@ -11,7 +11,7 @@ namespace webcc { class RestServiceManager { - public: +public: RestServiceManager() = default; WEBCC_DELETE_COPY_ASSIGN(RestServiceManager); @@ -30,9 +30,9 @@ class RestServiceManager { RestServicePtr GetService(const std::string& url, std::vector* sub_matches); - private: +private: class ServiceItem { - public: + public: ServiceItem(RestServicePtr _service, const std::string& _url, bool _is_regex) : service(_service), url(_url), is_regex(_is_regex) { diff --git a/webcc/rest_ssl_client.cc b/webcc/rest_ssl_client.cc deleted file mode 100644 index 9a47ca8..0000000 --- a/webcc/rest_ssl_client.cc +++ /dev/null @@ -1,54 +0,0 @@ -#include "webcc/rest_ssl_client.h" - -#include "boost/algorithm/string.hpp" - -#include "webcc/utility.h" - -namespace webcc { - -RestClientBase::RestClientBase(HttpClientBase* http_client_base, - const SSMap& headers) - : http_client_base_(http_client_base), - content_media_type_(http::media_types::kApplicationJson), - content_charset_(http::charsets::kUtf8), - headers_(headers) { -} - - -RestSslClient::RestSslClient(const std::string& host, const std::string& port, - bool ssl_verify, const SSMap& headers, - std::size_t buffer_size) - : RestClientBase(&http_ssl_client_, headers), - host_(host), port_(port), - http_ssl_client_(ssl_verify, buffer_size) { - AdjustHostPort(host_, port_); -} - -bool RestSslClient::Request(const std::string& method, const std::string& url, - std::string&& content, const SSMap& headers, - std::size_t buffer_size) { - HttpRequest http_request(method, url, host_, port_); - - if (!content.empty()) { - http_request.SetContent(std::move(content), true); - http_request.SetContentType(content_media_type_, content_charset_); - } - - for (auto& h : headers_) { - http_request.SetHeader(h.first, h.second); - } - - for (auto& h : headers) { - http_request.SetHeader(h.first, h.second); - } - - http_request.Prepare(); - - if (!http_ssl_client_.Request(http_request, buffer_size)) { - return false; - } - - return true; -} - -} // namespace webcc diff --git a/webcc/rest_ssl_client.h b/webcc/rest_ssl_client.h deleted file mode 100644 index f03a3cd..0000000 --- a/webcc/rest_ssl_client.h +++ /dev/null @@ -1,130 +0,0 @@ -#ifndef WEBCC_REST_SSL_CLIENT_H_ -#define WEBCC_REST_SSL_CLIENT_H_ - -#include -#include -#include -#include // for move() - -#include "webcc/globals.h" -#include "webcc/http_request.h" -#include "webcc/http_response.h" -#include "webcc/http_ssl_client.h" - -namespace webcc { - -typedef std::map SSMap; - -class RestClientBase { -public: - RestClientBase(HttpClientBase* http_client_base, - const SSMap& headers = {}); - - virtual ~RestClientBase() = default; - - WEBCC_DELETE_COPY_ASSIGN(RestClientBase); - - void SetTimeout(int seconds) { - http_client_base_->SetTimeout(seconds); - } - - // Overwrite the default content type (json & utf-8). - void SetContentType(const std::string& media_type, - const std::string& charset) { - content_media_type_ = media_type; - content_charset_ = charset; - } - - HttpResponsePtr response() const { - return http_client_base_->response(); - } - - int response_status() const { - assert(response()); - return response()->status(); - } - - const std::string& response_content() const { - assert(response()); - return response()->content(); - } - - bool timed_out() const { - return http_client_base_->timed_out(); - } - - Error error() const { - return http_client_base_->error(); - } - -protected: - // Default: "application/json". - std::string content_media_type_; - // Default: "utf-8". - std::string content_charset_; - - // Default headers for each request sent from this session. - std::map headers_; - -private: - HttpClientBase* http_client_base_; -}; - - -class RestSslClient : public RestClientBase { -public: - // If |port| is empty, |host| will be checked to see if it contains port or - // not (separated by ':'). - explicit RestSslClient(const std::string& host, - const std::string& port = "", - bool ssl_verify = true, - const SSMap& headers = {}, - std::size_t buffer_size = 0); - - ~RestSslClient() = default; - - // NOTE: - // The return value of the following methods (Get, Post, etc.) only indicates - // if the socket communication is successful or not. Check error() and - // timed_out() for more information if it's failed. Check response_status() - // instead for the HTTP status code. - - inline bool Get(const std::string& url, const SSMap& headers = {}, - std::size_t buffer_size = 0) { - return Request(kHttpGet, url, "", headers, buffer_size); - } - - inline bool Post(const std::string& url, std::string&& content, - const SSMap& headers = {}, std::size_t buffer_size = 0) { - return Request(Post, url, std::move(content), headers, buffer_size); - } - - inline bool Put(const std::string& url, std::string&& content, - const SSMap& headers = {}, std::size_t buffer_size = 0) { - return Request(kHttpPut, url, std::move(content), headers, buffer_size); - } - - inline bool Patch(const std::string& url, std::string&& content, - const SSMap& headers = {}, std::size_t buffer_size = 0) { - return Request(kHttpPatch, url, std::move(content), headers, buffer_size); - } - - inline bool Delete(const std::string& url, const SSMap& headers = {}, - std::size_t buffer_size = 0) { - return Request(kHttpDelete, url, "", headers, buffer_size); - } - - bool Request(const std::string& method, const std::string& url, - std::string&& content, const SSMap& headers = {}, - std::size_t buffer_size = 0); - - private: - std::string host_; - std::string port_; - - HttpSslClient http_ssl_client_; -}; - -} // namespace webcc - -#endif // WEBCC_REST_SSL_CLIENT_H_ diff --git a/webcc/soap_async_client.cc b/webcc/soap_async_client.cc deleted file mode 100644 index 331ba72..0000000 --- a/webcc/soap_async_client.cc +++ /dev/null @@ -1,102 +0,0 @@ -#include "webcc/soap_async_client.h" - -#include -#include // for move() - -#include "webcc/soap_globals.h" -#include "webcc/soap_request.h" -#include "webcc/soap_response.h" -#include "webcc/utility.h" - -namespace webcc { - -SoapAsyncClient::SoapAsyncClient(boost::asio::io_context& io_context, - const std::string& host, - const std::string& port, - SoapVersion soap_version, - std::size_t buffer_size) - : io_context_(io_context), - host_(host), port_(port), - soap_version_(soap_version), - buffer_size_(buffer_size), - format_raw_(true), timeout_seconds_(0) { - AdjustHostPort(host_, port_); -} - -void SoapAsyncClient::Request(const std::string& operation, - std::vector&& parameters, - SoapResponseCallback soap_response_callback) { - assert(service_ns_.IsValid()); - assert(!url_.empty() && !host_.empty()); - assert(!result_name_.empty()); - - SoapRequest soap_request; - - // Set SOAP envelope namespace according to SOAP version. - if (soap_version_ == kSoapV11) { - soap_request.set_soapenv_ns(kSoapEnvNamespaceV11); - } else { - soap_request.set_soapenv_ns(kSoapEnvNamespaceV12); - } - - soap_request.set_service_ns(service_ns_); - - soap_request.set_operation(operation); - - for (SoapParameter& p : parameters) { - soap_request.AddParameter(std::move(p)); - } - - std::string http_content; - soap_request.ToXml(format_raw_, indent_str_, &http_content); - - HttpRequestPtr http_request(new HttpRequest(kHttpPost, url_, host_, port_)); - - http_request->SetContent(std::move(http_content), true); - - if (soap_version_ == kSoapV11) { - http_request->SetContentType(http::media_types::kTextXml, - http::charsets::kUtf8); - } else { - http_request->SetContentType(http::media_types::kApplicationSoapXml, - http::charsets::kUtf8); - } - - http_request->SetHeader(kSoapAction, operation); - http_request->Prepare(); - - auto http_async_client = HttpAsyncClient::New(io_context_, buffer_size_); - - if (timeout_seconds_ > 0) { - http_async_client->SetTimeout(timeout_seconds_); - } - - auto http_response_callback = std::bind(&SoapAsyncClient::OnHttpResponse, - this, soap_response_callback, - std::placeholders::_1, - std::placeholders::_2, - std::placeholders::_3); - - http_async_client->Request(http_request, http_response_callback); -} - -void SoapAsyncClient::OnHttpResponse(SoapResponseCallback soap_response_callback, - HttpResponsePtr http_response, - Error error, bool timed_out) { - if (error != kNoError) { - soap_response_callback("", error, timed_out); - } else { - SoapResponse soap_response; - // TODO - //soap_response.set_result_name(result_name_); - - if (!soap_response.FromXml(http_response->content())) { - soap_response_callback("", kXmlError, false); - } else { - // TODO - //soap_response_callback(soap_response.result_moved(), kNoError, false); - } - } -} - -} // namespace webcc diff --git a/webcc/soap_async_client.h b/webcc/soap_async_client.h deleted file mode 100644 index c514464..0000000 --- a/webcc/soap_async_client.h +++ /dev/null @@ -1,91 +0,0 @@ -#ifndef WEBCC_SOAP_ASYNC_CLIENT_H_ -#define WEBCC_SOAP_ASYNC_CLIENT_H_ - -#include -#include -#include - -#include "webcc/http_async_client.h" -#include "webcc/soap_message.h" -#include "webcc/soap_parameter.h" - -namespace webcc { - -// Response callback. -typedef std::function SoapResponseCallback; - -class SoapAsyncClient { - public: - // If |port| is empty, |host| will be checked to see if it contains port or - // not (separated by ':'). - SoapAsyncClient(boost::asio::io_context& io_context, // NOLINT - const std::string& host, const std::string& port = "", - SoapVersion soap_version = kSoapV12, - std::size_t buffer_size = 0); - - ~SoapAsyncClient() = default; - - WEBCC_DELETE_COPY_ASSIGN(SoapAsyncClient); - - void set_timeout_seconds(int timeout_seconds) { - timeout_seconds_ = timeout_seconds; - } - - void set_url(const std::string& url) { url_ = url; } - - void set_service_ns(const SoapNamespace& service_ns) { - service_ns_ = service_ns; - } - - void set_result_name(const std::string& result_name) { - result_name_ = result_name; - } - - void set_format_raw(bool format_raw) { format_raw_ = format_raw; } - - void set_indent_str(const std::string& indent_str) { - indent_str_ = indent_str; - } - - void Request(const std::string& operation, - std::vector&& parameters, - SoapResponseCallback soap_response_callback); - - private: - void OnHttpResponse(SoapResponseCallback soap_response_callback, - HttpResponsePtr http_response, - Error error, bool timed_out); - - boost::asio::io_context& io_context_; - - std::string host_; - std::string port_; // Leave this empty to use default 80. - - SoapVersion soap_version_; - - std::size_t buffer_size_; - - // Request URL. - std::string url_; - - // Namespace for your web service. - SoapNamespace service_ns_; - - // Response result XML node name. - // E.g., "Result". - std::string result_name_; - - // Format request XML without any indentation or line breaks. - bool format_raw_; - - // Indent string for request XML. - // Applicable when |format_raw_| is false. - std::string indent_str_; - - // Timeout in seconds; only effective when > 0. - int timeout_seconds_; -}; - -} // namespace webcc - -#endif // WEBCC_SOAP_ASYNC_CLIENT_H_ diff --git a/webcc/soap_client.h b/webcc/soap_client.h index 8445b8a..ad27555 100644 --- a/webcc/soap_client.h +++ b/webcc/soap_client.h @@ -12,7 +12,7 @@ namespace webcc { class SoapClient { - public: +public: // If |port| is empty, |host| will be checked to see if it contains port or // not (separated by ':'). explicit SoapClient(const std::string& host, const std::string& port = "", @@ -69,7 +69,7 @@ class SoapClient { std::shared_ptr fault() const { return fault_; } - private: +private: std::string host_; std::string port_; // Leave this empty to use default 80. diff --git a/webcc/soap_message.h b/webcc/soap_message.h index 360240f..cc19c4c 100644 --- a/webcc/soap_message.h +++ b/webcc/soap_message.h @@ -11,7 +11,7 @@ namespace webcc { // Base class for SOAP request and response. class SoapMessage { - public: +public: virtual ~SoapMessage() = default; // E.g., set as kSoapEnvNamespace. @@ -38,7 +38,7 @@ class SoapMessage { // Parse from SOAP XML. bool FromXml(const std::string& xml_string); - protected: +public: // Convert to SOAP body XML. virtual void ToXmlBody(pugi::xml_node xbody) = 0; diff --git a/webcc/soap_parameter.h b/webcc/soap_parameter.h index ccdda20..9effe85 100644 --- a/webcc/soap_parameter.h +++ b/webcc/soap_parameter.h @@ -9,7 +9,7 @@ namespace webcc { // Key-value SOAP parameter. class SoapParameter { - public: +public: SoapParameter() : as_cdata_(false) { } @@ -77,7 +77,7 @@ class SoapParameter { bool as_cdata() const { return as_cdata_; } - private: +private: std::string key_; std::string value_; bool as_cdata_; diff --git a/webcc/soap_request.h b/webcc/soap_request.h index cf145e0..06f36eb 100644 --- a/webcc/soap_request.h +++ b/webcc/soap_request.h @@ -13,7 +13,7 @@ namespace webcc { // Used to compose the SOAP request envelope XML which will be sent as the HTTP // request body. class SoapRequest : public SoapMessage { - public: +public: void AddParameter(const SoapParameter& parameter); void AddParameter(SoapParameter&& parameter); @@ -21,11 +21,11 @@ class SoapRequest : public SoapMessage { // Get parameter value by key. const std::string& GetParameter(const std::string& key) const; - protected: +public: void ToXmlBody(pugi::xml_node xbody) override; bool FromXmlBody(pugi::xml_node xbody) override; - private: +private: std::vector parameters_; }; diff --git a/webcc/soap_response.h b/webcc/soap_response.h index a679027..14d5f4c 100644 --- a/webcc/soap_response.h +++ b/webcc/soap_response.h @@ -12,7 +12,7 @@ namespace webcc { class SoapResponse : public SoapMessage { - public: +public: // Response result parser. // Called on each child of the response node. // Example: @@ -50,11 +50,11 @@ class SoapResponse : public SoapMessage { // - composer(xxxResponse); // The composer then add proper children to xxxResponse as the result. class Composer { - public: + public: void operator()(pugi::xml_node xresponse) { Compose(xresponse); } - private: + private: virtual void Compose(pugi::xml_node xresponse) = 0; }; @@ -127,12 +127,12 @@ class SoapResponse : public SoapMessage { // TODO: Set fault from server. - protected: +public: void ToXmlBody(pugi::xml_node xbody) override; bool FromXmlBody(pugi::xml_node xbody) override; - private: +private: // Fault element if any. std::shared_ptr fault_; diff --git a/webcc/soap_server.h b/webcc/soap_server.h index a80ff6a..79a81b3 100644 --- a/webcc/soap_server.h +++ b/webcc/soap_server.h @@ -11,7 +11,7 @@ namespace webcc { class SoapServer : public HttpServer { - public: +public: SoapServer(std::uint16_t port, std::size_t workers, SoapVersion soap_version = kSoapV12) : HttpServer(port, workers), @@ -36,7 +36,7 @@ class SoapServer : public HttpServer { return request_handler_.Bind(service, url); } - private: +private: HttpRequestHandler* GetRequestHandler() override { return &request_handler_; } diff --git a/webcc/soap_service.h b/webcc/soap_service.h index adcde22..8b34ada 100644 --- a/webcc/soap_service.h +++ b/webcc/soap_service.h @@ -12,14 +12,14 @@ class SoapResponse; // Base class for your SOAP service. class SoapService { - public: +public: virtual ~SoapService() = default; // Handle SOAP request, output the response. virtual bool Handle(const SoapRequest& soap_request, SoapResponse* soap_response) = 0; - protected: +public: http::Status http_status_ = http::Status::kOK; }; diff --git a/webcc/soap_xml.h b/webcc/soap_xml.h index b47fcfb..949ff32 100644 --- a/webcc/soap_xml.h +++ b/webcc/soap_xml.h @@ -73,7 +73,7 @@ std::string GetNSAttr(const pugi::xml_node& xnode, // XmlStringWriter writer(&xml_string); // xdoc.save/print(writer); class XmlStringWriter : public pugi::xml_writer { - public: +public: explicit XmlStringWriter(std::string* result) : result_(result) { result_->clear(); } @@ -82,7 +82,7 @@ class XmlStringWriter : public pugi::xml_writer { result_->append(static_cast(data), size); } - private: +private: std::string* result_; }; diff --git a/webcc/url.h b/webcc/url.h index 7b3ba71..958058a 100644 --- a/webcc/url.h +++ b/webcc/url.h @@ -7,6 +7,8 @@ #include #include +#include "webcc/globals.h" + namespace webcc { // ----------------------------------------------------------------------------- @@ -57,9 +59,36 @@ class Url { public: Url() = default; - // TODO: decode/encode/encoded? explicit Url(const std::string& str, bool decode = true); +#if WEBCC_DEFAULT_MOVE_COPY_ASSIGN + + Url(Url&&) = default; + Url& operator=(Url&&) = default; + +#else + + Url(Url&& rhs) + : scheme_(std::move(rhs.scheme_)), + host_(std::move(rhs.host_)), + port_(std::move(rhs.port_)), + path_(std::move(rhs.path_)), + query_(std::move(rhs.query_)) { + } + + Url& operator=(Url&& rhs) { + if (&rhs != this) { + scheme_ = std::move(rhs.scheme_); + host_ = std::move(rhs.host_); + port_ = std::move(rhs.port_); + path_ = std::move(rhs.path_); + query_ = std::move(rhs.query_); + } + return *this; + } + +#endif // WEBCC_DEFAULT_MOVE_COPY_ASSIGN + void Init(const std::string& str, bool decode = true, bool clear = true); const std::string& scheme() const {