websocket_stream_test.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
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) 75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <algorithm> 8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <string> 95d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include <utility> 10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include <vector> 11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_vector.h" 13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/run_loop.h" 145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h" 15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/base/net_errors.h" 165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_request_headers.h" 175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_response_headers.h" 18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/client_socket_handle.h" 19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/socket_test_util.h" 20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/url_request/url_request_test_util.h" 21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_basic_handshake_stream.h" 225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_frame.h" 235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_request_info.h" 245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_response_info.h" 25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_handshake_stream_create_helper.h" 26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_test_util.h" 27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h" 28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h" 29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace net { 31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace { 32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef std::pair<std::string, std::string> HeaderKeyValuePair; 345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<HeaderKeyValuePair> ToVector(const HttpRequestHeaders& headers) { 365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) HttpRequestHeaders::Iterator it(headers); 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<HeaderKeyValuePair> result; 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (it.GetNext()) 395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result.push_back(HeaderKeyValuePair(it.name(), it.value())); 405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return result; 415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<HeaderKeyValuePair> ToVector(const HttpResponseHeaders& headers) { 445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void* iter = NULL; 455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string name, value; 465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<HeaderKeyValuePair> result; 475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) while (headers.EnumerateHeaderLines(&iter, &name, &value)) 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) result.push_back(HeaderKeyValuePair(name, value)); 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return result; 505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a 53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// deterministic key to use in the WebSocket handshake. 54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class DeterministicKeyWebSocketHandshakeStreamCreateHelper 55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) : public WebSocketHandshakeStreamCreateHelper { 56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public: 57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DeterministicKeyWebSocketHandshakeStreamCreateHelper( 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) WebSocketStream::ConnectDelegate* connect_delegate, 59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& requested_subprotocols) 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : WebSocketHandshakeStreamCreateHelper(connect_delegate, 615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) requested_subprotocols) {} 62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) virtual WebSocketHandshakeStreamBase* CreateBasicStream( 64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<ClientSocketHandle> connection, 65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) bool using_proxy) OVERRIDE { 66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketHandshakeStreamCreateHelper::CreateBasicStream(connection.Pass(), 67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) using_proxy); 68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // This will break in an obvious way if the type created by 69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // CreateBasicStream() changes. 70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static_cast<WebSocketBasicHandshakeStream*>(stream()) 71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ=="); 72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return stream(); 73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class WebSocketStreamCreateTest : public ::testing::Test { 77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) protected: 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) WebSocketStreamCreateTest(): has_failed_(false) {} 79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectCustomResponse( 81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_url, 82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_path, 83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin, 85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& extra_request_headers, 86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& response_body) { 87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_request_context_host_.SetExpectations( 88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketStandardRequest(socket_path, origin, extra_request_headers), 89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) response_body); 90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStream(socket_url, sub_protocols, origin); 91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // |extra_request_headers| and |extra_response_headers| must end in "\r\n" or 94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // errors like "Unable to perform synchronous IO while stopped" will occur. 95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectStandard(const std::string& socket_url, 96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_path, 97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin, 99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& extra_request_headers, 100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& extra_response_headers) { 101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse( 102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_url, 103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_path, 104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols, 105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) origin, 106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) extra_request_headers, 107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketStandardResponse(extra_response_headers)); 108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectRawExpectations( 111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& socket_url, 112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin, 114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data) { 115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_request_context_host_.SetRawExpectations(socket_data.Pass()); 116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStream(socket_url, sub_protocols, origin); 117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // A wrapper for CreateAndConnectStreamForTesting that knows about our default 120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // parameters. 121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) void CreateAndConnectStream(const std::string& socket_url, 122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::vector<std::string>& sub_protocols, 123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) const std::string& origin) { 1245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate( 1255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) new TestConnectDelegate(this)); 1265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) WebSocketStream::ConnectDelegate* delegate = connect_delegate.get(); 127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_ = ::net::CreateAndConnectStreamForTesting( 128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GURL(socket_url), 129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<WebSocketHandshakeStreamCreateHelper>( 130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicKeyWebSocketHandshakeStreamCreateHelper( 1315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) delegate, sub_protocols)), 132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) GURL(origin), 133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) url_request_context_host_.GetURLRequestContext(), 134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) BoundNetLog(), 1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) connect_delegate.Pass()); 136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); } 139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // A simple function to make the tests more readable. Creates an empty vector. 141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static std::vector<std::string> NoSubProtocols() { 142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) return std::vector<std::string>(); 143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& failure_message() const { return failure_message_; } 1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool has_failed() const { return has_failed_; } 147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) class TestConnectDelegate : public WebSocketStream::ConnectDelegate { 149a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public: 1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) explicit TestConnectDelegate(WebSocketStreamCreateTest* owner) 1515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) : owner_(owner) {} 152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE { 154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream.swap(owner_->stream_); 155a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void OnFailure(const std::string& message) OVERRIDE { 1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) owner_->has_failed_ = true; 1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) owner_->failure_message_ = message; 1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void OnStartOpeningHandshake( 1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE { 1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (owner_->request_info_) 1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ADD_FAILURE(); 1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) owner_->request_info_ = request.Pass(); 1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) virtual void OnFinishOpeningHandshake( 1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE { 1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) if (owner_->response_info_) 1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ADD_FAILURE(); 1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) owner_->response_info_ = response.Pass(); 173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) } 174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 175a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private: 176a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketStreamCreateTest* owner_; 177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) }; 178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) WebSocketTestURLRequestContextHost url_request_context_host_; 180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<WebSocketStreamRequest> stream_request_; 181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // Only set if the connection succeeded. 182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<WebSocketStream> stream_; 1835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Only set if the connection failed. 1845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string failure_message_; 1855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) bool has_failed_; 1865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<WebSocketHandshakeRequestInfo> request_info_; 1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) scoped_ptr<WebSocketHandshakeResponseInfo> response_info_; 1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}; 1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// There are enough tests of the Sec-WebSocket-Extensions header that they 1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// deserve their own test fixture. 1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class WebSocketStreamCreateExtensionTest : public WebSocketStreamCreateTest { 1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public: 1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Performs a standard connect, with the value of the Sec-WebSocket-Extensions 1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // header in the response set to |extensions_header_value|. Runs the event 1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // loop to allow the connect to complete. 1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) void CreateAndConnectWithExtensions( 1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) const std::string& extensions_header_value) { 1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectStandard( 2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "ws://localhost/testing_path", 2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "/testing_path", 2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NoSubProtocols(), 2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://localhost/", 2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "", 2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n"); 2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RunUntilIdle(); 2075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}; 209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 210a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the basic case works as expected. 211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SimpleSuccess) { 212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(request_info_); 2155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 218a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(request_info_); 2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(response_info_); 2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, HandshakeInfo) { 2245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static const char kResponse[] = 2255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 2265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Upgrade: websocket\r\n" 2275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Connection: Upgrade\r\n" 2285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 2295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "foo: bar, baz\r\n" 2305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "hoge: fuga\r\n" 2315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "hoge: piyo\r\n" 2325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "\r\n"; 2335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectCustomResponse( 2355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "ws://localhost/", 2365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "/", 2375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NoSubProtocols(), 2385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://localhost/", 2395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "", 2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kResponse); 2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(request_info_); 2425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RunUntilIdle(); 2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(stream_); 2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_TRUE(request_info_); 2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_TRUE(response_info_); 2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<HeaderKeyValuePair> request_headers = 2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ToVector(request_info_->headers); 2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // We examine the contents of request_info_ and response_info_ 2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // mainly only in this test case. 2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(GURL("ws://localhost/"), request_info_->url); 2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(GURL("ws://localhost/"), response_info_->url); 2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(101, response_info_->status_code); 2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Switching Protocols", response_info_->status_text); 2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_EQ(12u, request_headers.size()); 2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]); 2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]); 2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]); 2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"), 2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_headers[3]); 2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]); 2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost/"), 2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_headers[5]); 2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"), 2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_headers[6]); 2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[7]); 2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip,deflate"), 2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_headers[8]); 2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"), 2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_headers[9]); 2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Sec-WebSocket-Key", request_headers[10].first); 2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions", 2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; client_max_window_bits"), 2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) request_headers[11]); 2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<HeaderKeyValuePair> response_headers = 2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ToVector(*response_info_->headers); 2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_EQ(6u, response_headers.size()); 2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) // Sort the headers for ease of verification. 2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::sort(response_headers.begin(), response_headers.end()); 2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), response_headers[0]); 2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first); 2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]); 2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("foo", "bar, baz"), response_headers[3]); 2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("hoge", "fuga"), response_headers[4]); 2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ(HeaderKeyValuePair("hoge", "piyo"), response_headers[5]); 288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 290a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the stream isn't established until the message loop runs. 291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) { 292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 295a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 296a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 297a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 298a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check the path is used. 299a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, PathIsUsed) { 300a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 301a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 302a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 303a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 304a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 305a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ""); 306a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 308a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 309a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 310a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 311a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that the origin is used. 312a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, OriginIsUsed) { 313a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 318a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ""); 319a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 322a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that sub-protocols are sent and parsed. 325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) { 326a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<std::string> sub_protocols; 327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv11.chromium.org"); 328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv20.chromium.org"); 329a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols, 332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 333a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv11.chromium.org, " 334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "chatv20.chromium.org\r\n", 335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); 336a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 3385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol()); 340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 342a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Unsolicited sub-protocols are rejected. 343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) { 344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 346a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n"); 350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 3525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 3535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Response must not include 'Sec-WebSocket-Protocol' header " 3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "if not present in request: chatv20.chromium.org", 3565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 358a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Missing sub-protocol response is rejected. 360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) { 3615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<std::string> sub_protocols; 3625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sub_protocols.push_back("chat.example.com"); 363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 364a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 3655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sub_protocols, 366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chat.example.com\r\n", 368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) ""); 369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 3715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 3725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 3735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sent non-empty 'Sec-WebSocket-Protocol' header " 3745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "but no response was received", 3755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 376a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 378a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Only one sub-protocol can be accepted. 379a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) { 380a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::vector<std::string> sub_protocols; 381a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv11.chromium.org"); 382a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols.push_back("chatv20.chromium.org"); 383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) sub_protocols, 386a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://google.com/", 387a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv11.chromium.org, " 388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "chatv20.chromium.org\r\n", 389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv11.chromium.org, " 390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "chatv20.chromium.org\r\n"); 391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 392a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 3935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 3945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 3955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Sec-WebSocket-Protocol' header must not appear " 3965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "more than once in a response", 3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 398a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 399a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Unmatched sub-protocol should be rejected. 4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnmatchedSubProtocolInResponse) { 4025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::vector<std::string> sub_protocols; 4035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sub_protocols.push_back("chatv11.chromium.org"); 4045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sub_protocols.push_back("chatv20.chromium.org"); 405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/testing_path", 406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/testing_path", 4075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) sub_protocols, 4085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://google.com/", 4095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv11.chromium.org, " 4105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "chatv20.chromium.org\r\n", 4115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n"); 4125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RunUntilIdle(); 4135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 4145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 4155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 4165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' " 4175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "in response does not match any of sent values", 4185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate extension basic success case. 4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateSuccess) { 4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions("permessage-deflate"); 4245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(stream_); 4255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate extensions success with all parameters. 4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateParamsSuccess) { 4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; client_no_context_takeover; " 4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "server_max_window_bits=11; client_max_window_bits=13; " 4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "server_no_context_takeover"); 4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(stream_); 4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Verify that incoming messages are actually decompressed with 4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate enabled. 4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) { 4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectCustomResponse( 4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "ws://localhost/testing_path", 4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "/testing_path", 4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NoSubProtocols(), 4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://localhost/", 4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "", 4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) WebSocketStandardResponse( 4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sec-WebSocket-Extensions: permessage-deflate\r\n") + 4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string( 4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "\xc1\x07" // WebSocket header (FIN + RSV1, Text payload 7 bytes) 4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "\xf2\x48\xcd\xc9\xc9\x07\x00", // "Hello" DEFLATE compressed 4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 9)); 453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_TRUE(stream_); 4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ScopedVector<WebSocketFrame> frames; 4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CompletionCallback callback; 4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_EQ(OK, stream_->ReadFrames(&frames, callback)); 4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_EQ(1U, frames.size()); 4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ASSERT_EQ(5U, frames[0]->header.payload_length); 4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Hello", std::string(frames[0]->data->data(), 5)); 4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Unknown extension in the response is rejected 4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, UnknownExtension) { 4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions("x-unknown-extension"); 4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Found an unsupported extension 'x-unknown-extension' " 4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "in 'Sec-WebSocket-Extensions' header", 4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Malformed extensions are rejected (this file does not cover all possible 4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// parse failures, as the parser is covered thoroughly by its own unit tests). 4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MalformedExtension) { 4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions(";"); 4795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: 'Sec-WebSocket-Extensions' header " 4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "value is rejected by the parser: ;", 4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The permessage-deflate extension may only be specified once. 4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, OnlyOnePerMessageDeflateAllowed) { 4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate, permessage-deflate; client_max_window_bits=10"); 4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received duplicate permessage-deflate " 4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "response", 4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters may not be duplicated. 5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, NoDuplicateParameters) { 5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; client_no_context_takeover; " 5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "client_no_context_takeover"); 5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received duplicate permessage-deflate " 5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "extension parameter client_no_context_takeover", 5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters must start with "client_" or "server_" 5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterPrefix) { 5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; absurd_no_context_takeover"); 516a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received an unexpected " 5205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate extension parameter", 5215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 523a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters must be either *_no_context_takeover or 5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits 5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterSuffix) { 5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; client_max_content_bits=5"); 5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received an unexpected " 5335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate extension parameter", 5345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 5355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_no_context_takeover parameters must not have an argument 5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterValue) { 5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; client_no_context_takeover=true"); 5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received invalid " 5455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "client_no_context_takeover parameter", 5465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 5475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must have an argument 5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, NoMaxWindowBitsArgument) { 5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions("permessage-deflate; client_max_window_bits"); 5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: client_max_window_bits must have " 5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "value", 5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be an integer 5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueInteger) { 5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; server_max_window_bits=banana"); 5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received invalid " 5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "server_max_window_bits parameter", 5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be >= 8 5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooSmall) { 5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; server_max_window_bits=7"); 5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received invalid " 5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "server_max_window_bits parameter", 5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 5825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be <= 15 5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooBig) { 5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; client_max_window_bits=16"); 5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received invalid " 5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "client_max_window_bits parameter", 5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 5945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 5955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must not start with 0 5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithZero) { 5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; client_max_window_bits=08"); 6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received invalid " 6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "client_max_window_bits parameter", 6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must not start with + 6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithPlus) { 6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectWithExtensions( 6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "permessage-deflate; server_max_window_bits=+9"); 6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ( 6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Error during WebSocket handshake: Received invalid " 6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "server_max_window_bits parameter", 6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 6185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(ricea): Check that WebSocketDeflateStream is initialised with the 6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// arguments from the server. This is difficult because the data written to the 6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// socket is randomly masked. 6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 624a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Additional Sec-WebSocket-Accept headers should be rejected. 625a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleAccept) { 626a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 627a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", 628a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 629a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 630a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 631a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 632a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"); 633a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 634a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Sec-WebSocket-Accept' header must not appear " 6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "more than once in a response", 6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 640a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 641a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 642a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Response code 200 must be rejected. 643a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) { 644a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kInvalidStatusCodeResponse[] = 645a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 200 OK\r\n" 646a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 647a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 648a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 649a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 650a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 651a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 652a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 653a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 654a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 655a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kInvalidStatusCodeResponse); 656a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 6575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 200", 6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 660a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 661a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 662a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Redirects are not followed (according to the WHATWG WebSocket API, which 663a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// overrides RFC6455 for browser applications). 664a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, RedirectsRejected) { 665a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kRedirectResponse[] = 666a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 302 Moved Temporarily\r\n" 667a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Content-Type: text/html\r\n" 668a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Content-Length: 34\r\n" 669a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: keep-alive\r\n" 670a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Location: ws://localhost/other\r\n" 671a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n" 672a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "<title>Moved</title><h1>Moved</h1>"; 673a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 674a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 675a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 676a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 677a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 678a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kRedirectResponse); 679a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 302", 6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 683a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 684a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 685a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Malformed responses should be rejected. HttpStreamParser will accept just 686a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// about any garbage in the middle of the headers. To make it give up, the junk 687a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// has to be at the start of the response. Even then, it just gets treated as an 688a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// HTTP/0.9 response. 689a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MalformedResponse) { 690a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMalformedResponse[] = 691a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "220 mx.google.com ESMTP\r\n" 692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 OK\r\n" 693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 694a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 695a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 696a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 698a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 699a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 700a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 701a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 702a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMalformedResponse); 703a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 200", 7065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 707a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 708a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 709a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Upgrade header must be present. 710a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) { 711a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMissingUpgradeResponse[] = 712a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 713a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 714a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 715a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 716a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 718a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 720a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMissingUpgradeResponse); 722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing", 7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 727a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// There must only be one upgrade header. 729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) { 730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 731a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", 732a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 733a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", "Upgrade: HTTP/2.0\r\n"); 736a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Upgrade' header must not appear more than once in a response", 7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// There must only be one correct upgrade header. 7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, IncorrectUpgradeHeader) { 7455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static const char kMissingUpgradeResponse[] = 7465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 7475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Connection: Upgrade\r\n" 7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Upgrade: hogefuga\r\n" 7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "\r\n"; 7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "/", 7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NoSubProtocols(), 7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://localhost/", 7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "", 7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kMissingUpgradeResponse); 7575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RunUntilIdle(); 7585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Upgrade' header value is not 'WebSocket': hogefuga", 7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 762a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 763a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 764a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header must be present. 765a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) { 766a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMissingConnectionResponse[] = 767a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 768a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 769a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 770a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 771a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 772a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 773a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 774a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 775a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 776a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMissingConnectionResponse); 777a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Connection' header is missing", 7815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Connection header must contain "Upgrade". 7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, IncorrectConnectionHeader) { 7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static const char kMissingConnectionResponse[] = 7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Upgrade: websocket\r\n" 7895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Connection: hogefuga\r\n" 7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "\r\n"; 7925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 7935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "/", 7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NoSubProtocols(), 7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://localhost/", 7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "", 7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) kMissingConnectionResponse); 7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RunUntilIdle(); 7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Connection' header value must contain 'Upgrade'", 8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 804a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 805a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header is permitted to contain other tokens. 806a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) { 807a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kAdditionalConnectionTokenResponse[] = 808a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 809a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 810a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade, Keep-Alive\r\n" 811a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n" 812a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 813a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 814a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 815a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 816a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 817a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 818a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kAdditionalConnectionTokenResponse); 819a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 821a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_TRUE(stream_); 822a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 823a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 824a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must be present. 825a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) { 826a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kMissingAcceptResponse[] = 827a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 828a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 829a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 830a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 831a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 832a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 833a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 834a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 835a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 836a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kMissingAcceptResponse); 837a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 8385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 8395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 8405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "'Sec-WebSocket-Accept' header is missing", 8415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 843a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 844a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must match the key that was sent. 845a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) { 846a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) static const char kIncorrectAcceptResponse[] = 847a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "HTTP/1.1 101 Switching Protocols\r\n" 848a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Upgrade: websocket\r\n" 849a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Connection: Upgrade\r\n" 850a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n" 851a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "\r\n"; 852a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectCustomResponse("ws://localhost/", 853a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "/", 854a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 855a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 856a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "", 857a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) kIncorrectAcceptResponse); 858a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 8595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 8605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error during WebSocket handshake: " 8615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "Incorrect 'Sec-WebSocket-Accept' header value", 8625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 863a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 864a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 865a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation works. 866a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, Cancellation) { 867a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectStandard( 868a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "ws://localhost/", "/", NoSubProtocols(), "http://localhost/", "", ""); 869a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 870a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 8715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 872a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 8735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(request_info_); 8745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 875a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 876a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 877a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect failure must look just like negotiation failure. 878a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionFailure) { 879a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data( 880a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, NULL, 0)); 881a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data( 882a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED)); 883a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 884a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", socket_data.Pass()); 885a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 8865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 8875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED", 8885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 8895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(request_info_); 8905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 891a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 892a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 893a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect timeout must look just like any other failure. 894a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) { 895a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data( 896a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, NULL, 0)); 897a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data( 898a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT)); 899a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(), 900a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", socket_data.Pass()); 901a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 9025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 9035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT", 9045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 905a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 906a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 907a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during connect works. 908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) { 909a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) scoped_ptr<DeterministicSocketData> socket_data( 910a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, NULL, 0)); 911a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING)); 912a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", 913a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 914a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 915a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data.Pass()); 916a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 917a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 9185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 919a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 920a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 921a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 922a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during write of the request headers works. 923a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) { 924a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // We seem to need at least two operations in order to use SetStop(). 925a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"), 926a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockWrite(ASYNC, 1, "1.1\r\n")}; 927a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) // We keep a copy of the pointer so that we can call RunFor() on it later. 928a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DeterministicSocketData* socket_data( 929a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) new DeterministicSocketData(NULL, 0, writes, arraysize(writes))); 930a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 931a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->SetStop(1); 932a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", 933a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 934a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 935a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) make_scoped_ptr(socket_data)); 936a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->Run(); 937a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 938a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 9395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 940a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 9415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(request_info_); 9425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 943a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 944a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 945a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during read of the response headers works. 946a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) { 947a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) std::string request = WebSocketStandardRequest("/", "http://localhost/", ""); 948a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())}; 949a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockRead reads[] = { 950a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"), 951a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) }; 952a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) DeterministicSocketData* socket_data(new DeterministicSocketData( 953a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) reads, arraysize(reads), writes, arraysize(writes))); 954a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 955a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->SetStop(1); 956a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", 957a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) NoSubProtocols(), 958a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) "http://localhost/", 959a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) make_scoped_ptr(socket_data)); 960a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) socket_data->Run(); 961a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) stream_request_.reset(); 962a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) RunUntilIdle(); 9635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(has_failed()); 9645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(stream_); 9655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(request_info_); 9665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 9675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 9685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 9695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Over-size response headers (> 256KB) should not cause a crash. This is a 9705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// regression test for crbug.com/339456. It is based on the layout test 9715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// "cookie-flood.html". 9725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, VeryLargeResponseHeaders) { 9735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string set_cookie_headers; 9745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) set_cookie_headers.reserve(45 * 10000); 9755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) for (int i = 0; i < 10000; ++i) { 9765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) set_cookie_headers += 9775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) base::StringPrintf("Set-Cookie: WK-websocket-test-flood-%d=1\r\n", i); 9785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 9795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectStandard("ws://localhost/", "/", NoSubProtocols(), 9805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://localhost/", "", set_cookie_headers); 9815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) RunUntilIdle(); 9825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 9835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 9845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 9855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 9865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If the remote host closes the connection without sending headers, we should 9875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// log the console message "Connection closed before receiving a handshake 9885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// response". 9895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, NoResponse) { 9905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) std::string request = WebSocketStandardRequest("/", "http://localhost/", ""); 9915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)}; 9925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) MockRead reads[] = {MockRead(ASYNC, 0, 1)}; 9935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) DeterministicSocketData* socket_data(new DeterministicSocketData( 9945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) reads, arraysize(reads), writes, arraysize(writes))); 9955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK)); 9965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) CreateAndConnectRawExpectations("ws://localhost/", 9975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) NoSubProtocols(), 9985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) "http://localhost/", 9995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) make_scoped_ptr(socket_data)); 10005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) socket_data->RunFor(2); 10015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_TRUE(has_failed()); 1002a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) EXPECT_FALSE(stream_); 10035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_FALSE(response_info_); 10045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) EXPECT_EQ("Connection closed before receiving a handshake response", 10055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) failure_message()); 1006a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} 1007a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) 1008a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace 1009a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)} // namespace net 1010