выкинул зависимость boost::url

This commit is contained in:
Vladislav Ostapov 2024-10-30 11:05:27 +03:00
parent 5c348ace87
commit 839198820e
6 changed files with 69 additions and 25 deletions

View File

@ -36,7 +36,7 @@ add_executable(terminal-web-server
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)
target_link_libraries(terminal-web-server ${Boost_LIBRARIES} ${OPENSSL_LIBRARIES})
target_include_directories(terminal-web-server PRIVATE ${Boost_INCLUDE_DIR} ${OPENSSL_INCLUDE_DIR})

View File

@ -13,7 +13,7 @@ namespace http::server {
}
void Connection::start() {
do_read();
doRead();
}
void Connection::stop() {
@ -22,11 +22,14 @@ namespace http::server {
Connection::~Connection() = default;
void Connection::do_read() {
void Connection::doRead() {
request_parser_.reset();
request_.headers.clear();
request_.method.clear();
request_.uri.clear();
request_.queryUri.clear();
if (request_.url != nullptr) {
request_.url.reset(nullptr);
}
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) {
@ -37,12 +40,12 @@ namespace http::server {
if (result == RequestParser::good) {
request_handler_(request_, reply_);
do_write();
doWrite();
} else if (result == RequestParser::bad) {
stockReply(bad_request, reply_);
do_write();
doWrite();
} else {
do_read();
doRead();
}
} else {
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});
if (!reply_.content.empty()) {
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"});
}
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());
async_write(socket_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {
if (!ec) {
// keep alive Connection
do_read();
doRead();
} else {
connection_manager_.stop(shared_from_this());
}
@ -97,7 +100,7 @@ namespace http::server {
request_parser_.reset();
request_.headers.clear();
request_.method.clear();
request_.uri.clear();
request_.queryUri.clear();
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) {
@ -130,7 +133,7 @@ namespace http::server {
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());
async_write(stream_, reply_.to_buffers(), [this, self](boost::system::error_code ec, std::size_t) {

View File

@ -47,10 +47,10 @@ namespace http::server {
~Connection() override;
private:
/// Perform an asynchronous read operation.
void do_read();
void doRead();
/// Perform an asynchronous write operation.
void do_write();
void doWrite();
/// Socket for the Connection.
boost::asio::ip::tcp::socket socket_;

View File

@ -3,14 +3,26 @@
#include <string>
#include <vector>
#include <map>
#include "header.hpp"
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.
struct Request {
std::string method;
std::string uri;
std::string queryUri;
std::unique_ptr<Url> url;
bool is_keep_alive;
int http_version_major;
int http_version_minor;

View File

@ -1,8 +1,38 @@
#include "request_parser.hpp"
#include <sstream>
#include "request.hpp"
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()
: state_(method_start) {
}
@ -38,7 +68,7 @@ namespace http::server {
} else if (is_ctl(input)) {
return bad;
} else {
req.uri.push_back(input);
req.queryUri.push_back(input);
return indeterminate;
}
case http_version_h:
@ -131,7 +161,7 @@ namespace http::server {
} else if (!is_char(input) || is_ctl(input) || is_tspecial(input)) {
return bad;
} else {
req.headers.push_back(header());
req.headers.emplace_back();
req.headers.back().name.push_back(input);
state_ = header_name;
return indeterminate;
@ -184,7 +214,11 @@ namespace http::server {
return bad;
}
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:
return bad;
}

View File

@ -1,7 +1,6 @@
#include "server.hpp"
#include <utility>
#include <boost/beast/core/basic_stream.hpp>
#include <boost/url/url_view.hpp>
namespace http::server {
@ -113,12 +112,8 @@ namespace http::server {
}
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 "..".
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);
return;
}
@ -128,7 +123,7 @@ namespace http::server {
rep.content.clear();
for (auto& res: resources) {
if (res->path != path) {
if (res->path != req.url->path) {
continue;
}
res->handle(req, rep);