From 581b104e8598f3e0c0981fa4dabdf06877510bbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=90=D0=BD=D1=82=D0=BE=D0=BD?= Date: Sat, 19 Apr 2025 12:07:04 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=D1=8B=D0=BD=D0=B5=D1=81=D0=B5=D0=BD?= =?UTF-8?q?=D0=B0=20=D1=84=D1=83=D0=BD=D0=BA=D1=86=D0=B8=D1=8F=20HandleReq?= =?UTF-8?q?uest.h?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (cherry picked from commit a5542aba7c322dee98a7236b1a5dad70355d179d) --- CMakeLists.txt | 3 +- src/endpoints_handlers/HandleRequest.h | 82 ++++++++++++++++++++++ src/main.cpp | 94 +------------------------- 3 files changed, 86 insertions(+), 93 deletions(-) create mode 100644 src/endpoints_handlers/HandleRequest.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e5c280e..9da1f06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,8 @@ find_package(Boost REQUIRED) add_executable(App ./src/main.cpp ./src/helpers/helpers.h - ./src/helpers/helpers.cpp) + ./src/helpers/helpers.cpp + ./src/endpoints_handlers/HandleRequest.h) target_link_libraries(App PRIVATE Boost::boost) diff --git a/src/endpoints_handlers/HandleRequest.h b/src/endpoints_handlers/HandleRequest.h new file mode 100644 index 0000000..8c5d3de --- /dev/null +++ b/src/endpoints_handlers/HandleRequest.h @@ -0,0 +1,82 @@ +#include + +namespace uad { +template +void HandleRequest(boost::beast::string_view doc_root, + boost::beast::http::request> &&req, + Send &&send) { + auto const bad_request = [&req](beast::string_view why) { + boost::beast::http::response res{boost::beast::http::status::bad_request, + req.version()}; + res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(boost::beast::http::field::content_type, "text/html"); + res.keep_alive(req.keep_alive()); + res.body() = std::string(why); + res.prepare_payload(); + return res; + }; + + auto const not_found = [&req](beast::string_view target) { + boost::beast::http::response res{boost::beast::http::status::not_found, + req.version()}; + res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(boost::beast::http::field::content_type, "text/html"); + res.keep_alive(req.keep_alive()); + res.body() = "The resource '" + std::string(target) + "' was not found."; + res.prepare_payload(); + return res; + }; + + auto const server_error = [&req](beast::string_view what) { + boost::beast::http::response res{boost::beast::http::status::internal_server_error, + req.version()}; + res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(boost::beast::http::field::content_type, "text/html"); + res.keep_alive(req.keep_alive()); + res.body() = "An error occurred: '" + std::string(what) + "'"; + res.prepare_payload(); + return res; + }; + + if (req.method() != boost::beast::http::verb::get && req.method() != boost::beast::http::verb::head) + return send(bad_request("Unknown boost::beast::HTTP-method")); + + if (req.target().empty() || req.target()[0] != '/' || + req.target().find("..") != beast::string_view::npos) + return send(bad_request("Illegal request-target")); + + std::string path = PathCat(doc_root, req.target()); + if (req.target().back() == '/') + path.append("index.html"); + + beast::error_code ec; + boost::beast::http::file_body::value_type body; + body.open(path.c_str(), beast::file_mode::scan, ec); + + if (ec == beast::errc::no_such_file_or_directory) + return send(not_found(req.target())); + + if (ec) + return send(server_error(ec.message())); + + auto const size = body.size(); + + if (req.method() == boost::beast::http::verb::head) { + boost::beast::http::response res{boost::beast::http::status::ok, req.version()}; + res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(boost::beast::http::field::content_type, MimeType(path)); + res.content_length(size); + res.keep_alive(req.keep_alive()); + return send(std::move(res)); + } + + boost::beast::http::response res{ + std::piecewise_construct, std::make_tuple(std::move(body)), + std::make_tuple(boost::beast::http::status::ok, req.version())}; + res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING); + res.set(boost::beast::http::field::content_type, MimeType(path)); + res.content_length(size); + res.keep_alive(req.keep_alive()); + return send(std::move(res)); +} +} diff --git a/src/main.cpp b/src/main.cpp index 45fb3d8..467ff18 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -18,6 +18,7 @@ #include #include "./helpers/helpers.h" +#include "./endpoints_handlers/HandleRequest.h" namespace beast = boost::beast; namespace http = beast::http; @@ -26,97 +27,6 @@ namespace net = boost::asio; using tcp = boost::asio::ip::tcp; using namespace uad; -template -void handle_request(beast::string_view doc_root, - http::request> &&req, - Send &&send) { - // Returns a bad request response - auto const bad_request = [&req](beast::string_view why) { - http::response res{http::status::bad_request, - req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, "text/html"); - res.keep_alive(req.keep_alive()); - res.body() = std::string(why); - res.prepare_payload(); - return res; - }; - - // Returns a not found response - auto const not_found = [&req](beast::string_view target) { - http::response res{http::status::not_found, - req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, "text/html"); - res.keep_alive(req.keep_alive()); - res.body() = "The resource '" + std::string(target) + "' was not found."; - res.prepare_payload(); - return res; - }; - - // Returns a server error response - auto const server_error = [&req](beast::string_view what) { - http::response res{http::status::internal_server_error, - req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, "text/html"); - res.keep_alive(req.keep_alive()); - res.body() = "An error occurred: '" + std::string(what) + "'"; - res.prepare_payload(); - return res; - }; - - // Make sure we can handle the method - if (req.method() != http::verb::get && req.method() != http::verb::head) - return send(bad_request("Unknown HTTP-method")); - - // Request path must be absolute and not contain "..". - if (req.target().empty() || req.target()[0] != '/' || - req.target().find("..") != beast::string_view::npos) - return send(bad_request("Illegal request-target")); - - // Build the path to the requested file - std::string path = PathCat(doc_root, req.target()); - if (req.target().back() == '/') - path.append("index.html"); - - // Attempt to open the file - beast::error_code ec; - http::file_body::value_type body; - body.open(path.c_str(), beast::file_mode::scan, ec); - - // Handle the case where the file doesn't exist - if (ec == beast::errc::no_such_file_or_directory) - return send(not_found(req.target())); - - // Handle an unknown error - if (ec) - return send(server_error(ec.message())); - - // Cache the size since we need it after the move - auto const size = body.size(); - - // Respond to HEAD request - if (req.method() == http::verb::head) { - http::response res{http::status::ok, req.version()}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, MimeType(path)); - res.content_length(size); - res.keep_alive(req.keep_alive()); - return send(std::move(res)); - } - - // Respond to GET request - http::response res{ - std::piecewise_construct, std::make_tuple(std::move(body)), - std::make_tuple(http::status::ok, req.version())}; - res.set(http::field::server, BOOST_BEAST_VERSION_STRING); - res.set(http::field::content_type, MimeType(path)); - res.content_length(size); - res.keep_alive(req.keep_alive()); - return send(std::move(res)); -} - //------------------------------------------------------------------------------ // Report a failure @@ -334,7 +244,7 @@ private: } // Send the response - handle_request(*doc_root_, parser_->release(), queue_); + HandleRequest(*doc_root_, parser_->release(), queue_); // If we aren't at the queue limit, try to pipeline another request if (!queue_.is_full())