void RFC6455::Client::HandleHandshake (const HTTP::Request& inRequest) { HTTP::Response response (HTTP::Code::BAD_REQUEST, inRequest.mVersion); bool isUpgraded (false); try { if (inRequest.GetHeaderValue ("Connection") == "Upgrade" && inRequest.GetHeaderValue ("Upgrade") == "websocket" && inRequest.GetHeaderValue ("Sec-WebSocket-Key") != "" && inRequest.mMethod == HTTP::Method::GET && inRequest.mVersion == HTTP::Version::V11 ) { const auto key (inRequest.GetHeaderValue ("Sec-WebSocket-Key")); const auto keyWithMagicString (key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); char base64[SHA1_BASE64_SIZE]; sha1 (keyWithMagicString.c_str ()).finalize().print_base64 (base64); response.SetHeader (HTTP::Header ("Connection", "Upgrade")); response.SetHeader (HTTP::Header ("Upgrade", "websocket")); response.SetHeader (HTTP::Header ("Sec-WebSocket-Accept", std::string (base64))); response.mCode = HTTP::Code::SWITCHING_PROTOCOLS; isUpgraded = true; } } catch (...) {} mResponseEncoder.Write (response); { using namespace HTTP; LOGINFO << "HTTP/" << VersionToString (response.mVersion) << " " << MethodToString (inRequest.mMethod) << " " << inRequest.mPath << " - " << response.mCode << " " << CodeToString (response.mCode) << " - RFC6455"; } if (!isUpgraded) { Quit (); } else { // Clear the stream, route the pipe through the frame decoder. GetReadStream ().Clear ().Pipe (mFrameDecoder).Pipe (this, &Client::HandleReceivedFrame); mResponseEncoder.Clear (); mPayloadStringEncoder.Pipe (mFrameEncoder).Pipe (GetWriteStream ()); mPayloadBinaryEncoder.Pipe (mFrameEncoder); } }
void SSE::Client::HandleHandshake (const HTTP::Request& inRequest) { HTTP::Response response (HTTP::Code::BAD_REQUEST, inRequest.mVersion); bool isUpgraded (false); try { if (inRequest.GetHeaderValue ("Accept") == "text/event-stream" && inRequest.mMethod == HTTP::Method::GET && inRequest.mVersion == HTTP::Version::V11 ) { // Standard SSE headers response.SetHeader (HTTP::Header ("Connection", "keep-alive")); response.SetHeader (HTTP::Header ("Content-Type", "text/event-stream")); // Prevent caching response.SetHeader (HTTP::Header ("Cache-Control", "no-cache")); // This SSE server most likely does not host the origin of the request // ==> Enable CORS. response.SetHeader (HTTP::Header ("Access-Control-Allow-Origin", "*")); response.SetHeader (HTTP::Header ("Access-Control-Allow-Credentials", "true")); // The response constructor sets the length to zero, this makes connections // assume there is no more data coming. Note: there is a stream in response, so the body // has variable length! Remove this header. response.RemoveHeaders ("Content-Length"); // Optionally check for last event ID. try { const auto list = inRequest.GetHeaders ("Last-Event-ID"); if (!list.empty ()) { uint8_t lastId = std::stoi (list[0].GetValue ()); mEventEncoder.SetLastId (lastId); } } catch (...) {} // Handshake completed. response.mCode = HTTP::Code::OK; isUpgraded = true; } } catch (...) {} // Send the handshake response mResponseEncoder.Write (response); { using namespace HTTP; LOGINFO << "HTTP/" << VersionToString (response.mVersion) << " " << MethodToString (inRequest.mMethod) << " " << inRequest.mPath << " - " << response.mCode << " " << CodeToString (response.mCode) << " - SSE"; } if (!isUpgraded) { Quit (); } else { // Clear the read stream (SSE only contains outgoing events) GetReadStream ().Clear (); mResponseEncoder.Clear (); mToStringConverter.Clear (); mToPacketConverter.Clear (); mRequestDecoder.Clear (); mResponseEncoder.Clear (); mEventEncoder.Pipe (mToPacketConverter).Pipe (GetWriteStream ()); } }