diff --git a/examples/handlers.cpp b/examples/handlers.cpp index 011baa4..ce10ab7 100644 --- a/examples/handlers.cpp +++ b/examples/handlers.cpp @@ -1,53 +1,59 @@ #include "handlers.hpp" -using namespace std; +#include +#include Response* RandomNumberHandler::callback(Request* req) { - Response* res = new Response; + Response* res = new Response(); res->setHeader("Content-Type", "text/html"); - string body; + + std::string randomNumber = std::to_string(std::rand() % 10 + 1); + std::string body; + body += ""; - body += ""; + body += ""; + + body += ""; + body += " Random Number Page"; + body += ""; + body += ""; - body += "

AP HTTP

"; - body += "

"; - body += "a random number in [1, 10] is: "; - body += to_string(rand() % 10 + 1); - body += "

"; - body += "

"; - body += "SessionId: "; - body += req->getSessionId(); - body += "

"; + body += "

AP HTTP

"; + body += "

A random number in [1, 10] is: " + randomNumber + "

"; + body += "

SessionId: " + req->getSessionId() + "

"; body += ""; + body += ""; res->setBody(body); return res; } Response* LoginHandler::callback(Request* req) { - string username = req->getBodyParam("username"); - string password = req->getBodyParam("password"); - if (username == "root") + std::string username = req->getBodyParam("username"); + std::string password = req->getBodyParam("password"); + if (username == "root") { throw Server::Exception("Remote root access has been disabled."); - cout << "username: " << username << ",\tpassword: " << password << endl; + } + std::cout << "username: " << username << ",\tpassword: " << password << std::endl; Response* res = Response::redirect("/rand"); res->setSessionId("SID"); return res; } Response* UploadHandler::callback(Request* req) { - string name = req->getBodyParam("file_name"); - string file = req->getBodyParam("file"); + std::string name = req->getBodyParam("file_name"); + std::string file = req->getBodyParam("file"); utils::writeToFile(file, name); Response* res = Response::redirect("/"); return res; } -ColorHandler::ColorHandler(string filePath) : TemplateHandler(filePath) {} +ColorHandler::ColorHandler(const std::string& filePath) + : TemplateHandler(filePath) {} -map ColorHandler::handle(Request* req) { - map context; - string newName = "I am " + req->getQueryParam("name"); +std::map ColorHandler::handle(Request* req) { + std::string newName = "I am " + req->getQueryParam("name"); + std::map context; context["name"] = newName; context["color"] = req->getQueryParam("color"); return context; diff --git a/examples/handlers.hpp b/examples/handlers.hpp index cc25b84..ed82807 100644 --- a/examples/handlers.hpp +++ b/examples/handlers.hpp @@ -1,31 +1,30 @@ #ifndef HANDLERS_HPP_INCLUDE #define HANDLERS_HPP_INCLUDE -#include // for rand and srand -#include // for time -#include +#include +#include #include "../server/server.hpp" class RandomNumberHandler : public RequestHandler { public: - Response* callback(Request*); + Response* callback(Request*) override; }; class LoginHandler : public RequestHandler { public: - Response* callback(Request*); + Response* callback(Request*) override; }; class UploadHandler : public RequestHandler { public: - Response* callback(Request*); + Response* callback(Request*) override; }; class ColorHandler : public TemplateHandler { public: - ColorHandler(std::string filePath); - std::map handle(Request* req); + ColorHandler(const std::string& filePath); + std::map handle(Request* req) override; }; #endif // HANDLERS_HPP_INCLUDE diff --git a/examples/main.cpp b/examples/main.cpp index fa76fac..dfa21c5 100644 --- a/examples/main.cpp +++ b/examples/main.cpp @@ -8,12 +8,12 @@ void mapServerPaths(Server& server) { server.setNotFoundErrPage("static/404.html"); server.get("/", new ShowPage("static/home.html")); server.get("/home.png", new ShowImage("static/home.png")); + server.get("/rand", new RandomNumberHandler()); server.get("/login", new ShowPage("static/logincss.html")); server.post("/login", new LoginHandler()); server.get("/up", new ShowPage("static/upload_form.html")); server.post("/up", new UploadHandler()); server.get("/colors", new ColorHandler("template/colors.html")); - server.get("/rand", new RandomNumberHandler()); server.get("/music", new ShowPage("static/music.html")); server.get("/music/moonlight.mp3", new ShowFile("static/moonlight.mp3", "audio/mpeg")); } diff --git a/server/route.cpp b/server/route.cpp index 19d15d6..b1f1a22 100644 --- a/server/route.cpp +++ b/server/route.cpp @@ -2,19 +2,23 @@ #include "server.hpp" -using namespace std; +Route::Route(Request::Method method, const std::string& path) + : method_(method), + path_(path), + handler_(nullptr) {} -Route::Route(Method _method, string _path) { - method = _method; - path = _path; +Route::~Route() { + delete handler_; } -void Route::setHandler(RequestHandler* _handler) { handler = _handler; } - -bool Route::isMatch(Method _method, string url) { - return (url == path) && (_method == method); +void Route::setHandler(RequestHandler* handler) { + handler_ = handler; } -Response* Route::handle(Request* req) { return handler->callback(req); } +Response* Route::handle(Request* req) { + return handler_->callback(req); +} -Route::~Route() { delete handler; } +bool Route::isMatch(Request::Method method, const std::string& url) { + return (method_ == method) && (url == path_); +} diff --git a/server/route.hpp b/server/route.hpp index 381222f..9bfb921 100644 --- a/server/route.hpp +++ b/server/route.hpp @@ -3,24 +3,24 @@ #include -#include "../utils/include.hpp" #include "../utils/request.hpp" -#include "../utils/response.hpp" +class Response; class RequestHandler; class Route { -private: - Method method; - std::string path; - RequestHandler* handler; - public: - Route(Method _method, std::string _path); + Route(Request::Method method, const std::string& path); ~Route(); - bool isMatch(Method, std::string url); + + void setHandler(RequestHandler* handler); Response* handle(Request* req); - void setHandler(RequestHandler* _handler); + bool isMatch(Request::Method, const std::string& url); + +private: + Request::Method method_; + std::string path_; + RequestHandler* handler_; }; #endif // ROUTE_HPP_INCLUDE diff --git a/server/server.cpp b/server/server.cpp index a7fdf6b..da74d04 100644 --- a/server/server.cpp +++ b/server/server.cpp @@ -58,25 +58,26 @@ static const char* getSocketError() { using namespace std; class NotFoundHandler : public RequestHandler { - string notFoundErrPage; - public: - NotFoundHandler(string notFoundErrPage = "") - : notFoundErrPage(notFoundErrPage) {} + NotFoundHandler(const string& notFoundErrPage = "") + : notFoundErrPage_(notFoundErrPage) {} Response* callback(Request* req) { - Response* res = new Response(404); - if (!notFoundErrPage.empty()) { - res->setHeader("Content-Type", "text/" + utils::getExtension(notFoundErrPage)); - res->setBody(utils::readFile(notFoundErrPage)); + Response* res = new Response(Response::Status::notFound); + if (!notFoundErrPage_.empty()) { + res->setHeader("Content-Type", "text/" + utils::getExtension(notFoundErrPage_)); + res->setBody(utils::readFile(notFoundErrPage_)); } return res; } + +private: + string notFoundErrPage_; }; class ServerErrorHandler { public: - static Response* callback(string msg) { - Response* res = new Response(500); + static Response* callback(const string& msg) { + Response* res = new Response(Response::Status::internalServerError); res->setHeader("Content-Type", "application/json"); res->setBody("{ \"code\": \"500\", \"message\": \"" + msg + "\" }\n"); return res; @@ -96,13 +97,13 @@ Request* parseRawReq(char* reqData, size_t length) { if (endOfHeader == string::npos) { throw Server::Exception("End of request header not found."); } - vector headers = utils::split(reqHeader, "\r\n"); + vector headers = strutils::split(reqHeader, "\r\n"); if (reqHeader.find('\0') != string::npos) { throw Server::Exception("Binary data in header."); } size_t realBodySize = length - endOfHeader - 4; // string("\r\n\r\n").size(); - vector R = utils::split(headers[0], ' '); + vector R = strutils::split(headers[0], ' '); if (R.size() != 3) { throw Server::Exception("Invalid header (request line)"); } @@ -110,9 +111,9 @@ Request* parseRawReq(char* reqData, size_t length) { req->setPath(R[1]); size_t pos = req->getPath().find('?'); if (pos != string::npos && pos != req->getPath().size() - 1) { - vector Q1 = utils::split(req->getPath().substr(pos + 1), '&'); + vector Q1 = strutils::split(req->getPath().substr(pos + 1), '&'); for (vector::size_type q = 0; q < Q1.size(); q++) { - vector Q2 = utils::split(Q1[q], '='); + vector Q2 = strutils::split(Q1[q], '='); if (Q2.size() == 2) req->setQueryParam(Q2[0], Q2[1], false); else @@ -123,23 +124,23 @@ Request* parseRawReq(char* reqData, size_t length) { for (size_t headerIndex = 1; headerIndex < headers.size(); headerIndex++) { string line = headers[headerIndex]; - vector R = utils::split(line, ": "); + vector R = strutils::split(line, ": "); if (R.size() != 2) throw Server::Exception("Invalid header"); req->setHeader(R[0], R[1], false); - if (utils::tolower(R[0]) == utils::tolower("Content-Length")) + if (strutils::tolower(R[0]) == strutils::tolower("Content-Length")) if (realBodySize != (size_t)atol(R[1].c_str())) return nullptr; } string contentType = req->getHeader("Content-Type"); if (realBodySize != 0 && !contentType.empty()) { - if (utils::startsWith(contentType, "application/x-www-form-urlencoded")) { - vector urlencodedParts = utils::split(reqBody, "\r\n"); + if (strutils::startsWith(contentType, "application/x-www-form-urlencoded")) { + vector urlencodedParts = strutils::split(reqBody, "\r\n"); for (const string& part : urlencodedParts) { - vector body = utils::split(part, '&'); + vector body = strutils::split(part, '&'); for (size_t i = 0; i < body.size(); i++) { - vector field = utils::split(body[i], '='); + vector field = strutils::split(body[i], '='); if (field.size() == 2) req->setBodyParam(field[0], field[1], "application/x-www-form-urlencoded", false); else if (field.size() == 1) @@ -149,7 +150,7 @@ Request* parseRawReq(char* reqData, size_t length) { } } } - else if (utils::startsWith(contentType, "multipart/form-data")) { + else if (strutils::startsWith(contentType, "multipart/form-data")) { boundary = contentType.substr(contentType.find("boundary=") + 9); size_t firstBoundary = reqBody.find("--" + boundary); if (firstBoundary == string::npos) { @@ -157,7 +158,7 @@ Request* parseRawReq(char* reqData, size_t length) { } reqBody.erase(reqBody.begin(), reqBody.begin() + firstBoundary + 2 + boundary.size()); - vector boundaries = utils::split(reqBody, "--" + boundary); + vector boundaries = strutils::split(reqBody, "--" + boundary); boundaries.pop_back(); for (string b : boundaries) { @@ -167,19 +168,19 @@ Request* parseRawReq(char* reqData, size_t length) { string boundaryContentType = "text/plain"; size_t endOfBoundaryHeader = b.find("\r\n\r\n") + 4; - vector abc = utils::split(b.substr(0, endOfBoundaryHeader - 4), "\r\n"); + vector abc = strutils::split(b.substr(0, endOfBoundaryHeader - 4), "\r\n"); for (const string& line : abc) { if (line.empty()) { break; } - vector R = utils::split(line, ": "); + vector R = strutils::split(line, ": "); if (R.size() != 2) throw Server::Exception("Invalid header"); - if (utils::tolower(R[0]) == utils::tolower("Content-Disposition")) { - vector A = utils::split(R[1], "; "); + if (strutils::tolower(R[0]) == strutils::tolower("Content-Disposition")) { + vector A = strutils::split(R[1], "; "); for (size_t i = 0; i < A.size(); i++) { - vector attr = utils::split(A[i], '='); + vector attr = strutils::split(A[i], '='); if (attr.size() == 2) { - if (utils::tolower(attr[0]) == utils::tolower("name")) { + if (strutils::tolower(attr[0]) == strutils::tolower("name")) { lastFieldKey = attr[1].substr(1, attr[1].size() - 2); } } @@ -188,8 +189,8 @@ Request* parseRawReq(char* reqData, size_t length) { } } } - else if (utils::tolower(R[0]) == utils::tolower("Content-Type")) { - boundaryContentType = utils::tolower(R[1]); + else if (strutils::tolower(R[0]) == strutils::tolower("Content-Type")) { + boundaryContentType = strutils::tolower(R[1]); } } lastFieldValue = b.substr(endOfBoundaryHeader); @@ -210,7 +211,7 @@ Request* parseRawReq(char* reqData, size_t length) { return req; } -Server::Server(int _port) : port(_port) { +Server::Server(int port) : port_(port) { #ifdef _WIN32 WSADATA wsa_data; int initializeResult = WSAStartup(MAKEWORD(2, 2), &wsa_data); @@ -220,44 +221,54 @@ Server::Server(int _port) : port(_port) { } #endif - notFoundHandler = new NotFoundHandler(); + notFoundHandler_ = new NotFoundHandler(); - sc = socket(AF_INET, SOCK_STREAM, 0); + sc_ = socket(AF_INET, SOCK_STREAM, 0); int sc_option = 1; #ifdef _WIN32 - setsockopt(sc, SOL_SOCKET, SO_REUSEADDR, (char*)&sc_option, - sizeof(sc_option)); + setsockopt(sc_, SOL_SOCKET, SO_REUSEADDR, (char*)&sc_option, sizeof(sc_option)); #else - setsockopt(sc, SOL_SOCKET, SO_REUSEADDR, &sc_option, sizeof(sc_option)); + setsockopt(sc_, SOL_SOCKET, SO_REUSEADDR, &sc_option, sizeof(sc_option)); #endif - if (!ISVALIDSOCKET(sc)) + if (!ISVALIDSOCKET(sc_)) { throw Exception("Error on opening socket: " + string(getSocketError())); + } struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; - serv_addr.sin_port = htons(port); + serv_addr.sin_port = htons(port_); - if (::bind(sc, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0) { + if (::bind(sc_, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) != 0) { throw Exception("Error on binding: " + string(getSocketError())); } } -void Server::get(string path, RequestHandler* handler) { - Route* route = new Route(GET, path); +void Server::mapRequest(const string& path, RequestHandler* handler, Request::Method method) { + Route* route = new Route(method, path); route->setHandler(handler); - routes.push_back(route); + routes_.push_back(route); } -void Server::post(string path, RequestHandler* handler) { - Route* route = new Route(POST, path); - route->setHandler(handler); - routes.push_back(route); +void Server::get(const std::string& path, RequestHandler* handler) { + mapRequest(path, handler, Request::Method::GET); +} + +void Server::post(const std::string& path, RequestHandler* handler) { + mapRequest(path, handler, Request::Method::POST); +} + +void Server::put(const std::string& path, RequestHandler* handler) { + mapRequest(path, handler, Request::Method::PUT); +} + +void Server::del(const std::string& path, RequestHandler* handler) { + mapRequest(path, handler, Request::Method::DEL); } void Server::run() { - ::listen(sc, 10); + ::listen(sc_, 10); struct sockaddr_in cli_addr; socklen_t clilen; @@ -265,14 +276,14 @@ void Server::run() { SOCKET newsc; while (true) { - newsc = ::accept(sc, (struct sockaddr*)&cli_addr, &clilen); + newsc = ::accept(sc_, (struct sockaddr*)&cli_addr, &clilen); if (!ISVALIDSOCKET(newsc)) throw Exception("Error on accept: " + string(getSocketError())); - Response* res = NULL; + Response* res = nullptr; try { char* data = new char[BUFSIZE + 1]; size_t recv_len, recv_total_len = 0; - Request* req = NULL; + Request* req = nullptr; while (!req) { recv_len = recv(newsc, data + recv_total_len, BUFSIZE - recv_total_len, 0); if (recv_len > 0) { @@ -290,14 +301,14 @@ void Server::run() { } req->log(); size_t i = 0; - for (; i < routes.size(); i++) { - if (routes[i]->isMatch(req->getMethod(), req->getPath())) { - res = routes[i]->handle(req); + for (; i < routes_.size(); i++) { + if (routes_[i]->isMatch(req->getMethod(), req->getPath())) { + res = routes_[i]->handle(req); break; } } - if (i == routes.size() && notFoundHandler) { - res = notFoundHandler->callback(req); + if (i == routes_.size() && notFoundHandler_) { + res = notFoundHandler_->callback(req); } delete req; } @@ -305,9 +316,9 @@ void Server::run() { delete res; res = ServerErrorHandler::callback(exc.getMessage()); } - int si; res->log(); - string res_data = res->print(si); + string res_data = res->getResponse(); + int si = res_data.size(); delete res; int wr = send(newsc, res_data.c_str(), si, 0); if (wr != si) @@ -317,57 +328,60 @@ void Server::run() { } Server::~Server() { - if (sc >= 0) - CLOSESOCKET(sc); - delete notFoundHandler; - for (size_t i = 0; i < routes.size(); ++i) - delete routes[i]; - + if (sc_ >= 0) { + CLOSESOCKET(sc_); + } + delete notFoundHandler_; + for (size_t i = 0; i < routes_.size(); ++i) { + delete routes_[i]; + } #ifdef _WIN32 WSACleanup(); #endif } -Server::Exception::Exception(const string msg) { message = msg; } +Server::Exception::Exception(const string message) : message_(message) {} -string Server::Exception::getMessage() const { return message; } +string Server::Exception::getMessage() const { return message_; } -ShowFile::ShowFile(string _filePath, string _fileType) { - filePath = _filePath; - fileType = _fileType; -} +ShowFile::ShowFile(const string& filePath, const string& fileType) + : filePath_(filePath), + fileType_(fileType) {} Response* ShowFile::callback(Request* req) { - Response* res = new Response; - res->setHeader("Content-Type", fileType); - res->setBody(utils::readFile(filePath)); + Response* res = new Response(); + res->setHeader("Content-Type", fileType_); + res->setBody(utils::readFile(filePath_)); return res; } -ShowPage::ShowPage(string filePath) +ShowPage::ShowPage(const string& filePath) : ShowFile(filePath, "text/" + utils::getExtension(filePath)) {} -ShowImage::ShowImage(string filePath) +ShowImage::ShowImage(const string& filePath) : ShowFile(filePath, "image/" + utils::getExtension(filePath)) {} -void Server::setNotFoundErrPage(std::string notFoundErrPage) { - delete notFoundHandler; - notFoundHandler = new NotFoundHandler(notFoundErrPage); +void Server::setNotFoundErrPage(const std::string& notFoundErrPage) { + delete notFoundHandler_; + notFoundHandler_ = new NotFoundHandler(notFoundErrPage); } RequestHandler::~RequestHandler() {} -TemplateHandler::TemplateHandler(string _filePath) { - filePath = _filePath; - parser = new TemplateParser(filePath); +TemplateHandler::TemplateHandler(const string& filePath) + : filePath_(filePath), + parser_(new TemplateParser(filePath)) {} + +TemplateHandler::~TemplateHandler() { + delete parser_; } Response* TemplateHandler::callback(Request* req) { map context; context = this->handle(req); - Response* res = new Response; + Response* res = new Response(); res->setHeader("Content-Type", "text/html"); - res->setBody(parser->getHtml(context)); + res->setBody(parser_->getHtml(context)); return res; } diff --git a/server/server.hpp b/server/server.hpp index fb01f8e..620273b 100644 --- a/server/server.hpp +++ b/server/server.hpp @@ -26,58 +26,68 @@ class RequestHandler { }; class ShowFile : public RequestHandler { - std::string filePath; - std::string fileType; - public: - ShowFile(std::string filePath, std::string fileType); - Response* callback(Request* req); + ShowFile(const std::string& filePath, const std::string& fileType); + Response* callback(Request* req) override; + +private: + std::string filePath_; + std::string fileType_; }; class ShowPage : public ShowFile { public: - ShowPage(std::string _filePath); + ShowPage(const std::string& filePath); }; class ShowImage : public ShowFile { public: - ShowImage(std::string _filePath); + ShowImage(const std::string& filePath); }; class TemplateHandler : public RequestHandler { - std::string filePath; - TemplateParser* parser; - public: - TemplateHandler(std::string _filePath); - Response* callback(Request* req); + TemplateHandler(const std::string& filePath); + ~TemplateHandler(); + + Response* callback(Request* req) override; virtual std::map handle(Request* req); + +private: + std::string filePath_; + TemplateParser* parser_; }; class Server { public: Server(int port = 5000); ~Server(); + void run(); - void get(std::string path, RequestHandler* handler); - void post(std::string path, RequestHandler* handler); - void setNotFoundErrPage(std::string); + + void get(const std::string& path, RequestHandler* handler); + void post(const std::string& path, RequestHandler* handler); + void put(const std::string& path, RequestHandler* handler); + void del(const std::string& path, RequestHandler* handler); + void setNotFoundErrPage(const std::string& notFoundErrPage); class Exception : public std::exception { public: - Exception() {} - Exception(const std::string); + Exception() = default; + Exception(const std::string message); std::string getMessage() const; private: - std::string message; + std::string message_; }; private: - SOCKET sc; - int port; - std::vector routes; - RequestHandler* notFoundHandler; + SOCKET sc_; + int port_; + std::vector routes_; + RequestHandler* notFoundHandler_; + + void mapRequest(const std::string& path, RequestHandler* handler, Request::Method method); }; #endif // SERVER_HPP_INCLUDE diff --git a/static/home.html b/static/home.html index 042f8eb..63ad7e8 100644 --- a/static/home.html +++ b/static/home.html @@ -10,6 +10,7 @@

AP HTTP

Home Logo
+ Go to rand page
Go to login page
Go to upload page
Go to colors page
diff --git a/static/music.html b/static/music.html index 12604de..8478749 100644 --- a/static/music.html +++ b/static/music.html @@ -1,16 +1,16 @@ - - - Music Page + + + Music Page -

Music

- +

Music

+ diff --git a/template/colors.html b/template/colors.html index a3e92fe..5b79a78 100644 --- a/template/colors.html +++ b/template/colors.html @@ -2,68 +2,65 @@ - - - Colors Page + + + Colors Page -
- Choose color: - - - - -
-