Cleanup async client APIs.
parent
ffa0794926
commit
31d0ea3c9d
@ -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.
|
|
@ -0,0 +1,2 @@
|
|||||||
|
add_executable(github_client main.cc)
|
||||||
|
target_link_libraries(github_client ${EXAMPLE_COMMON_LIBS} jsoncpp)
|
@ -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;
|
|
||||||
}
|
|
@ -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;
|
|
||||||
}
|
|
@ -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}")
|
|
@ -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>
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
@ -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_
|
|
Loading…
Reference in New Issue