| // Copyright 2013 The Chromium Authors. All rights reserved. | |
| /* Modifications: Copyright 2017 The Cobalt Authors. All Rights Reserved. | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include "cobalt/websocket/web_socket_handshake_helper.h" | |
| #include "base/strings/string_piece.h" | |
| #include "net/http/http_request_headers.h" | |
| #include "net/http/http_util.h" | |
| #include "net/websockets/websocket_frame.h" | |
| #include "starboard/memory.h" | |
| #include "testing/gtest/include/gtest/gtest.h" | |
| #include "url/gurl.h" | |
| namespace { | |
| using cobalt::websocket::SecWebSocketKey; | |
| SecWebSocketKey NullMaskingKeyGenerator() { | |
| SecWebSocketKey::SecWebSocketKeyBytes key_bytes; | |
| memset(&key_bytes, 0, sizeof(key_bytes)); | |
| return SecWebSocketKey(key_bytes); | |
| } | |
| std::vector<net::HttpRequestHeaders::HeaderKeyValuePair> RequestHeadersToVector( | |
| const net::HttpRequestHeaders &headers) { | |
| net::HttpRequestHeaders::Iterator it(headers); | |
| std::vector<net::HttpRequestHeaders::HeaderKeyValuePair> result; | |
| while (it.GetNext()) | |
| result.push_back( | |
| net::HttpRequestHeaders::HeaderKeyValuePair(it.name(), it.value())); | |
| return result; | |
| } | |
| const char kTestUserAgent[] = | |
| "Mozilla/5.0 (X11; Linux x86_64) Cobalt/9.27875-debug (unlike Gecko) " | |
| "Starboard/2"; | |
| } // namespace | |
| namespace net { | |
| bool operator==(const HttpRequestHeaders::HeaderKeyValuePair &lhs, | |
| const HttpRequestHeaders::HeaderKeyValuePair &rhs) { | |
| return (lhs.key == rhs.key) && (lhs.value == rhs.value); | |
| } | |
| std::ostream &operator<<(std::ostream &os, | |
| const HttpRequestHeaders::HeaderKeyValuePair &obj) { | |
| os << obj.key << ":" << obj.value; | |
| return os; | |
| } | |
| } // namespace net | |
| namespace cobalt { | |
| namespace websocket { | |
| class WebSocketHandshakeHelperTest : public ::testing::Test { | |
| public: | |
| WebSocketHandshakeHelperTest() | |
| : handshake_helper_(kTestUserAgent, &NullMaskingKeyGenerator) {} | |
| WebSocketHandshakeHelper handshake_helper_; | |
| std::vector<std::string> sub_protocols_; | |
| }; | |
| TEST_F(WebSocketHandshakeHelperTest, null_key) { | |
| EXPECT_EQ(static_cast<int>(SecWebSocketKey::kKeySizeInBytes), 16); | |
| handshake_helper_.GenerateSecWebSocketKey(); | |
| std::string null_key(SecWebSocketKey::kKeySizeInBytes, '\0'); | |
| EXPECT_EQ( | |
| memcmp(null_key.data(), | |
| handshake_helper_.sec_websocket_key_.GetRawKeyBytes(), | |
| SecWebSocketKey::kKeySizeInBytes), | |
| 0); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, HandshakeInfo) { | |
| std::string handshake_request; | |
| GURL localhost_websocket_endpoint("ws://localhost/"); | |
| handshake_helper_.GenerateHandshakeRequest(localhost_websocket_endpoint, | |
| "http://localhost", sub_protocols_, | |
| &handshake_request); | |
| char end_of_line[] = "\r\n"; | |
| std::size_t first_line_end = handshake_request.find(end_of_line); | |
| ASSERT_NE(first_line_end, std::string::npos); | |
| net::HttpRequestHeaders headers; | |
| base::StringPiece handshake_request_stringpiece( | |
| handshake_request.data() + first_line_end + sizeof(end_of_line) - 1); | |
| headers.AddHeadersFromString(handshake_request_stringpiece); | |
| std::vector<net::HttpRequestHeaders::HeaderKeyValuePair> request_headers = | |
| RequestHeadersToVector(headers); | |
| typedef net::HttpRequestHeaders::HeaderKeyValuePair HeaderKeyValuePair; | |
| ASSERT_EQ(10u, request_headers.size()); | |
| EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]); | |
| EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); | |
| EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); | |
| EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), | |
| request_headers[3]); | |
| EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", ""), | |
| request_headers[5]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), | |
| request_headers[6]); | |
| EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"), | |
| request_headers[7]); | |
| EXPECT_EQ("Sec-WebSocket-Key", request_headers[8].key); | |
| EXPECT_EQ(HeaderKeyValuePair("User-Agent", kTestUserAgent), | |
| request_headers[9]); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, HandshakeWithPort) { | |
| std::string handshake_request; | |
| GURL localhost_websocket_endpoint("ws://localhost:4541/"); | |
| handshake_helper_.GenerateHandshakeRequest(localhost_websocket_endpoint, | |
| "http://localhost", sub_protocols_, | |
| &handshake_request); | |
| char end_of_line[] = "\r\n"; | |
| std::size_t first_line_end = handshake_request.find(end_of_line); | |
| ASSERT_NE(first_line_end, std::string::npos); | |
| net::HttpRequestHeaders headers; | |
| base::StringPiece handshake_request_stringpiece( | |
| handshake_request.data() + first_line_end + sizeof(end_of_line) - 1); | |
| headers.AddHeadersFromString(handshake_request_stringpiece); | |
| std::vector<net::HttpRequestHeaders::HeaderKeyValuePair> request_headers = | |
| RequestHeadersToVector(headers); | |
| typedef net::HttpRequestHeaders::HeaderKeyValuePair HeaderKeyValuePair; | |
| ASSERT_EQ(10u, request_headers.size()); | |
| EXPECT_EQ(HeaderKeyValuePair("Host", "localhost:4541"), request_headers[0]); | |
| EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); | |
| EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); | |
| EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), | |
| request_headers[3]); | |
| EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", ""), | |
| request_headers[5]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), | |
| request_headers[6]); | |
| EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"), | |
| request_headers[7]); | |
| EXPECT_EQ("Sec-WebSocket-Key", request_headers[8].key); | |
| EXPECT_EQ(HeaderKeyValuePair("User-Agent", kTestUserAgent), | |
| request_headers[9]); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, HandshakePath) { | |
| std::string handshake_request; | |
| GURL localhost_websocket_endpoint("ws://localhost:4541/abc-def"); | |
| handshake_helper_.GenerateHandshakeRequest(localhost_websocket_endpoint, | |
| "http://localhost", sub_protocols_, | |
| &handshake_request); | |
| char end_of_line[] = "\r\n"; | |
| std::size_t first_line_end = handshake_request.find(end_of_line); | |
| ASSERT_NE(first_line_end, std::string::npos); | |
| std::string http_GET_line = handshake_request.substr(0, first_line_end); | |
| EXPECT_EQ(http_GET_line, "GET /abc-def HTTP/1.1"); | |
| net::HttpRequestHeaders headers; | |
| base::StringPiece handshake_request_stringpiece( | |
| handshake_request.data() + first_line_end + sizeof(end_of_line) - 1); | |
| headers.AddHeadersFromString(handshake_request_stringpiece); | |
| std::vector<net::HttpRequestHeaders::HeaderKeyValuePair> request_headers = | |
| RequestHeadersToVector(headers); | |
| typedef net::HttpRequestHeaders::HeaderKeyValuePair HeaderKeyValuePair; | |
| ASSERT_EQ(10u, request_headers.size()); | |
| EXPECT_EQ(HeaderKeyValuePair("Host", "localhost:4541"), request_headers[0]); | |
| EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); | |
| EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); | |
| EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), | |
| request_headers[3]); | |
| EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", ""), | |
| request_headers[5]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), | |
| request_headers[6]); | |
| EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"), | |
| request_headers[7]); | |
| EXPECT_EQ("Sec-WebSocket-Key", request_headers[8].key); | |
| EXPECT_EQ(HeaderKeyValuePair("User-Agent", kTestUserAgent), | |
| request_headers[9]); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, HandshakePathWithQuery) { | |
| std::string handshake_request; | |
| GURL localhost_websocket_endpoint("ws://localhost:4541/abc?one=1&two=2"); | |
| handshake_helper_.GenerateHandshakeRequest(localhost_websocket_endpoint, | |
| "http://localhost", sub_protocols_, | |
| &handshake_request); | |
| char end_of_line[] = "\r\n"; | |
| std::size_t first_line_end = handshake_request.find(end_of_line); | |
| ASSERT_NE(first_line_end, std::string::npos); | |
| std::string http_GET_line = handshake_request.substr(0, first_line_end); | |
| EXPECT_EQ(http_GET_line, "GET /abc?one=1&two=2 HTTP/1.1"); | |
| net::HttpRequestHeaders headers; | |
| base::StringPiece handshake_request_stringpiece( | |
| handshake_request.data() + first_line_end + sizeof(end_of_line) - 1); | |
| headers.AddHeadersFromString(handshake_request_stringpiece); | |
| std::vector<net::HttpRequestHeaders::HeaderKeyValuePair> request_headers = | |
| RequestHeadersToVector(headers); | |
| typedef net::HttpRequestHeaders::HeaderKeyValuePair HeaderKeyValuePair; | |
| ASSERT_EQ(10u, request_headers.size()); | |
| EXPECT_EQ(HeaderKeyValuePair("Host", "localhost:4541"), request_headers[0]); | |
| EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); | |
| EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); | |
| EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), | |
| request_headers[3]); | |
| EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", ""), | |
| request_headers[5]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), | |
| request_headers[6]); | |
| EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"), | |
| request_headers[7]); | |
| EXPECT_EQ("Sec-WebSocket-Key", request_headers[8].key); | |
| EXPECT_EQ(HeaderKeyValuePair("User-Agent", kTestUserAgent), | |
| request_headers[9]); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, HandshakePathWithDesiredProtocols) { | |
| sub_protocols_.push_back("chat"); | |
| sub_protocols_.push_back("superchat"); | |
| std::string handshake_request; | |
| GURL localhost_websocket_endpoint("ws://localhost/"); | |
| handshake_helper_.GenerateHandshakeRequest(localhost_websocket_endpoint, | |
| "http://localhost", sub_protocols_, | |
| &handshake_request); | |
| char end_of_line[] = "\r\n"; | |
| std::size_t first_line_end = handshake_request.find(end_of_line); | |
| ASSERT_NE(first_line_end, std::string::npos); | |
| std::string http_GET_line = handshake_request.substr(0, first_line_end); | |
| EXPECT_EQ(http_GET_line, "GET / HTTP/1.1"); | |
| net::HttpRequestHeaders headers; | |
| base::StringPiece handshake_request_stringpiece( | |
| handshake_request.data() + first_line_end + sizeof(end_of_line) - 1); | |
| headers.AddHeadersFromString(handshake_request_stringpiece); | |
| std::vector<net::HttpRequestHeaders::HeaderKeyValuePair> request_headers = | |
| RequestHeadersToVector(headers); | |
| typedef net::HttpRequestHeaders::HeaderKeyValuePair HeaderKeyValuePair; | |
| ASSERT_EQ(11u, request_headers.size()); | |
| EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]); | |
| EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); | |
| EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); | |
| EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), | |
| request_headers[3]); | |
| EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", ""), | |
| request_headers[5]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), | |
| request_headers[6]); | |
| EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"), | |
| request_headers[7]); | |
| EXPECT_EQ("Sec-WebSocket-Key", request_headers[8].key); | |
| EXPECT_EQ(HeaderKeyValuePair("User-Agent", kTestUserAgent), | |
| request_headers[9]); | |
| EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Protocol", "chat,superchat"), | |
| request_headers[10]); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckValidResponseCode) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n" | |
| "\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_TRUE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_TRUE(error.empty()); | |
| EXPECT_EQ(error, ""); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckInValidResponseCode) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 200 OK\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept: Ei4axqShP74o6nOtmL3e5uRpei8=\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, "Invalid response code 200"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckValidUpgradeHeader) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_TRUE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_TRUE(error.empty()); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckMissingUpgradeHeader) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, "'Upgrade' header is missing"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckMultipleUpgradeHeaders) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Upgrade: HyperSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, | |
| "'Upgrade' header must not appear more than once in a response"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckValidSecWebSocketAccept) { | |
| // To verify Sec-WebSocket-Accept values for testing, python was used. | |
| // In [1]: import struct | |
| // In [2]: import hashlib | |
| // In [3]: import base64 | |
| // In [5]: h = hashlib.sha1(base64.b64encode(struct.pack('QQ', 0, 0)) + | |
| // b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") | |
| // In [6]: base64.b64encode(h.digest()) | |
| // Out[6]: 'ICX+Yqv66kxgM0FcWaLWlFLwTAI=' | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:ICX+Yqv66kxgM0FcWaLWlFLwTAI=\r\n"; | |
| std::string handshake_request; | |
| GURL localhost_websocket_endpoint("ws://localhost:4541/abc?one=1&two=2"); | |
| handshake_helper_.GenerateHandshakeRequest(localhost_websocket_endpoint, | |
| "http://localhost", sub_protocols_, | |
| &handshake_request); | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_TRUE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_TRUE(error.empty()); | |
| EXPECT_EQ(error, ""); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckMissingSecWebSocketAccept) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, "'Sec-WebSocket-Accept' header is missing"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckMultipleSecWebSocketAccept) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, | |
| "'Sec-WebSocket-Accept' header must not appear more than once in a " | |
| "response"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckValidConnection) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_TRUE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_TRUE(error.empty()); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckMissingConnectionHeader) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, "'Connection' header is missing"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckValidInvalidSubprotocol) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n" | |
| "Sec-WebSocket-Protocol:chat\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_FALSE(error.empty()); | |
| EXPECT_EQ(error, | |
| "Response must not include 'Sec-WebSocket-Protocol' header if not " | |
| "present in request: chat"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckValidInvalidDifferentSubprotocol) { | |
| sub_protocols_.push_back("superchat"); | |
| std::string handshake_request; | |
| GURL localhost_websocket_endpoint("ws://localhost/"); | |
| handshake_helper_.GenerateHandshakeRequest(localhost_websocket_endpoint, | |
| "http://localhost", sub_protocols_, | |
| &handshake_request); | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n" | |
| "Sec-WebSocket-Protocol:chat\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_FALSE(error.empty()); | |
| EXPECT_EQ(error, "Incorrect 'Sec-WebSocket-Accept' header value"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckSubprotocolHeaderIsOptional) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_TRUE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_TRUE(error.empty()); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckValidExtensionHeader) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n" | |
| "Sec-WebSocket-Extensions:mux\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, "Cobalt does not support any websocket extensions"); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckExtensionHeaderIsOptional) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_TRUE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_TRUE(error.empty()); | |
| } | |
| TEST_F(WebSocketHandshakeHelperTest, CheckMultipleExtensionHeadersAreOK) { | |
| char response_on_wire[] = | |
| "HTTP/1.1 101 Switching Protocols\r\n" | |
| "Upgrade: WebSocket\r\n" | |
| "Connection: Upgrade\r\n" | |
| "Sec-WebSocket-Accept:\r\n" | |
| "Sec-WebSocket-Extensions:mux\r\n" | |
| "Sec-WebSocket-Extensions:demux\r\n"; | |
| std::string transformed_headers = net::HttpUtil::AssembleRawHeaders( | |
| response_on_wire, arraysize(response_on_wire)); | |
| scoped_refptr<net::HttpResponseHeaders> responseHeaders = | |
| new net::HttpResponseHeaders(transformed_headers); | |
| std::string error; | |
| EXPECT_FALSE(handshake_helper_.IsResponseValid(*responseHeaders, &error)); | |
| EXPECT_EQ(error, "Cobalt does not support any websocket extensions"); | |
| } | |
| } // namespace websocket | |
| } // namespace cobalt |