Refactoring according Google C++ Style.
parent
189a246221
commit
1bab2da8f4
@ -0,0 +1,169 @@
|
|||||||
|
#include "webcc/http_async_client.h"
|
||||||
|
|
||||||
|
#if WEBCC_DEBUG_OUTPUT
|
||||||
|
#include <iostream>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include "boost/asio.hpp"
|
||||||
|
#else
|
||||||
|
#include "boost/asio/connect.hpp"
|
||||||
|
//#include "boost/asio/ip/tcp.hpp"
|
||||||
|
#include "boost/asio/read.hpp"
|
||||||
|
#include "boost/asio/write.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "webcc/http_response_parser.h"
|
||||||
|
#include "webcc/http_request.h"
|
||||||
|
#include "webcc/http_response.h"
|
||||||
|
|
||||||
|
using boost::asio::ip::tcp;
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
HttpAsyncClient::HttpAsyncClient(boost::asio::io_context& io_context)
|
||||||
|
: socket_(io_context) {
|
||||||
|
|
||||||
|
resolver_.reset(new tcp::resolver(io_context));
|
||||||
|
|
||||||
|
response_.reset(new HttpResponse());
|
||||||
|
parser_.reset(new HttpResponseParser(response_.get()));
|
||||||
|
}
|
||||||
|
|
||||||
|
Error HttpAsyncClient::SendRequest(std::shared_ptr<HttpRequest> request,
|
||||||
|
HttpResponseHandler response_handler) {
|
||||||
|
request_ = request;
|
||||||
|
|
||||||
|
std::string port = request->port();
|
||||||
|
if (port.empty()) {
|
||||||
|
port = "80";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto handler = std::bind(&HttpAsyncClient::HandleResolve,
|
||||||
|
this,
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2);
|
||||||
|
|
||||||
|
resolver_->async_resolve(tcp::v4(), request->host(), port, handler);
|
||||||
|
|
||||||
|
return kNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpAsyncClient::HandleResolve(boost::system::error_code ec,
|
||||||
|
tcp::resolver::results_type results) {
|
||||||
|
if (ec) {
|
||||||
|
std::cerr << "Resolve: " << ec.message() << std::endl;
|
||||||
|
// return kHostResolveError;
|
||||||
|
} else {
|
||||||
|
endpoints_ = results;
|
||||||
|
DoConnect(endpoints_.begin());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpAsyncClient::DoConnect(tcp::resolver::results_type::iterator endpoint_it) {
|
||||||
|
if (endpoint_it != endpoints_.end()) {
|
||||||
|
socket_.async_connect(endpoint_it->endpoint(),
|
||||||
|
std::bind(&HttpAsyncClient::HandleConnect,
|
||||||
|
this,
|
||||||
|
std::placeholders::_1,
|
||||||
|
endpoint_it));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpAsyncClient::HandleConnect(boost::system::error_code ec,
|
||||||
|
tcp::resolver::results_type::iterator endpoint_it) {
|
||||||
|
if (ec) {
|
||||||
|
// Will be here if the end point is v6.
|
||||||
|
std::cout << "Connect error: " << ec.message() << std::endl;
|
||||||
|
// return kEndpointConnectError;
|
||||||
|
|
||||||
|
socket_.close();
|
||||||
|
|
||||||
|
// Try the next available endpoint.
|
||||||
|
DoConnect(++endpoint_it);
|
||||||
|
} else {
|
||||||
|
DoWrite();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send HTTP request.
|
||||||
|
void HttpAsyncClient::DoWrite() {
|
||||||
|
boost::asio::async_write(socket_,
|
||||||
|
request_->ToBuffers(),
|
||||||
|
std::bind(&HttpAsyncClient::HandleWrite,
|
||||||
|
this,
|
||||||
|
std::placeholders::_1));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpAsyncClient::HandleWrite(boost::system::error_code ec) {
|
||||||
|
if (ec) {
|
||||||
|
//return kSocketWriteError;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DoRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpAsyncClient::DoRead() {
|
||||||
|
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||||
|
std::bind(&HttpAsyncClient::HandleRead,
|
||||||
|
this,
|
||||||
|
std::placeholders::_1,
|
||||||
|
std::placeholders::_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HttpAsyncClient::HandleRead(boost::system::error_code ec,
|
||||||
|
std::size_t length) {
|
||||||
|
if (ec || length == 0) {
|
||||||
|
//return kSocketReadError;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WEBCC_DEBUG_OUTPUT
|
||||||
|
// NOTE: the content XML might not be well formated.
|
||||||
|
std::cout.write(buffer_.data(), length);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Parse the response piece just read.
|
||||||
|
// If the content has been fully received, next time flag "finished_"
|
||||||
|
// will be set.
|
||||||
|
Error error = parser_->Parse(buffer_.data(), length);
|
||||||
|
|
||||||
|
if (error != kNoError) {
|
||||||
|
//return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser_->finished()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read and parse HTTP response.
|
||||||
|
|
||||||
|
// NOTE:
|
||||||
|
// We must stop trying to read once all content has been received,
|
||||||
|
// because some servers will block extra call to read_some().
|
||||||
|
//while (!parser_.finished()) {
|
||||||
|
// size_t length = socket_.read_some(boost::asio::buffer(buffer_), ec);
|
||||||
|
|
||||||
|
//if (length == 0 || ec) {
|
||||||
|
// return kSocketReadError;
|
||||||
|
//}
|
||||||
|
|
||||||
|
// Parse the response piece just read.
|
||||||
|
// If the content has been fully received, next time flag "finished_"
|
||||||
|
// will be set.
|
||||||
|
//Error error = parser_.Parse(buffer_.data(), length);
|
||||||
|
|
||||||
|
//if (error != kNoError) {
|
||||||
|
// return error;
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
|
//#if WEBCC_DEBUG_OUTPUT
|
||||||
|
// std::cout << std::endl;
|
||||||
|
// std::cout << "--- RESPONSE (PARSED) ---" << std::endl;
|
||||||
|
// std::cout << *response << std::endl;
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webcc
|
@ -0,0 +1,62 @@
|
|||||||
|
#ifndef WEBCC_HTTP_ASYNC_CLIENT_H_
|
||||||
|
#define WEBCC_HTTP_ASYNC_CLIENT_H_
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "boost/smart_ptr/scoped_ptr.hpp"
|
||||||
|
|
||||||
|
#include "boost/asio/io_context.hpp"
|
||||||
|
#include "boost/asio/ip/tcp.hpp"
|
||||||
|
|
||||||
|
#include "webcc/common.h"
|
||||||
|
#include "webcc/http_response_parser.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
class HttpRequest;
|
||||||
|
class HttpResponse;
|
||||||
|
|
||||||
|
typedef void(*HttpResponseHandler)(std::shared_ptr<HttpResponse>);
|
||||||
|
|
||||||
|
class HttpAsyncClient {
|
||||||
|
public:
|
||||||
|
HttpAsyncClient(boost::asio::io_context& io_context);
|
||||||
|
|
||||||
|
Error SendRequest(std::shared_ptr<HttpRequest> request,
|
||||||
|
HttpResponseHandler response_handler);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void HandleResolve(boost::system::error_code ec,
|
||||||
|
boost::asio::ip::tcp::resolver::results_type results);
|
||||||
|
|
||||||
|
void DoConnect(boost::asio::ip::tcp::resolver::results_type::iterator endpoint_it);
|
||||||
|
|
||||||
|
void HandleConnect(boost::system::error_code ec,
|
||||||
|
boost::asio::ip::tcp::resolver::results_type::iterator endpoint_it);
|
||||||
|
|
||||||
|
void DoWrite();
|
||||||
|
|
||||||
|
void HandleWrite(boost::system::error_code ec);
|
||||||
|
|
||||||
|
void DoRead();
|
||||||
|
|
||||||
|
void HandleRead(boost::system::error_code ec, std::size_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
boost::asio::ip::tcp::socket socket_;
|
||||||
|
|
||||||
|
std::shared_ptr<HttpRequest> request_;
|
||||||
|
|
||||||
|
std::unique_ptr<boost::asio::ip::tcp::resolver> resolver_;
|
||||||
|
boost::asio::ip::tcp::resolver::results_type endpoints_;
|
||||||
|
|
||||||
|
std::array<char, kBufferSize> buffer_;
|
||||||
|
|
||||||
|
std::unique_ptr<HttpResponseParser> parser_;
|
||||||
|
|
||||||
|
std::shared_ptr<HttpResponse> response_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webcc
|
||||||
|
|
||||||
|
#endif // WEBCC_HTTP_ASYNC_CLIENT_H_
|
@ -0,0 +1,31 @@
|
|||||||
|
#include "webcc/rest_client.h"
|
||||||
|
|
||||||
|
#include "webcc/http_client.h"
|
||||||
|
#include "webcc/http_request.h"
|
||||||
|
#include "webcc/http_response.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
bool RestClient::Request(const std::string& method,
|
||||||
|
const std::string& url,
|
||||||
|
const std::string& content,
|
||||||
|
HttpResponse* response) {
|
||||||
|
HttpRequest request;
|
||||||
|
|
||||||
|
request.set_method(method);
|
||||||
|
request.set_url(url);
|
||||||
|
request.SetHost(host_, port_);
|
||||||
|
|
||||||
|
if (!content.empty()) {
|
||||||
|
request.SetContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
request.Build();
|
||||||
|
|
||||||
|
HttpClient http_client;
|
||||||
|
Error error = http_client.MakeRequest(request, response);
|
||||||
|
|
||||||
|
return error == kNoError;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webcc
|
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef WEBCC_REST_CLIENT_H_
|
||||||
|
#define WEBCC_REST_CLIENT_H_
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "webcc/globals.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
class HttpResponse;
|
||||||
|
|
||||||
|
class RestClient {
|
||||||
|
public:
|
||||||
|
RestClient(const std::string& host, const std::string& port)
|
||||||
|
: host_(host), port_(port) {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Get(const std::string& url, HttpResponse* response) {
|
||||||
|
return Request(kHttpGet, url, "", response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Post(const std::string& url,
|
||||||
|
const std::string& content,
|
||||||
|
HttpResponse* response) {
|
||||||
|
return Request(kHttpPost, url, content, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Put(const std::string& url,
|
||||||
|
const std::string& content,
|
||||||
|
HttpResponse* response) {
|
||||||
|
return Request(kHttpPut, url, content, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Patch(const std::string& url,
|
||||||
|
const std::string& content,
|
||||||
|
HttpResponse* response) {
|
||||||
|
return Request(kHttpPatch, url, content, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Delete(const std::string& url, HttpResponse* response) {
|
||||||
|
return Request(kHttpDelete, url, "", response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool Request(const std::string& method,
|
||||||
|
const std::string& url,
|
||||||
|
const std::string& content,
|
||||||
|
HttpResponse* response);
|
||||||
|
|
||||||
|
std::string host_;
|
||||||
|
std::string port_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webcc
|
||||||
|
|
||||||
|
#endif // WEBCC_REST_CLIENT_H_
|
@ -0,0 +1,50 @@
|
|||||||
|
#include "webcc/rest_request_handler.h"
|
||||||
|
|
||||||
|
#include "webcc/logger.h"
|
||||||
|
#include "webcc/url.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
bool RestRequestHandler::RegisterService(RestServicePtr service,
|
||||||
|
const std::string& url) {
|
||||||
|
return service_manager_.AddService(service, url);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RestRequestHandler::HandleSession(HttpSessionPtr session) {
|
||||||
|
Url url(session->request().url(), true);
|
||||||
|
|
||||||
|
if (!url.IsValid()) {
|
||||||
|
session->SendResponse(HttpStatus::kBadRequest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> sub_matches;
|
||||||
|
RestServicePtr service = service_manager_.GetService(url.path(),
|
||||||
|
&sub_matches);
|
||||||
|
if (!service) {
|
||||||
|
LOG_WARN("No service matches the URL: %s", url.path().c_str());
|
||||||
|
session->SendResponse(HttpStatus::kBadRequest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Only for GET?
|
||||||
|
UrlQuery query;
|
||||||
|
Url::SplitQuery(url.query(), &query);
|
||||||
|
|
||||||
|
std::string content;
|
||||||
|
bool ok = service->Handle(session->request().method(),
|
||||||
|
sub_matches,
|
||||||
|
query,
|
||||||
|
session->request().content(),
|
||||||
|
&content);
|
||||||
|
if (!ok) {
|
||||||
|
// TODO: Could be other than kBadRequest.
|
||||||
|
session->SendResponse(HttpStatus::kBadRequest);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
session->SetResponseContent(std::move(content), kTextJsonUtf8);
|
||||||
|
session->SendResponse(HttpStatus::kOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webcc
|
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef WEBCC_REST_REQUEST_HANDLER_H_
|
||||||
|
#define WEBCC_REST_REQUEST_HANDLER_H_
|
||||||
|
|
||||||
|
// HTTP server handling REST requests.
|
||||||
|
|
||||||
|
#include "webcc/http_request_handler.h"
|
||||||
|
#include "webcc/rest_service_manager.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
class RestRequestHandler : public HttpRequestHandler {
|
||||||
|
public:
|
||||||
|
~RestRequestHandler() override = default;
|
||||||
|
|
||||||
|
// Register a REST service to the given URL path.
|
||||||
|
// 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:
|
||||||
|
void HandleSession(HttpSessionPtr session) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
RestServiceManager service_manager_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webcc
|
||||||
|
|
||||||
|
#endif // WEBCC_REST_REQUEST_HANDLER_H_
|
@ -1,114 +0,0 @@
|
|||||||
#include "webcc/rest_server.h"
|
|
||||||
|
|
||||||
#include "webcc/logger.h"
|
|
||||||
#include "webcc/url.h"
|
|
||||||
|
|
||||||
namespace webcc {
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool RestServiceManager::AddService(RestServicePtr service,
|
|
||||||
const std::string& url) {
|
|
||||||
assert(service);
|
|
||||||
|
|
||||||
ServiceItem item(service, url);
|
|
||||||
|
|
||||||
std::regex::flag_type flags = std::regex::ECMAScript | std::regex::icase;
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Compile the regex.
|
|
||||||
item.url_regex.assign(url, flags);
|
|
||||||
|
|
||||||
service_items_.push_back(item);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
} catch (std::regex_error& e) {
|
|
||||||
LOG_ERRO("URL is not a valid regular expression: %s", e.what());
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
RestServicePtr RestServiceManager::GetService(
|
|
||||||
const std::string& url,
|
|
||||||
std::vector<std::string>* sub_matches) {
|
|
||||||
assert(sub_matches != NULL);
|
|
||||||
|
|
||||||
for (ServiceItem& item : service_items_) {
|
|
||||||
std::smatch match;
|
|
||||||
|
|
||||||
if (std::regex_match(url, match, item.url_regex)) {
|
|
||||||
// Any sub-matches?
|
|
||||||
// NOTE: Start from 1 because match[0] is the whole string itself.
|
|
||||||
for (size_t i = 1; i < match.size(); ++i) {
|
|
||||||
sub_matches->push_back(match[i].str());
|
|
||||||
}
|
|
||||||
|
|
||||||
return item.service;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RestServicePtr();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
bool RestRequestHandler::RegisterService(RestServicePtr service,
|
|
||||||
const std::string& url) {
|
|
||||||
return service_manager_.AddService(service, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RestRequestHandler::HandleSession(HttpSessionPtr session) {
|
|
||||||
Url url(session->request().url());
|
|
||||||
|
|
||||||
if (!url.IsValid()) {
|
|
||||||
session->SendResponse(HttpStatus::kBadRequest);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::string> sub_matches;
|
|
||||||
RestServicePtr service = service_manager_.GetService(url.path(), &sub_matches);
|
|
||||||
if (!service) {
|
|
||||||
LOG_WARN("No service matches the URL: %s", url.path().c_str());
|
|
||||||
session->SendResponse(HttpStatus::kBadRequest);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Only for GET?
|
|
||||||
UrlQuery query;
|
|
||||||
Url::SplitQuery(url.query(), &query);
|
|
||||||
|
|
||||||
std::string content;
|
|
||||||
bool ok = service->Handle(session->request().method(),
|
|
||||||
sub_matches,
|
|
||||||
query,
|
|
||||||
session->request().content(),
|
|
||||||
&content);
|
|
||||||
if (!ok) {
|
|
||||||
// TODO: Could be other than kBadRequest.
|
|
||||||
session->SendResponse(HttpStatus::kBadRequest);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
session->SetResponseContent(std::move(content), kTextJsonUtf8);
|
|
||||||
session->SendResponse(HttpStatus::kOK);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
RestServer::RestServer(unsigned short port, std::size_t workers)
|
|
||||||
: HttpServer(port, workers)
|
|
||||||
, request_handler_(new RestRequestHandler()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
RestServer::~RestServer() {
|
|
||||||
delete request_handler_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RestServer::RegisterService(RestServicePtr service,
|
|
||||||
const std::string& url) {
|
|
||||||
return request_handler_->RegisterService(service, url);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace webcc
|
|
@ -0,0 +1,55 @@
|
|||||||
|
#include "webcc/rest_service_manager.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "webcc/logger.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
bool RestServiceManager::AddService(RestServicePtr service,
|
||||||
|
const std::string& url) {
|
||||||
|
assert(service);
|
||||||
|
|
||||||
|
ServiceItem item(service, url);
|
||||||
|
|
||||||
|
std::regex::flag_type flags = std::regex::ECMAScript | std::regex::icase;
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Compile the regex.
|
||||||
|
item.url_regex.assign(url, flags);
|
||||||
|
|
||||||
|
service_items_.push_back(item);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (std::regex_error& e) {
|
||||||
|
LOG_ERRO("URL is not a valid regular expression: %s", e.what());
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
RestServicePtr RestServiceManager::GetService(
|
||||||
|
const std::string& url,
|
||||||
|
std::vector<std::string>* sub_matches) {
|
||||||
|
|
||||||
|
assert(sub_matches != NULL);
|
||||||
|
|
||||||
|
for (ServiceItem& item : service_items_) {
|
||||||
|
std::smatch match;
|
||||||
|
|
||||||
|
if (std::regex_match(url, match, item.url_regex)) {
|
||||||
|
// Any sub-matches?
|
||||||
|
// NOTE: Start from 1 because match[0] is the whole string itself.
|
||||||
|
for (size_t i = 1; i < match.size(); ++i) {
|
||||||
|
sub_matches->push_back(match[i].str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return item.service;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return RestServicePtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace webcc
|
@ -0,0 +1,59 @@
|
|||||||
|
#ifndef WEBCC_REST_SERVICE_MANAGER_H_
|
||||||
|
#define WEBCC_REST_SERVICE_MANAGER_H_
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "webcc/rest_service.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
class RestServiceManager {
|
||||||
|
public:
|
||||||
|
RestServiceManager() = default;
|
||||||
|
|
||||||
|
// Add a service and bind it with the given URL.
|
||||||
|
// The |url| should start with "/" and could be a regular expression or not.
|
||||||
|
// E.g., "/instances". "/instances/(\\d+)"
|
||||||
|
bool AddService(RestServicePtr service, const std::string& url);
|
||||||
|
|
||||||
|
// The |sub_matches| is only available when the |url| bound to the
|
||||||
|
// service is a regular expression and has sub-expressions.
|
||||||
|
// E.g., the URL bound to the service is "/instances/(\\d+)", now match
|
||||||
|
// "/instances/12345" against it, you will get one sub-match of "12345".
|
||||||
|
RestServicePtr GetService(const std::string& url,
|
||||||
|
std::vector<std::string>* sub_matches);
|
||||||
|
|
||||||
|
private:
|
||||||
|
class ServiceItem {
|
||||||
|
public:
|
||||||
|
ServiceItem(RestServicePtr _service, const std::string& _url)
|
||||||
|
: service(_service), url(_url) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ServiceItem(const ServiceItem& rhs) = default;
|
||||||
|
ServiceItem& operator=(const ServiceItem& rhs) = default;
|
||||||
|
|
||||||
|
ServiceItem(ServiceItem&& rhs)
|
||||||
|
: url(std::move(rhs.url)),
|
||||||
|
url_regex(std::move(rhs.url_regex)),
|
||||||
|
service(rhs.service) { // No move
|
||||||
|
}
|
||||||
|
|
||||||
|
RestServicePtr service;
|
||||||
|
|
||||||
|
// URL string, e.g., "/instances/(\\d+)".
|
||||||
|
std::string url;
|
||||||
|
|
||||||
|
// Compiled regex for URL string.
|
||||||
|
std::regex url_regex;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<ServiceItem> service_items_;
|
||||||
|
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(RestServiceManager);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webcc
|
||||||
|
|
||||||
|
#endif // WEBCC_REST_SERVICE_MANAGER_H_
|
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef WEBCC_SOAP_REQUEST_HANDLER_H_
|
||||||
|
#define WEBCC_SOAP_REQUEST_HANDLER_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "webcc/http_request_handler.h"
|
||||||
|
|
||||||
|
namespace webcc {
|
||||||
|
|
||||||
|
class SoapRequestHandler : public HttpRequestHandler {
|
||||||
|
public:
|
||||||
|
SoapRequestHandler() = default;
|
||||||
|
~SoapRequestHandler() override = default;
|
||||||
|
|
||||||
|
// Register a SOAP service to the given URL path.
|
||||||
|
// 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:
|
||||||
|
void HandleSession(HttpSessionPtr session) override;
|
||||||
|
|
||||||
|
SoapServicePtr GetServiceByUrl(const std::string& url);
|
||||||
|
|
||||||
|
typedef std::map<std::string, SoapServicePtr> UrlServiceMap;
|
||||||
|
UrlServiceMap url_service_map_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace webcc
|
||||||
|
|
||||||
|
#endif // WEBCC_SOAP_REQUEST_HANDLER_H_
|
Loading…
Reference in New Issue