diff --git a/src/http/request.cpp b/src/http/request.cpp index 680a902..8830f98 100644 --- a/src/http/request.cpp +++ b/src/http/request.cpp @@ -27,8 +27,17 @@ namespace Http std::string requestTypeString; ss >> requestTypeString; request.requestType = ToEnum(requestTypeString, HttpRequest::typeStrings); + if (request.requestType == HttpRequest::Type::UNKNOWN) + { + throw std::runtime_error("Bad request type"); + } - ss >> request.path; + std::string rawUrl; + ss >> rawUrl; + if(!request.url.TryParseFromUrlString(rawUrl)) + { + throw std::runtime_error("Bad url in request"); + } std::string httpProtocolString; ss >> httpProtocolString; diff --git a/src/http/request.hpp b/src/http/request.hpp index ef0f595..9012fbc 100644 --- a/src/http/request.hpp +++ b/src/http/request.hpp @@ -1,12 +1,13 @@ #pragma once #include "../constants/httprequest.hpp" +#include "url.hpp" namespace Http { struct Request { HttpRequest::Type requestType; - std::string path; + Url url; static Request Deserialize(std::vector const & bytes); }; diff --git a/src/http/url.cpp b/src/http/url.cpp new file mode 100644 index 0000000..37b6fc5 --- /dev/null +++ b/src/http/url.cpp @@ -0,0 +1,53 @@ +#include "url.hpp" + +namespace Http +{ + bool Url::HasPath() const + { + return path.size() > 1; + } + + bool Url::HasQuery() const + { + return query.size() > 1; + } + + std::string const & Url::GetPath() const + { + return path; + } + + std::string const & Url::GetQuery() const + { + return query; + } + + bool Url::TryParseFromUrlString(std::string urlstring) + { + unsigned queryPos = 0; + static std::string const validSpecialCharacters = "-._~:/?#[]@!$&'()*+,;="; + for(unsigned i = 0; i < urlstring.size(); ++i) + { + if (!std::isalnum(urlstring[i]) && validSpecialCharacters.find(urlstring[i]) == std::string::npos) + { + return false; + } + else if (urlstring[i] == '?' && queryPos == 0) + { + queryPos = i; + } + } + + if (queryPos == 0) + { + path = urlstring; + } + else + { + path = urlstring.substr(0, queryPos); + query = urlstring.substr(queryPos, urlstring.size()); + } + + return true; + } +} \ No newline at end of file diff --git a/src/http/url.hpp b/src/http/url.hpp new file mode 100644 index 0000000..21a23f8 --- /dev/null +++ b/src/http/url.hpp @@ -0,0 +1,21 @@ +#pragma once +#include + +namespace Http +{ + class Url + { + private: + std::string path; + std::string query; + + public: + bool HasPath() const; + bool HasQuery() const; + + std::string const & GetPath() const; + std::string const & GetQuery() const; + + bool TryParseFromUrlString(std::string urlstring); + }; +} \ No newline at end of file diff --git a/src/middleware/notfound.cpp b/src/middleware/notfound.cpp index 5419271..7ae46ce 100644 --- a/src/middleware/notfound.cpp +++ b/src/middleware/notfound.cpp @@ -5,7 +5,7 @@ namespace Middleware { void NotFound::HandleRequest(Http::Request const & request, Http::Response & response) { - if (response.code != HttpResponse::Code::UNKNOWN) + if (response.code != HttpResponse::Code::UNKNOWN || request.requestType != HttpRequest::Type::GET) { return; } @@ -15,7 +15,7 @@ namespace Middleware std::stringstream ss; ss << "404 - file not found\n"; ss << "File: "; - ss << request.path << '\n'; + ss << request.url.GetPath() << '\n'; auto responseContent = ss.str(); response.content.insert(response.content.begin(), diff --git a/src/middleware/staticcontent.cpp b/src/middleware/staticcontent.cpp index ab7e039..97b4888 100644 --- a/src/middleware/staticcontent.cpp +++ b/src/middleware/staticcontent.cpp @@ -34,24 +34,18 @@ namespace Middleware } std::filesystem::path path; - if (request.path.size() == 1) + if (request.url.HasPath()) + { + path = root + request.url.GetPath(); + } + else { // TODO make configurable? path = root + "/index.html"; } - else - { - path = root + request.path; - } if (!std::filesystem::exists(path)) { - std::stringstream ss; - ss << "Static file <"; - ss << path.string(); - ss << "> not found"; - Logger::GetInstance().Info(ss.str()); - return; } diff --git a/src/server/connectionoperator.cpp b/src/server/connectionoperator.cpp index f456b4f..0431175 100644 --- a/src/server/connectionoperator.cpp +++ b/src/server/connectionoperator.cpp @@ -6,12 +6,34 @@ #include #include +void ConnectionOperator::SendResponse(Connection const & connection, Http::Response const & response) const +{ + auto bytesToSend = response.Serialize(); + connection.WriteBytes(bytesToSend); +} + void ConnectionOperator::HandleNewConnection(Connection const & newConnection) { auto requestBytes = newConnection.ReadBytes(); - Http::Request request = Http::Request::Deserialize(requestBytes); - + Http::Request request; Http::Response response; + try + { + request = Http::Request::Deserialize(requestBytes); + } + catch (std::runtime_error & e) + { + std::stringstream ss; + ss << "Error during parsing of request <"; + ss << e.what(); + ss << '>'; + Logger::GetInstance().Error(ss.str()); + + response.code = HttpResponse::Code::BAD_REQUEST; + SendResponse(newConnection, response); + return; + } + for(size_t i = 0; i < middlewares.size(); ++i) { middlewares[i]->HandleRequest(request, response); @@ -20,10 +42,15 @@ void ConnectionOperator::HandleNewConnection(Connection const & newConnection) if (response.code == HttpResponse::Code::UNKNOWN) { std::stringstream ss; - ss << "Unhandled request for file <"; - ss << request.path; + ss << "Unhandled "; + ss << HttpRequest::typeStrings[static_cast(request.requestType)]; + ss << " request for file <"; + ss << request.url.GetPath(); ss << '>'; Logger::GetInstance().Error(ss.str()); + + response.code = HttpResponse::Code::NOT_IMPLEMENTED; + SendResponse(newConnection, response); return; } diff --git a/src/server/connectionoperator.hpp b/src/server/connectionoperator.hpp index ba850a7..f7f5f5e 100644 --- a/src/server/connectionoperator.hpp +++ b/src/server/connectionoperator.hpp @@ -10,6 +10,8 @@ class ConnectionOperator private: std::vector> middlewares; + void SendResponse(Connection const & connection, Http::Response const & response) const; + public: void HandleNewConnection(Connection const & newConnection); diff --git a/src/server/url.cpp b/src/server/url.cpp deleted file mode 100644 index cbcfe9b..0000000 --- a/src/server/url.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "url.hpp" - -bool Url::HasPath() const -{ - return path.size() > 1; -} - -bool Url::HasQuery() const -{ - // TODO implement - return false; -} - -bool Url::HasFragment() const -{ - // TODO implement - return false; -} - -std::string const & Url::GetPath() const -{ - return path; -} - -std::string const & Url::GetQuery() const -{ - return query; -} - -std::string const & Url::GetFragment() const -{ - return fragment; -} \ No newline at end of file diff --git a/src/server/url.hpp b/src/server/url.hpp deleted file mode 100644 index eb2cde9..0000000 --- a/src/server/url.hpp +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once -#include - -class Url -{ -private: - std::string path; - std::string query; - std::string fragment; - -public: - bool HasPath() const; - bool HasQuery() const; - bool HasFragment() const; - - std::string const & GetPath() const; - std::string const & GetQuery() const; - std::string const & GetFragment() const; -}; \ No newline at end of file