99 lines
3.1 KiB
C++
99 lines
3.1 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>();
|
||
|
MMiddleWareHandler->HandlePre(MRequest);
|
||
|
auto 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
|