/*! \internal Called with an incoming connection */ void QJsonServer::handleLocalConnection() { QLocalServer *server = qobject_cast<QLocalServer *>(sender()); if (!server) return; if (QLocalSocket *socket = server->nextPendingConnection()) { socket->setReadBufferSize(64*1024); Q_D(QJsonServer); QJsonAuthority *authority = d->m_localServers.value(server); QJsonServerClient *client = new QJsonServerClient(this); client->setAuthority(authority); client->setSocket(socket); connect(client, SIGNAL(authorized(const QString&)), this, SLOT(handleClientAuthorized(const QString&))); connect(client, SIGNAL(disconnected(const QString&)), this, SLOT(clientDisconnected(const QString&))); connect(client, SIGNAL(messageReceived(const QString&, const QJsonObject&)), this, SLOT(receiveMessage(const QString&, const QJsonObject&))); connect(client, SIGNAL(authorizationFailed()), this, SLOT(handleAuthorizationFailed())); client->start(); }
/** * handles http header reading for WebSocket upgrade * @param client WSclient_t * ///< pointer to the client struct * @param headerLine String ///< the header being read / processed */ void WebSocketsServer::handleHeader(WSclient_t * client, String * headerLine) { headerLine->trim(); // remove \r if(headerLine->length() > 0) { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] RX: %s\n", client->num, headerLine->c_str()); // websocket requests always start with GET see rfc6455 if(headerLine->startsWith("GET ")) { // cut URL out client->cUrl = headerLine->substring(4, headerLine->indexOf(' ', 4)); //reset non-websocket http header validation state for this client client->cHttpHeadersValid = true; client->cMandatoryHeadersCount = 0; } else if(headerLine->indexOf(':')) { String headerName = headerLine->substring(0, headerLine->indexOf(':')); String headerValue = headerLine->substring(headerLine->indexOf(':') + 2); if(headerName.equalsIgnoreCase("Connection")) { headerValue.toLowerCase(); if(headerValue.indexOf("upgrade") >= 0) { client->cIsUpgrade = true; } } else if(headerName.equalsIgnoreCase("Upgrade")) { if(headerValue.equalsIgnoreCase("websocket")) { client->cIsWebsocket = true; } } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Version")) { client->cVersion = headerValue.toInt(); } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Key")) { client->cKey = headerValue; client->cKey.trim(); // see rfc6455 } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Protocol")) { client->cProtocol = headerValue; } else if(headerName.equalsIgnoreCase("Sec-WebSocket-Extensions")) { client->cExtensions = headerValue; } else if(headerName.equalsIgnoreCase("Authorization")) { client->base64Authorization = headerValue; } else { client->cHttpHeadersValid &= execHttpHeaderValidation(headerName, headerValue); if (_mandatoryHttpHeaderCount > 0 && hasMandatoryHeader(headerName)) { client->cMandatoryHeadersCount++; } } } else { DEBUG_WEBSOCKETS("[WS-Client][handleHeader] Header error (%s)\n", headerLine->c_str()); } (*headerLine) = ""; #if (WEBSOCKETS_NETWORK_TYPE == NETWORK_ESP8266_ASYNC) client->tcp->readStringUntil('\n', &(client->cHttpLine), std::bind(&WebSocketsServer::handleHeader, this, client, &(client->cHttpLine))); #endif } else { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Header read fin.\n", client->num); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cURL: %s\n", client->num, client->cUrl.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsUpgrade: %d\n", client->num, client->cIsUpgrade); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cIsWebsocket: %d\n", client->num, client->cIsWebsocket); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cKey: %s\n", client->num, client->cKey.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cProtocol: %s\n", client->num, client->cProtocol.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cExtensions: %s\n", client->num, client->cExtensions.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cVersion: %d\n", client->num, client->cVersion); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - base64Authorization: %s\n", client->num, client->base64Authorization.c_str()); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cHttpHeadersValid: %d\n", client->num, client->cHttpHeadersValid); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - cMandatoryHeadersCount: %d\n", client->num, client->cMandatoryHeadersCount); bool ok = (client->cIsUpgrade && client->cIsWebsocket); if(ok) { if(client->cUrl.length() == 0) { ok = false; } if(client->cKey.length() == 0) { ok = false; } if(client->cVersion != 13) { ok = false; } if(!client->cHttpHeadersValid) { ok = false; } if (client->cMandatoryHeadersCount != _mandatoryHttpHeaderCount) { ok = false; } } if(_base64Authorization.length() > 0) { if(client->base64Authorization.length() > 0) { String auth = "Basic "; auth += _base64Authorization; if(auth != client->base64Authorization) { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] HTTP Authorization failed!\n", client->num); handleAuthorizationFailed(client); return; } } else { ok = false; } } if(ok) { DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] Websocket connection incoming.\n", client->num); // generate Sec-WebSocket-Accept key String sKey = acceptKey(client->cKey); DEBUG_WEBSOCKETS("[WS-Server][%d][handleHeader] - sKey: %s\n", client->num, sKey.c_str()); client->status = WSC_CONNECTED; client->tcp->write("HTTP/1.1 101 Switching Protocols\r\n" "Server: arduino-WebSocketsServer\r\n" "Upgrade: websocket\r\n" "Connection: Upgrade\r\n" "Sec-WebSocket-Version: 13\r\n" "Sec-WebSocket-Accept: "); client->tcp->write(sKey.c_str(), sKey.length()); if(_origin.length() > 0) { String origin = "\r\nAccess-Control-Allow-Origin: "; origin += _origin; origin += "\r\n"; client->tcp->write(origin.c_str(), origin.length()); } if(client->cProtocol.length() > 0) { String protocol = "\r\nSec-WebSocket-Protocol: "; protocol += _protocol; protocol += "\r\n"; client->tcp->write(protocol.c_str(), protocol.length()); } else { client->tcp->write("\r\n"); } // header end client->tcp->write("\r\n"); headerDone(client); // send ping WebSockets::sendFrame(client, WSop_ping); runCbEvent(client->num, WStype_CONNECTED, (uint8_t *) client->cUrl.c_str(), client->cUrl.length()); } else { handleNonWebsocketConnection(client); } } }