diff --git a/CMakeLists.txt b/CMakeLists.txt index 04337c1..88b430b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,10 @@ add_executable(Application src/main.cpp src/request_handler.cpp ) +add_custom_target(copy_frontend ALL + COMMAND ${CMAKE_COMMAND} -E copy_directory ${PROJECT_SOURCE_DIR}/frontend ${CMAKE_BINARY_DIR}/frontend +) + find_package(Boost REQUIRED filesystem system) if(Boost_FOUND) diff --git a/frontend/index.html b/frontend/index.html index d4e3922..673756a 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -24,6 +24,7 @@ flex-direction: column; align-items: center; justify-content: center; + background-color: transparent; } @@ -38,6 +39,7 @@
+
diff --git a/frontend/index.js b/frontend/index.js index d3a85fd..3c312be 100644 --- a/frontend/index.js +++ b/frontend/index.js @@ -17,18 +17,26 @@ document.getElementById("urlInput").addEventListener("input", function() { document.getElementById("shortenButton").addEventListener("click", async function() { const urlInput = document.getElementById("urlInput").value; const outputContainer = document.getElementById("output-container"); + const errorContainer = document.getElementById("error-container"); if (urlInput) { // const shortenedUrl = urlInput + "-short"; // only for testing - const shortenedUrl = await fetch("0.0.0.0:8080/", { + const response = await fetch("/", { method: "POST", headers: { "Content-Type": "text/plain", }, body: urlInput, }); - - outputContainer.innerHTML = `

Shortened URL: ${shortenedUrl}

`; + if (response.ok){ + const shortenedUrl = await response.text(); + outputContainer.innerHTML = `

Shortened URL: ${shortenedUrl}

`; + errorContainer.innerHTML = ""; + }else{ + const error = await response.text(); + errorContainer.innerHTML = `

Something went wrong: ${error}

`; + outputContainer.innerHTML = ""; + } } }); diff --git a/includes/http_connection.hpp b/includes/http_connection.hpp index ab53345..493c11c 100644 --- a/includes/http_connection.hpp +++ b/includes/http_connection.hpp @@ -8,6 +8,7 @@ #include #include #include +#include using namespace std; using namespace boost::asio; @@ -25,7 +26,7 @@ private: ip::tcp::socket socket_; boost::beast::flat_buffer buffer_; http::request request_; - http::response response_; + variant, http::response> response_; RequestHandler request_handler_; void read(); diff --git a/includes/request_handler.hpp b/includes/request_handler.hpp index 2d14176..5382f6f 100644 --- a/includes/request_handler.hpp +++ b/includes/request_handler.hpp @@ -4,14 +4,20 @@ #include #include #include +#include using namespace boost::beast; class RequestHandler { public: - http::response handle(const http::request& request); +std::variant< + http::response, + http::response + > handle(const http::request& request); private: + http::response BadRequest(const std::string& why); + http::response handle_file_request(const std::string& filename, boost::system::error_code& ec); }; #endif \ No newline at end of file diff --git a/src/http_connection.cpp b/src/http_connection.cpp index 7741622..6f1a2fe 100644 --- a/src/http_connection.cpp +++ b/src/http_connection.cpp @@ -36,9 +36,10 @@ void HttpConnection::read() { void HttpConnection::write() { auto self = shared_from_this(); - http::async_write(socket_, response_, + std::visit( + [this, self](auto& response) { + http::async_write(socket_, response, [self](boost::beast::error_code error_code, size_t bytes_transferred) { - cout << "Sending response:\n" << self->response_ << endl; if (!error_code) { auto error_code_socket = self->socket_.shutdown(ip::tcp::socket::shutdown_send, error_code); if (error_code_socket) { @@ -52,4 +53,6 @@ void HttpConnection::write() { } } }); + + }, response_); } \ No newline at end of file diff --git a/src/request_handler.cpp b/src/request_handler.cpp index f137959..f4b47a4 100644 --- a/src/request_handler.cpp +++ b/src/request_handler.cpp @@ -5,37 +5,32 @@ #include #include #include +#include "request_handler.hpp" -http::response BadRequest(const std::string& why) { +http::response RequestHandler::BadRequest(const std::string& why) { http::response response; response.result(http::status::bad_request); response.set(http::field::server, "Beast"); response.set(http::field::content_type, "text/html"); response.body() = why; + response.keep_alive(false); response.prepare_payload(); return response; } -http::response RequestHandler::handle(const http::request& request) { - string_view target = request.target(); +std::variant< + http::response, + http::response + > + RequestHandler::handle(const http::request& request) { + std::string target = request.target(); http::verb method = request.method(); - if (target == "/") { - if(method == http::verb::get) { - //case 1: "/" -> serve angular frontend or static frontend what ever - http::response response; - response.result(http::status::ok); - response.version(request.version()); - response.set(http::field::server, "Beast"); - response.set(http::field::content_type, "text/html"); - //todo: load angular application / plain html & js - response.body() = "

TEST

"; - - response.prepare_payload(); - return response; + if(method == http::verb::post){ + if(target != "/") { + return BadRequest("Cannot post to anything other than /"); } - else if (method == http::verb::post) { - if(request.find(http::field::content_type) == request.end()) { + if(request.find(http::field::content_type) == request.end()) { return BadRequest("Content-Type header is required for POST requests"); } auto content_type = request[http::field::content_type]; @@ -53,11 +48,27 @@ http::response RequestHandler::handle(const http::request response; + response.result(http::status::created); + response.set(http::field::server, "Beast"); + response.set(http::field::content_type, "text/plain"); + response.body() = "127.0.0.1:8080/asdf"; + response.keep_alive(false); + response.prepare_payload(); + return response; + } else if (method == http::verb::get) { + if(target == "/"){ + target = "/index.html"; } - }else { - if(method == http::verb::get){ + if(target == "/index.html" || target == "/index.js") { + error_code ec; + http::response response = handle_file_request("frontend" + target, ec); + if(ec) { + return BadRequest("Error reading file"); + }else { + return response; + } + } else { http::response response; std::string short_url = target.substr(1); @@ -68,15 +79,27 @@ http::response RequestHandler::handle(const http::request redirect to expanded url - //case 3: neither -> redirect to 404 + } + return BadRequest("No rule matched."); +} +http::response RequestHandler::handle_file_request(const std::string& path, error_code &ec) { + http::file_body::value_type file; + file.open(path.c_str(), file_mode::read, ec); + http::response response; + if(!ec){ + response.result(http::status::ok); + response.set(http::field::server, "Beast"); + response.set(http::field::content_type, "text/html"); + response.body() = std::move(file); + response.keep_alive(false); + response.prepare_payload(); + }; + return response; + } \ No newline at end of file