integrate files with serving (even though ugly)
This commit is contained in:
parent
63fd2b7cca
commit
897310fe28
7 changed files with 83 additions and 36 deletions
|
|
@ -15,6 +15,10 @@ add_executable(Application src/main.cpp
|
||||||
src/request_handler.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)
|
find_package(Boost REQUIRED filesystem system)
|
||||||
|
|
||||||
if(Boost_FOUND)
|
if(Boost_FOUND)
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
background-color: transparent;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
@ -38,6 +39,7 @@
|
||||||
<input type="button" id="shortenButton" value="Submit">
|
<input type="button" id="shortenButton" value="Submit">
|
||||||
</div>
|
</div>
|
||||||
<div id="output-container"></div>
|
<div id="output-container"></div>
|
||||||
|
<div id="error-container"></div>
|
||||||
</div>
|
</div>
|
||||||
<script src="index.js"></script>
|
<script src="index.js"></script>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
|
|
@ -17,18 +17,26 @@ document.getElementById("urlInput").addEventListener("input", function() {
|
||||||
document.getElementById("shortenButton").addEventListener("click", async function() {
|
document.getElementById("shortenButton").addEventListener("click", async function() {
|
||||||
const urlInput = document.getElementById("urlInput").value;
|
const urlInput = document.getElementById("urlInput").value;
|
||||||
const outputContainer = document.getElementById("output-container");
|
const outputContainer = document.getElementById("output-container");
|
||||||
|
const errorContainer = document.getElementById("error-container");
|
||||||
|
|
||||||
if (urlInput) {
|
if (urlInput) {
|
||||||
// const shortenedUrl = urlInput + "-short"; // only for testing
|
// const shortenedUrl = urlInput + "-short"; // only for testing
|
||||||
|
|
||||||
const shortenedUrl = await fetch("0.0.0.0:8080/", {
|
const response = await fetch("/", {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
headers: {
|
headers: {
|
||||||
"Content-Type": "text/plain",
|
"Content-Type": "text/plain",
|
||||||
},
|
},
|
||||||
body: urlInput,
|
body: urlInput,
|
||||||
});
|
});
|
||||||
|
if (response.ok){
|
||||||
outputContainer.innerHTML = `<p>Shortened URL: <a href="${shortenedUrl}" target="_blank">${shortenedUrl}</a></p>`;
|
const shortenedUrl = await response.text();
|
||||||
|
outputContainer.innerHTML = `<p>Shortened URL: <a href="${shortenedUrl}" target="_blank">${shortenedUrl}</a></p>`;
|
||||||
|
errorContainer.innerHTML = "";
|
||||||
|
}else{
|
||||||
|
const error = await response.text();
|
||||||
|
errorContainer.innerHTML = `<p>Something went wrong: ${error}</p>`;
|
||||||
|
outputContainer.innerHTML = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@
|
||||||
#include <boost/beast/http/string_body.hpp>
|
#include <boost/beast/http/string_body.hpp>
|
||||||
#include <boost/beast/http.hpp>
|
#include <boost/beast/http.hpp>
|
||||||
#include <boost/beast/core.hpp>
|
#include <boost/beast/core.hpp>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace boost::asio;
|
using namespace boost::asio;
|
||||||
|
|
@ -25,7 +26,7 @@ private:
|
||||||
ip::tcp::socket socket_;
|
ip::tcp::socket socket_;
|
||||||
boost::beast::flat_buffer buffer_;
|
boost::beast::flat_buffer buffer_;
|
||||||
http::request<http::string_body> request_;
|
http::request<http::string_body> request_;
|
||||||
http::response<http::string_body> response_;
|
variant<http::response<http::string_body>, http::response<http::file_body>> response_;
|
||||||
RequestHandler request_handler_;
|
RequestHandler request_handler_;
|
||||||
|
|
||||||
void read();
|
void read();
|
||||||
|
|
|
||||||
|
|
@ -4,14 +4,20 @@
|
||||||
#include <boost/beast/http.hpp>
|
#include <boost/beast/http.hpp>
|
||||||
#include <boost/beast/http/message.hpp>
|
#include <boost/beast/http/message.hpp>
|
||||||
#include <boost/beast/http/string_body.hpp>
|
#include <boost/beast/http/string_body.hpp>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
using namespace boost::beast;
|
using namespace boost::beast;
|
||||||
|
|
||||||
class RequestHandler {
|
class RequestHandler {
|
||||||
public:
|
public:
|
||||||
http::response<http::string_body> handle(const http::request<http::string_body>& request);
|
std::variant<
|
||||||
|
http::response<http::string_body>,
|
||||||
|
http::response<http::file_body>
|
||||||
|
> handle(const http::request<http::string_body>& request);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
http::response<http::string_body> BadRequest(const std::string& why);
|
||||||
|
http::response<http::file_body> handle_file_request(const std::string& filename, boost::system::error_code& ec);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -36,9 +36,10 @@ void HttpConnection::read() {
|
||||||
|
|
||||||
void HttpConnection::write() {
|
void HttpConnection::write() {
|
||||||
auto self = shared_from_this();
|
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) {
|
[self](boost::beast::error_code error_code, size_t bytes_transferred) {
|
||||||
cout << "Sending response:\n" << self->response_ << endl;
|
|
||||||
if (!error_code) {
|
if (!error_code) {
|
||||||
auto error_code_socket = self->socket_.shutdown(ip::tcp::socket::shutdown_send, error_code);
|
auto error_code_socket = self->socket_.shutdown(ip::tcp::socket::shutdown_send, error_code);
|
||||||
if (error_code_socket) {
|
if (error_code_socket) {
|
||||||
|
|
@ -52,4 +53,6 @@ void HttpConnection::write() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}, response_);
|
||||||
}
|
}
|
||||||
|
|
@ -5,37 +5,32 @@
|
||||||
#include <boost/beast/http/status.hpp>
|
#include <boost/beast/http/status.hpp>
|
||||||
#include <boost/beast/http/string_body.hpp>
|
#include <boost/beast/http/string_body.hpp>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
|
#include "request_handler.hpp"
|
||||||
|
|
||||||
http::response<http::string_body> BadRequest(const std::string& why) {
|
http::response<http::string_body> RequestHandler::BadRequest(const std::string& why) {
|
||||||
http::response<http::string_body> response;
|
http::response<http::string_body> response;
|
||||||
response.result(http::status::bad_request);
|
response.result(http::status::bad_request);
|
||||||
response.set(http::field::server, "Beast");
|
response.set(http::field::server, "Beast");
|
||||||
response.set(http::field::content_type, "text/html");
|
response.set(http::field::content_type, "text/html");
|
||||||
response.body() = why;
|
response.body() = why;
|
||||||
|
response.keep_alive(false);
|
||||||
response.prepare_payload();
|
response.prepare_payload();
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
http::response<http::string_body> RequestHandler::handle(const http::request<http::string_body>& request) {
|
std::variant<
|
||||||
string_view target = request.target();
|
http::response<http::string_body>,
|
||||||
|
http::response<http::file_body>
|
||||||
|
>
|
||||||
|
RequestHandler::handle(const http::request<http::string_body>& request) {
|
||||||
|
std::string target = request.target();
|
||||||
http::verb method = request.method();
|
http::verb method = request.method();
|
||||||
if (target == "/") {
|
|
||||||
if(method == http::verb::get) {
|
|
||||||
//case 1: "/" -> serve angular frontend or static frontend what ever
|
|
||||||
http::response<http::string_body> 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
|
if(method == http::verb::post){
|
||||||
response.body() = "<html><h1>TEST</h1></html>";
|
if(target != "/") {
|
||||||
|
return BadRequest("Cannot post to anything other than /");
|
||||||
response.prepare_payload();
|
|
||||||
return response;
|
|
||||||
}
|
}
|
||||||
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");
|
return BadRequest("Content-Type header is required for POST requests");
|
||||||
}
|
}
|
||||||
auto content_type = request[http::field::content_type];
|
auto content_type = request[http::field::content_type];
|
||||||
|
|
@ -53,11 +48,27 @@ http::response<http::string_body> RequestHandler::handle(const http::request<htt
|
||||||
}
|
}
|
||||||
|
|
||||||
//todo: save url to database and return short url
|
//todo: save url to database and return short url
|
||||||
|
http::response<http::string_body> response;
|
||||||
return BadRequest("Request is actually not bad. processing " + url);
|
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(target == "/index.html" || target == "/index.js") {
|
||||||
if(method == http::verb::get){
|
error_code ec;
|
||||||
|
http::response<http::file_body> response = handle_file_request("frontend" + target, ec);
|
||||||
|
if(ec) {
|
||||||
|
return BadRequest("Error reading file");
|
||||||
|
}else {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
http::response<http::string_body> response;
|
http::response<http::string_body> response;
|
||||||
std::string short_url = target.substr(1);
|
std::string short_url = target.substr(1);
|
||||||
|
|
||||||
|
|
@ -68,15 +79,27 @@ http::response<http::string_body> RequestHandler::handle(const http::request<htt
|
||||||
response.version(request.version());
|
response.version(request.version());
|
||||||
response.set(http::field::server, "Beast");
|
response.set(http::field::server, "Beast");
|
||||||
response.body() = "Redirecting to " + expanded_url;
|
response.body() = "Redirecting to " + expanded_url;
|
||||||
|
response.keep_alive(false);
|
||||||
response.prepare_payload();
|
response.prepare_payload();
|
||||||
return response;
|
return response;
|
||||||
} else {
|
|
||||||
return BadRequest("Method not allowed");
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
//case 2: "/url" -> redirect to expanded url
|
}
|
||||||
//case 3: neither -> redirect to 404
|
|
||||||
|
|
||||||
return BadRequest("No rule matched.");
|
return BadRequest("No rule matched.");
|
||||||
}
|
}
|
||||||
|
http::response<http::file_body> 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<http::file_body> 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;
|
||||||
|
|
||||||
|
}
|
||||||
Reference in a new issue