Compare commits
1 commit
main
...
request-ha
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48d1851541 |
2 changed files with 70 additions and 14 deletions
|
|
@ -38,6 +38,7 @@ void HttpConnection::write() {
|
||||||
auto self = shared_from_this();
|
auto self = shared_from_this();
|
||||||
http::async_write(socket_, 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) {
|
||||||
|
|
@ -45,6 +46,10 @@ void HttpConnection::write() {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
cerr << "Error writing response: " << error_code.message() << endl;
|
cerr << "Error writing response: " << error_code.message() << endl;
|
||||||
|
auto error_code_socket = self->socket_.shutdown(ip::tcp::socket::shutdown_both, error_code);
|
||||||
|
if (error_code_socket) {
|
||||||
|
cerr << "Error shuting down socket: " << error_code_socket.message() << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -4,28 +4,79 @@
|
||||||
#include <boost/beast/http/message.hpp>
|
#include <boost/beast/http/message.hpp>
|
||||||
#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>
|
||||||
|
|
||||||
|
http::response<http::string_body> BadRequest(const std::string& why) {
|
||||||
|
http::response<http::string_body> 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.prepare_payload();
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
http::response<http::string_body> RequestHandler::handle(const http::request<http::string_body>& request) {
|
http::response<http::string_body> RequestHandler::handle(const http::request<http::string_body>& request) {
|
||||||
string_view target = request.target();
|
string_view target = request.target();
|
||||||
|
http::verb method = request.method();
|
||||||
if (target == "/") {
|
if (target == "/") {
|
||||||
//case 1: "/" -> serve angular frontend or static frontend what ever
|
if(method == http::verb::get) {
|
||||||
http::response<http::string_body> response;
|
//case 1: "/" -> serve angular frontend or static frontend what ever
|
||||||
response.result(http::status::ok);
|
http::response<http::string_body> response;
|
||||||
response.version(request.version());
|
response.result(http::status::ok);
|
||||||
response.set(http::field::server, "Beast");
|
response.version(request.version());
|
||||||
response.set(http::field::content_type, "text/html");
|
response.set(http::field::server, "Beast");
|
||||||
response.keep_alive();
|
response.set(http::field::content_type, "text/html");
|
||||||
|
|
||||||
//todo: load angular application / plain html & js
|
//todo: load angular application / plain html & js
|
||||||
response.body() = "<html><h1>TEST</h1></html>";
|
response.body() = "<html><h1>TEST</h1></html>";
|
||||||
|
|
||||||
response.prepare_payload();
|
response.prepare_payload();
|
||||||
return response;
|
return response;
|
||||||
|
}
|
||||||
|
else if (method == http::verb::post) {
|
||||||
|
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];
|
||||||
|
if(content_type != "text/plain") {
|
||||||
|
return BadRequest("Content-Type must be text/plain");
|
||||||
|
}
|
||||||
|
std::string url = request.body();
|
||||||
|
std::regex url_regex("^(https?://)?(?:www\\.)?[-a-zA-Z0-9@%._\\+~#=]{1,256}\\.[a-zA-Z0-9()]{1,6}\\b(?:[-a-zA-Z0-9()@:%_\\+.~#?&/=]*)$");
|
||||||
|
std::smatch url_match;
|
||||||
|
if(!std::regex_match(url, url_match, url_regex)) {
|
||||||
|
return BadRequest("Invalid URL");
|
||||||
|
}
|
||||||
|
if(!url_match[1].matched){
|
||||||
|
url = "https://" + url;
|
||||||
|
}
|
||||||
|
|
||||||
|
//todo: save url to database and return short url
|
||||||
|
|
||||||
|
return BadRequest("Request is actually not bad. processing " + url);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
if(method == http::verb::get){
|
||||||
|
http::response<http::string_body> response;
|
||||||
|
std::string short_url = target.substr(1);
|
||||||
|
|
||||||
|
std::string expanded_url = "https://google.com"; //todo: get expanded url from database
|
||||||
|
|
||||||
|
response.result(http::status::moved_permanently);
|
||||||
|
response.set(http::field::location, expanded_url);
|
||||||
|
response.version(request.version());
|
||||||
|
response.set(http::field::server, "Beast");
|
||||||
|
response.body() = "Redirecting to " + expanded_url;
|
||||||
|
response.prepare_payload();
|
||||||
|
return response;
|
||||||
|
} else {
|
||||||
|
return BadRequest("Method not allowed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//case 2: "/url" -> redirect to expanded url
|
//case 2: "/url" -> redirect to expanded url
|
||||||
//case 3: neither -> redirect to 404
|
//case 3: neither -> redirect to 404
|
||||||
|
|
||||||
return http::response<http::string_body>{http::status::bad_request, request.version()};
|
return BadRequest("No rule matched.");
|
||||||
}
|
}
|
||||||
Reference in a new issue