Use url parsing

This commit is contained in:
2019-06-15 20:52:40 +02:00
parent 22d5430e57
commit 71a7aa147c
10 changed files with 126 additions and 71 deletions

View File

@@ -27,8 +27,17 @@ namespace Http
std::string requestTypeString;
ss >> requestTypeString;
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;
ss >> httpProtocolString;

View File

@@ -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<char> const & bytes);
};

53
src/http/url.cpp Normal file
View 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
View 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);
};
}

View File

@@ -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(),

View File

@@ -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;
}

View File

@@ -6,12 +6,34 @@
#include <cstdio>
#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)
{
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<int>(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;
}

View File

@@ -10,6 +10,8 @@ class ConnectionOperator
private:
std::vector<std::unique_ptr<Middleware::BaseMiddleware>> middlewares;
void SendResponse(Connection const & connection, Http::Response const & response) const;
public:
void HandleNewConnection(Connection const & newConnection);

View File

@@ -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;
}

View File

@@ -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;
};