107 lines
2.3 KiB
C++
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());
|
|
}
|
|
} |