websocket_stream_test.cc revision a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7
1a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 2a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 3a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// found in the LICENSE file. 4a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_stream.h" 6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <string> 8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <vector> 9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/run_loop.h" 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/base/net_errors.h" 12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/client_socket_handle.h" 13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/socket_test_util.h" 14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/url_request/url_request_test_util.h" 15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_basic_handshake_stream.h" 16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_handshake_stream_create_helper.h" 17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_test_util.h" 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h" 20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace net { 22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace { 23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// deterministic key to use in the WebSocket handshake. 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class DeterministicKeyWebSocketHandshakeStreamCreateHelper 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : public WebSocketHandshakeStreamCreateHelper { 28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public: 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DeterministicKeyWebSocketHandshakeStreamCreateHelper( 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& requested_subprotocols) 31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : WebSocketHandshakeStreamCreateHelper(requested_subprotocols) {} 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) virtual WebSocketHandshakeStreamBase* CreateBasicStream( 34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<ClientSocketHandle> connection, 35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool using_proxy) OVERRIDE { 36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketHandshakeStreamCreateHelper::CreateBasicStream(connection.Pass(), 37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) using_proxy); 38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // This will break in an obvious way if the type created by 39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // CreateBasicStream() changes. 40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static_cast<WebSocketBasicHandshakeStream*>(stream()) 41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ=="); 42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return stream(); 43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class WebSocketStreamCreateTest : public ::testing::Test { 47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) protected: 48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketStreamCreateTest() : websocket_error_(0) {} 49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectCustomResponse( 51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_url, 52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_path, 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin, 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& extra_request_headers, 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& response_body) { 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_request_context_host_.SetExpectations( 58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketStandardRequest(socket_path, origin, extra_request_headers), 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) response_body); 60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStream(socket_url, sub_protocols, origin); 61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // |extra_request_headers| and |extra_response_headers| must end in "\r\n" or 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // errors like "Unable to perform synchronous IO while stopped" will occur. 65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectStandard(const std::string& socket_url, 66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_path, 67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin, 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& extra_request_headers, 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& extra_response_headers) { 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse( 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_url, 73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_path, 74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols, 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) origin, 76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) extra_request_headers, 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketStandardResponse(extra_response_headers)); 78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectRawExpectations( 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_url, 82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin, 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data) { 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_request_context_host_.SetRawExpectations(socket_data.Pass()); 86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStream(socket_url, sub_protocols, origin); 87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // A wrapper for CreateAndConnectStreamForTesting that knows about our default 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // parameters. 91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectStream(const std::string& socket_url, 92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin) { 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_ = ::net::CreateAndConnectStreamForTesting( 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GURL(socket_url), 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<WebSocketHandshakeStreamCreateHelper>( 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicKeyWebSocketHandshakeStreamCreateHelper( 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols)), 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GURL(origin), 100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_request_context_host_.GetURLRequestContext(), 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BoundNetLog(), 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<WebSocketStream::ConnectDelegate>( 103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new TestConnectDelegate(this))); 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // A simple function to make the tests more readable. Creates an empty vector. 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static std::vector<std::string> NoSubProtocols() { 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return std::vector<std::string>(); 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) uint16 error() const { return websocket_error_; } 114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) class TestConnectDelegate : public WebSocketStream::ConnectDelegate { 116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public: 117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) TestConnectDelegate(WebSocketStreamCreateTest* owner) : owner_(owner) {} 118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE { 120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream.swap(owner_->stream_); 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) virtual void OnFailure(uint16 websocket_error) OVERRIDE { 124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) owner_->websocket_error_ = websocket_error; 125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private: 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketStreamCreateTest* owner_; 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) }; 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketTestURLRequestContextHost url_request_context_host_; 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<WebSocketStreamRequest> stream_request_; 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Only set if the connection succeeded. 134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<WebSocketStream> stream_; 135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Only set if the connection failed. 0 otherwise. 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) uint16 websocket_error_; 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the basic case works as expected. 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the stream isn't established until the message loop runs. 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) { 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 150a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check the path is used. 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, PathIsUsed) { 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ""); 162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 164a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 165a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 166a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that the origin is used. 167a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, OriginIsUsed) { 168a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 169a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 170a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 171a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 172a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ""); 174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that sub-protocols are sent and parsed. 179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) { 180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<std::string> sub_protocols; 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv11.chromium.org"); 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv20.chromium.org"); 183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols, 186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv11.chromium.org, " 188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "chatv20.chromium.org\r\n", 189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); 190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol()); 193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Unsolicited sub-protocols are rejected. 196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) { 197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); 203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Missing sub-protocol response is rejected. 209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) { 210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<std::string>(1, "chat.example.com"), 213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chat.example.com\r\n", 215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ""); 216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 218a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Only one sub-protocol can be accepted. 222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) { 223a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<std::string> sub_protocols; 224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv11.chromium.org"); 225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv20.chromium.org"); 226a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 227a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols, 229a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 230a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv11.chromium.org, " 231a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "chatv20.chromium.org\r\n", 232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv11.chromium.org, " 233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "chatv20.chromium.org\r\n"); 234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Unknown extension in the response is rejected 240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnknownExtension) { 241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 245a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 246a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Extensions: x-unknown-extension\r\n"); 247a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 248a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 249a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 251a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 252a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Additional Sec-WebSocket-Accept headers should be rejected. 253a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleAccept) { 254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", 256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 257a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); 261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 264a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Response code 200 must be rejected. 267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) { 268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kInvalidStatusCodeResponse[] = 269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 200 OK\r\n" 270a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 271a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 274a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 275a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 276a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kInvalidStatusCodeResponse); 280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 282a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 283a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 284a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Redirects are not followed (according to the WHATWG WebSocket API, which 285a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// overrides RFC6455 for browser applications). 286a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, RedirectsRejected) { 287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kRedirectResponse[] = 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 302 Moved Temporarily\r\n" 289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Content-Type: text/html\r\n" 290a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Content-Length: 34\r\n" 291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: keep-alive\r\n" 292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Location: ws://localhost/other\r\n" 293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n" 294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "<title>Moved</title><h1>Moved</h1>"; 295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 296a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 297a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 298a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 299a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 300a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kRedirectResponse); 301a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 302a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 304a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Malformed responses should be rejected. HttpStreamParser will accept just 306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// about any garbage in the middle of the headers. To make it give up, the junk 307a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// has to be at the start of the response. Even then, it just gets treated as an 308a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// HTTP/0.9 response. 309a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MalformedResponse) { 310a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMalformedResponse[] = 311a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "220 mx.google.com ESMTP\r\n" 312a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 OK\r\n" 313a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 318a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 319a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 322a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMalformedResponse); 323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 326a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Upgrade header must be present. 328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) { 329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMissingUpgradeResponse[] = 330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 336a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMissingUpgradeResponse); 340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// There must only be one upgrade header. 345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) { 346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", 348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", "Upgrade: HTTP/2.0\r\n"); 352a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 354a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 356a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header must be present. 357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) { 358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMissingConnectionResponse[] = 359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 361a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 362a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMissingConnectionResponse); 369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 373a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header is permitted to contain other tokens. 374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) { 375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kAdditionalConnectionTokenResponse[] = 376a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 378a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade, Keep-Alive\r\n" 379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 386a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kAdditionalConnectionTokenResponse); 387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must be present. 392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) { 393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMissingAcceptResponse[] = 394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 397a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 400a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 401a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMissingAcceptResponse); 404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must match the key that was sent. 409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) { 410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kIncorrectAcceptResponse[] = 411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 412a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n" 415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 419a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 420a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 421a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kIncorrectAcceptResponse); 422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation works. 427a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, Cancellation) { 428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 429a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 433a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 434a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 435a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect failure must look just like negotiation failure. 436a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { 437a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data( 438a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, NULL, 0)); 439a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data( 440a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); 441a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 442a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", socket_data.Pass()); 443a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 444a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 445a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 446a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 447a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect timeout must look just like any other failure. 448a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { 449a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data( 450a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, NULL, 0)); 451a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data( 452a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); 453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", socket_data.Pass()); 455a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 456a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ(1006, error()); 457a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 458a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 459a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during connect works. 460a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { 461a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data( 462a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, NULL, 0)); 463a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); 464a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", 465a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 466a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 467a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data.Pass()); 468a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 469a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 470a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 471a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 472a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 473a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during write of the request headers works. 474a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) { 475a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // We seem to need at least two operations in order to use SetStop(). 476a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"), 477a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockWrite(ASYNC, 1, "1.1\r\n")}; 478a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // We keep a copy of the pointer so that we can call RunFor() on it later. 479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DeterministicSocketData* socket_data( 480a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, writes, arraysize(writes))); 481a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 482a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->SetStop(1); 483a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", 484a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 485a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 486a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) make_scoped_ptr(socket_data)); 487a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->Run(); 488a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 489a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 490a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 491a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 492a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 493a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during read of the response headers works. 494a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { 495a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string request = WebSocketStandardRequest("/", "http://localhost/", ""); 496a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())}; 497a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockRead reads[] = { 498a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), 499a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) }; 500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DeterministicSocketData* socket_data(new DeterministicSocketData( 501a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) reads, arraysize(reads), writes, arraysize(writes))); 502a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 503a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->SetStop(1); 504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", 505a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 506a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 507a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) make_scoped_ptr(socket_data)); 508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->Run(); 509a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 510a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 511a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 512a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 514a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace 515a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace net 516