Implemented better testing and fixed skipepd frames

This commit is contained in:
Martino Ferrari
2026-07-01 16:39:34 +02:00
parent 7a326c5d78
commit 0bea41f866
46 changed files with 4358 additions and 1739 deletions
+53 -2
View File
@@ -199,6 +199,52 @@ bool WSServer::UpgradeHTTP(BasicTCPSocket *sock) {
if (strstr(hdrBuf, "\r\n\r\n") != static_cast<char *>(0)) { break; }
}
/* Origin validation (CSWSH / CSRF defence, RFC 6455 §10.2).
* If an Origin header is present, its host must match the Host header
* (same-origin). Non-browser clients (no Origin) are allowed. */
const char *originHdr = FindSubstr(hdrBuf, "Origin:");
if (originHdr != static_cast<const char *>(0)) {
originHdr += 7; /* skip "Origin:" */
while (*originHdr == ' ') { originHdr++; }
/* Extract the host part of Origin: "scheme://host[:port]" */
char originHost[256];
uint32 ohLen = 0u;
const char *op = originHdr;
/* Skip scheme:// */
const char *schemeEnd = strstr(op, "://");
if (schemeEnd != static_cast<const char *>(0)) { op = schemeEnd + 3; }
while (*op != '\r' && *op != '\n' && *op != '\0' &&
*op != '/' && ohLen < 255u) {
originHost[ohLen++] = *op++;
}
originHost[ohLen] = '\0';
/* Extract Host header value */
const char *hostHdr = FindSubstr(hdrBuf, "Host:");
if (hostHdr != static_cast<const char *>(0)) {
hostHdr += 5; /* skip "Host:" */
while (*hostHdr == ' ') { hostHdr++; }
char hostVal[256];
uint32 hvLen = 0u;
while (*hostHdr != '\r' && *hostHdr != '\n' &&
*hostHdr != '\0' && hvLen < 255u) {
hostVal[hvLen++] = *hostHdr++;
}
hostVal[hvLen] = '\0';
if (strcmp(originHost, hostVal) != 0) {
/* Cross-origin — reject the upgrade */
const char *forbidden =
"HTTP/1.1 403 Forbidden\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n"
"\r\nOrigin not allowed\r\n";
uint32 forbLen = static_cast<uint32>(strlen(forbidden));
(void) sock->Write(forbidden, forbLen);
return false;
}
}
}
/* Find Sec-WebSocket-Key */
const char *keyHdr = FindSubstr(hdrBuf, "Sec-WebSocket-Key:");
if (keyHdr == static_cast<const char *>(0)) { return false; }
@@ -246,8 +292,9 @@ void WSServer::ClientReadLoop(uint32 slotIdx) {
WSClientSlot &slot = clients[slotIdx];
BasicTCPSocket *sock = slot.sock;
/* Receive buffer (grows as needed by simple state machine) */
static const uint32 kRecvBuf = WS_MAX_RECV_PAYLOAD + 14u;
/* Receive buffer: WS_MAX_RECV_PAYLOAD + max header (14: 2 + 8 ext-length +
* 4 mask) + 1 spare byte for in-place NUL-termination of the payload. */
static const uint32 kRecvBuf = WS_MAX_RECV_PAYLOAD + 14u + 1u;
uint8 *buf = new uint8[kRecvBuf];
uint32 filled = 0u;
@@ -431,6 +478,9 @@ uint32 WSServer::AllocSlot(BasicTCPSocket *sock) {
void WSServer::FreeSlot(uint32 idx) {
if (idx >= WS_MAX_CLIENTS) { return; }
/* HI-5: acquire writeMutex before modifying active/sock to prevent
* use-after-free when BroadcastText/BroadcastBinary are iterating. */
(void) clients[idx].writeMutex.FastLock();
(void) clientsMutex.FastLock();
if (clients[idx].active) {
clients[idx].active = false;
@@ -442,6 +492,7 @@ void WSServer::FreeSlot(uint32 idx) {
if (numClients > 0u) { numClients--; }
}
clientsMutex.FastUnLock();
clients[idx].writeMutex.FastUnLock();
}
} /* namespace StreamHub */