Remove http prefix
parent
2ea04b9705
commit
e621025cc3
@ -0,0 +1,82 @@
|
||||
#ifndef WEBCC_CONNECTION_H_
|
||||
#define WEBCC_CONNECTION_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "boost/asio/ip/tcp.hpp" // for ip::tcp::socket
|
||||
|
||||
#include "webcc/globals.h"
|
||||
#include "webcc/request.h"
|
||||
#include "webcc/request_parser.h"
|
||||
#include "webcc/response.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class Connection;
|
||||
class ConnectionPool;
|
||||
class RequestHandler;
|
||||
|
||||
using ConnectionPtr = std::shared_ptr<Connection>;
|
||||
|
||||
class Connection : public std::enable_shared_from_this<Connection> {
|
||||
public:
|
||||
Connection(boost::asio::ip::tcp::socket socket, ConnectionPool* pool,
|
||||
RequestHandler* handler);
|
||||
|
||||
~Connection() = default;
|
||||
|
||||
Connection(const Connection&) = delete;
|
||||
Connection& operator=(const Connection&) = delete;
|
||||
|
||||
RequestPtr request() const {
|
||||
return request_;
|
||||
}
|
||||
|
||||
// Start to read and process the client request.
|
||||
void Start();
|
||||
|
||||
// Close the socket.
|
||||
void Close();
|
||||
|
||||
// Send response to client.
|
||||
void SendResponse(ResponsePtr response);
|
||||
|
||||
void SendResponse(Status status);
|
||||
|
||||
private:
|
||||
void DoRead();
|
||||
void OnRead(boost::system::error_code ec, std::size_t length);
|
||||
|
||||
void DoWrite();
|
||||
void OnWrite(boost::system::error_code ec, std::size_t length);
|
||||
|
||||
// Shutdown the socket.
|
||||
void Shutdown();
|
||||
|
||||
// Socket for the connection.
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
// The pool for this connection.
|
||||
ConnectionPool* pool_;
|
||||
|
||||
// Buffer for incoming data.
|
||||
std::vector<char> buffer_;
|
||||
|
||||
// The handler used to process the incoming request.
|
||||
RequestHandler* request_handler_;
|
||||
|
||||
// The incoming request.
|
||||
RequestPtr request_;
|
||||
|
||||
// The parser for the incoming request.
|
||||
RequestParser request_parser_;
|
||||
|
||||
// The response to be sent back to the client.
|
||||
ResponsePtr response_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_CONNECTION_H_
|
@ -1,25 +1,25 @@
|
||||
#include "webcc/http_connection_pool.h"
|
||||
#include "webcc/connection_pool.h"
|
||||
|
||||
#include "webcc/logger.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
HttpConnectionPool::HttpConnectionPool() {
|
||||
ConnectionPool::ConnectionPool() {
|
||||
}
|
||||
|
||||
void HttpConnectionPool::Start(HttpConnectionPtr c) {
|
||||
void ConnectionPool::Start(ConnectionPtr c) {
|
||||
LOG_VERB("Starting connection...");
|
||||
connections_.insert(c);
|
||||
c->Start();
|
||||
}
|
||||
|
||||
void HttpConnectionPool::Close(HttpConnectionPtr c) {
|
||||
void ConnectionPool::Close(ConnectionPtr c) {
|
||||
LOG_VERB("Closing connection...");
|
||||
connections_.erase(c);
|
||||
c->Close();
|
||||
}
|
||||
|
||||
void HttpConnectionPool::CloseAll() {
|
||||
void ConnectionPool::CloseAll() {
|
||||
LOG_VERB("Closing all (%u) connections...", connections_.size());
|
||||
for (auto& c : connections_) {
|
||||
c->Close();
|
@ -0,0 +1,33 @@
|
||||
#ifndef WEBCC_CONNECTION_POOL_H_
|
||||
#define WEBCC_CONNECTION_POOL_H_
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "webcc/connection.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class ConnectionPool {
|
||||
public:
|
||||
ConnectionPool(const ConnectionPool&) = delete;
|
||||
ConnectionPool& operator=(const ConnectionPool&) = delete;
|
||||
|
||||
ConnectionPool();
|
||||
|
||||
// Add a connection to the pool and start it.
|
||||
void Start(ConnectionPtr c);
|
||||
|
||||
// Close a connection.
|
||||
void Close(ConnectionPtr c);
|
||||
|
||||
// Close all connections.
|
||||
void CloseAll();
|
||||
|
||||
private:
|
||||
/// The managed connections.
|
||||
std::set<ConnectionPtr> connections_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_CONNECTION_POOL_H_
|
@ -1,82 +0,0 @@
|
||||
#ifndef WEBCC_HTTP_CONNECTION_H_
|
||||
#define WEBCC_HTTP_CONNECTION_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "boost/asio/ip/tcp.hpp" // for ip::tcp::socket
|
||||
|
||||
#include "webcc/globals.h"
|
||||
#include "webcc/http_request.h"
|
||||
#include "webcc/http_request_parser.h"
|
||||
#include "webcc/http_response.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpConnection;
|
||||
class HttpConnectionPool;
|
||||
class HttpRequestHandler;
|
||||
|
||||
typedef std::shared_ptr<HttpConnection> HttpConnectionPtr;
|
||||
|
||||
class HttpConnection : public std::enable_shared_from_this<HttpConnection> {
|
||||
public:
|
||||
HttpConnection(boost::asio::ip::tcp::socket socket, HttpConnectionPool* pool,
|
||||
HttpRequestHandler* handler);
|
||||
|
||||
~HttpConnection() = default;
|
||||
|
||||
HttpConnection(const HttpConnection&) = delete;
|
||||
HttpConnection& operator=(const HttpConnection&) = delete;
|
||||
|
||||
HttpRequestPtr request() const {
|
||||
return request_;
|
||||
}
|
||||
|
||||
// Start to read and process the client request.
|
||||
void Start();
|
||||
|
||||
// Close the socket.
|
||||
void Close();
|
||||
|
||||
// Send response to client.
|
||||
void SendResponse(HttpResponsePtr response);
|
||||
|
||||
void SendResponse(http::Status status);
|
||||
|
||||
private:
|
||||
void DoRead();
|
||||
void OnRead(boost::system::error_code ec, std::size_t length);
|
||||
|
||||
void DoWrite();
|
||||
void OnWrite(boost::system::error_code ec, std::size_t length);
|
||||
|
||||
// Shutdown the socket.
|
||||
void Shutdown();
|
||||
|
||||
// Socket for the connection.
|
||||
boost::asio::ip::tcp::socket socket_;
|
||||
|
||||
// The pool for this connection.
|
||||
HttpConnectionPool* pool_;
|
||||
|
||||
// Buffer for incoming data.
|
||||
std::vector<char> buffer_;
|
||||
|
||||
// The handler used to process the incoming request.
|
||||
HttpRequestHandler* request_handler_;
|
||||
|
||||
// The incoming request.
|
||||
HttpRequestPtr request_;
|
||||
|
||||
// The parser for the incoming request.
|
||||
HttpRequestParser request_parser_;
|
||||
|
||||
// The response to be sent back to the client.
|
||||
HttpResponsePtr response_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_CONNECTION_H_
|
@ -1,33 +0,0 @@
|
||||
#ifndef WEBCC_HTTP_CONNECTION_POOL_H_
|
||||
#define WEBCC_HTTP_CONNECTION_POOL_H_
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "webcc/http_connection.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpConnectionPool {
|
||||
public:
|
||||
HttpConnectionPool(const HttpConnectionPool&) = delete;
|
||||
HttpConnectionPool& operator=(const HttpConnectionPool&) = delete;
|
||||
|
||||
HttpConnectionPool();
|
||||
|
||||
// Add a connection to the pool and start it.
|
||||
void Start(HttpConnectionPtr c);
|
||||
|
||||
// Close a connection.
|
||||
void Close(HttpConnectionPtr c);
|
||||
|
||||
// Close all connections.
|
||||
void CloseAll();
|
||||
|
||||
private:
|
||||
/// The managed connections.
|
||||
std::set<HttpConnectionPtr> connections_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_CONNECTION_POOL_H_
|
@ -1,92 +0,0 @@
|
||||
#include "webcc/http_request_builder.h"
|
||||
|
||||
#include "webcc/base64.h"
|
||||
#include "webcc/logger.h"
|
||||
#include "webcc/utility.h"
|
||||
#include "webcc/zlib_wrapper.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
HttpRequestPtr HttpRequestBuilder::Build() {
|
||||
assert(parameters_.size() % 2 == 0);
|
||||
assert(headers_.size() % 2 == 0);
|
||||
|
||||
auto request = std::make_shared<HttpRequest>(method_, url_);
|
||||
|
||||
for (std::size_t i = 1; i < parameters_.size(); i += 2) {
|
||||
request->AddQuery(parameters_[i - 1], parameters_[i]);
|
||||
}
|
||||
|
||||
for (std::size_t i = 1; i < headers_.size(); i += 2) {
|
||||
request->SetHeader(std::move(headers_[i - 1]), std::move(headers_[i]));
|
||||
}
|
||||
|
||||
// No keep-alive?
|
||||
if (!keep_alive_) {
|
||||
request->SetHeader(http::headers::kConnection, "Close");
|
||||
}
|
||||
|
||||
if (!data_.empty()) {
|
||||
SetContent(request, std::move(data_));
|
||||
|
||||
// TODO: Request-level charset.
|
||||
if (json_) {
|
||||
request->SetContentType(http::media_types::kApplicationJson, "");
|
||||
}
|
||||
} else if (!form_parts_.empty()) {
|
||||
request->set_form_parts(std::move(form_parts_));
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& HttpRequestBuilder::File(const std::string& name,
|
||||
const Path& path,
|
||||
const std::string& mime_type) {
|
||||
assert(!name.empty());
|
||||
form_parts_.push_back(FormPart{ name, path, mime_type });
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& HttpRequestBuilder::Form(const std::string& name,
|
||||
std::string&& data,
|
||||
const std::string& mime_type) {
|
||||
assert(!name.empty());
|
||||
form_parts_.push_back(FormPart{ name, std::move(data), mime_type });
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& HttpRequestBuilder::Auth(const std::string& type,
|
||||
const std::string& credentials) {
|
||||
headers_.push_back(http::headers::kAuthorization);
|
||||
headers_.push_back(type + " " + credentials);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& HttpRequestBuilder::AuthBasic(const std::string& login,
|
||||
const std::string& password) {
|
||||
auto credentials = Base64Encode(login + ":" + password);
|
||||
return Auth("Basic", credentials);
|
||||
}
|
||||
|
||||
HttpRequestBuilder& HttpRequestBuilder::AuthToken(const std::string& token) {
|
||||
return Auth("Token", token);
|
||||
}
|
||||
|
||||
void HttpRequestBuilder::SetContent(HttpRequestPtr request,
|
||||
std::string&& data) {
|
||||
if (gzip_ && data.size() > kGzipThreshold) {
|
||||
std::string compressed;
|
||||
if (Compress(data, &compressed)) {
|
||||
request->SetContent(std::move(compressed), true);
|
||||
request->SetHeader(http::headers::kContentEncoding, "gzip");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_WARN("Cannot compress the content data!");
|
||||
}
|
||||
|
||||
request->SetContent(std::move(data), true);
|
||||
}
|
||||
|
||||
} // namespace webcc
|
@ -1,144 +0,0 @@
|
||||
#ifndef WEBCC_HTTP_REQUEST_BUILDER_H_
|
||||
#define WEBCC_HTTP_REQUEST_BUILDER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/http_request.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpRequestBuilder {
|
||||
public:
|
||||
explicit HttpRequestBuilder(const std::string& method = "")
|
||||
: method_(method) {
|
||||
}
|
||||
|
||||
~HttpRequestBuilder() = default;
|
||||
|
||||
HttpRequestBuilder(const HttpRequestBuilder&) = delete;
|
||||
HttpRequestBuilder& operator=(const HttpRequestBuilder&) = delete;
|
||||
|
||||
// Build the request.
|
||||
HttpRequestPtr Build();
|
||||
|
||||
HttpRequestPtr operator()() {
|
||||
return Build();
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Get() { return Method(http::methods::kGet); }
|
||||
HttpRequestBuilder& Head() { return Method(http::methods::kHead); }
|
||||
HttpRequestBuilder& Post() { return Method(http::methods::kPost); }
|
||||
HttpRequestBuilder& Put() { return Method(http::methods::kPut); }
|
||||
HttpRequestBuilder& Delete() { return Method(http::methods::kDelete); }
|
||||
HttpRequestBuilder& Patch() { return Method(http::methods::kPatch); }
|
||||
|
||||
// NOTE:
|
||||
// The naming convention doesn't follow Google C++ Style for
|
||||
// consistency and simplicity.
|
||||
|
||||
HttpRequestBuilder& Method(const std::string& method) {
|
||||
method_ = method;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Url(const std::string& url) {
|
||||
url_ = url;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Query(const std::string& key,
|
||||
const std::string& value) {
|
||||
parameters_.push_back(key);
|
||||
parameters_.push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Data(const std::string& data) {
|
||||
data_ = data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Data(std::string&& data) {
|
||||
data_ = std::move(data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Json(bool json = true) {
|
||||
json_ = json;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Upload a file.
|
||||
HttpRequestBuilder& File(const std::string& name, const Path& path,
|
||||
const std::string& mime_type = "");
|
||||
|
||||
HttpRequestBuilder& Form(FormPart&& part) {
|
||||
form_parts_.push_back(std::move(part));
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Form(const std::string& name, std::string&& data,
|
||||
const std::string& mime_type = "");
|
||||
|
||||
HttpRequestBuilder& Gzip(bool gzip = true) {
|
||||
gzip_ = gzip;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Header(const std::string& key,
|
||||
const std::string& value) {
|
||||
headers_.push_back(key);
|
||||
headers_.push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& KeepAlive(bool keep_alive = true) {
|
||||
keep_alive_ = keep_alive;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HttpRequestBuilder& Auth(const std::string& type,
|
||||
const std::string& credentials);
|
||||
|
||||
HttpRequestBuilder& AuthBasic(const std::string& login,
|
||||
const std::string& password);
|
||||
|
||||
HttpRequestBuilder& AuthToken(const std::string& token);
|
||||
|
||||
private:
|
||||
void SetContent(HttpRequestPtr request, std::string&& data);
|
||||
|
||||
private:
|
||||
std::string method_;
|
||||
|
||||
std::string url_;
|
||||
|
||||
// URL query parameters.
|
||||
std::vector<std::string> parameters_;
|
||||
|
||||
// Data to send in the body of the request.
|
||||
std::string data_;
|
||||
|
||||
// Is the data to send a JSON string?
|
||||
bool json_ = false;
|
||||
|
||||
// Files to upload for a POST request.
|
||||
std::vector<FormPart> form_parts_;
|
||||
|
||||
// Compress the request content.
|
||||
// NOTE: Most servers don't support compressed requests.
|
||||
// Even the requests module from Python doesn't have a built-in support.
|
||||
// See: https://github.com/kennethreitz/requests/issues/1753
|
||||
bool gzip_ = false;
|
||||
|
||||
// Additional request headers.
|
||||
std::vector<std::string> headers_;
|
||||
|
||||
// Persistent connection.
|
||||
bool keep_alive_ = true;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_REQUEST_BUILDER_H_
|
@ -1,48 +0,0 @@
|
||||
#ifndef WEBCC_HTTP_REQUEST_HANDLER_H_
|
||||
#define WEBCC_HTTP_REQUEST_HANDLER_H_
|
||||
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/http_connection.h"
|
||||
#include "webcc/queue.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpRequest;
|
||||
class HttpResponse;
|
||||
|
||||
// The common handler for all incoming requests.
|
||||
class HttpRequestHandler {
|
||||
public:
|
||||
HttpRequestHandler() = default;
|
||||
virtual ~HttpRequestHandler() = default;
|
||||
|
||||
HttpRequestHandler(const HttpRequestHandler&) = delete;
|
||||
HttpRequestHandler& operator=(const HttpRequestHandler&) = delete;
|
||||
|
||||
// Put the connection into the queue.
|
||||
void Enqueue(HttpConnectionPtr connection);
|
||||
|
||||
// Start worker threads.
|
||||
void Start(std::size_t count);
|
||||
|
||||
// Clear pending connections from the queue and stop worker threads.
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void WorkerRoutine();
|
||||
|
||||
// Called by the worker routine.
|
||||
virtual void HandleConnection(HttpConnectionPtr connection) = 0;
|
||||
|
||||
private:
|
||||
Queue<HttpConnectionPtr> queue_;
|
||||
|
||||
std::vector<std::thread> workers_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_REQUEST_HANDLER_H_
|
@ -1,39 +0,0 @@
|
||||
#ifndef WEBCC_HTTP_RESPONSE_H_
|
||||
#define WEBCC_HTTP_RESPONSE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "webcc/http_message.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpResponse;
|
||||
typedef std::shared_ptr<HttpResponse> HttpResponsePtr;
|
||||
|
||||
class HttpResponse : public HttpMessage {
|
||||
public:
|
||||
explicit HttpResponse(http::Status status = http::Status::kOK)
|
||||
: status_(status) {
|
||||
}
|
||||
|
||||
~HttpResponse() override = default;
|
||||
|
||||
int status() const {
|
||||
return status_;
|
||||
}
|
||||
|
||||
void set_status(int status) {
|
||||
status_ = status;
|
||||
}
|
||||
|
||||
// Set start line according to status code.
|
||||
void Prepare() final;
|
||||
|
||||
private:
|
||||
int status_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_RESPONSE_H_
|
@ -1,30 +0,0 @@
|
||||
#ifndef WEBCC_HTTP_RESPONSE_PARSER_H_
|
||||
#define WEBCC_HTTP_RESPONSE_PARSER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webcc/http_parser.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class HttpResponse;
|
||||
|
||||
class HttpResponseParser : public HttpParser {
|
||||
public:
|
||||
explicit HttpResponseParser(HttpResponse* response = nullptr);
|
||||
|
||||
~HttpResponseParser() override = default;
|
||||
|
||||
void Init(HttpResponse* response);
|
||||
|
||||
private:
|
||||
// Parse HTTP start line; E.g., "HTTP/1.1 200 OK".
|
||||
bool ParseStartLine(const std::string& line) final;
|
||||
|
||||
// The result response message.
|
||||
HttpResponse* response_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_HTTP_RESPONSE_PARSER_H_
|
@ -0,0 +1,91 @@
|
||||
#include "webcc/request_builder.h"
|
||||
|
||||
#include "webcc/base64.h"
|
||||
#include "webcc/logger.h"
|
||||
#include "webcc/utility.h"
|
||||
#include "webcc/zlib_wrapper.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
RequestPtr RequestBuilder::Build() {
|
||||
assert(parameters_.size() % 2 == 0);
|
||||
assert(headers_.size() % 2 == 0);
|
||||
|
||||
auto request = std::make_shared<Request>(method_, url_);
|
||||
|
||||
for (std::size_t i = 1; i < parameters_.size(); i += 2) {
|
||||
request->AddQuery(parameters_[i - 1], parameters_[i]);
|
||||
}
|
||||
|
||||
for (std::size_t i = 1; i < headers_.size(); i += 2) {
|
||||
request->SetHeader(std::move(headers_[i - 1]), std::move(headers_[i]));
|
||||
}
|
||||
|
||||
// No keep-alive?
|
||||
if (!keep_alive_) {
|
||||
request->SetHeader(headers::kConnection, "Close");
|
||||
}
|
||||
|
||||
if (!data_.empty()) {
|
||||
SetContent(request, std::move(data_));
|
||||
|
||||
// TODO: Request-level charset.
|
||||
if (json_) {
|
||||
request->SetContentType(media_types::kApplicationJson, "");
|
||||
}
|
||||
} else if (!form_parts_.empty()) {
|
||||
request->set_form_parts(std::move(form_parts_));
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::File(const std::string& name,
|
||||
const Path& path,
|
||||
const std::string& media_type) {
|
||||
assert(!name.empty());
|
||||
form_parts_.push_back(FormPart{ name, path, media_type });
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::Form(const std::string& name,
|
||||
std::string&& data,
|
||||
const std::string& media_type) {
|
||||
assert(!name.empty());
|
||||
form_parts_.push_back(FormPart{ name, std::move(data), media_type });
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::Auth(const std::string& type,
|
||||
const std::string& credentials) {
|
||||
headers_.push_back(headers::kAuthorization);
|
||||
headers_.push_back(type + " " + credentials);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::AuthBasic(const std::string& login,
|
||||
const std::string& password) {
|
||||
auto credentials = Base64Encode(login + ":" + password);
|
||||
return Auth("Basic", credentials);
|
||||
}
|
||||
|
||||
RequestBuilder& RequestBuilder::AuthToken(const std::string& token) {
|
||||
return Auth("Token", token);
|
||||
}
|
||||
|
||||
void RequestBuilder::SetContent(RequestPtr request, std::string&& data) {
|
||||
if (gzip_ && data.size() > kGzipThreshold) {
|
||||
std::string compressed;
|
||||
if (Compress(data, &compressed)) {
|
||||
request->SetContent(std::move(compressed), true);
|
||||
request->SetHeader(headers::kContentEncoding, "gzip");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_WARN("Cannot compress the content data!");
|
||||
}
|
||||
|
||||
request->SetContent(std::move(data), true);
|
||||
}
|
||||
|
||||
} // namespace webcc
|
@ -0,0 +1,141 @@
|
||||
#ifndef WEBCC_REQUEST_BUILDER_H_
|
||||
#define WEBCC_REQUEST_BUILDER_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/request.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class RequestBuilder {
|
||||
public:
|
||||
explicit RequestBuilder(const std::string& method = "")
|
||||
: method_(method) {
|
||||
}
|
||||
|
||||
~RequestBuilder() = default;
|
||||
|
||||
RequestBuilder(const RequestBuilder&) = delete;
|
||||
RequestBuilder& operator=(const RequestBuilder&) = delete;
|
||||
|
||||
// Build the request.
|
||||
RequestPtr Build();
|
||||
|
||||
RequestPtr operator()() {
|
||||
return Build();
|
||||
}
|
||||
|
||||
RequestBuilder& Get() { return Method(methods::kGet); }
|
||||
RequestBuilder& Head() { return Method(methods::kHead); }
|
||||
RequestBuilder& Post() { return Method(methods::kPost); }
|
||||
RequestBuilder& Put() { return Method(methods::kPut); }
|
||||
RequestBuilder& Delete() { return Method(methods::kDelete); }
|
||||
RequestBuilder& Patch() { return Method(methods::kPatch); }
|
||||
|
||||
// NOTE:
|
||||
// The naming convention doesn't follow Google C++ Style for
|
||||
// consistency and simplicity.
|
||||
|
||||
RequestBuilder& Method(const std::string& method) {
|
||||
method_ = method;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Url(const std::string& url) {
|
||||
url_ = url;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Query(const std::string& key, const std::string& value) {
|
||||
parameters_.push_back(key);
|
||||
parameters_.push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Data(const std::string& data) {
|
||||
data_ = data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Data(std::string&& data) {
|
||||
data_ = std::move(data);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Json(bool json = true) {
|
||||
json_ = json;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Upload a file.
|
||||
RequestBuilder& File(const std::string& name, const Path& path,
|
||||
const std::string& media_type = "");
|
||||
|
||||
RequestBuilder& Form(FormPart&& part) {
|
||||
form_parts_.push_back(std::move(part));
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Form(const std::string& name, std::string&& data,
|
||||
const std::string& media_type = "");
|
||||
|
||||
RequestBuilder& Gzip(bool gzip = true) {
|
||||
gzip_ = gzip;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Header(const std::string& key, const std::string& value) {
|
||||
headers_.push_back(key);
|
||||
headers_.push_back(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& KeepAlive(bool keep_alive = true) {
|
||||
keep_alive_ = keep_alive;
|
||||
return *this;
|
||||
}
|
||||
|
||||
RequestBuilder& Auth(const std::string& type, const std::string& credentials);
|
||||
|
||||
RequestBuilder& AuthBasic(const std::string& login,
|
||||
const std::string& password);
|
||||
|
||||
RequestBuilder& AuthToken(const std::string& token);
|
||||
|
||||
private:
|
||||
void SetContent(RequestPtr request, std::string&& data);
|
||||
|
||||
private:
|
||||
std::string method_;
|
||||
|
||||
std::string url_;
|
||||
|
||||
// URL query parameters.
|
||||
std::vector<std::string> parameters_;
|
||||
|
||||
// Data to send in the body of the request.
|
||||
std::string data_;
|
||||
|
||||
// Is the data to send a JSON string?
|
||||
bool json_ = false;
|
||||
|
||||
// Files to upload for a POST request.
|
||||
std::vector<FormPart> form_parts_;
|
||||
|
||||
// Compress the request content.
|
||||
// NOTE: Most servers don't support compressed requests.
|
||||
// Even the requests module from Python doesn't have a built-in support.
|
||||
// See: https://github.com/kennethreitz/requests/issues/1753
|
||||
bool gzip_ = false;
|
||||
|
||||
// Additional request headers.
|
||||
std::vector<std::string> headers_;
|
||||
|
||||
// Persistent connection.
|
||||
bool keep_alive_ = true;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_REQUEST_BUILDER_H_
|
@ -0,0 +1,48 @@
|
||||
#ifndef WEBCC_REQUEST_HANDLER_H_
|
||||
#define WEBCC_REQUEST_HANDLER_H_
|
||||
|
||||
#include <list>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include "webcc/connection.h"
|
||||
#include "webcc/queue.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class Request;
|
||||
class Response;
|
||||
|
||||
// The common handler for all incoming requests.
|
||||
class RequestHandler {
|
||||
public:
|
||||
RequestHandler() = default;
|
||||
virtual ~RequestHandler() = default;
|
||||
|
||||
RequestHandler(const RequestHandler&) = delete;
|
||||
RequestHandler& operator=(const RequestHandler&) = delete;
|
||||
|
||||
// Put the connection into the queue.
|
||||
void Enqueue(ConnectionPtr connection);
|
||||
|
||||
// Start worker threads.
|
||||
void Start(std::size_t count);
|
||||
|
||||
// Clear pending connections from the queue and stop worker threads.
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
void WorkerRoutine();
|
||||
|
||||
// Called by the worker routine.
|
||||
virtual void HandleConnection(ConnectionPtr connection) = 0;
|
||||
|
||||
private:
|
||||
Queue<ConnectionPtr> queue_;
|
||||
|
||||
std::vector<std::thread> workers_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_REQUEST_HANDLER_H_
|
@ -0,0 +1,39 @@
|
||||
#ifndef WEBCC_RESPONSE_H_
|
||||
#define WEBCC_RESPONSE_H_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "webcc/message.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class Response;
|
||||
using ResponsePtr = std::shared_ptr<Response>;
|
||||
|
||||
class Response : public Message {
|
||||
public:
|
||||
explicit Response(Status status = Status::kOK)
|
||||
: status_(status) {
|
||||
}
|
||||
|
||||
~Response() override = default;
|
||||
|
||||
int status() const {
|
||||
return status_;
|
||||
}
|
||||
|
||||
void set_status(int status) {
|
||||
status_ = status;
|
||||
}
|
||||
|
||||
// Set start line according to status code.
|
||||
void Prepare() final;
|
||||
|
||||
private:
|
||||
int status_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_RESPONSE_H_
|
@ -1,22 +1,22 @@
|
||||
#include "webcc/http_response_parser.h"
|
||||
#include "webcc/response_parser.h"
|
||||
|
||||
#include "boost/algorithm/string.hpp"
|
||||
|
||||
#include "webcc/http_response.h"
|
||||
#include "webcc/response.h"
|
||||
#include "webcc/logger.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
HttpResponseParser::HttpResponseParser(HttpResponse* response)
|
||||
: HttpParser(response), response_(response) {
|
||||
ResponseParser::ResponseParser(Response* response)
|
||||
: Parser(response), response_(response) {
|
||||
}
|
||||
|
||||
void HttpResponseParser::Init(HttpResponse* response) {
|
||||
HttpParser::Init(response);
|
||||
void ResponseParser::Init(Response* response) {
|
||||
Parser::Init(response);
|
||||
response_ = response;
|
||||
}
|
||||
|
||||
bool HttpResponseParser::ParseStartLine(const std::string& line) {
|
||||
bool ResponseParser::ParseStartLine(const std::string& line) {
|
||||
std::vector<std::string> parts;
|
||||
boost::split(parts, line, boost::is_any_of(" "), boost::token_compress_on);
|
||||
|
@ -0,0 +1,30 @@
|
||||
#ifndef WEBCC_RESPONSE_PARSER_H_
|
||||
#define WEBCC_RESPONSE_PARSER_H_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "webcc/parser.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
class Response;
|
||||
|
||||
class ResponseParser : public Parser {
|
||||
public:
|
||||
explicit ResponseParser(Response* response = nullptr);
|
||||
|
||||
~ResponseParser() override = default;
|
||||
|
||||
void Init(Response* response);
|
||||
|
||||
private:
|
||||
// Parse HTTP start line; E.g., "HTTP/1.1 200 OK".
|
||||
bool ParseStartLine(const std::string& line) final;
|
||||
|
||||
// The result response message.
|
||||
Response* response_;
|
||||
};
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_RESPONSE_PARSER_H_
|
Loading…
Reference in New Issue