/* static */ void OpWebSocket::Destroy(OpWebSocket** socket) { WS_NEW_DBG; WebSocketProtocol* obj = static_cast<WebSocketProtocol*>(*socket); if (obj->m_state != WS_CLOSED) obj->Stop(); *socket = NULL; SComm::SafeDestruction(obj); }
void HttpSocket<isServer>::onData(uS::Socket s, char *data, int length) { HttpSocket httpSocket(s); HttpSocket::Data *httpData = httpSocket.getData(); httpSocket.cork(true); if (httpData->contentLength) { httpData->missedDeadline = false; if (httpData->contentLength >= length) { getGroup<isServer>(s)->httpDataHandler(httpData->outstandingResponsesTail, data, length, httpData->contentLength -= length); return; } else { getGroup<isServer>(s)->httpDataHandler(httpData->outstandingResponsesTail, data, httpData->contentLength, 0); data += httpData->contentLength; length -= httpData->contentLength; httpData->contentLength = 0; } } if (FORCE_SLOW_PATH || httpData->httpBuffer.length()) { if (httpData->httpBuffer.length() + length > MAX_HEADER_BUFFER_SIZE) { httpSocket.onEnd(s); return; } httpData->httpBuffer.reserve(httpData->httpBuffer.length() + length + WebSocketProtocol<uWS::CLIENT>::CONSUME_POST_PADDING); httpData->httpBuffer.append(data, length); data = (char *) httpData->httpBuffer.data(); length = httpData->httpBuffer.length(); } char *end = data + length; char *cursor = data; *end = '\r'; Header headers[MAX_HEADERS]; do { char *lastCursor = cursor; if ((cursor = getHeaders(cursor, end, headers, MAX_HEADERS))) { HttpRequest req(headers); if (isServer) { headers->valueLength = std::max<int>(0, headers->valueLength - 9); httpData->missedDeadline = false; if (req.getHeader("upgrade", 7)) { if (getGroup<SERVER>(s)->httpUpgradeHandler) { getGroup<SERVER>(s)->httpUpgradeHandler(HttpSocket<isServer>(s), req); } else { Header secKey = req.getHeader("sec-websocket-key", 17); Header extensions = req.getHeader("sec-websocket-extensions", 24); Header subprotocol = req.getHeader("sec-websocket-protocol", 22); if (secKey.valueLength == 24) { bool perMessageDeflate; httpSocket.upgrade(secKey.value, extensions.value, extensions.valueLength, subprotocol.value, subprotocol.valueLength, &perMessageDeflate); getGroup<SERVER>(s)->removeHttpSocket(s); s.enterState<WebSocket<SERVER>>(new WebSocket<SERVER>::Data(perMessageDeflate, httpData)); getGroup<SERVER>(s)->addWebSocket(s); s.cork(true); getGroup<SERVER>(s)->connectionHandler(WebSocket<SERVER>(s), req); s.cork(false); delete httpData; } else { httpSocket.onEnd(s); } } return; } else { if (getGroup<SERVER>(s)->httpRequestHandler) { HttpResponse *res = HttpResponse::allocateResponse(httpSocket, httpData); if (httpData->outstandingResponsesTail) { httpData->outstandingResponsesTail->next = res; } else { httpData->outstandingResponsesHead = res; } httpData->outstandingResponsesTail = res; Header contentLength; if (req.getMethod() != HttpMethod::METHOD_GET && (contentLength = req.getHeader("content-length", 14))) { httpData->contentLength = atoi(contentLength.value); size_t bytesToRead = std::min<int>(httpData->contentLength, end - cursor); getGroup<SERVER>(s)->httpRequestHandler(res, req, cursor, bytesToRead, httpData->contentLength -= bytesToRead); cursor += bytesToRead; } else { getGroup<SERVER>(s)->httpRequestHandler(res, req, nullptr, 0, 0); } if (s.isClosed() || s.isShuttingDown()) { return; } } else { httpSocket.onEnd(s); return; } } } else { if (req.getHeader("upgrade", 7)) { s.enterState<WebSocket<CLIENT>>(new WebSocket<CLIENT>::Data(false, httpData)); httpSocket.cancelTimeout(); httpSocket.setUserData(httpData->httpUser); getGroup<CLIENT>(s)->addWebSocket(s); s.cork(true); getGroup<CLIENT>(s)->connectionHandler(WebSocket<CLIENT>(s), req); s.cork(false); if (!(s.isClosed() || s.isShuttingDown())) { WebSocketProtocol<CLIENT> *kws = (WebSocketProtocol<CLIENT> *) ((WebSocket<CLIENT>::Data *) s.getSocketData()); kws->consume(cursor, end - cursor, s); } delete httpData; } else { httpSocket.onEnd(s); } return; } } else { if (!httpData->httpBuffer.length()) { if (length > MAX_HEADER_BUFFER_SIZE) { httpSocket.onEnd(s); } else { httpData->httpBuffer.append(lastCursor, end - lastCursor); } } return; } } while(cursor != end); httpSocket.cork(false); httpData->httpBuffer.clear(); }
void WebSockets::addProtocol(const string& name, WebSocketProtocol& protocol) { protocol.setName(name); protocol.setProtocolIndex(protocols.size()); protocol.websockets = this; protocols.push_back(make_pair(name, &protocol)); }
void HTTPSocket<isServer>::onData(uS::Socket s, char *data, int length) { HTTPSocket httpSocket(s); HTTPSocket::Data *httpData = httpSocket.getData(); // 5k = force close! if (httpData->httpBuffer.length() + length > 1024 * 5) { httpSocket.onEnd(s); return; } httpData->httpBuffer.append(data, length); size_t endOfHTTPBuffer = httpData->httpBuffer.find("\r\n\r\n"); if (endOfHTTPBuffer != std::string::npos) { if (isServer) { HTTPParser httpParser = (char *) httpData->httpBuffer.data(); std::pair<char *, size_t> secKey = {}, extensions = {}, subprotocol = {}, path = httpParser.value; for (httpParser++; httpParser.key.second; httpParser++) { if (httpParser.key.second == 17 || httpParser.key.second == 24 || httpParser.key.second == 22) { // lowercase the key for (size_t i = 0; i < httpParser.key.second; i++) { httpParser.key.first[i] = tolower(httpParser.key.first[i]); } if (!strncmp(httpParser.key.first, "sec-websocket-key", httpParser.key.second)) { secKey = httpParser.value; } else if (!strncmp(httpParser.key.first, "sec-websocket-extensions", httpParser.key.second)) { extensions = httpParser.value; } else if (!strncmp(httpParser.key.first, "sec-websocket-protocol", httpParser.key.second)) { subprotocol = httpParser.value; } } } if (secKey.first && secKey.second == 24) { // this needs to be part of upgrade itself, and shared with Hub::upgrade! bool perMessageDeflate = false; std::string extensionsResponse; if (extensions.first) { Group<isServer> *group = (Group<isServer> *) s.getNodeData(s.getSocketData()); ExtensionsNegotiator<uWS::SERVER> extensionsNegotiator(group->extensionOptions); extensionsNegotiator.readOffer(std::string(extensions.first, extensions.second)); extensionsResponse = extensionsNegotiator.generateOffer(); if (extensionsNegotiator.getNegotiatedOptions() & PERMESSAGE_DEFLATE) { perMessageDeflate = true; } } if (httpSocket.upgrade(secKey.first, extensionsResponse.data(), extensionsResponse.length(), subprotocol.first, subprotocol.second)) { s.cancelTimeout(); s.enterState<WebSocket<SERVER>>(new WebSocket<SERVER>::Data(perMessageDeflate, httpData)); ((Group<SERVER> *) s.getSocketData()->nodeData)->addWebSocket(s); //s.cork(true); ((Group<SERVER> *) s.getSocketData()->nodeData)->connectionHandler(WebSocket<SERVER>(s), {path.first, subprotocol.first, path.second, subprotocol.second}); //s.cork(false); delete httpData; } } else { httpSocket.onEnd(s); } } else { httpData->httpBuffer.resize(httpData->httpBuffer.length() + WebSocketProtocol<uWS::CLIENT>::CONSUME_POST_PADDING); bool isUpgrade = false; HTTPParser httpParser = (char *) httpData->httpBuffer.data(); //std::pair<char *, size_t> secKey = {}, extensions = {}; for (httpParser++; httpParser.key.second; httpParser++) { if (httpParser.key.second == 7) { // lowercase the key for (size_t i = 0; i < httpParser.key.second; i++) { httpParser.key.first[i] = tolower(httpParser.key.first[i]); } // lowercase the value for (size_t i = 0; i < httpParser.value.second; i++) { httpParser.value.first[i] = tolower(httpParser.value.first[i]); } if (!strncmp(httpParser.key.first, "upgrade", httpParser.key.second)) { if (!strncmp(httpParser.value.first, "websocket", 9)) { isUpgrade = true; } break; } } } if (isUpgrade) { s.enterState<WebSocket<CLIENT>>(new WebSocket<CLIENT>::Data(false, httpData)); //s.cork(true); httpSocket.cancelTimeout(); httpSocket.setUserData(httpData->httpUser); ((Group<CLIENT> *) s.getSocketData()->nodeData)->addWebSocket(s); ((Group<CLIENT> *) s.getSocketData()->nodeData)->connectionHandler(WebSocket<CLIENT>(s), {nullptr, nullptr, 0, 0}); //s.cork(false); if (!(s.isClosed() || s.isShuttingDown())) { WebSocketProtocol<CLIENT> *kws = (WebSocketProtocol<CLIENT> *) ((WebSocket<CLIENT>::Data *) s.getSocketData()); kws->consume((char *) httpData->httpBuffer.data() + endOfHTTPBuffer + 4, httpData->httpBuffer.length() - endOfHTTPBuffer - 4 - WebSocketProtocol<uWS::CLIENT>::CONSUME_POST_PADDING, s); } delete httpData; } else { httpSocket.onEnd(s); } } } }