Rename RegisterService to Bind and add is_regex parameter; indent public/protected/private by one space; refine rest example.
This commit is contained in:
@@ -26,18 +26,23 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ListBooks() {
|
bool ListBooks() {
|
||||||
|
std::cout << "ListBooks" << std::endl;
|
||||||
|
|
||||||
webcc::HttpResponse http_response;
|
webcc::HttpResponse http_response;
|
||||||
if (!rest_client_.Get("/books", &http_response)) {
|
if (!rest_client_.Get("/books", &http_response)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "result:\n" << http_response.content() << std::endl;
|
std::cout << http_response.content() << std::endl;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CreateBook(const std::string& id,
|
bool CreateBook(const std::string& id,
|
||||||
const std::string& title,
|
const std::string& title,
|
||||||
double price) {
|
double price) {
|
||||||
|
std::cout << "CreateBook: " << id << " " << title << " " << price
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
Json::Value json(Json::objectValue);
|
Json::Value json(Json::objectValue);
|
||||||
json["id"] = id;
|
json["id"] = id;
|
||||||
json["title"] = title;
|
json["title"] = title;
|
||||||
@@ -66,6 +71,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool GetBook(const std::string& id) {
|
bool GetBook(const std::string& id) {
|
||||||
|
std::cout << "GetBook: " << id << std::endl;
|
||||||
|
|
||||||
webcc::HttpResponse http_response;
|
webcc::HttpResponse http_response;
|
||||||
if (!rest_client_.Get("/book/" + id, &http_response)) {
|
if (!rest_client_.Get("/book/" + id, &http_response)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -78,13 +85,16 @@ public:
|
|||||||
bool UpdateBook(const std::string& id,
|
bool UpdateBook(const std::string& id,
|
||||||
const std::string& title,
|
const std::string& title,
|
||||||
double price) {
|
double price) {
|
||||||
|
std::cout << "UpdateBook: " << id << " " << title << " " << price
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
// NOTE: ID is already in the URL.
|
// NOTE: ID is already in the URL.
|
||||||
Json::Value json(Json::objectValue);
|
Json::Value json(Json::objectValue);
|
||||||
json["title"] = title;
|
json["title"] = title;
|
||||||
json["price"] = price;
|
json["price"] = price;
|
||||||
|
|
||||||
webcc::HttpResponse http_response;
|
webcc::HttpResponse http_response;
|
||||||
if (!rest_client_.Post("/book/" + id, JsonToString(json), &http_response)) {
|
if (!rest_client_.Put("/book/" + id, JsonToString(json), &http_response)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +103,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool DeleteBook(const std::string& id) {
|
bool DeleteBook(const std::string& id) {
|
||||||
|
std::cout << "DeleteBook: " << id << std::endl;
|
||||||
|
|
||||||
webcc::HttpResponse http_response;
|
webcc::HttpResponse http_response;
|
||||||
if (!rest_client_.Delete("/book/" + id, &http_response)) {
|
if (!rest_client_.Delete("/book/" + id, &http_response)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -108,119 +120,35 @@ private:
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
std::string g_host;
|
|
||||||
std::string g_port;
|
|
||||||
|
|
||||||
void Help(const char* argv0) {
|
void Help(const char* argv0) {
|
||||||
std::cout << "Usage: " << argv0 << " <host> <port>" << std::endl;
|
std::cout << "Usage: " << argv0 << " <host> <port>" << std::endl;
|
||||||
std::cout << " E.g.," << std::endl;
|
std::cout << " E.g.," << std::endl;
|
||||||
std::cout << " " << argv0 << " localhost 8080" << std::endl;
|
std::cout << " " << argv0 << " localhost 8080" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string GetUserInput() {
|
|
||||||
char input[256];
|
|
||||||
std::cout << ">> ";
|
|
||||||
std::cin.getline(input, 256);
|
|
||||||
return input;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ParseJsonInput(const std::string& input, Json::Value* root) {
|
|
||||||
Json::CharReaderBuilder builder;
|
|
||||||
std::stringstream stream(input);
|
|
||||||
std::string errs;
|
|
||||||
if (Json::parseFromStream(builder, stream, root, &errs)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
std::cerr << errs << std::endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char* argv[]) {
|
int main(int argc, char* argv[]) {
|
||||||
if (argc != 3) {
|
if (argc != 3) {
|
||||||
Help(argv[0]);
|
Help(argv[0]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_INIT(webcc::VERB, 0);
|
LOG_INIT(webcc::ERRO, 0);
|
||||||
|
|
||||||
g_host = argv[1];
|
std::string host = argv[1];
|
||||||
g_port = argv[2];
|
std::string port = argv[2];
|
||||||
|
|
||||||
// Type commands to execute actions.
|
BookListClient list_client(host, port);
|
||||||
// Commands: list, create, detail, update, delete and exit.
|
BookDetailClient detail_client(host, port);
|
||||||
// Examples:
|
|
||||||
// >> list
|
|
||||||
// >> create 1 { "title": "1984", "price": 12.3 }
|
|
||||||
// >> detail 1
|
|
||||||
// >> update 1 { "title": "1Q84", "price": 32.1 }
|
|
||||||
// >> delete 1
|
|
||||||
// >> exit
|
|
||||||
|
|
||||||
// A very naive implementation of interaction mode.
|
list_client.ListBooks();
|
||||||
while (true) {
|
list_client.CreateBook("1", "1984", 12.3);
|
||||||
std::string input = GetUserInput();
|
|
||||||
boost::trim(input);
|
|
||||||
|
|
||||||
std::string command;
|
detail_client.GetBook("1");
|
||||||
std::size_t i = input.find(' ');
|
detail_client.UpdateBook("1", "1Q84", 32.1);
|
||||||
if (i == std::string::npos) {
|
detail_client.GetBook("1");
|
||||||
command = input;
|
detail_client.DeleteBook("1");
|
||||||
} else {
|
|
||||||
command = input.substr(0, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == "exit") {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == "list") {
|
|
||||||
BookListClient client(g_host, g_port);
|
|
||||||
client.ListBooks();
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
++i;
|
|
||||||
|
|
||||||
std::size_t j = input.find(' ', i);
|
|
||||||
std::string id = input.substr(i, j - i);
|
|
||||||
i = j + 1;
|
|
||||||
|
|
||||||
if (command == "create") {
|
|
||||||
std::string json = input.substr(i);
|
|
||||||
|
|
||||||
Json::Value root;
|
|
||||||
if (ParseJsonInput(json, &root)) {
|
|
||||||
BookListClient client(g_host, g_port);
|
|
||||||
client.CreateBook(id, root["title"].asString(), root["price"].asDouble());
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == "update") {
|
|
||||||
std::string json = input.substr(i);
|
|
||||||
|
|
||||||
Json::Value root;
|
|
||||||
if (ParseJsonInput(json, &root)) {
|
|
||||||
BookDetailClient client(g_host, g_port);
|
|
||||||
client.UpdateBook(id, root["title"].asString(), root["price"].asDouble());
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == "detail") {
|
|
||||||
BookDetailClient client(g_host, g_port);
|
|
||||||
client.GetBook(id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (command == "delete") {
|
|
||||||
BookDetailClient client(g_host, g_port);
|
|
||||||
client.DeleteBook(id);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
list_client.ListBooks();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ public:
|
|||||||
if (it != books_.end()) {
|
if (it != books_.end()) {
|
||||||
it->title = book.title;
|
it->title = book.title;
|
||||||
it->price = book.price;
|
it->price = book.price;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -162,10 +163,10 @@ bool BookDetailService::Get(const std::vector<std::string>& url_sub_matches,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update a book partially.
|
// Update a book.
|
||||||
bool BookDetailService::Patch(const std::vector<std::string>& url_sub_matches,
|
bool BookDetailService::Put(const std::vector<std::string>& url_sub_matches,
|
||||||
const std::string& request_content,
|
const std::string& request_content,
|
||||||
std::string* response_content) {
|
std::string* response_content) {
|
||||||
if (url_sub_matches.size() != 1) {
|
if (url_sub_matches.size() != 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,9 +35,9 @@ class BookDetailService : public webcc::RestDetailService {
|
|||||||
const webcc::UrlQuery& query,
|
const webcc::UrlQuery& query,
|
||||||
std::string* response_content) final;
|
std::string* response_content) final;
|
||||||
|
|
||||||
bool Patch(const std::vector<std::string>& url_sub_matches,
|
bool Put(const std::vector<std::string>& url_sub_matches,
|
||||||
const std::string& request_content,
|
const std::string& request_content,
|
||||||
std::string* response_content) final;
|
std::string* response_content) final;
|
||||||
|
|
||||||
bool Delete(const std::vector<std::string>& url_sub_matches) final;
|
bool Delete(const std::vector<std::string>& url_sub_matches) final;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,11 +26,9 @@ int main(int argc, char* argv[]) {
|
|||||||
try {
|
try {
|
||||||
webcc::RestServer server(port, workers);
|
webcc::RestServer server(port, workers);
|
||||||
|
|
||||||
server.RegisterService(std::make_shared<BookListService>(),
|
server.Bind(std::make_shared<BookListService>(), "/books", false);
|
||||||
"/books");
|
|
||||||
|
|
||||||
server.RegisterService(std::make_shared<BookDetailService>(),
|
server.Bind(std::make_shared<BookDetailService>(), "/book/(\\d+)", true);
|
||||||
"/book/(\\d+)");
|
|
||||||
|
|
||||||
server.Run();
|
server.Run();
|
||||||
|
|
||||||
|
|||||||
@@ -24,8 +24,7 @@ int main(int argc, char* argv[]) {
|
|||||||
try {
|
try {
|
||||||
webcc::SoapServer server(port, workers);
|
webcc::SoapServer server(port, workers);
|
||||||
|
|
||||||
server.RegisterService(std::make_shared<CalcService>(),
|
server.Bind(std::make_shared<CalcService>(), "/calculator");
|
||||||
"/calculator");
|
|
||||||
|
|
||||||
server.Run();
|
server.Run();
|
||||||
|
|
||||||
|
|||||||
@@ -91,8 +91,8 @@ Parameter::Parameter(const std::string& key, bool value)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Parameter::Parameter(Parameter&& rhs)
|
Parameter::Parameter(Parameter&& rhs)
|
||||||
: key_(std::move(rhs.key_))
|
: key_(std::move(rhs.key_)),
|
||||||
, value_(std::move(rhs.value_)) {
|
value_(std::move(rhs.value_)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Parameter& Parameter::operator=(Parameter&& rhs) {
|
Parameter& Parameter::operator=(Parameter&& rhs) {
|
||||||
|
|||||||
+2
-2
@@ -113,7 +113,7 @@ const char* GetErrorMessage(Error error);
|
|||||||
|
|
||||||
// Key-value parameter.
|
// Key-value parameter.
|
||||||
class Parameter {
|
class Parameter {
|
||||||
public:
|
public:
|
||||||
Parameter() = default;
|
Parameter() = default;
|
||||||
Parameter(const Parameter&) = default;
|
Parameter(const Parameter&) = default;
|
||||||
Parameter& operator=(const Parameter&) = default;
|
Parameter& operator=(const Parameter&) = default;
|
||||||
@@ -150,7 +150,7 @@ public:
|
|||||||
// Return "key=value" string.
|
// Return "key=value" string.
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string key_;
|
std::string key_;
|
||||||
std::string value_;
|
std::string value_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -36,8 +36,7 @@ HttpClient::HttpClient()
|
|||||||
CheckDeadline();
|
CheckDeadline();
|
||||||
}
|
}
|
||||||
|
|
||||||
Error HttpClient::MakeRequest(const HttpRequest& request,
|
Error HttpClient::Request(const HttpRequest& request, HttpResponse* response) {
|
||||||
HttpResponse* response) {
|
|
||||||
assert(response != NULL);
|
assert(response != NULL);
|
||||||
|
|
||||||
Error error = kNoError;
|
Error error = kNoError;
|
||||||
|
|||||||
@@ -17,23 +17,19 @@ class HttpRequest;
|
|||||||
class HttpResponse;
|
class HttpResponse;
|
||||||
|
|
||||||
class HttpClient {
|
class HttpClient {
|
||||||
public:
|
public:
|
||||||
HttpClient();
|
HttpClient();
|
||||||
~HttpClient() = default;
|
~HttpClient() = default;
|
||||||
|
|
||||||
HttpClient(const HttpClient&) = delete;
|
|
||||||
HttpClient& operator=(const HttpClient&) = delete;
|
|
||||||
|
|
||||||
void set_timeout_seconds(int timeout_seconds) {
|
void set_timeout_seconds(int timeout_seconds) {
|
||||||
timeout_seconds_ = timeout_seconds;
|
timeout_seconds_ = timeout_seconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a HTTP request.
|
|
||||||
// Connect to the server, send the request, wait until the response is
|
// Connect to the server, send the request, wait until the response is
|
||||||
// received.
|
// received.
|
||||||
Error MakeRequest(const HttpRequest& request, HttpResponse* response);
|
Error Request(const HttpRequest& request, HttpResponse* response);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Error Connect(const HttpRequest& request);
|
Error Connect(const HttpRequest& request);
|
||||||
|
|
||||||
Error SendReqeust(const HttpRequest& request);
|
Error SendReqeust(const HttpRequest& request);
|
||||||
@@ -42,7 +38,6 @@ private:
|
|||||||
|
|
||||||
void CheckDeadline();
|
void CheckDeadline();
|
||||||
|
|
||||||
private:
|
|
||||||
boost::asio::io_context io_context_;
|
boost::asio::io_context io_context_;
|
||||||
|
|
||||||
boost::asio::ip::tcp::socket socket_;
|
boost::asio::ip::tcp::socket socket_;
|
||||||
@@ -57,6 +52,8 @@ private:
|
|||||||
|
|
||||||
// Timer for the timeout control.
|
// Timer for the timeout control.
|
||||||
boost::asio::deadline_timer deadline_timer_;
|
boost::asio::deadline_timer deadline_timer_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(HttpClient);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webcc
|
} // namespace webcc
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class HttpHeader {
|
class HttpHeader {
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string value;
|
std::string value;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Base class for HTTP request and response messages.
|
// Base class for HTTP request and response messages.
|
||||||
class HttpMessage {
|
class HttpMessage {
|
||||||
public:
|
public:
|
||||||
virtual ~HttpMessage() = default;
|
virtual ~HttpMessage() = default;
|
||||||
|
|
||||||
const std::string& start_line() const {
|
const std::string& start_line() const {
|
||||||
@@ -51,13 +51,12 @@ public:
|
|||||||
SetContentLength(content_.size());
|
SetContentLength(content_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
protected:
|
||||||
void SetContentLength(std::size_t content_length) {
|
void SetContentLength(std::size_t content_length) {
|
||||||
content_length_ = content_length;
|
content_length_ = content_length;
|
||||||
SetHeader(kContentLength, std::to_string(content_length));
|
SetHeader(kContentLength, std::to_string(content_length));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
|
||||||
// Start line with trailing "\r\n".
|
// Start line with trailing "\r\n".
|
||||||
std::string start_line_;
|
std::string start_line_;
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class HttpResponse;
|
|||||||
|
|
||||||
// The common handler for all incoming requests.
|
// The common handler for all incoming requests.
|
||||||
class HttpRequestHandler {
|
class HttpRequestHandler {
|
||||||
public:
|
public:
|
||||||
HttpRequestHandler() = default;
|
HttpRequestHandler() = default;
|
||||||
virtual ~HttpRequestHandler() = default;
|
virtual ~HttpRequestHandler() = default;
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ public:
|
|||||||
// Close pending sessions and stop worker threads.
|
// Close pending sessions and stop worker threads.
|
||||||
void Stop();
|
void Stop();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void WorkerRoutine();
|
void WorkerRoutine();
|
||||||
|
|
||||||
// Called by the worker routine.
|
// Called by the worker routine.
|
||||||
|
|||||||
@@ -8,12 +8,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:
|
||||||
Error ParseStartLine(const std::string& line) override;
|
Error ParseStartLine(const std::string& line) override;
|
||||||
|
|
||||||
HttpRequest* request_;
|
HttpRequest* request_;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ class HttpResponse;
|
|||||||
std::ostream& operator<<(std::ostream& os, const HttpResponse& response);
|
std::ostream& operator<<(std::ostream& os, const HttpResponse& response);
|
||||||
|
|
||||||
class HttpResponse : public HttpMessage {
|
class HttpResponse : public HttpMessage {
|
||||||
public:
|
public:
|
||||||
HttpResponse() = default;
|
HttpResponse() = default;
|
||||||
~HttpResponse() override = default;
|
~HttpResponse() override = default;
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ public:
|
|||||||
// Get a fault response when HTTP status is not OK.
|
// Get a fault response when HTTP status is not OK.
|
||||||
static HttpResponse Fault(HttpStatus::Enum status);
|
static HttpResponse Fault(HttpStatus::Enum status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend std::ostream& operator<<(std::ostream& os,
|
friend std::ostream& operator<<(std::ostream& os,
|
||||||
const HttpResponse& response);
|
const HttpResponse& response);
|
||||||
|
|
||||||
|
|||||||
@@ -8,16 +8,15 @@ 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".
|
||||||
Error ParseStartLine(const std::string& line) override;
|
Error ParseStartLine(const std::string& line) override;
|
||||||
|
|
||||||
private:
|
|
||||||
// The result response message.
|
// The result response message.
|
||||||
HttpResponse* response_;
|
HttpResponse* response_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#include "boost/scoped_ptr.hpp"
|
#include "boost/scoped_ptr.hpp"
|
||||||
#include "boost/thread/thread.hpp"
|
#include "boost/thread/thread.hpp"
|
||||||
|
|
||||||
|
#include "webcc/globals.h"
|
||||||
#include "webcc/http_session.h"
|
#include "webcc/http_session.h"
|
||||||
|
|
||||||
namespace webcc {
|
namespace webcc {
|
||||||
@@ -19,10 +20,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(const HttpServer&) = delete;
|
|
||||||
HttpServer& operator=(const HttpServer&) = delete;
|
|
||||||
|
|
||||||
HttpServer(unsigned short port, std::size_t workers);
|
HttpServer(unsigned short port, std::size_t workers);
|
||||||
|
|
||||||
virtual ~HttpServer() = default;
|
virtual ~HttpServer() = default;
|
||||||
@@ -30,7 +28,7 @@ public:
|
|||||||
// Run the server's io_service loop.
|
// Run the server's io_service loop.
|
||||||
void Run();
|
void Run();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Initiate an asynchronous accept operation.
|
// Initiate an asynchronous accept operation.
|
||||||
void AsyncAccept();
|
void AsyncAccept();
|
||||||
|
|
||||||
@@ -40,7 +38,6 @@ private:
|
|||||||
// Get the handler for incoming requests.
|
// Get the handler for incoming requests.
|
||||||
virtual HttpRequestHandler* GetRequestHandler() = 0;
|
virtual HttpRequestHandler* GetRequestHandler() = 0;
|
||||||
|
|
||||||
private:
|
|
||||||
// The number of worker threads.
|
// The number of worker threads.
|
||||||
std::size_t workers_;
|
std::size_t workers_;
|
||||||
|
|
||||||
@@ -52,6 +49,8 @@ private:
|
|||||||
|
|
||||||
// Acceptor used to listen for incoming connections.
|
// Acceptor used to listen for incoming connections.
|
||||||
boost::scoped_ptr<boost::asio::ip::tcp::acceptor> acceptor_;
|
boost::scoped_ptr<boost::asio::ip::tcp::acceptor> acceptor_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(HttpServer);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace webcc
|
} // namespace webcc
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace webcc {
|
|||||||
class HttpRequestHandler;
|
class HttpRequestHandler;
|
||||||
|
|
||||||
class HttpSession : public std::enable_shared_from_this<HttpSession> {
|
class HttpSession : public std::enable_shared_from_this<HttpSession> {
|
||||||
public:
|
public:
|
||||||
HttpSession(const HttpSession&) = delete;
|
HttpSession(const HttpSession&) = delete;
|
||||||
HttpSession& operator=(const HttpSession&) = delete;
|
HttpSession& operator=(const HttpSession&) = delete;
|
||||||
|
|
||||||
@@ -41,14 +41,13 @@ public:
|
|||||||
// Send response to client with the given status.
|
// Send response to client with the given status.
|
||||||
void SendResponse(HttpStatus::Enum status);
|
void SendResponse(HttpStatus::Enum status);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void AsyncRead();
|
void AsyncRead();
|
||||||
void ReadHandler(boost::system::error_code ec, std::size_t length);
|
void ReadHandler(boost::system::error_code ec, std::size_t length);
|
||||||
|
|
||||||
void AsyncWrite();
|
void AsyncWrite();
|
||||||
void WriteHandler(boost::system::error_code ec, std::size_t length);
|
void WriteHandler(boost::system::error_code ec, std::size_t length);
|
||||||
|
|
||||||
private:
|
|
||||||
// Socket for the connection.
|
// Socket for the connection.
|
||||||
boost::asio::ip::tcp::socket socket_;
|
boost::asio::ip::tcp::socket socket_;
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -14,7 +14,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;
|
||||||
@@ -51,7 +51,7 @@ public:
|
|||||||
not_empty_cv_.notify_one();
|
not_empty_cv_.notify_one();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<T> message_list_;
|
std::list<T> message_list_;
|
||||||
boost::mutex mutex_;
|
boost::mutex mutex_;
|
||||||
boost::condition_variable not_empty_cv_;
|
boost::condition_variable not_empty_cv_;
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ bool RestClient::Request(const std::string& method,
|
|||||||
request.Build();
|
request.Build();
|
||||||
|
|
||||||
HttpClient http_client;
|
HttpClient http_client;
|
||||||
Error error = http_client.MakeRequest(request, response);
|
Error error = http_client.Request(request, response);
|
||||||
|
|
||||||
return error == kNoError;
|
return error == kNoError;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ namespace webcc {
|
|||||||
class HttpResponse;
|
class HttpResponse;
|
||||||
|
|
||||||
class RestClient {
|
class RestClient {
|
||||||
public:
|
public:
|
||||||
RestClient(const std::string& host, const std::string& port)
|
RestClient(const std::string& host, const std::string& port)
|
||||||
: host_(host), port_(port) {
|
: host_(host), port_(port) {
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ public:
|
|||||||
return Request(kHttpDelete, url, "", response);
|
return Request(kHttpDelete, url, "", response);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool Request(const std::string& method,
|
bool Request(const std::string& method,
|
||||||
const std::string& url,
|
const std::string& url,
|
||||||
const std::string& content,
|
const std::string& content,
|
||||||
|
|||||||
@@ -5,9 +5,10 @@
|
|||||||
|
|
||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
bool RestRequestHandler::RegisterService(RestServicePtr service,
|
bool RestRequestHandler::Bind(RestServicePtr service,
|
||||||
const std::string& url) {
|
const std::string& url,
|
||||||
return service_manager_.AddService(service, url);
|
bool is_regex) {
|
||||||
|
return service_manager_.AddService(service, url, is_regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RestRequestHandler::HandleSession(HttpSessionPtr session) {
|
void RestRequestHandler::HandleSession(HttpSessionPtr session) {
|
||||||
|
|||||||
@@ -9,18 +9,14 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class RestRequestHandler : public HttpRequestHandler {
|
class RestRequestHandler : public HttpRequestHandler {
|
||||||
public:
|
public:
|
||||||
~RestRequestHandler() override = default;
|
~RestRequestHandler() override = default;
|
||||||
|
|
||||||
// Register a REST service to the given URL path.
|
bool Bind(RestServicePtr service, const std::string& url, bool is_regex);
|
||||||
// The URL should start with "/" and could be a regular expression or not.
|
|
||||||
// E.g., "/instances". "/instances/(\\d+)"
|
|
||||||
bool RegisterService(RestServicePtr service, const std::string& url);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandleSession(HttpSessionPtr session) override;
|
void HandleSession(HttpSessionPtr session) override;
|
||||||
|
|
||||||
private:
|
|
||||||
RestServiceManager service_manager_;
|
RestServiceManager service_manager_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+12
-10
@@ -10,28 +10,30 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class RestServer : public HttpServer {
|
class RestServer : public HttpServer {
|
||||||
public:
|
public:
|
||||||
RestServer(unsigned short port, std::size_t workers)
|
RestServer(unsigned short port, std::size_t workers)
|
||||||
: HttpServer(port, workers) {
|
: HttpServer(port, workers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~RestServer() override = default;
|
~RestServer() override = default;
|
||||||
|
|
||||||
// Register a REST service to the given URL path.
|
// Bind a REST service to the given URL path.
|
||||||
// The URL should start with "/" and could be a regular expression or not.
|
// The URL should start with "/" and it will be treated as a regular
|
||||||
// E.g., "/instances". "/instances/(\\d+)"
|
// expression if |is_regex| is true.
|
||||||
// NOTE: Registering to the same URL multiple times is allowed, but only the
|
// Examples:
|
||||||
// last one takes effect.
|
// - "/instances"
|
||||||
bool RegisterService(RestServicePtr service, const std::string& url) {
|
// - "/instances/(\\d+)"
|
||||||
return request_handler_.RegisterService(service, url);
|
// Binding to the same URL multiple times is allowed, but only the last one
|
||||||
|
// takes effect.
|
||||||
|
bool Bind(RestServicePtr service, const std::string& url, bool is_regex) {
|
||||||
|
return request_handler_.Bind(service, url, is_regex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HttpRequestHandler* GetRequestHandler() override {
|
HttpRequestHandler* GetRequestHandler() override {
|
||||||
return &request_handler_;
|
return &request_handler_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
RestRequestHandler request_handler_;
|
RestRequestHandler request_handler_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class UrlQuery;
|
|||||||
|
|
||||||
// Base class for your REST service.
|
// Base class for your REST service.
|
||||||
class RestService {
|
class RestService {
|
||||||
public:
|
public:
|
||||||
virtual ~RestService() {
|
virtual ~RestService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,16 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
bool RestServiceManager::AddService(RestServicePtr service,
|
bool RestServiceManager::AddService(RestServicePtr service,
|
||||||
const std::string& url) {
|
const std::string& url,
|
||||||
|
bool is_regex) {
|
||||||
assert(service);
|
assert(service);
|
||||||
|
|
||||||
ServiceItem item(service, url);
|
ServiceItem item(service, url, is_regex);
|
||||||
|
|
||||||
|
if (!is_regex) {
|
||||||
|
service_items_.push_back(std::move(item));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
std::regex::flag_type flags = std::regex::ECMAScript | std::regex::icase;
|
std::regex::flag_type flags = std::regex::ECMAScript | std::regex::icase;
|
||||||
|
|
||||||
@@ -18,15 +24,13 @@ bool RestServiceManager::AddService(RestServicePtr service,
|
|||||||
// Compile the regex.
|
// Compile the regex.
|
||||||
item.url_regex.assign(url, flags);
|
item.url_regex.assign(url, flags);
|
||||||
|
|
||||||
service_items_.push_back(item);
|
service_items_.push_back(std::move(item));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (std::regex_error& e) {
|
} catch (std::regex_error& e) {
|
||||||
LOG_ERRO("URL is not a valid regular expression: %s", e.what());
|
LOG_ERRO("URL is not a valid regular expression: %s", e.what());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
RestServicePtr RestServiceManager::GetService(
|
RestServicePtr RestServiceManager::GetService(
|
||||||
@@ -36,16 +40,22 @@ RestServicePtr RestServiceManager::GetService(
|
|||||||
assert(sub_matches != NULL);
|
assert(sub_matches != NULL);
|
||||||
|
|
||||||
for (ServiceItem& item : service_items_) {
|
for (ServiceItem& item : service_items_) {
|
||||||
std::smatch match;
|
if (item.is_regex) {
|
||||||
|
std::smatch match;
|
||||||
|
|
||||||
if (std::regex_match(url, match, item.url_regex)) {
|
if (std::regex_match(url, match, item.url_regex)) {
|
||||||
// Any sub-matches?
|
// Any sub-matches?
|
||||||
// NOTE: Start from 1 because match[0] is the whole string itself.
|
// NOTE: Start from 1 because match[0] is the whole string itself.
|
||||||
for (size_t i = 1; i < match.size(); ++i) {
|
for (size_t i = 1; i < match.size(); ++i) {
|
||||||
sub_matches->push_back(match[i].str());
|
sub_matches->push_back(match[i].str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.service;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (item.url == url) {
|
||||||
|
return item.service;
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.service;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,15 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class RestServiceManager {
|
class RestServiceManager {
|
||||||
public:
|
public:
|
||||||
RestServiceManager() = default;
|
RestServiceManager() = default;
|
||||||
|
|
||||||
// Add a service and bind it with the given URL.
|
// Add a service and bind it with the given URL.
|
||||||
// The |url| should start with "/" and could be a regular expression or not.
|
// The |url| should start with "/" and will be treated as a regular expression
|
||||||
// E.g., "/instances". "/instances/(\\d+)"
|
// if |regex| is true.
|
||||||
bool AddService(RestServicePtr service, const std::string& url);
|
// Examples: "/instances", "/instances/(\\d+)".
|
||||||
|
bool AddService(RestServicePtr service, const std::string& url,
|
||||||
|
bool is_regex);
|
||||||
|
|
||||||
// The |sub_matches| is only available when the |url| bound to the
|
// The |sub_matches| is only available when the |url| bound to the
|
||||||
// service is a regular expression and has sub-expressions.
|
// service is a regular expression and has sub-expressions.
|
||||||
@@ -24,20 +26,22 @@ public:
|
|||||||
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,
|
||||||
: service(_service), url(_url) {
|
bool _is_regex)
|
||||||
|
: service(_service), url(_url), is_regex(_is_regex) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ServiceItem(const ServiceItem& rhs) = default;
|
ServiceItem(const ServiceItem&) = default;
|
||||||
ServiceItem& operator=(const ServiceItem& rhs) = default;
|
ServiceItem& operator=(const ServiceItem&) = default;
|
||||||
|
|
||||||
ServiceItem(ServiceItem&& rhs)
|
ServiceItem(ServiceItem&& rhs)
|
||||||
: url(std::move(rhs.url)),
|
: service(rhs.service),
|
||||||
url_regex(std::move(rhs.url_regex)),
|
url(std::move(rhs.url)),
|
||||||
service(rhs.service) { // No move
|
is_regex(rhs.is_regex),
|
||||||
|
url_regex(std::move(rhs.url_regex)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
RestServicePtr service;
|
RestServicePtr service;
|
||||||
@@ -45,6 +49,9 @@ private:
|
|||||||
// URL string, e.g., "/instances/(\\d+)".
|
// URL string, e.g., "/instances/(\\d+)".
|
||||||
std::string url;
|
std::string url;
|
||||||
|
|
||||||
|
// If the URL is a regular expression or not.
|
||||||
|
bool is_regex;
|
||||||
|
|
||||||
// Compiled regex for URL string.
|
// Compiled regex for URL string.
|
||||||
std::regex url_regex;
|
std::regex url_regex;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ Error SoapClient::Call(const std::string& operation,
|
|||||||
http_client.set_timeout_seconds(timeout_seconds_);
|
http_client.set_timeout_seconds(timeout_seconds_);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error error = http_client.MakeRequest(http_request, &http_response);
|
Error error = http_client.Request(http_request, &http_response);
|
||||||
|
|
||||||
if (error != kNoError) {
|
if (error != kNoError) {
|
||||||
return error;
|
return error;
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ namespace webcc {
|
|||||||
// Set URL, host, port, etc. in your sub-class before make the call.
|
// Set URL, host, port, etc. in your sub-class before make the call.
|
||||||
//
|
//
|
||||||
class SoapClient {
|
class SoapClient {
|
||||||
public:
|
public:
|
||||||
virtual ~SoapClient() = default;
|
virtual ~SoapClient() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
SoapClient() = default;
|
SoapClient() = default;
|
||||||
|
|
||||||
// A generic wrapper to make a call.
|
// A generic wrapper to make a call.
|
||||||
@@ -25,7 +25,6 @@ protected:
|
|||||||
std::vector<Parameter>&& parameters,
|
std::vector<Parameter>&& parameters,
|
||||||
std::string* result);
|
std::string* result);
|
||||||
|
|
||||||
protected:
|
|
||||||
// -1 means default timeout (normally 30s) will be used.
|
// -1 means default timeout (normally 30s) will be used.
|
||||||
int timeout_seconds_ = -1;
|
int timeout_seconds_ = -1;
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace webcc {
|
|||||||
// XML namespace name/url pair.
|
// XML namespace name/url pair.
|
||||||
// E.g., { "soap", "http://schemas.xmlsoap.org/soap/envelope/" }
|
// E.g., { "soap", "http://schemas.xmlsoap.org/soap/envelope/" }
|
||||||
class SoapNamespace {
|
class SoapNamespace {
|
||||||
public:
|
public:
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string url;
|
std::string url;
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ extern const SoapNamespace kSoapEnvNamespace;
|
|||||||
|
|
||||||
// Base class for SOAP request and response.
|
// Base class for SOAP request and response.
|
||||||
class SoapMessage {
|
class SoapMessage {
|
||||||
public:
|
public:
|
||||||
virtual ~SoapMessage() {}
|
virtual ~SoapMessage() {}
|
||||||
|
|
||||||
// E.g., set as kSoapEnvNamespace.
|
// E.g., set as kSoapEnvNamespace.
|
||||||
@@ -52,14 +52,13 @@ public:
|
|||||||
// Parse from SOAP request XML.
|
// Parse from SOAP request XML.
|
||||||
bool FromXml(const std::string& xml_string);
|
bool FromXml(const std::string& xml_string);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// 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;
|
||||||
|
|
||||||
// Parse from SOAP body XML.
|
// Parse from SOAP body XML.
|
||||||
virtual bool FromXmlBody(pugi::xml_node xbody) = 0;
|
virtual bool FromXmlBody(pugi::xml_node xbody) = 0;
|
||||||
|
|
||||||
protected:
|
|
||||||
SoapNamespace soapenv_ns_; // SOAP envelope namespace.
|
SoapNamespace soapenv_ns_; // SOAP envelope namespace.
|
||||||
SoapNamespace service_ns_; // Namespace for your web service.
|
SoapNamespace service_ns_; // Namespace for your web service.
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,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 Parameter& parameter);
|
void AddParameter(const Parameter& parameter);
|
||||||
|
|
||||||
void AddParameter(Parameter&& parameter);
|
void AddParameter(Parameter&& parameter);
|
||||||
@@ -19,11 +19,11 @@ public:
|
|||||||
// 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:
|
protected:
|
||||||
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<Parameter> parameters_;
|
std::vector<Parameter> parameters_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,7 @@
|
|||||||
|
|
||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
bool SoapRequestHandler::RegisterService(SoapServicePtr service,
|
bool SoapRequestHandler::Bind(SoapServicePtr service, const std::string& url) {
|
||||||
const std::string& url) {
|
|
||||||
assert(service);
|
assert(service);
|
||||||
|
|
||||||
url_service_map_[url] = service;
|
url_service_map_[url] = service;
|
||||||
|
|||||||
@@ -8,17 +8,13 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class SoapRequestHandler : public HttpRequestHandler {
|
class SoapRequestHandler : public HttpRequestHandler {
|
||||||
public:
|
public:
|
||||||
SoapRequestHandler() = default;
|
SoapRequestHandler() = default;
|
||||||
~SoapRequestHandler() override = default;
|
~SoapRequestHandler() override = default;
|
||||||
|
|
||||||
// Register a SOAP service to the given URL path.
|
bool Bind(SoapServicePtr service, const std::string& url);
|
||||||
// The |url| path must start with "/", e.g., "/calculator".
|
|
||||||
// Registering to the same URL multiple times is allowed, but only the last
|
|
||||||
// one takes effect.
|
|
||||||
bool RegisterService(SoapServicePtr service, const std::string& url);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandleSession(HttpSessionPtr session) override;
|
void HandleSession(HttpSessionPtr session) override;
|
||||||
|
|
||||||
SoapServicePtr GetServiceByUrl(const std::string& url);
|
SoapServicePtr GetServiceByUrl(const std::string& url);
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ namespace webcc {
|
|||||||
|
|
||||||
// SOAP response.
|
// SOAP response.
|
||||||
class SoapResponse : public SoapMessage {
|
class SoapResponse : public SoapMessage {
|
||||||
public:
|
public:
|
||||||
// Could be "Price" for an operation/method like "GetXyzPrice".
|
// Could be "Price" for an operation/method like "GetXyzPrice".
|
||||||
// Really depend on the service.
|
// Really depend on the service.
|
||||||
// Most services use a general name "Result".
|
// Most services use a general name "Result".
|
||||||
@@ -27,12 +27,12 @@ public:
|
|||||||
result_ = std::move(result);
|
result_ = std::move(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
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:
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// Multiple results might be necessary. But for most cases, single result
|
// Multiple results might be necessary. But for most cases, single result
|
||||||
// should be enough, because an API normally returns only one value.
|
// should be enough, because an API normally returns only one value.
|
||||||
|
|||||||
@@ -9,18 +9,22 @@
|
|||||||
namespace webcc {
|
namespace webcc {
|
||||||
|
|
||||||
class SoapServer : public HttpServer {
|
class SoapServer : public HttpServer {
|
||||||
public:
|
public:
|
||||||
SoapServer(unsigned short port, std::size_t workers)
|
SoapServer(unsigned short port, std::size_t workers)
|
||||||
: HttpServer(port, workers) {
|
: HttpServer(port, workers) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~SoapServer() override = default;
|
~SoapServer() override = default;
|
||||||
|
|
||||||
bool RegisterService(SoapServicePtr service, const std::string& url) {
|
// Bind a SOAP service to the given URL path.
|
||||||
return request_handler_.RegisterService(service, url);
|
// The |url| path must start with "/", e.g., "/calculator".
|
||||||
|
// Binding to the same URL multiple times is allowed, but only the last
|
||||||
|
// one takes effect.
|
||||||
|
bool Bind(SoapServicePtr service, const std::string& 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:
|
protected:
|
||||||
HttpStatus::Enum http_status_ = HttpStatus::kOK;
|
HttpStatus::Enum http_status_ = HttpStatus::kOK;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -19,7 +19,7 @@ namespace webcc {
|
|||||||
|
|
||||||
// URL query parameters.
|
// URL query parameters.
|
||||||
class UrlQuery {
|
class UrlQuery {
|
||||||
public:
|
public:
|
||||||
typedef std::vector<Parameter> Parameters;
|
typedef std::vector<Parameter> Parameters;
|
||||||
|
|
||||||
UrlQuery() = default;
|
UrlQuery() = default;
|
||||||
@@ -49,18 +49,17 @@ public:
|
|||||||
// E.g., "item=12731&color=blue&size=large".
|
// E.g., "item=12731&color=blue&size=large".
|
||||||
std::string ToString() const;
|
std::string ToString() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
typedef Parameters::const_iterator ConstIterator;
|
typedef Parameters::const_iterator ConstIterator;
|
||||||
ConstIterator Find(const std::string& key) const;
|
ConstIterator Find(const std::string& key) const;
|
||||||
|
|
||||||
private:
|
|
||||||
Parameters parameters_;
|
Parameters parameters_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
class Url {
|
class Url {
|
||||||
public:
|
public:
|
||||||
Url() = default;
|
Url() = default;
|
||||||
Url(const std::string& str, bool decode);
|
Url(const std::string& str, bool decode);
|
||||||
|
|
||||||
@@ -88,7 +87,7 @@ public:
|
|||||||
// Split query string into key-value parameters.
|
// Split query string into key-value parameters.
|
||||||
static void SplitQuery(const std::string& str, UrlQuery* query);
|
static void SplitQuery(const std::string& str, UrlQuery* query);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Init(const std::string& str);
|
void Init(const std::string& str);
|
||||||
|
|
||||||
std::string path_;
|
std::string path_;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ TEST(RestServiceManager, URL_RegexBasic) {
|
|||||||
{
|
{
|
||||||
RestServicePtr service = std::make_shared<TestRestService>();
|
RestServicePtr service = std::make_shared<TestRestService>();
|
||||||
|
|
||||||
service_manager.AddService(service, "/instances/(\\d+)");
|
service_manager.AddService(service, "/instances/(\\d+)", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> sub_matches;
|
std::vector<std::string> sub_matches;
|
||||||
@@ -39,3 +39,20 @@ TEST(RestServiceManager, URL_RegexBasic) {
|
|||||||
|
|
||||||
EXPECT_FALSE(!!service);
|
EXPECT_FALSE(!!service);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(RestServiceManager, URL_NonRegex) {
|
||||||
|
RestServiceManager service_manager;
|
||||||
|
|
||||||
|
{
|
||||||
|
RestServicePtr service = std::make_shared<TestRestService>();
|
||||||
|
|
||||||
|
service_manager.AddService(service, "/instances", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> sub_matches;
|
||||||
|
std::string url = "/instances";
|
||||||
|
RestServicePtr service = service_manager.GetService(url, &sub_matches);
|
||||||
|
|
||||||
|
EXPECT_TRUE(!!service);
|
||||||
|
EXPECT_EQ(0, sub_matches.size());
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user