VWeb/Source/RequestHandler.cpp
2022-08-23 16:40:57 +02:00

106 lines
3.3 KiB
C++

#include "StringUtils.h"
#include <VWeb.h>
namespace VWeb {
HttpMethod StringToHTTPMethod(std::string &method) {
static std::unordered_map<std::string, HttpMethod> s_StringToMethodMap{
{"get", HttpMethod::GET}, {"head", HttpMethod::HEAD},
{"options", HttpMethod::OPTIONS}, {"post", HttpMethod::POST},
{"put", HttpMethod::PUT}, {"patch", HttpMethod::PATCH},
{"delete", HttpMethod::DELETE}, {"fallback", HttpMethod::FALLBACK},
};
String::ToLowerCase(method);
if (s_StringToMethodMap.contains(method))
return s_StringToMethodMap[method];
return s_StringToMethodMap["fallback"];
}
bool ParseRequest(Ref<Request> &request) {
std::istringstream resp(request->Body);
std::string line;
std::string::size_type index;
while (std::getline(resp, line) && line != "\r") {
index = line.find(':', 0);
if (index != std::string::npos) {
auto key = line.substr(0, index);
String::Trim(key);
request->Header(key).Add(String::TrimCopy(line.substr(index + 1)));
} else if (line.find("HTTP")) {
auto headers = String::Split(line, " ");
if (headers.size() != 3)
return false;
request->Method = StringToHTTPMethod(headers[0]);
request->URI = String::UrlDecode(headers[1]);
} else {
return false;
}
}
return true;
}
struct RequestJob : public WorkerJob {
Ref<Request> MRequest{};
Ref<Router> MRouter{};
Ref<MiddleWareHandler> MMiddleWareHandler{};
RequestHandler *MRequestHandler{nullptr};
void Execute() override {
if (!ParseRequest(MRequest)) {
fprintf(stderr, "[Request] >> Request failed to parse\n");
SocketUtils::Close(MRequest->ID);
return;
}
MRequest->CookieData = CreateRef<Cookies>();
MRequest->SessionData = CreateRef<Session>();
Ref<Response> response;
auto preValue = MMiddleWareHandler->HandlePre(MRequest);
if (preValue.has_value()) {
response = preValue.value();
response->SessionData = MRequest->SessionData;
response->CookieData = MRequest->CookieData;
} else {
response = MRouter->HandleRoute(MRequest);
}
MMiddleWareHandler->HandlePost(MRequest, response);
auto content = response->GetResponse();
MRequestHandler->AddSendResponse(
{0, (ssize_t)content.size(), MRequest->ID, content});
MMiddleWareHandler->Shutdown(MRequest, response);
}
};
RequestHandler::RequestHandler(const Ref<SocketManager> &manager)
: m_SocketManager(manager), m_MiddleWare(CreateRef<MiddleWareHandler>()) {
m_MiddleWare = CreateRef<MiddleWareHandler>();
}
void RequestHandler::InitThreads(int count) {
m_Pool.SetThreadCount(count);
m_Pool.Create();
}
void RequestHandler::AddRequest(Ref<Request> &request) {
if (m_Router) {
auto job = CreateRef<RequestJob>();
job->MRequest = request;
job->MMiddleWareHandler = m_MiddleWare;
job->MRequestHandler = this;
job->MRouter = m_Router;
m_Pool.Dispatch(job);
}
}
void RequestHandler::Stop() {
m_Pool.Stop();
}
void RequestHandler::SetRouter(Ref<Router> &router) {
m_Router = router;
}
void RequestHandler::AddSendResponse(SendData sendData) {
auto id = sendData.SocketID;
m_Server->m_OutRequest.Add(id, sendData);
if (!m_SocketManager->SetSendListen(id)) {
SocketUtils::Close(id);
m_Server->m_OutRequest.Remove(id);
}
}
} // namespace VWeb