diff --git a/bakanet/src/bakanet/http/http_packet.cpp b/bakanet/src/bakanet/http/http_packet.cpp new file mode 100755 index 0000000..7f01423 --- /dev/null +++ b/bakanet/src/bakanet/http/http_packet.cpp @@ -0,0 +1,80 @@ +#include "http_packet.h" +namespace Bk::Net { + HttpRequest::HttpRequest(std::string method, + std::string url, + std::string version, + HttpParams params, + std::string body) + : method(method), url(url), version(version), params(params), body(body) {} + + HttpRequest::HttpRequest(std::string data) + { + auto lines = Tools::string_split(data, "\n"); + auto first_line = std::string(lines->at(0)); + auto req_data = Tools::string_split(first_line, " "); + method = req_data->at(0); + url = req_data->at(1); + version = req_data->at(2); + body = std::string(lines->at(lines->size() - 1)); + + lines->erase(lines->begin()); + lines->erase(lines->end()); + + for (auto line : *lines) + { + auto param = Tools::string_split(line, ":", 1); + if (param->size() >= 2) + { + Tools::string_trim(param->at(1)); + params.insert({param->at(0), param->at(1)}); + } + } + } + + std::string HttpRequest::to_string() + { + std::string request = ""; + request += method + " " + url + " " + version + "\r\n"; + std::string param_order[] = + { + "Host", + "User-Agent", + "Accept", + "Accept-Language", + "Accept-Encoding", + "Connection", + "Upgrade-Insecure-Requests", + "Sec-Fetch-Dest", + "Sec-Fetch-Mode", + "Sec-Fetch-Site" + }; + if (params.size()) for ( const auto& param : param_order) if (params[param].length()) request += param + ": " + params[param] + "\r\n"; + request += "\r\n"; + if (body.length()) request += body; + return request; + } + + HttpReponse::HttpReponse(std::string status, + std::string version, + HttpParams params, + std::string body) + : status(status), version(version), params(params), body(body) {} + + HttpReponse::HttpReponse(std::string data) + { + status = ""; + version = ""; + params = HttpParams(0); + body = ""; + } + + std::string HttpReponse::to_string() + { + std::string reponse = ""; + reponse = version + " " + status + " \r\n"; + if (params.size()) for ( const auto& pair : params) reponse += pair.first + ": " + pair.second + " \r\n"; + reponse += "\r\n"; + if (body.length()) reponse += body; + return reponse; + } +} \ No newline at end of file diff --git a/bakanet/src/bakanet/http/http_packet.h b/bakanet/src/bakanet/http/http_packet.h new file mode 100755 index 0000000..c8fe12d --- /dev/null +++ b/bakanet/src/bakanet/http/http_packet.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include + +#define HTTP_RES_200 "200 OK" + +#define HTTP_RES_303 "303 See Other" + +#define HTTP_RES_400 "400 Bad Request" +#define HTTP_RES_401 "401 Unauthorized" +#define HTTP_RES_402 "402 Payment Required" +#define HTTP_RES_403 "403 Forbidden" +#define HTTP_RES_404 "404 Not Found" +#define HTTP_RES_405 "405 Method Not Allowed" +#define HTTP_RES_406 "406 Not Acceptable" +#define HTTP_RES_408 "408 Request Timeout" + +namespace Bk::Net { + using HttpParams = std::unordered_map; + + class HttpRequest + { + public: + HttpRequest(std::string method, + std::string url, + std::string version, + HttpParams params = HttpParams(0), + std::string body = ""); + + HttpRequest(std::string data); + + std::string to_string(); + + std::string method; + std::string url; + std::string version; + HttpParams params; + std::string body; + }; + + class HttpReponse + { + public: + HttpReponse(std::string status, + std::string version, + HttpParams params = HttpParams(0), + std::string body = ""); + + HttpReponse(std::string data); + + std::string to_string(); + + std::string status; + std::string version; + HttpParams params; + std::string body; + }; +} \ No newline at end of file diff --git a/bakanet/src/bakanet/http/http_server.cpp b/bakanet/src/bakanet/http/http_server.cpp new file mode 100755 index 0000000..1292865 --- /dev/null +++ b/bakanet/src/bakanet/http/http_server.cpp @@ -0,0 +1,52 @@ +#include "http_server.h" +namespace Bk::Net { + HttpServer::HttpServer(IpAddress ip, int port) + { + socket = Socket::create(ip, port, IpProtocol::TCP); + } + + void HttpServer::start() + { + bool running = socket->init() && socket->start(5); + while (running) + { + log("BEFORE") + Connection conn = socket->ack(); + if(conn >= 0) + { + log("AFTER") + route_request(conn, recv_request(conn)); + close(conn); + } + + } + } + + HttpRequest HttpServer::recv_request(Connection conn) + { + Packet req; + bool reading = true; + while(reading) + { + auto data = socket->obtain(conn, 4); + log("SIZE " << data.size()) + reading = req.append_data(data); + } + int req_size = req.size(); + if (req_size) return HttpRequest(std::string(req.pull(req_size).release(), req_size)); + return HttpRequest("", "", ""); + } + + void HttpServer::send_reponse(Connection conn, HttpReponse res) + { + Packet res_packet; + std::string str_res = res.to_string(); + res_packet.push(str_res.c_str(), str_res.length()); + socket->emit(conn, res_packet.payload); + } + + void HttpServer::route_request(Connection conn, HttpRequest req) + { + if(req_mapper[req.url]) send_reponse(conn, req_mapper[req.url](req)); + } +} \ No newline at end of file diff --git a/bakanet/src/bakanet/http/http_server.h b/bakanet/src/bakanet/http/http_server.h new file mode 100755 index 0000000..3d1658b --- /dev/null +++ b/bakanet/src/bakanet/http/http_server.h @@ -0,0 +1,26 @@ +#pragma once + +#include +#include +#include +#include +#include "http_packet.h" + +namespace Bk::Net { + class HttpServer + { + using RequestHandler = std::function; + public: + HttpServer(IpAddress ip, int port); + ~HttpServer() = default; + void start(); + void get(std::string url, RequestHandler req_handler) { req_mapper.insert({ url, req_handler }); } + private: + std::unique_ptr socket; + std::unordered_map req_mapper; + + HttpRequest recv_request(Connection conn); + void send_reponse(Connection conn, HttpReponse res); + void route_request(Connection conn, HttpRequest req); + }; +} \ No newline at end of file