Use url parsing
This commit is contained in:
@@ -27,8 +27,17 @@ namespace Http
|
|||||||
std::string requestTypeString;
|
std::string requestTypeString;
|
||||||
ss >> requestTypeString;
|
ss >> requestTypeString;
|
||||||
request.requestType = ToEnum<HttpRequest::Type>(requestTypeString, HttpRequest::typeStrings);
|
request.requestType = ToEnum<HttpRequest::Type>(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;
|
std::string httpProtocolString;
|
||||||
ss >> httpProtocolString;
|
ss >> httpProtocolString;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../constants/httprequest.hpp"
|
#include "../constants/httprequest.hpp"
|
||||||
|
#include "url.hpp"
|
||||||
|
|
||||||
namespace Http
|
namespace Http
|
||||||
{
|
{
|
||||||
struct Request
|
struct Request
|
||||||
{
|
{
|
||||||
HttpRequest::Type requestType;
|
HttpRequest::Type requestType;
|
||||||
std::string path;
|
Url url;
|
||||||
|
|
||||||
static Request Deserialize(std::vector<char> const & bytes);
|
static Request Deserialize(std::vector<char> const & bytes);
|
||||||
};
|
};
|
||||||
|
|||||||
53
src/http/url.cpp
Normal file
53
src/http/url.cpp
Normal file
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
src/http/url.hpp
Normal file
21
src/http/url.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ namespace Middleware
|
|||||||
{
|
{
|
||||||
void NotFound::HandleRequest(Http::Request const & request, Http::Response & response)
|
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;
|
return;
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,7 @@ namespace Middleware
|
|||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "404 - file not found\n";
|
ss << "404 - file not found\n";
|
||||||
ss << "File: ";
|
ss << "File: ";
|
||||||
ss << request.path << '\n';
|
ss << request.url.GetPath() << '\n';
|
||||||
|
|
||||||
auto responseContent = ss.str();
|
auto responseContent = ss.str();
|
||||||
response.content.insert(response.content.begin(),
|
response.content.insert(response.content.begin(),
|
||||||
|
|||||||
@@ -34,24 +34,18 @@ namespace Middleware
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::filesystem::path path;
|
std::filesystem::path path;
|
||||||
if (request.path.size() == 1)
|
if (request.url.HasPath())
|
||||||
|
{
|
||||||
|
path = root + request.url.GetPath();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// TODO make configurable?
|
// TODO make configurable?
|
||||||
path = root + "/index.html";
|
path = root + "/index.html";
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
path = root + request.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!std::filesystem::exists(path))
|
if (!std::filesystem::exists(path))
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
|
||||||
ss << "Static file <";
|
|
||||||
ss << path.string();
|
|
||||||
ss << "> not found";
|
|
||||||
Logger::GetInstance().Info(ss.str());
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,34 @@
|
|||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
void ConnectionOperator::SendResponse(Connection const & connection, Http::Response const & response) const
|
||||||
|
{
|
||||||
|
auto bytesToSend = response.Serialize();
|
||||||
|
connection.WriteBytes(bytesToSend);
|
||||||
|
}
|
||||||
|
|
||||||
void ConnectionOperator::HandleNewConnection(Connection const & newConnection)
|
void ConnectionOperator::HandleNewConnection(Connection const & newConnection)
|
||||||
{
|
{
|
||||||
auto requestBytes = newConnection.ReadBytes();
|
auto requestBytes = newConnection.ReadBytes();
|
||||||
Http::Request request = Http::Request::Deserialize(requestBytes);
|
Http::Request request;
|
||||||
|
|
||||||
Http::Response response;
|
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)
|
for(size_t i = 0; i < middlewares.size(); ++i)
|
||||||
{
|
{
|
||||||
middlewares[i]->HandleRequest(request, response);
|
middlewares[i]->HandleRequest(request, response);
|
||||||
@@ -20,10 +42,15 @@ void ConnectionOperator::HandleNewConnection(Connection const & newConnection)
|
|||||||
if (response.code == HttpResponse::Code::UNKNOWN)
|
if (response.code == HttpResponse::Code::UNKNOWN)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss << "Unhandled request for file <";
|
ss << "Unhandled ";
|
||||||
ss << request.path;
|
ss << HttpRequest::typeStrings[static_cast<int>(request.requestType)];
|
||||||
|
ss << " request for file <";
|
||||||
|
ss << request.url.GetPath();
|
||||||
ss << '>';
|
ss << '>';
|
||||||
Logger::GetInstance().Error(ss.str());
|
Logger::GetInstance().Error(ss.str());
|
||||||
|
|
||||||
|
response.code = HttpResponse::Code::NOT_IMPLEMENTED;
|
||||||
|
SendResponse(newConnection, response);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ class ConnectionOperator
|
|||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<Middleware::BaseMiddleware>> middlewares;
|
std::vector<std::unique_ptr<Middleware::BaseMiddleware>> middlewares;
|
||||||
|
|
||||||
|
void SendResponse(Connection const & connection, Http::Response const & response) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void HandleNewConnection(Connection const & newConnection);
|
void HandleNewConnection(Connection const & newConnection);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
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;
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user