Files
http-server/src/middleware/staticcontent.cpp

107 lines
2.3 KiB
C++

#include "../http/mime.hpp"
#include "../logger.hpp"
#include <fstream>
#include <ios>
#include "staticcontent.hpp"
#include <sstream>
#include <unistd.h>
namespace Middleware
{
bool TryReadAllBytes(std::string const & filePath, std::vector<char> & buffer)
{
std::ifstream ifs(filePath, std::ios_base::binary | std::ios_base::ate);
if (!ifs.is_open())
{
return false;
}
std::ifstream::pos_type length = ifs.tellg();
auto const oldBufferSize = buffer.size();
buffer.resize(oldBufferSize + length);
ifs.seekg(0, std::ios_base::beg);
ifs.read(&buffer[oldBufferSize], length);
return true;
}
bool ContainsDoubleDots(std::string const & s)
{
bool previousWasDot = false;
for(unsigned i = 0; i < s.size(); ++i)
{
if (s[i] == '.')
{
if(previousWasDot)
{
return true;
}
previousWasDot = true;
}
else
{
previousWasDot = false;
}
}
return false;
}
void StaticContent::HandleRequest(State & state, ScheduleHelper & scheduleHelper)
{
if (!(state.request.type == HttpRequest::Type::GET || state.request.type == HttpRequest::Type::HEAD))
{
return;
}
std::string path;
if (state.request.url.HasPath())
{
path = root + state.request.url.GetPath();
}
else
{
// TODO make configurable?
path = root + "/index.html";
}
if (ContainsDoubleDots(state.request.url.GetPath()))
{
// We cannot deal with this, we are not going to bother checking if
// this double dot escapes our root directory
return;
}
if (access(path.c_str(), F_OK) != 0)
{
// File does not exist
return;
}
state.response.code = HttpResponse::Code::OK;
state.response.contentType = Http::GetMimeType(path);
// Regular file descriptors are not supported by epoll, so we have to "just read it"
if (state.request.type == HttpRequest::Type::GET && !TryReadAllBytes(path, state.response.content))
{
state.response.code = HttpResponse::Code::INTERNAL_SERVER_ERROR;
state.response.contentType = Http::GetMimeType("");
}
// HEAD request
state.finished = true;
return;
}
StaticContent::StaticContent(Logger & _logger, std::string const & staticFileRoot)
: BaseMiddleware(_logger),
root(staticFileRoot)
{
std::stringstream ss;
ss << "Using static file root " << root;
_logger.Info(ss.str());
}
}