WebSocketImpl* WebSocket::completeHandshake(HTTPClientSession& cs, HTTPResponse& response, const std::string& key) { std::string connection = response.get("Connection", ""); if (Poco::icompare(connection, "Upgrade") != 0) throw WebSocketException("No Connection: Upgrade header in handshake response", WS_ERR_NO_HANDSHAKE); std::string upgrade = response.get("Upgrade", ""); if (Poco::icompare(upgrade, "websocket") != 0) throw WebSocketException("No Upgrade: websocket header in handshake response", WS_ERR_NO_HANDSHAKE); std::string accept = response.get("Sec-WebSocket-Accept", ""); if (accept != computeAccept(key)) throw WebSocketException("Invalid or missing Sec-WebSocket-Accept header in handshake response", WS_ERR_NO_HANDSHAKE); return new WebSocketImpl(static_cast<StreamSocketImpl*>(cs.socket().impl()), true); }
std::string WebSocketClientHeaderIETF_HYBI17::generateResponse(unsigned short port, const char *webSocketServerProtocolName) { bool secureFlag = false; std::string::size_type pos; std::string message; auto secWebSocketKeyIterator = fields.find("Sec-WebSocket-Key"); if(secWebSocketKeyIterator == fields.end()) { throw WebSocketException("No `Sec-WebSocket-Key` header found"); } std::string secWebSocketAccept = (*secWebSocketKeyIterator).second + std::string("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); secWebSocketAccept = StringUtil::SHA1(secWebSocketAccept); secWebSocketAccept = StringUtil::base64Encode(secWebSocketAccept); message.append("HTTP/1.1 101 Switching Protocols\r\n"); message.append("Upgrade: WebSocket\r\n"); message.append("Connection: Upgrade\r\n"); message.append(std::string("Sec-WebSocket-Accept: ") + secWebSocketAccept + std::string("\r\n")); message.append((webSocketServerProtocolName ? (std::string("Sec-WebSocket-Protocol: ") + std::string(webSocketServerProtocolName) + std::string("\r\n")) : "")); message.append("\r\n"); return message; }
void WebSocketClientHeaderIETF_HYBI17::read(std::string &packet) { std::string line; std::string::size_type startPos = 0, crlfPos; line = WebSocketClientHeader::getLine(packet, startPos, crlfPos); readFirstLine(line); //Read all of the fields. Field ending is denoted by a pair of CRLF. startPos = crlfPos + 2; do { line = WebSocketClientHeader::getLine(packet, startPos, crlfPos); readFieldLine(line); startPos = crlfPos + 2; if( (startPos + 2) > packet.size() ) { throw WebSocketException(INVALID_HEADER_EXCEPTION_MESSAGE); } } while(packet[startPos] != '\r' && packet[startPos + 1] != '\n'); //Skip over the last crlf. startPos += 2; packet.erase(0, startPos); }
WebSocketImpl* WebSocket::connect(HTTPClientSession& cs, HTTPRequest& request, HTTPResponse& response, HTTPCredentials& credentials) { if (!cs.getProxyHost().empty() && !cs.secure()) { cs.proxyTunnel(); } std::string key = createKey(); request.set("Connection", "Upgrade"); request.set("Upgrade", "websocket"); request.set("Sec-WebSocket-Version", WEBSOCKET_VERSION); request.set("Sec-WebSocket-Key", key); request.setChunkedTransferEncoding(false); cs.setKeepAlive(true); cs.sendRequest(request); std::istream& istr = cs.receiveResponse(response); if (response.getStatus() == HTTPResponse::HTTP_SWITCHING_PROTOCOLS) { return completeHandshake(cs, response, key); } else if (response.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED) { Poco::NullOutputStream null; Poco::StreamCopier::copyStream(istr, null); credentials.authenticate(request, response); if (!cs.getProxyHost().empty() && !cs.secure()) { cs.reset(); cs.proxyTunnel(); } cs.sendRequest(request); cs.receiveResponse(response); if (response.getStatus() == HTTPResponse::HTTP_SWITCHING_PROTOCOLS) { return completeHandshake(cs, response, key); } else if (response.getStatus() == HTTPResponse::HTTP_UNAUTHORIZED) { throw WebSocketException("Not authorized", WS_ERR_UNAUTHORIZED); } } throw WebSocketException("Cannot upgrade to WebSocket connection", response.getReason(), WS_ERR_NO_HANDSHAKE); }
WebSocketImpl* WebSocket::accept(HTTPServerRequest& request, HTTPServerResponse& response) { if (icompare(request.get("Connection", ""), "Upgrade") == 0 && icompare(request.get("Upgrade", ""), "websocket") == 0) { std::string version = request.get("Sec-WebSocket-Version", ""); if (version.empty()) throw WebSocketException("Missing Sec-WebSocket-Version in handshake request", WS_ERR_HANDSHAKE_NO_VERSION); if (version != WEBSOCKET_VERSION) throw WebSocketException("Unsupported WebSocket version requested", version, WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION); std::string key = request.get("Sec-WebSocket-Key", ""); Poco::trimInPlace(key); if (key.empty()) throw WebSocketException("Missing Sec-WebSocket-Key in handshake request", WS_ERR_HANDSHAKE_NO_KEY); response.setStatusAndReason(HTTPResponse::HTTP_SWITCHING_PROTOCOLS); response.set("Upgrade", "websocket"); response.set("Connection", "Upgrade"); response.set("Sec-WebSocket-Accept", computeAccept(key)); response.setContentLength(0); response.send().flush(); return new WebSocketImpl(static_cast<StreamSocketImpl*>(static_cast<HTTPServerRequestImpl&>(request).detachSocket().impl()), false); } else throw WebSocketException("No WebSocket handshake", WS_ERR_NO_HANDSHAKE); }