выкинул зависимость boost::url
This commit is contained in:
parent
5c348ace87
commit
839198820e
@ -36,7 +36,7 @@ add_executable(terminal-web-server
|
|||||||
src/server/resource.h
|
src/server/resource.h
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Boost 1.53.0 COMPONENTS system thread filesystem url log log_setup REQUIRED)
|
find_package(Boost 1.53.0 COMPONENTS system thread filesystem log log_setup REQUIRED)
|
||||||
find_package(OpenSSL REQUIRED)
|
find_package(OpenSSL REQUIRED)
|
||||||
target_link_libraries(terminal-web-server ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES})
|
target_link_libraries(terminal-web-server ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES})
|
||||||
target_include_directories(terminal-web-server PRIVATE ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
|
target_include_directories(terminal-web-server PRIVATE ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})
|
||||||
|
@ -13,7 +13,7 @@ namespace http::server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Connection::start() {
|
void Connection::start() {
|
||||||
do_read();
|
doRead();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::stop() {
|
void Connection::stop() {
|
||||||
@ -22,11 +22,14 @@ namespace http::server {
|
|||||||
|
|
||||||
Connection::~Connection() = default;
|
Connection::~Connection() = default;
|
||||||
|
|
||||||
void Connection::do_read() {
|
void Connection::doRead() {
|
||||||
request_parser_.reset();
|
request_parser_.reset();
|
||||||
request_.headers.clear();
|
request_.headers.clear();
|
||||||
request_.method.clear();
|
request_.method.clear();
|
||||||
request_.uri.clear();
|
request_.queryUri.clear();
|
||||||
|
if (request_.url != nullptr) {
|
||||||
|
request_.url.reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
socket_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
socket_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
||||||
@ -37,12 +40,12 @@ namespace http::server {
|
|||||||
|
|
||||||
if (result == RequestParser::good) {
|
if (result == RequestParser::good) {
|
||||||
request_handler_(request_, reply_);
|
request_handler_(request_, reply_);
|
||||||
do_write();
|
doWrite();
|
||||||
} else if (result == RequestParser::bad) {
|
} else if (result == RequestParser::bad) {
|
||||||
stockReply(bad_request, reply_);
|
stockReply(bad_request, reply_);
|
||||||
do_write();
|
doWrite();
|
||||||
} else {
|
} else {
|
||||||
do_read();
|
doRead();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
connection_manager_.stop(shared_from_this());
|
connection_manager_.stop(shared_from_this());
|
||||||
@ -50,7 +53,7 @@ namespace http::server {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Connection::do_write() {
|
void Connection::doWrite() {
|
||||||
reply_.headers.push_back({.name = "Server", .value = SERVER_HEADER_VALUE});
|
reply_.headers.push_back({.name = "Server", .value = SERVER_HEADER_VALUE});
|
||||||
if (!reply_.content.empty()) {
|
if (!reply_.content.empty()) {
|
||||||
reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())});
|
reply_.headers.push_back({.name = "Content-Length", .value = std::to_string(reply_.content.size())});
|
||||||
@ -59,13 +62,13 @@ namespace http::server {
|
|||||||
reply_.headers.push_back({.name = "Connection", .value = "keep-alive"});
|
reply_.headers.push_back({.name = "Connection", .value = "keep-alive"});
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "HTTP query " << reply_.status << " " << request_.method << " " << request_.uri;
|
BOOST_LOG_TRIVIAL(info) << "HTTP query " << reply_.status << " " << request_.method << " " << request_.queryUri;
|
||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
||||||
if (!ec) {
|
if (!ec) {
|
||||||
// keep alive Connection
|
// keep alive Connection
|
||||||
do_read();
|
doRead();
|
||||||
} else {
|
} else {
|
||||||
connection_manager_.stop(shared_from_this());
|
connection_manager_.stop(shared_from_this());
|
||||||
}
|
}
|
||||||
@ -97,7 +100,7 @@ namespace http::server {
|
|||||||
request_parser_.reset();
|
request_parser_.reset();
|
||||||
request_.headers.clear();
|
request_.headers.clear();
|
||||||
request_.method.clear();
|
request_.method.clear();
|
||||||
request_.uri.clear();
|
request_.queryUri.clear();
|
||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
stream_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
stream_.async_read_some(boost::asio::buffer(buffer_), [this, self](boost::system::error_code ec, std::size_t bytes_transferred) {
|
||||||
@ -130,7 +133,7 @@ namespace http::server {
|
|||||||
reply_.headers.push_back({.name = "Connection", .value = "keep-alive"});
|
reply_.headers.push_back({.name = "Connection", .value = "keep-alive"});
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "HTTP query " << reply_.status << " " << request_.method << " " << request_.uri;
|
BOOST_LOG_TRIVIAL(info) << "HTTPS query " << reply_.status << " " << request_.method << " " << request_.queryUri;
|
||||||
|
|
||||||
auto self(shared_from_this());
|
auto self(shared_from_this());
|
||||||
async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
|
||||||
|
@ -47,10 +47,10 @@ namespace http::server {
|
|||||||
~Connection() override;
|
~Connection() override;
|
||||||
private:
|
private:
|
||||||
/// Perform an asynchronous read operation.
|
/// Perform an asynchronous read operation.
|
||||||
void do_read();
|
void doRead();
|
||||||
|
|
||||||
/// Perform an asynchronous write operation.
|
/// Perform an asynchronous write operation.
|
||||||
void do_write();
|
void doWrite();
|
||||||
|
|
||||||
/// Socket for the Connection.
|
/// Socket for the Connection.
|
||||||
boost::asio::ip::tcp::socket socket_;
|
boost::asio::ip::tcp::socket socket_;
|
||||||
|
@ -3,14 +3,26 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <map>
|
||||||
#include "header.hpp"
|
#include "header.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace http::server {
|
namespace http::server {
|
||||||
|
class Url {
|
||||||
|
public:
|
||||||
|
explicit Url(const std::string& url);
|
||||||
|
|
||||||
|
std::string path;
|
||||||
|
std::map<std::string, std::string> params;
|
||||||
|
|
||||||
|
~Url();
|
||||||
|
};
|
||||||
|
|
||||||
/// A request received from a client.
|
/// A request received from a client.
|
||||||
struct Request {
|
struct Request {
|
||||||
std::string method;
|
std::string method;
|
||||||
std::string uri;
|
std::string queryUri;
|
||||||
|
std::unique_ptr<Url> url;
|
||||||
bool is_keep_alive;
|
bool is_keep_alive;
|
||||||
int http_version_major;
|
int http_version_major;
|
||||||
int http_version_minor;
|
int http_version_minor;
|
||||||
|
@ -1,8 +1,38 @@
|
|||||||
#include "request_parser.hpp"
|
#include "request_parser.hpp"
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
#include "request.hpp"
|
#include "request.hpp"
|
||||||
|
|
||||||
|
|
||||||
namespace http::server {
|
namespace http::server {
|
||||||
|
static void parseParams(Url& u, const std::string& query) {
|
||||||
|
std::istringstream iss(query);
|
||||||
|
std::string param;
|
||||||
|
while (std::getline(iss, param, '&')) {
|
||||||
|
size_t equal_pos = param.find('=');
|
||||||
|
if (equal_pos != std::string::npos) {
|
||||||
|
const std::string key = param.substr(0, equal_pos);
|
||||||
|
const std::string value = param.substr(equal_pos + 1);
|
||||||
|
u.params[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Url::Url(const std::string &url) {
|
||||||
|
size_t question_mark_pos = url.find('?');
|
||||||
|
if (question_mark_pos != std::string::npos) {
|
||||||
|
path = url.substr(0, question_mark_pos);
|
||||||
|
const std::string query = url.substr(question_mark_pos + 1);
|
||||||
|
parseParams(*this, query);
|
||||||
|
} else {
|
||||||
|
path = url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Url::~Url() = default;
|
||||||
|
|
||||||
|
|
||||||
RequestParser::RequestParser()
|
RequestParser::RequestParser()
|
||||||
: state_(method_start) {
|
: state_(method_start) {
|
||||||
}
|
}
|
||||||
@ -38,7 +68,7 @@ namespace http::server {
|
|||||||
} else if (is_ctl(input)) {
|
} else if (is_ctl(input)) {
|
||||||
return bad;
|
return bad;
|
||||||
} else {
|
} else {
|
||||||
req.uri.push_back(input);
|
req.queryUri.push_back(input);
|
||||||
return indeterminate;
|
return indeterminate;
|
||||||
}
|
}
|
||||||
case http_version_h:
|
case http_version_h:
|
||||||
@ -131,7 +161,7 @@ namespace http::server {
|
|||||||
} else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
} else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
|
||||||
return bad;
|
return bad;
|
||||||
} else {
|
} else {
|
||||||
req.headers.push_back(header());
|
req.headers.emplace_back();
|
||||||
req.headers.back().name.push_back(input);
|
req.headers.back().name.push_back(input);
|
||||||
state_ = header_name;
|
state_ = header_name;
|
||||||
return indeterminate;
|
return indeterminate;
|
||||||
@ -184,7 +214,11 @@ namespace http::server {
|
|||||||
return bad;
|
return bad;
|
||||||
}
|
}
|
||||||
case expecting_newline_3:
|
case expecting_newline_3:
|
||||||
return (input == '\n') ? good : bad;
|
if (input == '\n') {
|
||||||
|
req.url = std::make_unique<Url>(req.queryUri);
|
||||||
|
return good;
|
||||||
|
}
|
||||||
|
return bad;
|
||||||
default:
|
default:
|
||||||
return bad;
|
return bad;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
#include "server.hpp"
|
#include "server.hpp"
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <boost/beast/core/basic_stream.hpp>
|
#include <boost/beast/core/basic_stream.hpp>
|
||||||
#include <boost/url/url_view.hpp>
|
|
||||||
|
|
||||||
|
|
||||||
namespace http::server {
|
namespace http::server {
|
||||||
@ -113,12 +112,8 @@ namespace http::server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Server::requestHandler(const Request &req, reply &rep) {
|
void Server::requestHandler(const Request &req, reply &rep) {
|
||||||
boost::urls::url_view url(req.uri);
|
|
||||||
|
|
||||||
const auto path = url.path();
|
|
||||||
|
|
||||||
// Request path must be absolute and not contain "..".
|
// Request path must be absolute and not contain "..".
|
||||||
if (path.empty() || path[0] != '/' || path.find("..") != std::string::npos) {
|
if (req.url->path.empty() || req.url->path[0] != '/' || req.url->path.find("..") != std::string::npos) {
|
||||||
stockReply(bad_request, rep);
|
stockReply(bad_request, rep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -128,7 +123,7 @@ namespace http::server {
|
|||||||
rep.content.clear();
|
rep.content.clear();
|
||||||
|
|
||||||
for (auto& res: resources) {
|
for (auto& res: resources) {
|
||||||
if (res->path != path) {
|
if (res->path != req.url->path) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
res->handle(req, rep);
|
res->handle(req, rep);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user