Implemented better testing and fixed skipepd frames
This commit is contained in:
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user