Cleanup async client APIs.
This commit is contained in:
+2
-33
@@ -118,48 +118,17 @@ endif()
|
|||||||
add_subdirectory(webcc)
|
add_subdirectory(webcc)
|
||||||
|
|
||||||
if(WEBCC_ENABLE_EXAMPLES)
|
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)
|
if(WEBCC_ENABLE_REST)
|
||||||
# For including jsoncpp as "json/json.h".
|
# For including jsoncpp as "json/json.h".
|
||||||
include_directories(${THIRD_PARTY_DIR}/src/jsoncpp)
|
include_directories(${THIRD_PARTY_DIR}/src/jsoncpp)
|
||||||
# REST examples need jsoncpp to parse and create JSON.
|
# REST examples need jsoncpp to parse and create JSON.
|
||||||
add_subdirectory(${THIRD_PARTY_DIR}/src/jsoncpp)
|
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()
|
endif()
|
||||||
|
|
||||||
if(WEBCC_ENABLE_SOAP)
|
add_subdirectory(example)
|
||||||
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()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WEBCC_ENABLE_UNITTEST)
|
if(WEBCC_ENABLE_UNITTEST)
|
||||||
add_subdirectory(third_party/src/gtest)
|
add_subdirectory(${THIRD_PARTY_DIR}/src/gtest)
|
||||||
add_subdirectory(unittest)
|
add_subdirectory(unittest)
|
||||||
endif()
|
endif()
|
||||||
|
|||||||
@@ -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)
|
||||||
@@ -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.
|
|
||||||
@@ -20,7 +20,7 @@ std::ostream& operator<<(std::ostream& os, const Book& book);
|
|||||||
extern const Book kNullBook;
|
extern const Book kNullBook;
|
||||||
|
|
||||||
class BookStore {
|
class BookStore {
|
||||||
public:
|
public:
|
||||||
const std::list<Book>& books() const { return books_; }
|
const std::list<Book>& books() const { return books_; }
|
||||||
|
|
||||||
const Book& GetBook(const std::string& id) const;
|
const Book& GetBook(const std::string& id) const;
|
||||||
@@ -33,7 +33,7 @@ class BookStore {
|
|||||||
|
|
||||||
bool DeleteBook(const std::string& id);
|
bool DeleteBook(const std::string& id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<Book>::const_iterator FindBook(const std::string& id) const;
|
std::list<Book>::const_iterator FindBook(const std::string& id) const;
|
||||||
|
|
||||||
std::list<Book>::iterator FindBook(const std::string& id);
|
std::list<Book>::iterator FindBook(const std::string& id);
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
add_executable(github_client main.cc)
|
||||||
|
target_link_libraries(github_client ${EXAMPLE_COMMON_LIBS} jsoncpp)
|
||||||
@@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "json/json.h"
|
#include "json/json.h"
|
||||||
|
|
||||||
|
#include "webcc/http_client_session.h"
|
||||||
#include "webcc/logger.h"
|
#include "webcc/logger.h"
|
||||||
#include "webcc/rest_ssl_client.h"
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -19,7 +19,7 @@ bool kSslVerify = false;
|
|||||||
bool kSslVerify = true;
|
bool kSslVerify = true;
|
||||||
#endif
|
#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)
|
#define PRINT_JSON_STRING(str)
|
||||||
#endif // PRINT_RESPONSE
|
#endif // PRINT_RESPONSE
|
||||||
|
|
||||||
static void PrintError(const webcc::RestSslClient& client) {
|
//static void PrintError(const webcc::RestSslClient& client) {
|
||||||
std::cout << webcc::DescribeError(client.error());
|
// std::cout << webcc::DescribeError(client.error());
|
||||||
if (client.timed_out()) {
|
// if (client.timed_out()) {
|
||||||
std::cout << " (timed out)";
|
// std::cout << " (timed out)";
|
||||||
}
|
// }
|
||||||
std::cout << std::endl;
|
// std::cout << std::endl;
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
// -----------------------------------------------------------------------------
|
//// -----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
// List public events.
|
//// List public events.
|
||||||
static void ListEvents(webcc::RestSslClient& client) {
|
//static void ListEvents(webcc::RestSslClient& client) {
|
||||||
if (client.Get("/events")) {
|
// if (client.Get("/events")) {
|
||||||
PRINT_JSON_STRING(client.response_content());
|
// PRINT_JSON_STRING(client.response_content());
|
||||||
} else {
|
// } else {
|
||||||
PrintError(client);
|
// PrintError(client);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
//
|
||||||
// List the followers of the given user.
|
//// List the followers of the given user.
|
||||||
static void ListUserFollowers(webcc::RestSslClient& client,
|
//static void ListUserFollowers(webcc::RestSslClient& client,
|
||||||
const std::string& user) {
|
// const std::string& user) {
|
||||||
if (client.Get("/users/" + user + "/followers")) {
|
// if (client.Get("/users/" + user + "/followers")) {
|
||||||
PRINT_JSON_STRING(client.response_content());
|
// PRINT_JSON_STRING(client.response_content());
|
||||||
} else {
|
// } else {
|
||||||
PrintError(client);
|
// PrintError(client);
|
||||||
}
|
// }
|
||||||
}
|
//}
|
||||||
|
|
||||||
// List the followers of the current authorized user.
|
// List the followers of the current authorized user.
|
||||||
// Header syntax: Authorization: <type> <credentials>
|
// Header syntax: Authorization: <type> <credentials>
|
||||||
static void ListAuthorizedUserFollowers(webcc::RestSslClient& client,
|
static void ListAuthorizedUserFollowers(webcc::HttpClientSession& session,
|
||||||
const std::string& auth) {
|
const std::string& auth) {
|
||||||
if (client.Get("/user/followers", { { "Authorization", auth } })) {
|
auto r = session.Request(webcc::HttpRequestArgs("GET").
|
||||||
PRINT_JSON_STRING(client.response_content());
|
url("https://api.github.com/user/followers").
|
||||||
|
headers({ { "Authorization", auth } }).
|
||||||
|
ssl_verify(kSslVerify).buffer_size(kBufferSize));
|
||||||
|
|
||||||
|
if (r) {
|
||||||
|
PRINT_JSON_STRING(r->content());
|
||||||
} else {
|
} else {
|
||||||
PrintError(client);
|
//PrintError(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,10 +107,10 @@ static void ListAuthorizedUserFollowers(webcc::RestSslClient& client,
|
|||||||
int main() {
|
int main() {
|
||||||
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
||||||
|
|
||||||
webcc::RestSslClient client(kGithubHost, "", kSslVerify, {}, 1500);
|
webcc::HttpClientSession session;
|
||||||
|
|
||||||
//ListAuthorizedUserFollowers(client, "Basic c3ByaW5mYWxsQGdtYWlsLmNvbTpYaWFvTHVhbjFA");
|
//ListAuthorizedUserFollowers(client, "Basic c3ByaW5mYWxsQGdtYWlsLmNvbTpYaWFvTHVhbjFA");
|
||||||
ListAuthorizedUserFollowers(client, "Token 1d42e2cce49929f2d24b1b6e96260003e5b3e1b0");
|
ListAuthorizedUserFollowers(session, "Token 1d42e2cce49929f2d24b1b6e96260003e5b3e1b0");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
add_executable(github_rest_client main.cc)
|
|
||||||
target_link_libraries(github_rest_client ${EXAMPLE_COMMON_LIBS} jsoncpp)
|
|
||||||
@@ -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}")
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
+20
-10
@@ -3,6 +3,14 @@
|
|||||||
#include "webcc/http_client_session.h"
|
#include "webcc/http_client_session.h"
|
||||||
#include "webcc/logger.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() {
|
int main() {
|
||||||
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
WEBCC_LOG_INIT("", webcc::LOG_CONSOLE);
|
||||||
|
|
||||||
@@ -29,21 +37,21 @@ int main() {
|
|||||||
// - constructor: HttpRequestArgs{ "GET" }
|
// - constructor: HttpRequestArgs{ "GET" }
|
||||||
// - move constructor: auto args = ...
|
// - move constructor: auto args = ...
|
||||||
|
|
||||||
auto args = HttpRequestArgs{"GET"}.
|
//auto args = HttpRequestArgs{"GET"}.
|
||||||
url("http://httpbin.org/get").
|
// url("http://httpbin.org/get").
|
||||||
parameters({ "key1", "value1", "key2", "value2" }).
|
// parameters({ "key1", "value1", "key2", "value2" }).
|
||||||
headers({ "Accept", "application/json" }).
|
// headers({ "Accept", "application/json" }).
|
||||||
buffer_size(1000);
|
// buffer_size(1000);
|
||||||
|
|
||||||
r = session.Request(std::move(args));
|
//r = session.Request(std::move(args));
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// Use pre-defined wrappers.
|
// Use pre-defined wrappers.
|
||||||
|
|
||||||
r = session.Get("http://httpbin.org/get",
|
//r = session.Get("http://httpbin.org/get",
|
||||||
{ "key1", "value1", "key2", "value2" },
|
// { "key1", "value1", "key2", "value2" },
|
||||||
{ "Accept", "application/json" },
|
// { "Accept", "application/json" },
|
||||||
HttpRequestArgs{}.buffer_size(1000));
|
// HttpRequestArgs{}.buffer_size(1000));
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// HTTPS is auto-detected from the URL schema.
|
// HTTPS is auto-detected from the URL schema.
|
||||||
@@ -56,5 +64,7 @@ int main() {
|
|||||||
std::cout << r->content() << std::endl;
|
std::cout << r->content() << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetBoostOrgLicense(session);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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})
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
add_executable(http_ssl_client main.cc)
|
|
||||||
target_link_libraries(http_ssl_client ${EXAMPLE_COMMON_LIBS})
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
||||||
@@ -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}")
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#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<void(webcc::HttpResponsePtr)> 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<void(std::string)> 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 << " <host> <port> [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;
|
|
||||||
}
|
|
||||||
@@ -9,8 +9,7 @@ set(SRCS
|
|||||||
|
|
||||||
add_executable(${TARGET_NAME} ${SRCS})
|
add_executable(${TARGET_NAME} ${SRCS})
|
||||||
|
|
||||||
target_link_libraries(${TARGET_NAME} webcc jsoncpp ${Boost_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${EXAMPLE_COMMON_LIBS} jsoncpp)
|
||||||
target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}")
|
|
||||||
|
|
||||||
# Install VLD DLLs to build dir so that the example can be launched from
|
# Install VLD DLLs to build dir so that the example can be launched from
|
||||||
# inside VS.
|
# inside VS.
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class BookClientBase {
|
class BookClientBase {
|
||||||
public:
|
public:
|
||||||
BookClientBase(const std::string& host, const std::string& port,
|
BookClientBase(const std::string& host, const std::string& port,
|
||||||
int timeout_seconds)
|
int timeout_seconds)
|
||||||
: host_(host), port_(port) {
|
: host_(host), port_(port) {
|
||||||
@@ -29,7 +29,7 @@ class BookClientBase {
|
|||||||
|
|
||||||
virtual ~BookClientBase() = default;
|
virtual ~BookClientBase() = default;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
// Helper function to make a request.
|
// Helper function to make a request.
|
||||||
webcc::HttpRequestPtr MakeRequest(const std::string& method,
|
webcc::HttpRequestPtr MakeRequest(const std::string& method,
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
@@ -71,7 +71,7 @@ class BookClientBase {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class BookListClient : public BookClientBase {
|
class BookListClient : public BookClientBase {
|
||||||
public:
|
public:
|
||||||
BookListClient(const std::string& host, const std::string& port,
|
BookListClient(const std::string& host, const std::string& port,
|
||||||
int timeout_seconds)
|
int timeout_seconds)
|
||||||
: BookClientBase(host, port, timeout_seconds) {
|
: BookClientBase(host, port, timeout_seconds) {
|
||||||
@@ -131,7 +131,7 @@ class BookListClient : public BookClientBase {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class BookDetailClient : public BookClientBase {
|
class BookDetailClient : public BookClientBase {
|
||||||
public:
|
public:
|
||||||
BookDetailClient(const std::string& host, const std::string& port,
|
BookDetailClient(const std::string& host, const std::string& port,
|
||||||
int timeout_seconds)
|
int timeout_seconds)
|
||||||
: BookClientBase(host, port, timeout_seconds) {
|
: BookClientBase(host, port, timeout_seconds) {
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class BookListService : public webcc::RestListService {
|
class BookListService : public webcc::RestListService {
|
||||||
public:
|
public:
|
||||||
explicit BookListService(int sleep_seconds)
|
explicit BookListService(int sleep_seconds)
|
||||||
: sleep_seconds_(sleep_seconds) {
|
: sleep_seconds_(sleep_seconds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
// Get a list of books based on query parameters.
|
// Get a list of books based on query parameters.
|
||||||
void Get(const webcc::UrlQuery& query, webcc::RestResponse* response) final;
|
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,
|
void Post(const std::string& request_content,
|
||||||
webcc::RestResponse* response) final;
|
webcc::RestResponse* response) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Sleep some seconds before send back the response.
|
// Sleep some seconds before send back the response.
|
||||||
// For testing timeout control in client side.
|
// For testing timeout control in client side.
|
||||||
int sleep_seconds_;
|
int sleep_seconds_;
|
||||||
@@ -33,12 +33,12 @@ class BookListService : public webcc::RestListService {
|
|||||||
// The URL is like '/books/{BookID}', and the 'url_sub_matches' parameter
|
// The URL is like '/books/{BookID}', and the 'url_sub_matches' parameter
|
||||||
// contains the matched book ID.
|
// contains the matched book ID.
|
||||||
class BookDetailService : public webcc::RestDetailService {
|
class BookDetailService : public webcc::RestDetailService {
|
||||||
public:
|
public:
|
||||||
explicit BookDetailService(int sleep_seconds)
|
explicit BookDetailService(int sleep_seconds)
|
||||||
: sleep_seconds_(sleep_seconds) {
|
: sleep_seconds_(sleep_seconds) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
// Get the detailed information of a book.
|
// Get the detailed information of a book.
|
||||||
void Get(const webcc::UrlSubMatches& url_sub_matches,
|
void Get(const webcc::UrlSubMatches& url_sub_matches,
|
||||||
const webcc::UrlQuery& query,
|
const webcc::UrlQuery& query,
|
||||||
@@ -53,7 +53,7 @@ class BookDetailService : public webcc::RestDetailService {
|
|||||||
void Delete(const webcc::UrlSubMatches& url_sub_matches,
|
void Delete(const webcc::UrlSubMatches& url_sub_matches,
|
||||||
webcc::RestResponse* response) final;
|
webcc::RestResponse* response) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Sleep some seconds before send back the response.
|
// Sleep some seconds before send back the response.
|
||||||
// For testing timeout control in client side.
|
// For testing timeout control in client side.
|
||||||
int sleep_seconds_;
|
int sleep_seconds_;
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ set(SRCS
|
|||||||
|
|
||||||
add_executable(${TARGET_NAME} ${SRCS})
|
add_executable(${TARGET_NAME} ${SRCS})
|
||||||
|
|
||||||
target_link_libraries(${TARGET_NAME} webcc pugixml ${Boost_LIBRARIES})
|
target_link_libraries(${TARGET_NAME} ${EXAMPLE_COMMON_LIBS} pugixml)
|
||||||
target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}")
|
|
||||||
|
|
||||||
# Install VLD DLLs to build dir so that the example can be launched from
|
# Install VLD DLLs to build dir so that the example can be launched from
|
||||||
# inside VS.
|
# inside VS.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "example/common/book.h"
|
#include "example/common/book.h"
|
||||||
|
|
||||||
class BookClient {
|
class BookClient {
|
||||||
public:
|
public:
|
||||||
BookClient(const std::string& host, const std::string& port);
|
BookClient(const std::string& host, const std::string& port);
|
||||||
|
|
||||||
int code() const { return code_; }
|
int code() const { return code_; }
|
||||||
@@ -28,7 +28,7 @@ class BookClient {
|
|||||||
// Delete a book by ID.
|
// Delete a book by ID.
|
||||||
bool DeleteBook(const std::string& id);
|
bool DeleteBook(const std::string& id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Call with 0 parameter.
|
// Call with 0 parameter.
|
||||||
bool Call0(const std::string& operation, std::string* result_str);
|
bool Call0(const std::string& operation, std::string* result_str);
|
||||||
|
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
#include "webcc/soap_service.h"
|
#include "webcc/soap_service.h"
|
||||||
|
|
||||||
class BookService : public webcc::SoapService {
|
class BookService : public webcc::SoapService {
|
||||||
public:
|
public:
|
||||||
bool Handle(const webcc::SoapRequest& soap_request,
|
bool Handle(const webcc::SoapRequest& soap_request,
|
||||||
webcc::SoapResponse* soap_response) override;
|
webcc::SoapResponse* soap_response) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreateBook(const webcc::SoapRequest& soap_request,
|
bool CreateBook(const webcc::SoapRequest& soap_request,
|
||||||
webcc::SoapResponse* soap_response);
|
webcc::SoapResponse* soap_response);
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
static const std::string kResultName = "Result";
|
static const std::string kResultName = "Result";
|
||||||
|
|
||||||
class CalcClient {
|
class CalcClient {
|
||||||
public:
|
public:
|
||||||
CalcClient(const std::string& host, const std::string& port)
|
CalcClient(const std::string& host, const std::string& port)
|
||||||
: soap_client_(host, port) {
|
: soap_client_(host, port) {
|
||||||
soap_client_.SetTimeout(5);
|
soap_client_.SetTimeout(5);
|
||||||
@@ -44,7 +44,7 @@ class CalcClient {
|
|||||||
return Calc("unknown", "x", "y", x, y, result);
|
return Calc("unknown", "x", "y", x, y, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Calc(const std::string& operation,
|
bool Calc(const std::string& operation,
|
||||||
const std::string& x_name, const std::string& y_name,
|
const std::string& x_name, const std::string& y_name,
|
||||||
double x, double y,
|
double x, double y,
|
||||||
@@ -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}")
|
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
static const std::string kResultName = "Result";
|
static const std::string kResultName = "Result";
|
||||||
|
|
||||||
class CalcClient {
|
class CalcClient {
|
||||||
public:
|
public:
|
||||||
// NOTE: Parasoft's calculator service uses SOAP V1.1.
|
// NOTE: Parasoft's calculator service uses SOAP V1.1.
|
||||||
CalcClient(const std::string& host, const std::string& port)
|
CalcClient(const std::string& host, const std::string& port)
|
||||||
: soap_client_(host, port, webcc::kSoapV11) {
|
: soap_client_(host, port, webcc::kSoapV11) {
|
||||||
@@ -45,7 +45,7 @@ class CalcClient {
|
|||||||
return Calc("unknown", "x", "y", x, y, result);
|
return Calc("unknown", "x", "y", x, y, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Calc(const std::string& operation,
|
bool Calc(const std::string& operation,
|
||||||
const std::string& x_name, const std::string& y_name,
|
const std::string& x_name, const std::string& y_name,
|
||||||
double x, double y,
|
double x, double y,
|
||||||
@@ -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}")
|
|
||||||
@@ -1,250 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="US-ASCII"?>
|
|
||||||
<!--generated by GLUE Standard 4.1.2 on Fri Nov 21 13:50:48 PST 2003-->
|
|
||||||
<wsdl:definitions name="Calculator"
|
|
||||||
targetNamespace="http://www.parasoft.com/wsdl/calculator/"
|
|
||||||
xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
|
|
||||||
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
|
|
||||||
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
|
|
||||||
xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/"
|
|
||||||
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
|
|
||||||
xmlns:tme="http://www.themindelectric.com/"
|
|
||||||
xmlns:tns="http://www.parasoft.com/wsdl/calculator/"
|
|
||||||
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
|
|
||||||
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
|
||||||
<wsdl:types>
|
|
||||||
<xsd:schema
|
|
||||||
elementFormDefault="qualified"
|
|
||||||
targetNamespace="http://www.parasoft.com/wsdl/calculator/">
|
|
||||||
<xsd:element
|
|
||||||
name="add">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="x" type="xsd:float"/>
|
|
||||||
<xsd:element name="y"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element
|
|
||||||
name="addResponse">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="Result"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element
|
|
||||||
name="divide">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="numerator" type="xsd:float"/>
|
|
||||||
<xsd:element
|
|
||||||
name="denominator"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element
|
|
||||||
name="divideResponse">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="Result"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element
|
|
||||||
name="multiply">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="x" type="xsd:float"/>
|
|
||||||
<xsd:element name="y"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element
|
|
||||||
name="multiplyResponse">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="Result"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element
|
|
||||||
name="subtract">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="x" type="xsd:float"/>
|
|
||||||
<xsd:element name="y"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
<xsd:element
|
|
||||||
name="subtractResponse">
|
|
||||||
<xsd:complexType>
|
|
||||||
<xsd:sequence>
|
|
||||||
<xsd:element
|
|
||||||
name="Result"
|
|
||||||
type="xsd:float"/>
|
|
||||||
</xsd:sequence>
|
|
||||||
</xsd:complexType>
|
|
||||||
</xsd:element>
|
|
||||||
</xsd:schema>
|
|
||||||
</wsdl:types>
|
|
||||||
<wsdl:message
|
|
||||||
name="add0In">
|
|
||||||
<wsdl:part element="tns:add"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message
|
|
||||||
name="add0Out">
|
|
||||||
<wsdl:part element="tns:addResponse"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message
|
|
||||||
name="divide1In">
|
|
||||||
<wsdl:part element="tns:divide"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message
|
|
||||||
name="divide1Out">
|
|
||||||
<wsdl:part element="tns:divideResponse"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message
|
|
||||||
name="multiply2In">
|
|
||||||
<wsdl:part element="tns:multiply"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message
|
|
||||||
name="multiply2Out">
|
|
||||||
<wsdl:part element="tns:multiplyResponse"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message
|
|
||||||
name="subtract3In">
|
|
||||||
<wsdl:part element="tns:subtract"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:message
|
|
||||||
name="subtract3Out">
|
|
||||||
<wsdl:part element="tns:subtractResponse"
|
|
||||||
name="parameters"/>
|
|
||||||
</wsdl:message>
|
|
||||||
<wsdl:portType
|
|
||||||
name="ICalculator">
|
|
||||||
<wsdl:operation name="add"
|
|
||||||
parameterOrder="x y">
|
|
||||||
<wsdl:input message="tns:add0In"
|
|
||||||
name="add0In"/>
|
|
||||||
<wsdl:output message="tns:add0Out"
|
|
||||||
name="add0Out"/>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation name="divide"
|
|
||||||
parameterOrder="numerator denominator">
|
|
||||||
<wsdl:input
|
|
||||||
message="tns:divide1In" name="divide1In"/>
|
|
||||||
<wsdl:output
|
|
||||||
message="tns:divide1Out"
|
|
||||||
name="divide1Out"/>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation
|
|
||||||
name="multiply" parameterOrder="x y">
|
|
||||||
<wsdl:input
|
|
||||||
message="tns:multiply2In" name="multiply2In"/>
|
|
||||||
<wsdl:output
|
|
||||||
message="tns:multiply2Out"
|
|
||||||
name="multiply2Out"/>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation
|
|
||||||
name="subtract" parameterOrder="x y">
|
|
||||||
<wsdl:input
|
|
||||||
message="tns:subtract3In" name="subtract3In"/>
|
|
||||||
<wsdl:output
|
|
||||||
message="tns:subtract3Out"
|
|
||||||
name="subtract3Out"/>
|
|
||||||
</wsdl:operation>
|
|
||||||
</wsdl:portType>
|
|
||||||
<wsdl:binding
|
|
||||||
name="ICalculator" type="tns:ICalculator">
|
|
||||||
<soap:binding
|
|
||||||
style="document"
|
|
||||||
transport="http://schemas.xmlsoap.org/soap/http"/>
|
|
||||||
<wsdl:operation
|
|
||||||
name="add">
|
|
||||||
<soap:operation soapAction="add"
|
|
||||||
style="document"/>
|
|
||||||
<wsdl:input name="add0In">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output
|
|
||||||
name="add0Out">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation
|
|
||||||
name="divide">
|
|
||||||
<soap:operation soapAction="divide"
|
|
||||||
style="document"/>
|
|
||||||
<wsdl:input name="divide1In">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output
|
|
||||||
name="divide1Out">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation
|
|
||||||
name="multiply">
|
|
||||||
<soap:operation soapAction="multiply"
|
|
||||||
style="document"/>
|
|
||||||
<wsdl:input name="multiply2In">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output
|
|
||||||
name="multiply2Out">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
<wsdl:operation
|
|
||||||
name="subtract">
|
|
||||||
<soap:operation soapAction="subtract"
|
|
||||||
style="document"/>
|
|
||||||
<wsdl:input name="subtract3In">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:input>
|
|
||||||
<wsdl:output
|
|
||||||
name="subtract3Out">
|
|
||||||
<soap:body
|
|
||||||
use="literal"/>
|
|
||||||
</wsdl:output>
|
|
||||||
</wsdl:operation>
|
|
||||||
</wsdl:binding>
|
|
||||||
<wsdl:service
|
|
||||||
name="Calculator">
|
|
||||||
<wsdl:documentation>instance of class webtool.soap.examples.calculator.Calculator</wsdl:documentation>
|
|
||||||
<wsdl:port
|
|
||||||
binding="tns:ICalculator" name="ICalculator">
|
|
||||||
<soap:address
|
|
||||||
location="http://ws1.parasoft.com/glue/calculator"/>
|
|
||||||
</wsdl:port>
|
|
||||||
</wsdl:service>
|
|
||||||
</wsdl:definitions>
|
|
||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "webcc/soap_service.h"
|
#include "webcc/soap_service.h"
|
||||||
|
|
||||||
class CalcService : public webcc::SoapService {
|
class CalcService : public webcc::SoapService {
|
||||||
public:
|
public:
|
||||||
CalcService() = default;
|
CalcService() = default;
|
||||||
~CalcService() override = default;
|
~CalcService() override = default;
|
||||||
|
|
||||||
|
|||||||
Vendored
+5
-5
@@ -693,7 +693,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
#ifndef JSONCPP_DOC_EXCLUDE_IMPLEMENTATION
|
||||||
class CZString {
|
class CZString {
|
||||||
public:
|
public:
|
||||||
enum DuplicationPolicy {
|
enum DuplicationPolicy {
|
||||||
noDuplication = 0,
|
noDuplication = 0,
|
||||||
duplicate,
|
duplicate,
|
||||||
@@ -1548,14 +1548,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
public:
|
public:
|
||||||
TokenType type_;
|
TokenType type_;
|
||||||
Location start_;
|
Location start_;
|
||||||
Location end_;
|
Location end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ErrorInfo {
|
class ErrorInfo {
|
||||||
public:
|
public:
|
||||||
Token token_;
|
Token token_;
|
||||||
JSONCPP_STRING message_;
|
JSONCPP_STRING message_;
|
||||||
Location extra_;
|
Location extra_;
|
||||||
@@ -1646,7 +1646,7 @@ public:
|
|||||||
Value* root, JSONCPP_STRING* errs) = 0;
|
Value* root, JSONCPP_STRING* errs) = 0;
|
||||||
|
|
||||||
class JSON_API Factory {
|
class JSON_API Factory {
|
||||||
public:
|
public:
|
||||||
virtual ~Factory() {}
|
virtual ~Factory() {}
|
||||||
/** \brief Allocate a CharReader via operator new().
|
/** \brief Allocate a CharReader via operator new().
|
||||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||||
@@ -1853,7 +1853,7 @@ public:
|
|||||||
/** \brief A simple abstract factory.
|
/** \brief A simple abstract factory.
|
||||||
*/
|
*/
|
||||||
class JSON_API Factory {
|
class JSON_API Factory {
|
||||||
public:
|
public:
|
||||||
virtual ~Factory();
|
virtual ~Factory();
|
||||||
/** \brief Allocate a CharReader via operator new().
|
/** \brief Allocate a CharReader via operator new().
|
||||||
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
* \throw std::exception if something goes wrong (e.g. invalid settings)
|
||||||
|
|||||||
Vendored
+2
-2
@@ -1191,14 +1191,14 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
public:
|
public:
|
||||||
TokenType type_;
|
TokenType type_;
|
||||||
Location start_;
|
Location start_;
|
||||||
Location end_;
|
Location end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ErrorInfo {
|
class ErrorInfo {
|
||||||
public:
|
public:
|
||||||
Token token_;
|
Token token_;
|
||||||
JSONCPP_STRING message_;
|
JSONCPP_STRING message_;
|
||||||
Location extra_;
|
Location extra_;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class TestRestService : public webcc::RestService {
|
class TestRestService : public webcc::RestService {
|
||||||
public:
|
public:
|
||||||
void Handle(const webcc::RestRequest& request,
|
void Handle(const webcc::RestRequest& request,
|
||||||
webcc::RestResponse* response) final {
|
webcc::RestResponse* response) final {
|
||||||
response->status = webcc::http::Status::kOK;
|
response->status = webcc::http::Status::kOK;
|
||||||
@@ -37,6 +37,23 @@ TEST(RestServiceManager, URL_RegexBasic) {
|
|||||||
EXPECT_FALSE(!!service);
|
EXPECT_FALSE(!!service);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RestServiceManager, URL_Temp) {
|
||||||
|
webcc::RestServiceManager service_manager;
|
||||||
|
|
||||||
|
service_manager.AddService(std::make_shared<TestRestService>(),
|
||||||
|
"/instance/([\\w.]+)", true);
|
||||||
|
|
||||||
|
std::vector<std::string> 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) {
|
TEST(RestServiceManager, URL_RegexMultiple) {
|
||||||
webcc::RestServiceManager service_manager;
|
webcc::RestServiceManager service_manager;
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,6 @@ include(GNUInstallDirs)
|
|||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
globals.h
|
globals.h
|
||||||
# http_async_client_base.h
|
|
||||||
# http_async_client.h
|
|
||||||
http_client_base.h
|
http_client_base.h
|
||||||
http_client.h
|
http_client.h
|
||||||
http_client_session.h
|
http_client_session.h
|
||||||
@@ -31,7 +29,6 @@ set(HEADERS
|
|||||||
http_response_parser.h
|
http_response_parser.h
|
||||||
http_server.h
|
http_server.h
|
||||||
http_ssl_client.h
|
http_ssl_client.h
|
||||||
# http_ssl_async_client.h
|
|
||||||
queue.h
|
queue.h
|
||||||
url.h
|
url.h
|
||||||
utility.h
|
utility.h
|
||||||
@@ -40,8 +37,6 @@ set(HEADERS
|
|||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
globals.cc
|
globals.cc
|
||||||
# http_async_client_base.cc
|
|
||||||
# http_async_client.cc
|
|
||||||
http_client_base.cc
|
http_client_base.cc
|
||||||
http_client.cc
|
http_client.cc
|
||||||
http_client_session.cc
|
http_client_session.cc
|
||||||
@@ -55,7 +50,6 @@ set(SOURCES
|
|||||||
http_response_parser.cc
|
http_response_parser.cc
|
||||||
http_server.cc
|
http_server.cc
|
||||||
http_ssl_client.cc
|
http_ssl_client.cc
|
||||||
# http_ssl_async_client.cc
|
|
||||||
logger.cc
|
logger.cc
|
||||||
url.cc
|
url.cc
|
||||||
utility.cc
|
utility.cc
|
||||||
@@ -63,16 +57,12 @@ set(SOURCES
|
|||||||
|
|
||||||
if(WEBCC_ENABLE_REST)
|
if(WEBCC_ENABLE_REST)
|
||||||
set(REST_HEADERS
|
set(REST_HEADERS
|
||||||
# rest_async_client.h
|
|
||||||
# rest_client.h
|
|
||||||
rest_request_handler.h
|
rest_request_handler.h
|
||||||
rest_server.h
|
rest_server.h
|
||||||
rest_service.h
|
rest_service.h
|
||||||
rest_service_manager.h
|
rest_service_manager.h
|
||||||
)
|
)
|
||||||
set(REST_SOURCES
|
set(REST_SOURCES
|
||||||
# rest_async_client.cc
|
|
||||||
# rest_client.cc
|
|
||||||
rest_request_handler.cc
|
rest_request_handler.cc
|
||||||
rest_service_manager.cc
|
rest_service_manager.cc
|
||||||
rest_service.cc
|
rest_service.cc
|
||||||
@@ -84,7 +74,6 @@ endif()
|
|||||||
|
|
||||||
if(WEBCC_ENABLE_SOAP)
|
if(WEBCC_ENABLE_SOAP)
|
||||||
set(SOAP_HEADERS
|
set(SOAP_HEADERS
|
||||||
# soap_async_client.h
|
|
||||||
soap_client.h
|
soap_client.h
|
||||||
soap_globals.h
|
soap_globals.h
|
||||||
soap_message.h
|
soap_message.h
|
||||||
@@ -98,7 +87,6 @@ if(WEBCC_ENABLE_SOAP)
|
|||||||
)
|
)
|
||||||
|
|
||||||
set(SOAP_SOURCES
|
set(SOAP_SOURCES
|
||||||
# soap_async_client.cc
|
|
||||||
soap_client.cc
|
soap_client.cc
|
||||||
soap_globals.cc
|
soap_globals.cc
|
||||||
soap_message.cc
|
soap_message.cc
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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<HttpAsyncClient> 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_
|
|
||||||
@@ -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<HttpRequest> 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
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
#ifndef WEBCC_HTTP_ASYNC_CLIENT_BASE_H_
|
|
||||||
#define WEBCC_HTTP_ASYNC_CLIENT_BASE_H_
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#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<void(HttpResponsePtr, Error, bool)> 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<HttpAsyncClientBase> {
|
|
||||||
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<void(boost::system::error_code, std::size_t)>
|
|
||||||
ReadHandler;
|
|
||||||
|
|
||||||
typedef std::function<void(boost::system::error_code, tcp::endpoint)>
|
|
||||||
ConnectHandler;
|
|
||||||
|
|
||||||
typedef std::function<void(boost::system::error_code, std::size_t)>
|
|
||||||
WriteHandler;
|
|
||||||
|
|
||||||
// To enable_shared_from_this for both parent and derived.
|
|
||||||
// See https://stackoverflow.com/q/657155/6825348
|
|
||||||
template <typename Derived>
|
|
||||||
std::shared_ptr<Derived> shared_from_base() {
|
|
||||||
return std::static_pointer_cast<Derived>(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<char> buffer_;
|
|
||||||
|
|
||||||
HttpResponsePtr response_;
|
|
||||||
std::unique_ptr<HttpResponseParser> 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_
|
|
||||||
+2
-2
@@ -7,12 +7,12 @@ namespace webcc {
|
|||||||
|
|
||||||
// HTTP synchronous client.
|
// HTTP synchronous client.
|
||||||
class HttpClient : public HttpClientBase {
|
class HttpClient : public HttpClientBase {
|
||||||
public:
|
public:
|
||||||
explicit HttpClient(std::size_t buffer_size = 0);
|
explicit HttpClient(std::size_t buffer_size = 0);
|
||||||
|
|
||||||
~HttpClient() = default;
|
~HttpClient() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Error Connect(const HttpRequest& request) final {
|
Error Connect(const HttpRequest& request) final {
|
||||||
return DoConnect(request, kPort80);
|
return DoConnect(request, kPort80);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace webcc {
|
|||||||
// or timeout occurs.
|
// or timeout occurs.
|
||||||
// Please don't use the same client object in multiple threads.
|
// Please don't use the same client object in multiple threads.
|
||||||
class HttpClientBase {
|
class HttpClientBase {
|
||||||
public:
|
public:
|
||||||
// The |buffer_size| is the bytes of the buffer for reading response.
|
// The |buffer_size| is the bytes of the buffer for reading response.
|
||||||
// 0 means default value (e.g., 1024) will be used.
|
// 0 means default value (e.g., 1024) will be used.
|
||||||
explicit HttpClientBase(std::size_t buffer_size = 0);
|
explicit HttpClientBase(std::size_t buffer_size = 0);
|
||||||
@@ -56,7 +56,7 @@ class HttpClientBase {
|
|||||||
|
|
||||||
Error error() const { return error_; }
|
Error error() const { return error_; }
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
typedef boost::asio::ip::tcp::resolver::results_type Endpoints;
|
typedef boost::asio::ip::tcp::resolver::results_type Endpoints;
|
||||||
|
|
||||||
typedef std::function<void(boost::system::error_code, std::size_t)>
|
typedef std::function<void(boost::system::error_code, std::size_t)>
|
||||||
|
|||||||
@@ -14,14 +14,20 @@ HttpResponsePtr HttpClientSession::Request(HttpRequestArgs&& args) {
|
|||||||
assert(args.parameters_.size() % 2 == 0);
|
assert(args.parameters_.size() % 2 == 0);
|
||||||
assert(args.headers_.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()) {
|
if (!args.data_.empty()) {
|
||||||
request.SetContent(std::move(args.data_), true);
|
request.SetContent(std::move(args.data_), true);
|
||||||
|
|
||||||
// TODO: charset/encoding
|
// TODO: Request-level charset.
|
||||||
if (args.json_) {
|
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_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,14 @@ public:
|
|||||||
|
|
||||||
~HttpClientSession() = default;
|
~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) {
|
void AddHeader(const std::string& key, const std::string& value) {
|
||||||
headers_.Add(key, value);
|
headers_.Add(key, value);
|
||||||
}
|
}
|
||||||
@@ -34,7 +42,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
void InitHeaders();
|
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_;
|
HttpHeaderDict headers_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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!
|
// ATTENTION: The buffers don't hold the memory!
|
||||||
std::vector<boost::asio::const_buffer> HttpMessage::ToBuffers() const {
|
std::vector<boost::asio::const_buffer> HttpMessage::ToBuffers() const {
|
||||||
assert(!start_line_.empty());
|
assert(!start_line_.empty());
|
||||||
|
|||||||
@@ -88,8 +88,6 @@ public:
|
|||||||
// TODO: Remove parameter |set_length|.
|
// TODO: Remove parameter |set_length|.
|
||||||
void SetContent(std::string&& content, bool 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).
|
// Make the message (e.g., update start line).
|
||||||
// Must be called before ToBuffers()!
|
// Must be called before ToBuffers()!
|
||||||
virtual bool Prepare() = 0;
|
virtual bool Prepare() = 0;
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@ class HttpMessage;
|
|||||||
|
|
||||||
// HttpParser parses HTTP request and response.
|
// HttpParser parses HTTP request and response.
|
||||||
class HttpParser {
|
class HttpParser {
|
||||||
public:
|
public:
|
||||||
explicit HttpParser(HttpMessage* message);
|
explicit HttpParser(HttpMessage* message);
|
||||||
|
|
||||||
virtual ~HttpParser() = default;
|
virtual ~HttpParser() = default;
|
||||||
@@ -24,7 +24,7 @@ class HttpParser {
|
|||||||
|
|
||||||
bool Parse(const char* data, std::size_t length);
|
bool Parse(const char* data, std::size_t length);
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
// Parse headers from pending data.
|
// Parse headers from pending data.
|
||||||
// Return false only on syntax errors.
|
// Return false only on syntax errors.
|
||||||
bool ParseHeaders();
|
bool ParseHeaders();
|
||||||
|
|||||||
@@ -4,16 +4,6 @@
|
|||||||
|
|
||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
HttpRequest::HttpRequest(const std::string& method,
|
|
||||||
const std::string& url,
|
|
||||||
const std::vector<std::string>& 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() {
|
bool HttpRequest::Prepare() {
|
||||||
if (url_.host().empty()) {
|
if (url_.host().empty()) {
|
||||||
LOG_ERRO("Invalid request: host is missing.");
|
LOG_ERRO("Invalid request: host is missing.");
|
||||||
@@ -41,17 +31,4 @@ bool HttpRequest::Prepare() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
HttpRequestPtr HttpRequest::New(const std::string& method,
|
|
||||||
const std::string& url,
|
|
||||||
const std::vector<std::string>& parameters,
|
|
||||||
bool prepare) {
|
|
||||||
HttpRequestPtr request{ new HttpRequest{ method, url, parameters } };
|
|
||||||
|
|
||||||
if (prepare) {
|
|
||||||
request->Prepare();
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webcc
|
} // namespace webcc
|
||||||
|
|||||||
+16
-30
@@ -11,7 +11,6 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class HttpRequest;
|
class HttpRequest;
|
||||||
class HttpRequestParser;
|
|
||||||
|
|
||||||
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
|
typedef std::shared_ptr<HttpRequest> HttpRequestPtr;
|
||||||
|
|
||||||
@@ -19,13 +18,25 @@ class HttpRequest : public HttpMessage {
|
|||||||
public:
|
public:
|
||||||
HttpRequest() = default;
|
HttpRequest() = default;
|
||||||
|
|
||||||
// TODO: Move parameters
|
HttpRequest(const std::string& method, const std::string& url)
|
||||||
HttpRequest(const std::string& method,
|
: method_(method), url_(url) {
|
||||||
const std::string& url,
|
}
|
||||||
const std::vector<std::string>& parameters = {});
|
|
||||||
|
|
||||||
~HttpRequest() override = default;
|
~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 {
|
const std::string& method() const {
|
||||||
return method_;
|
return method_;
|
||||||
}
|
}
|
||||||
@@ -46,36 +57,11 @@ public:
|
|||||||
return port().empty() ? default_port : port();
|
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.
|
// Prepare payload.
|
||||||
// Compose start line, set Host header, etc.
|
// Compose start line, set Host header, etc.
|
||||||
bool Prepare() override;
|
bool Prepare() override;
|
||||||
|
|
||||||
// TODO: Re-place
|
|
||||||
static HttpRequestPtr New(const std::string& method,
|
|
||||||
const std::string& url,
|
|
||||||
const std::vector<std::string>& parameters = {},
|
|
||||||
bool prepare = true);
|
|
||||||
|
|
||||||
private:
|
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_;
|
std::string method_;
|
||||||
Url url_;
|
Url url_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,8 +19,8 @@ bool HttpRequestParser::ParseStartLine(const std::string& line) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
request_->set_method(strs[0]);
|
request_->set_method(std::move(strs[0]));
|
||||||
request_->set_url(strs[1]);
|
request_->set_url(std::move(strs[1]));
|
||||||
|
|
||||||
// HTTP version is ignored.
|
// HTTP version is ignored.
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ namespace webcc {
|
|||||||
class HttpRequest;
|
class HttpRequest;
|
||||||
|
|
||||||
class HttpRequestParser : public HttpParser {
|
class HttpRequestParser : public HttpParser {
|
||||||
public:
|
public:
|
||||||
explicit HttpRequestParser(HttpRequest* request);
|
explicit HttpRequestParser(HttpRequest* request);
|
||||||
|
|
||||||
~HttpRequestParser() override = default;
|
~HttpRequestParser() override = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool ParseStartLine(const std::string& line) override;
|
bool ParseStartLine(const std::string& line) override;
|
||||||
|
|
||||||
HttpRequest* request_;
|
HttpRequest* request_;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class HttpResponse : public HttpMessage {
|
class HttpResponse : public HttpMessage {
|
||||||
public:
|
public:
|
||||||
HttpResponse() : status_(http::Status::kOK) {}
|
HttpResponse() : status_(http::Status::kOK) {}
|
||||||
|
|
||||||
~HttpResponse() override = default;
|
~HttpResponse() override = default;
|
||||||
@@ -25,7 +25,7 @@ class HttpResponse : public HttpMessage {
|
|||||||
// TODO: Avoid copy.
|
// TODO: Avoid copy.
|
||||||
static HttpResponse Fault(http::Status status);
|
static HttpResponse Fault(http::Status status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int status_;
|
int status_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -10,12 +10,12 @@ namespace webcc {
|
|||||||
class HttpResponse;
|
class HttpResponse;
|
||||||
|
|
||||||
class HttpResponseParser : public HttpParser {
|
class HttpResponseParser : public HttpParser {
|
||||||
public:
|
public:
|
||||||
explicit HttpResponseParser(HttpResponse* response);
|
explicit HttpResponseParser(HttpResponse* response);
|
||||||
|
|
||||||
~HttpResponseParser() override = default;
|
~HttpResponseParser() override = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Parse HTTP start line; E.g., "HTTP/1.1 200 OK".
|
// Parse HTTP start line; E.g., "HTTP/1.1 200 OK".
|
||||||
bool ParseStartLine(const std::string& line) override;
|
bool ParseStartLine(const std::string& line) override;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -17,7 +17,7 @@ class HttpRequestHandler;
|
|||||||
// HTTP server accepts TCP connections from TCP clients.
|
// HTTP server accepts TCP connections from TCP clients.
|
||||||
// NOTE: Only support IPv4.
|
// NOTE: Only support IPv4.
|
||||||
class HttpServer {
|
class HttpServer {
|
||||||
public:
|
public:
|
||||||
HttpServer(std::uint16_t port, std::size_t workers);
|
HttpServer(std::uint16_t port, std::size_t workers);
|
||||||
|
|
||||||
virtual ~HttpServer() = default;
|
virtual ~HttpServer() = default;
|
||||||
@@ -27,7 +27,7 @@ class HttpServer {
|
|||||||
// Run the server's io_service loop.
|
// Run the server's io_service loop.
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Register to handle the signals that indicate when the server should exit.
|
// Register to handle the signals that indicate when the server should exit.
|
||||||
void RegisterSignals();
|
void RegisterSignals();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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<HttpSslAsyncClient> 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<HttpSslAsyncClient> shared_from_this() {
|
|
||||||
return shared_from_base<HttpSslAsyncClient>();
|
|
||||||
}
|
|
||||||
|
|
||||||
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<boost::asio::ip::tcp::socket> ssl_socket_;
|
|
||||||
|
|
||||||
// Verify the certificate of the peer (remote server) or not.
|
|
||||||
bool ssl_verify_;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace webcc
|
|
||||||
|
|
||||||
#endif // WEBCC_HTTP_SSL_ASYNC_CLIENT_H_
|
|
||||||
@@ -9,7 +9,7 @@ namespace webcc {
|
|||||||
|
|
||||||
// HTTP SSL (a.k.a., HTTPS) synchronous client.
|
// HTTP SSL (a.k.a., HTTPS) synchronous client.
|
||||||
class HttpSslClient : public HttpClientBase {
|
class HttpSslClient : public HttpClientBase {
|
||||||
public:
|
public:
|
||||||
// SSL verification (|ssl_verify|) needs CA certificates to be found
|
// SSL verification (|ssl_verify|) needs CA certificates to be found
|
||||||
// in the default verify paths of OpenSSL. On Windows, it means you need to
|
// in the default verify paths of OpenSSL. On Windows, it means you need to
|
||||||
// set environment variable SSL_CERT_FILE properly.
|
// set environment variable SSL_CERT_FILE properly.
|
||||||
@@ -17,7 +17,7 @@ class HttpSslClient : public HttpClientBase {
|
|||||||
|
|
||||||
~HttpSslClient() = default;
|
~HttpSslClient() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Error Handshake(const std::string& host);
|
Error Handshake(const std::string& host);
|
||||||
|
|
||||||
// Override to do handshake after connected.
|
// Override to do handshake after connected.
|
||||||
|
|||||||
+2
-2
@@ -12,7 +12,7 @@ namespace webcc {
|
|||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class Queue {
|
class Queue {
|
||||||
public:
|
public:
|
||||||
Queue() = default;
|
Queue() = default;
|
||||||
|
|
||||||
Queue(const Queue&) = delete;
|
Queue(const Queue&) = delete;
|
||||||
@@ -49,7 +49,7 @@ class Queue {
|
|||||||
not_empty_cv_.notify_one();
|
not_empty_cv_.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<T> message_list_;
|
std::list<T> message_list_;
|
||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
std::condition_variable not_empty_cv_;
|
std::condition_variable not_empty_cv_;
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#ifndef WEBCC_REST_ASYNC_CLIENT_H_
|
|
||||||
#define WEBCC_REST_ASYNC_CLIENT_H_
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <utility> // 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_
|
|
||||||
@@ -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
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
#ifndef WEBCC_REST_CLIENT_H_
|
|
||||||
#define WEBCC_REST_CLIENT_H_
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <string>
|
|
||||||
#include <utility> // 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_
|
|
||||||
+2
-2
@@ -12,7 +12,7 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class RestServer : public HttpServer {
|
class RestServer : public HttpServer {
|
||||||
public:
|
public:
|
||||||
RestServer(std::uint16_t port, std::size_t workers)
|
RestServer(std::uint16_t port, std::size_t workers)
|
||||||
: HttpServer(port, workers) {
|
: HttpServer(port, workers) {
|
||||||
}
|
}
|
||||||
@@ -31,7 +31,7 @@ class RestServer : public HttpServer {
|
|||||||
return request_handler_.Bind(service, url, is_regex);
|
return request_handler_.Bind(service, url, is_regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpRequestHandler* GetRequestHandler() override {
|
HttpRequestHandler* GetRequestHandler() override {
|
||||||
return &request_handler_;
|
return &request_handler_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ struct RestResponse {
|
|||||||
|
|
||||||
// Base class for your REST service.
|
// Base class for your REST service.
|
||||||
class RestService {
|
class RestService {
|
||||||
public:
|
public:
|
||||||
virtual ~RestService() = default;
|
virtual ~RestService() = default;
|
||||||
|
|
||||||
// Handle REST request, output response.
|
// Handle REST request, output response.
|
||||||
@@ -58,10 +58,10 @@ typedef std::shared_ptr<RestService> RestServicePtr;
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class RestListService : public RestService {
|
class RestListService : public RestService {
|
||||||
public:
|
public:
|
||||||
void Handle(const RestRequest& request, RestResponse* response) final;
|
void Handle(const RestRequest& request, RestResponse* response) final;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
RestListService() = default;
|
RestListService() = default;
|
||||||
|
|
||||||
virtual void Get(const UrlQuery& query, RestResponse* response) {
|
virtual void Get(const UrlQuery& query, RestResponse* response) {
|
||||||
@@ -75,10 +75,10 @@ class RestListService : public RestService {
|
|||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class RestDetailService : public RestService {
|
class RestDetailService : public RestService {
|
||||||
public:
|
public:
|
||||||
void Handle(const RestRequest& request, RestResponse* response) final;
|
void Handle(const RestRequest& request, RestResponse* response) final;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
virtual void Get(const UrlSubMatches& url_sub_matches,
|
virtual void Get(const UrlSubMatches& url_sub_matches,
|
||||||
const UrlQuery& query,
|
const UrlQuery& query,
|
||||||
RestResponse* response) {
|
RestResponse* response) {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class RestServiceManager {
|
class RestServiceManager {
|
||||||
public:
|
public:
|
||||||
RestServiceManager() = default;
|
RestServiceManager() = default;
|
||||||
|
|
||||||
WEBCC_DELETE_COPY_ASSIGN(RestServiceManager);
|
WEBCC_DELETE_COPY_ASSIGN(RestServiceManager);
|
||||||
@@ -30,7 +30,7 @@ class RestServiceManager {
|
|||||||
RestServicePtr GetService(const std::string& url,
|
RestServicePtr GetService(const std::string& url,
|
||||||
std::vector<std::string>* sub_matches);
|
std::vector<std::string>* sub_matches);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class ServiceItem {
|
class ServiceItem {
|
||||||
public:
|
public:
|
||||||
ServiceItem(RestServicePtr _service, const std::string& _url,
|
ServiceItem(RestServicePtr _service, const std::string& _url,
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -1,130 +0,0 @@
|
|||||||
#ifndef WEBCC_REST_SSL_CLIENT_H_
|
|
||||||
#define WEBCC_REST_SSL_CLIENT_H_
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
#include <utility> // 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<std::string, std::string> 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<std::string, std::string> 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_
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
#include "webcc/soap_async_client.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
|
||||||
#include <utility> // 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<SoapParameter>&& 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
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
#ifndef WEBCC_SOAP_ASYNC_CLIENT_H_
|
|
||||||
#define WEBCC_SOAP_ASYNC_CLIENT_H_
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
#include <string>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "webcc/http_async_client.h"
|
|
||||||
#include "webcc/soap_message.h"
|
|
||||||
#include "webcc/soap_parameter.h"
|
|
||||||
|
|
||||||
namespace webcc {
|
|
||||||
|
|
||||||
// Response callback.
|
|
||||||
typedef std::function<void(std::string, Error, bool)> 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<SoapParameter>&& 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_
|
|
||||||
+2
-2
@@ -12,7 +12,7 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class SoapClient {
|
class SoapClient {
|
||||||
public:
|
public:
|
||||||
// If |port| is empty, |host| will be checked to see if it contains port or
|
// If |port| is empty, |host| will be checked to see if it contains port or
|
||||||
// not (separated by ':').
|
// not (separated by ':').
|
||||||
explicit SoapClient(const std::string& host, const std::string& port = "",
|
explicit SoapClient(const std::string& host, const std::string& port = "",
|
||||||
@@ -69,7 +69,7 @@ class SoapClient {
|
|||||||
|
|
||||||
std::shared_ptr<SoapFault> fault() const { return fault_; }
|
std::shared_ptr<SoapFault> fault() const { return fault_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string host_;
|
std::string host_;
|
||||||
std::string port_; // Leave this empty to use default 80.
|
std::string port_; // Leave this empty to use default 80.
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace webcc {
|
|||||||
|
|
||||||
// Base class for SOAP request and response.
|
// Base class for SOAP request and response.
|
||||||
class SoapMessage {
|
class SoapMessage {
|
||||||
public:
|
public:
|
||||||
virtual ~SoapMessage() = default;
|
virtual ~SoapMessage() = default;
|
||||||
|
|
||||||
// E.g., set as kSoapEnvNamespace.
|
// E.g., set as kSoapEnvNamespace.
|
||||||
@@ -38,7 +38,7 @@ class SoapMessage {
|
|||||||
// Parse from SOAP XML.
|
// Parse from SOAP XML.
|
||||||
bool FromXml(const std::string& xml_string);
|
bool FromXml(const std::string& xml_string);
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
// Convert to SOAP body XML.
|
// Convert to SOAP body XML.
|
||||||
virtual void ToXmlBody(pugi::xml_node xbody) = 0;
|
virtual void ToXmlBody(pugi::xml_node xbody) = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace webcc {
|
|||||||
|
|
||||||
// Key-value SOAP parameter.
|
// Key-value SOAP parameter.
|
||||||
class SoapParameter {
|
class SoapParameter {
|
||||||
public:
|
public:
|
||||||
SoapParameter() : as_cdata_(false) {
|
SoapParameter() : as_cdata_(false) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ class SoapParameter {
|
|||||||
|
|
||||||
bool as_cdata() const { return as_cdata_; }
|
bool as_cdata() const { return as_cdata_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string key_;
|
std::string key_;
|
||||||
std::string value_;
|
std::string value_;
|
||||||
bool as_cdata_;
|
bool as_cdata_;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ namespace webcc {
|
|||||||
// Used to compose the SOAP request envelope XML which will be sent as the HTTP
|
// Used to compose the SOAP request envelope XML which will be sent as the HTTP
|
||||||
// request body.
|
// request body.
|
||||||
class SoapRequest : public SoapMessage {
|
class SoapRequest : public SoapMessage {
|
||||||
public:
|
public:
|
||||||
void AddParameter(const SoapParameter& parameter);
|
void AddParameter(const SoapParameter& parameter);
|
||||||
|
|
||||||
void AddParameter(SoapParameter&& parameter);
|
void AddParameter(SoapParameter&& parameter);
|
||||||
@@ -21,11 +21,11 @@ class SoapRequest : public SoapMessage {
|
|||||||
// Get parameter value by key.
|
// Get parameter value by key.
|
||||||
const std::string& GetParameter(const std::string& key) const;
|
const std::string& GetParameter(const std::string& key) const;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
void ToXmlBody(pugi::xml_node xbody) override;
|
void ToXmlBody(pugi::xml_node xbody) override;
|
||||||
bool FromXmlBody(pugi::xml_node xbody) override;
|
bool FromXmlBody(pugi::xml_node xbody) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<SoapParameter> parameters_;
|
std::vector<SoapParameter> parameters_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class SoapResponse : public SoapMessage {
|
class SoapResponse : public SoapMessage {
|
||||||
public:
|
public:
|
||||||
// Response result parser.
|
// Response result parser.
|
||||||
// Called on each child of the response node.
|
// Called on each child of the response node.
|
||||||
// Example:
|
// Example:
|
||||||
@@ -127,12 +127,12 @@ class SoapResponse : public SoapMessage {
|
|||||||
|
|
||||||
// TODO: Set fault from server.
|
// TODO: Set fault from server.
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
void ToXmlBody(pugi::xml_node xbody) override;
|
void ToXmlBody(pugi::xml_node xbody) override;
|
||||||
|
|
||||||
bool FromXmlBody(pugi::xml_node xbody) override;
|
bool FromXmlBody(pugi::xml_node xbody) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Fault element if any.
|
// Fault element if any.
|
||||||
std::shared_ptr<SoapFault> fault_;
|
std::shared_ptr<SoapFault> fault_;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -11,7 +11,7 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class SoapServer : public HttpServer {
|
class SoapServer : public HttpServer {
|
||||||
public:
|
public:
|
||||||
SoapServer(std::uint16_t port, std::size_t workers,
|
SoapServer(std::uint16_t port, std::size_t workers,
|
||||||
SoapVersion soap_version = kSoapV12)
|
SoapVersion soap_version = kSoapV12)
|
||||||
: HttpServer(port, workers),
|
: HttpServer(port, workers),
|
||||||
@@ -36,7 +36,7 @@ class SoapServer : public HttpServer {
|
|||||||
return request_handler_.Bind(service, url);
|
return request_handler_.Bind(service, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpRequestHandler* GetRequestHandler() override {
|
HttpRequestHandler* GetRequestHandler() override {
|
||||||
return &request_handler_;
|
return &request_handler_;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ class SoapResponse;
|
|||||||
|
|
||||||
// Base class for your SOAP service.
|
// Base class for your SOAP service.
|
||||||
class SoapService {
|
class SoapService {
|
||||||
public:
|
public:
|
||||||
virtual ~SoapService() = default;
|
virtual ~SoapService() = default;
|
||||||
|
|
||||||
// Handle SOAP request, output the response.
|
// Handle SOAP request, output the response.
|
||||||
virtual bool Handle(const SoapRequest& soap_request,
|
virtual bool Handle(const SoapRequest& soap_request,
|
||||||
SoapResponse* soap_response) = 0;
|
SoapResponse* soap_response) = 0;
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
http::Status http_status_ = http::Status::kOK;
|
http::Status http_status_ = http::Status::kOK;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -73,7 +73,7 @@ std::string GetNSAttr(const pugi::xml_node& xnode,
|
|||||||
// XmlStringWriter writer(&xml_string);
|
// XmlStringWriter writer(&xml_string);
|
||||||
// xdoc.save/print(writer);
|
// xdoc.save/print(writer);
|
||||||
class XmlStringWriter : public pugi::xml_writer {
|
class XmlStringWriter : public pugi::xml_writer {
|
||||||
public:
|
public:
|
||||||
explicit XmlStringWriter(std::string* result) : result_(result) {
|
explicit XmlStringWriter(std::string* result) : result_(result) {
|
||||||
result_->clear();
|
result_->clear();
|
||||||
}
|
}
|
||||||
@@ -82,7 +82,7 @@ class XmlStringWriter : public pugi::xml_writer {
|
|||||||
result_->append(static_cast<const char*>(data), size);
|
result_->append(static_cast<const char*>(data), size);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string* result_;
|
std::string* result_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+30
-1
@@ -7,6 +7,8 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "webcc/globals.h"
|
||||||
|
|
||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -57,9 +59,36 @@ class Url {
|
|||||||
public:
|
public:
|
||||||
Url() = default;
|
Url() = default;
|
||||||
|
|
||||||
// TODO: decode/encode/encoded?
|
|
||||||
explicit Url(const std::string& str, bool decode = true);
|
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);
|
void Init(const std::string& str, bool decode = true, bool clear = true);
|
||||||
|
|
||||||
const std::string& scheme() const {
|
const std::string& scheme() const {
|
||||||
|
|||||||
Reference in New Issue
Block a user