Refactor
This commit is contained in:
@@ -69,7 +69,7 @@ std::string GuessContentType(const std::filesystem::path& assetPath)
|
||||
}
|
||||
|
||||
ControlServer::ControlServer()
|
||||
: mListenSocket(INVALID_SOCKET), mPort(0), mRunning(false)
|
||||
: mPort(0), mRunning(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -86,15 +86,15 @@ bool ControlServer::Start(const std::filesystem::path& uiRoot, unsigned short pr
|
||||
if (!InitializeWinsock(error))
|
||||
return false;
|
||||
|
||||
mListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (mListenSocket == INVALID_SOCKET)
|
||||
mListenSocket.reset(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
|
||||
if (!mListenSocket.valid())
|
||||
{
|
||||
error = "Could not create listening socket.";
|
||||
return false;
|
||||
}
|
||||
|
||||
u_long nonBlocking = 1;
|
||||
ioctlsocket(mListenSocket, FIONBIO, &nonBlocking);
|
||||
ioctlsocket(mListenSocket.get(), FIONBIO, &nonBlocking);
|
||||
|
||||
sockaddr_in address = {};
|
||||
address.sin_family = AF_INET;
|
||||
@@ -104,7 +104,7 @@ bool ControlServer::Start(const std::filesystem::path& uiRoot, unsigned short pr
|
||||
for (unsigned short offset = 0; offset < 20; ++offset)
|
||||
{
|
||||
address.sin_port = htons(static_cast<u_short>(preferredPort + offset));
|
||||
if (bind(mListenSocket, reinterpret_cast<sockaddr*>(&address), sizeof(address)) == 0)
|
||||
if (bind(mListenSocket.get(), reinterpret_cast<sockaddr*>(&address), sizeof(address)) == 0)
|
||||
{
|
||||
mPort = preferredPort + offset;
|
||||
bound = true;
|
||||
@@ -115,16 +115,14 @@ bool ControlServer::Start(const std::filesystem::path& uiRoot, unsigned short pr
|
||||
if (!bound)
|
||||
{
|
||||
error = "Could not bind the local control server to any port in the preferred range.";
|
||||
closesocket(mListenSocket);
|
||||
mListenSocket = INVALID_SOCKET;
|
||||
mListenSocket.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (listen(mListenSocket, SOMAXCONN) != 0)
|
||||
if (listen(mListenSocket.get(), SOMAXCONN) != 0)
|
||||
{
|
||||
error = "Could not start listening on the local control server socket.";
|
||||
closesocket(mListenSocket);
|
||||
mListenSocket = INVALID_SOCKET;
|
||||
mListenSocket.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -135,27 +133,17 @@ bool ControlServer::Start(const std::filesystem::path& uiRoot, unsigned short pr
|
||||
|
||||
void ControlServer::Stop()
|
||||
{
|
||||
const bool wasActive = mRunning || mListenSocket != INVALID_SOCKET || mThread.joinable();
|
||||
const bool wasActive = mRunning || mListenSocket.valid() || mThread.joinable();
|
||||
mRunning = false;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
for (ClientConnection& client : mClients)
|
||||
{
|
||||
if (client.socket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(client.socket);
|
||||
client.socket = INVALID_SOCKET;
|
||||
}
|
||||
}
|
||||
client.socket.reset();
|
||||
mClients.clear();
|
||||
}
|
||||
|
||||
if (mListenSocket != INVALID_SOCKET)
|
||||
{
|
||||
closesocket(mListenSocket);
|
||||
mListenSocket = INVALID_SOCKET;
|
||||
}
|
||||
mListenSocket.reset();
|
||||
|
||||
if (mThread.joinable())
|
||||
mThread.join();
|
||||
@@ -179,30 +167,27 @@ void ControlServer::ServerLoop()
|
||||
}
|
||||
}
|
||||
|
||||
bool ControlServer::HandleHttpClient(SOCKET clientSocket)
|
||||
bool ControlServer::HandleHttpClient(UniqueSocket clientSocket)
|
||||
{
|
||||
std::string request;
|
||||
char buffer[8192];
|
||||
int received = recv(clientSocket, buffer, sizeof(buffer), 0);
|
||||
int received = recv(clientSocket.get(), buffer, sizeof(buffer), 0);
|
||||
if (received <= 0)
|
||||
return false;
|
||||
|
||||
request.assign(buffer, buffer + received);
|
||||
return HandleHttpRequest(clientSocket, request);
|
||||
return HandleHttpRequest(std::move(clientSocket), request);
|
||||
}
|
||||
|
||||
bool ControlServer::TryAcceptClient()
|
||||
{
|
||||
sockaddr_in clientAddress = {};
|
||||
int addressSize = sizeof(clientAddress);
|
||||
SOCKET clientSocket = accept(mListenSocket, reinterpret_cast<sockaddr*>(&clientAddress), &addressSize);
|
||||
if (clientSocket == INVALID_SOCKET)
|
||||
UniqueSocket clientSocket(accept(mListenSocket.get(), reinterpret_cast<sockaddr*>(&clientAddress), &addressSize));
|
||||
if (!clientSocket.valid())
|
||||
return false;
|
||||
|
||||
bool handled = HandleHttpClient(clientSocket);
|
||||
if (!handled)
|
||||
closesocket(clientSocket);
|
||||
return handled;
|
||||
return HandleHttpClient(std::move(clientSocket));
|
||||
}
|
||||
|
||||
bool ControlServer::SendHttpResponse(SOCKET clientSocket, const std::string& status, const std::string& contentType, const std::string& body)
|
||||
@@ -218,144 +203,181 @@ bool ControlServer::SendHttpResponse(SOCKET clientSocket, const std::string& sta
|
||||
return send(clientSocket, payload.c_str(), static_cast<int>(payload.size()), 0) == static_cast<int>(payload.size());
|
||||
}
|
||||
|
||||
bool ControlServer::HandleHttpRequest(SOCKET clientSocket, const std::string& request)
|
||||
bool ControlServer::SendHttpResponse(SOCKET clientSocket, const HttpResponse& response)
|
||||
{
|
||||
const std::string method = GetRequestMethod(request);
|
||||
const std::string path = GetRequestPath(request);
|
||||
return SendHttpResponse(clientSocket, response.status, response.contentType, response.body);
|
||||
}
|
||||
|
||||
if (ToLower(GetHeaderValue(request, "Upgrade")) == "websocket")
|
||||
return HandleWebSocketUpgrade(clientSocket, request);
|
||||
|
||||
if (method == "GET")
|
||||
bool ControlServer::HandleHttpRequest(UniqueSocket clientSocket, const std::string& request)
|
||||
{
|
||||
HttpRequest httpRequest;
|
||||
if (!ParseHttpRequest(request, httpRequest))
|
||||
{
|
||||
if (path == "/" || path == "/index.html")
|
||||
{
|
||||
std::string contentType;
|
||||
std::string body = LoadUiAsset("index.html", contentType);
|
||||
SendHttpResponse(clientSocket, "200 OK", contentType, body);
|
||||
closesocket(clientSocket);
|
||||
return true;
|
||||
}
|
||||
if (path == "/api/state")
|
||||
{
|
||||
SendHttpResponse(clientSocket, "200 OK", "application/json", mCallbacks.getStateJson ? mCallbacks.getStateJson() : "{}");
|
||||
closesocket(clientSocket);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string contentType;
|
||||
std::string body = LoadUiAsset(path.substr(1), contentType);
|
||||
if (!body.empty())
|
||||
{
|
||||
SendHttpResponse(clientSocket, "200 OK", contentType, body);
|
||||
closesocket(clientSocket);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else if (method == "POST")
|
||||
{
|
||||
std::string body = GetRequestBody(request);
|
||||
JsonValue root;
|
||||
std::string parseError;
|
||||
if (!ParseJson(body, root, parseError))
|
||||
{
|
||||
SendHttpResponse(clientSocket, "400 Bad Request", "application/json", BuildJsonResponse(false, parseError));
|
||||
closesocket(clientSocket);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool success = false;
|
||||
std::string actionError;
|
||||
|
||||
if (path == "/api/layers/add")
|
||||
{
|
||||
const JsonValue* shaderId = root.find("shaderId");
|
||||
success = shaderId && mCallbacks.addLayer && mCallbacks.addLayer(shaderId->asString(), actionError);
|
||||
}
|
||||
else if (path == "/api/layers/remove")
|
||||
{
|
||||
const JsonValue* layerId = root.find("layerId");
|
||||
success = layerId && mCallbacks.removeLayer && mCallbacks.removeLayer(layerId->asString(), actionError);
|
||||
}
|
||||
else if (path == "/api/layers/move")
|
||||
{
|
||||
const JsonValue* layerId = root.find("layerId");
|
||||
const JsonValue* direction = root.find("direction");
|
||||
if (layerId && direction && mCallbacks.moveLayer)
|
||||
success = mCallbacks.moveLayer(layerId->asString(), static_cast<int>(direction->asNumber()), actionError);
|
||||
}
|
||||
else if (path == "/api/layers/reorder")
|
||||
{
|
||||
const JsonValue* layerId = root.find("layerId");
|
||||
const JsonValue* targetIndex = root.find("targetIndex");
|
||||
if (layerId && targetIndex && mCallbacks.moveLayerToIndex)
|
||||
success = mCallbacks.moveLayerToIndex(layerId->asString(), static_cast<std::size_t>(targetIndex->asNumber()), actionError);
|
||||
}
|
||||
else if (path == "/api/layers/set-bypass")
|
||||
{
|
||||
const JsonValue* layerId = root.find("layerId");
|
||||
const JsonValue* bypass = root.find("bypass");
|
||||
if (layerId && bypass && mCallbacks.setLayerBypass)
|
||||
success = mCallbacks.setLayerBypass(layerId->asString(), bypass->asBoolean(), actionError);
|
||||
}
|
||||
else if (path == "/api/layers/set-shader")
|
||||
{
|
||||
const JsonValue* layerId = root.find("layerId");
|
||||
const JsonValue* shaderId = root.find("shaderId");
|
||||
if (layerId && shaderId && mCallbacks.setLayerShader)
|
||||
success = mCallbacks.setLayerShader(layerId->asString(), shaderId->asString(), actionError);
|
||||
}
|
||||
else if (path == "/api/layers/update-parameter")
|
||||
{
|
||||
const JsonValue* layerId = root.find("layerId");
|
||||
const JsonValue* parameterId = root.find("parameterId");
|
||||
const JsonValue* value = root.find("value");
|
||||
if (layerId && parameterId && value && mCallbacks.updateLayerParameter)
|
||||
success = mCallbacks.updateLayerParameter(layerId->asString(), parameterId->asString(), SerializeJson(*value, false), actionError);
|
||||
}
|
||||
else if (path == "/api/layers/reset-parameters")
|
||||
{
|
||||
const JsonValue* layerId = root.find("layerId");
|
||||
if (layerId && mCallbacks.resetLayerParameters)
|
||||
success = mCallbacks.resetLayerParameters(layerId->asString(), actionError);
|
||||
}
|
||||
else if (path == "/api/stack-presets/save")
|
||||
{
|
||||
const JsonValue* presetName = root.find("presetName");
|
||||
if (presetName && mCallbacks.saveStackPreset)
|
||||
success = mCallbacks.saveStackPreset(presetName->asString(), actionError);
|
||||
}
|
||||
else if (path == "/api/stack-presets/load")
|
||||
{
|
||||
const JsonValue* presetName = root.find("presetName");
|
||||
if (presetName && mCallbacks.loadStackPreset)
|
||||
success = mCallbacks.loadStackPreset(presetName->asString(), actionError);
|
||||
}
|
||||
else if (path == "/api/reload")
|
||||
{
|
||||
if (mCallbacks.reloadShader)
|
||||
success = mCallbacks.reloadShader(actionError);
|
||||
}
|
||||
|
||||
SendHttpResponse(clientSocket, success ? "200 OK" : "400 Bad Request", "application/json", BuildJsonResponse(success, actionError));
|
||||
closesocket(clientSocket);
|
||||
if (success)
|
||||
BroadcastState();
|
||||
SendHttpResponse(clientSocket.get(), "400 Bad Request", "text/plain", "Bad Request");
|
||||
return true;
|
||||
}
|
||||
|
||||
SendHttpResponse(clientSocket, "404 Not Found", "text/plain", "Not Found");
|
||||
closesocket(clientSocket);
|
||||
if (ToLower(GetHeaderValue(httpRequest, "Upgrade")) == "websocket")
|
||||
return HandleWebSocketUpgrade(std::move(clientSocket), httpRequest);
|
||||
|
||||
const HttpResponse response = RouteHttpRequest(httpRequest);
|
||||
SendHttpResponse(clientSocket.get(), response);
|
||||
if (response.broadcastState)
|
||||
BroadcastState();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ControlServer::HandleWebSocketUpgrade(SOCKET clientSocket, const std::string& request)
|
||||
ControlServer::HttpResponse ControlServer::RouteHttpRequest(const HttpRequest& request)
|
||||
{
|
||||
if (request.method == "GET")
|
||||
return ServeGetRequest(request);
|
||||
|
||||
if (request.method == "POST")
|
||||
return HandleApiPost(request);
|
||||
|
||||
return { "404 Not Found", "text/plain", "Not Found" };
|
||||
}
|
||||
|
||||
ControlServer::HttpResponse ControlServer::ServeGetRequest(const HttpRequest& request) const
|
||||
{
|
||||
if (request.path == "/" || request.path == "/index.html")
|
||||
return ServeUiAsset("index.html");
|
||||
|
||||
if (request.path == "/api/state")
|
||||
return { "200 OK", "application/json", mCallbacks.getStateJson ? mCallbacks.getStateJson() : "{}" };
|
||||
|
||||
if (request.path.size() > 1)
|
||||
{
|
||||
const HttpResponse assetResponse = ServeUiAsset(request.path.substr(1));
|
||||
if (!assetResponse.body.empty())
|
||||
return assetResponse;
|
||||
}
|
||||
|
||||
return { "404 Not Found", "text/plain", "Not Found" };
|
||||
}
|
||||
|
||||
ControlServer::HttpResponse ControlServer::ServeUiAsset(const std::string& relativePath) const
|
||||
{
|
||||
std::string contentType;
|
||||
const std::string body = LoadUiAsset(relativePath, contentType);
|
||||
return body.empty()
|
||||
? HttpResponse{ "404 Not Found", "text/plain", "Not Found" }
|
||||
: HttpResponse{ "200 OK", contentType, body };
|
||||
}
|
||||
|
||||
ControlServer::HttpResponse ControlServer::HandleApiPost(const HttpRequest& request)
|
||||
{
|
||||
JsonValue root;
|
||||
std::string parseError;
|
||||
if (!ParseJson(request.body, root, parseError))
|
||||
return { "400 Bad Request", "application/json", BuildJsonResponse(false, parseError) };
|
||||
|
||||
std::string actionError;
|
||||
const bool success = InvokePostRoute(request.path, root, actionError);
|
||||
return {
|
||||
success ? "200 OK" : "400 Bad Request",
|
||||
"application/json",
|
||||
BuildJsonResponse(success, actionError),
|
||||
success
|
||||
};
|
||||
}
|
||||
|
||||
bool ControlServer::InvokePostRoute(const std::string& path, const JsonValue& root, std::string& actionError)
|
||||
{
|
||||
using PostHandler = std::function<bool(const JsonValue&, std::string&)>;
|
||||
const std::map<std::string, PostHandler> postRoutes =
|
||||
{
|
||||
{ "/api/layers/add", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* shaderId = json.find("shaderId");
|
||||
return shaderId && mCallbacks.addLayer && mCallbacks.addLayer(shaderId->asString(), error);
|
||||
}
|
||||
},
|
||||
{ "/api/layers/remove", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* layerId = json.find("layerId");
|
||||
return layerId && mCallbacks.removeLayer && mCallbacks.removeLayer(layerId->asString(), error);
|
||||
}
|
||||
},
|
||||
{ "/api/layers/move", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* layerId = json.find("layerId");
|
||||
const JsonValue* direction = json.find("direction");
|
||||
return layerId && direction && mCallbacks.moveLayer &&
|
||||
mCallbacks.moveLayer(layerId->asString(), static_cast<int>(direction->asNumber()), error);
|
||||
}
|
||||
},
|
||||
{ "/api/layers/reorder", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* layerId = json.find("layerId");
|
||||
const JsonValue* targetIndex = json.find("targetIndex");
|
||||
return layerId && targetIndex && mCallbacks.moveLayerToIndex &&
|
||||
mCallbacks.moveLayerToIndex(layerId->asString(), static_cast<std::size_t>(targetIndex->asNumber()), error);
|
||||
}
|
||||
},
|
||||
{ "/api/layers/set-bypass", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* layerId = json.find("layerId");
|
||||
const JsonValue* bypass = json.find("bypass");
|
||||
return layerId && bypass && mCallbacks.setLayerBypass &&
|
||||
mCallbacks.setLayerBypass(layerId->asString(), bypass->asBoolean(), error);
|
||||
}
|
||||
},
|
||||
{ "/api/layers/set-shader", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* layerId = json.find("layerId");
|
||||
const JsonValue* shaderId = json.find("shaderId");
|
||||
return layerId && shaderId && mCallbacks.setLayerShader &&
|
||||
mCallbacks.setLayerShader(layerId->asString(), shaderId->asString(), error);
|
||||
}
|
||||
},
|
||||
{ "/api/layers/update-parameter", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* layerId = json.find("layerId");
|
||||
const JsonValue* parameterId = json.find("parameterId");
|
||||
const JsonValue* value = json.find("value");
|
||||
return layerId && parameterId && value && mCallbacks.updateLayerParameter &&
|
||||
mCallbacks.updateLayerParameter(layerId->asString(), parameterId->asString(), SerializeJson(*value, false), error);
|
||||
}
|
||||
},
|
||||
{ "/api/layers/reset-parameters", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* layerId = json.find("layerId");
|
||||
return layerId && mCallbacks.resetLayerParameters &&
|
||||
mCallbacks.resetLayerParameters(layerId->asString(), error);
|
||||
}
|
||||
},
|
||||
{ "/api/stack-presets/save", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* presetName = json.find("presetName");
|
||||
return presetName && mCallbacks.saveStackPreset &&
|
||||
mCallbacks.saveStackPreset(presetName->asString(), error);
|
||||
}
|
||||
},
|
||||
{ "/api/stack-presets/load", [this](const JsonValue& json, std::string& error)
|
||||
{
|
||||
const JsonValue* presetName = json.find("presetName");
|
||||
return presetName && mCallbacks.loadStackPreset &&
|
||||
mCallbacks.loadStackPreset(presetName->asString(), error);
|
||||
}
|
||||
},
|
||||
{ "/api/reload", [this](const JsonValue&, std::string& error)
|
||||
{
|
||||
return mCallbacks.reloadShader && mCallbacks.reloadShader(error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const auto route = postRoutes.find(path);
|
||||
return route != postRoutes.end() && route->second(root, actionError);
|
||||
}
|
||||
|
||||
bool ControlServer::HandleWebSocketUpgrade(UniqueSocket clientSocket, const HttpRequest& request)
|
||||
{
|
||||
const std::string clientKey = GetHeaderValue(request, "Sec-WebSocket-Key");
|
||||
if (clientKey.empty())
|
||||
{
|
||||
SendHttpResponse(clientSocket, "400 Bad Request", "text/plain", "Missing Sec-WebSocket-Key");
|
||||
closesocket(clientSocket);
|
||||
SendHttpResponse(clientSocket.get(), "400 Bad Request", "text/plain", "Missing Sec-WebSocket-Key");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -366,14 +388,14 @@ bool ControlServer::HandleWebSocketUpgrade(SOCKET clientSocket, const std::strin
|
||||
response << "Sec-WebSocket-Accept: " << ComputeWebSocketAcceptKey(clientKey) << "\r\n\r\n";
|
||||
|
||||
const std::string payload = response.str();
|
||||
send(clientSocket, payload.c_str(), static_cast<int>(payload.size()), 0);
|
||||
send(clientSocket.get(), payload.c_str(), static_cast<int>(payload.size()), 0);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mMutex);
|
||||
ClientConnection client;
|
||||
client.socket = clientSocket;
|
||||
client.socket.reset(clientSocket.release());
|
||||
client.websocket = true;
|
||||
mClients.push_back(client);
|
||||
mClients.push_back(std::move(client));
|
||||
BroadcastStateLocked();
|
||||
}
|
||||
return true;
|
||||
@@ -409,9 +431,8 @@ void ControlServer::BroadcastStateLocked()
|
||||
const std::string stateMessage = mCallbacks.getStateJson ? mCallbacks.getStateJson() : "{}";
|
||||
for (auto it = mClients.begin(); it != mClients.end();)
|
||||
{
|
||||
if (!SendWebSocketText(it->socket, stateMessage))
|
||||
if (!SendWebSocketText(it->socket.get(), stateMessage))
|
||||
{
|
||||
closesocket(it->socket);
|
||||
it = mClients.erase(it);
|
||||
}
|
||||
else
|
||||
@@ -480,46 +501,55 @@ std::string ControlServer::ComputeWebSocketAcceptKey(const std::string& clientKe
|
||||
return Base64Encode(digest, digestLength);
|
||||
}
|
||||
|
||||
std::string ControlServer::GetHeaderValue(const std::string& request, const std::string& headerName)
|
||||
std::string ControlServer::GetHeaderValue(const HttpRequest& request, const std::string& headerName)
|
||||
{
|
||||
const std::string lowerRequest = ToLower(request);
|
||||
const std::string lowerHeaderName = ToLower(headerName) + ":";
|
||||
const std::size_t start = lowerRequest.find(lowerHeaderName);
|
||||
if (start == std::string::npos)
|
||||
return std::string();
|
||||
|
||||
const std::size_t valueStart = start + lowerHeaderName.size();
|
||||
const std::size_t lineEnd = request.find("\r\n", valueStart);
|
||||
if (lineEnd == std::string::npos)
|
||||
return std::string();
|
||||
|
||||
std::string value = request.substr(valueStart, lineEnd - valueStart);
|
||||
const std::size_t first = value.find_first_not_of(" \t");
|
||||
const std::size_t last = value.find_last_not_of(" \t");
|
||||
return first == std::string::npos ? std::string() : value.substr(first, last - first + 1);
|
||||
const auto header = request.headers.find(ToLower(headerName));
|
||||
return header == request.headers.end() ? std::string() : header->second;
|
||||
}
|
||||
|
||||
std::string ControlServer::GetRequestPath(const std::string& request)
|
||||
bool ControlServer::ParseHttpRequest(const std::string& rawRequest, HttpRequest& request)
|
||||
{
|
||||
const std::size_t methodEnd = request.find(' ');
|
||||
const std::size_t requestLineEnd = rawRequest.find("\r\n");
|
||||
if (requestLineEnd == std::string::npos)
|
||||
return false;
|
||||
|
||||
const std::string requestLine = rawRequest.substr(0, requestLineEnd);
|
||||
const std::size_t methodEnd = requestLine.find(' ');
|
||||
if (methodEnd == std::string::npos)
|
||||
return "/";
|
||||
const std::size_t pathEnd = request.find(' ', methodEnd + 1);
|
||||
return false;
|
||||
|
||||
const std::size_t pathEnd = requestLine.find(' ', methodEnd + 1);
|
||||
if (pathEnd == std::string::npos)
|
||||
return "/";
|
||||
return request.substr(methodEnd + 1, pathEnd - methodEnd - 1);
|
||||
}
|
||||
return false;
|
||||
|
||||
std::string ControlServer::GetRequestMethod(const std::string& request)
|
||||
{
|
||||
const std::size_t methodEnd = request.find(' ');
|
||||
return methodEnd == std::string::npos ? std::string() : request.substr(0, methodEnd);
|
||||
}
|
||||
request.method = requestLine.substr(0, methodEnd);
|
||||
request.path = requestLine.substr(methodEnd + 1, pathEnd - methodEnd - 1);
|
||||
request.headers.clear();
|
||||
|
||||
std::string ControlServer::GetRequestBody(const std::string& request)
|
||||
{
|
||||
const std::size_t separator = request.find("\r\n\r\n");
|
||||
if (separator == std::string::npos)
|
||||
return std::string();
|
||||
return request.substr(separator + 4);
|
||||
const std::size_t headersStart = requestLineEnd + 2;
|
||||
const std::size_t bodySeparator = rawRequest.find("\r\n\r\n", headersStart);
|
||||
const std::size_t headersEnd = bodySeparator == std::string::npos ? rawRequest.size() : bodySeparator;
|
||||
|
||||
for (std::size_t lineStart = headersStart; lineStart < headersEnd;)
|
||||
{
|
||||
const std::size_t lineEnd = rawRequest.find("\r\n", lineStart);
|
||||
const std::size_t currentLineEnd = lineEnd == std::string::npos ? headersEnd : std::min(lineEnd, headersEnd);
|
||||
const std::string line = rawRequest.substr(lineStart, currentLineEnd - lineStart);
|
||||
const std::size_t separator = line.find(':');
|
||||
if (separator != std::string::npos)
|
||||
{
|
||||
const std::string key = ToLower(line.substr(0, separator));
|
||||
std::string value = line.substr(separator + 1);
|
||||
const std::size_t first = value.find_first_not_of(" \t");
|
||||
const std::size_t last = value.find_last_not_of(" \t");
|
||||
request.headers[key] = first == std::string::npos ? std::string() : value.substr(first, last - first + 1);
|
||||
}
|
||||
|
||||
if (lineEnd == std::string::npos || lineEnd >= headersEnd)
|
||||
break;
|
||||
lineStart = lineEnd + 2;
|
||||
}
|
||||
|
||||
request.body = bodySeparator == std::string::npos ? std::string() : rawRequest.substr(bodySeparator + 4);
|
||||
return !request.method.empty() && !request.path.empty();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user