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_handshake_stream_create_helper.h"
6a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/base/completion_callback.h"
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/base/net_errors.h"
9a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/http/http_request_headers.h"
10a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/http/http_request_info.h"
11a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/http/http_response_headers.h"
12a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/http/http_response_info.h"
13a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/client_socket_handle.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/socket_test_util.h"
15a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_basic_handshake_stream.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_stream.h"
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_test_util.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace net {
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// This class encapsulates the details of creating a mock ClientSocketHandle.
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class MockClientSocketHandleFactory {
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
27a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockClientSocketHandleFactory()
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : histograms_("a"),
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        pool_(1, 1, &histograms_, socket_factory_maker_.factory()) {}
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // The created socket expects |expect_written| to be written to the socket,
32a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // and will respond with |return_to_read|. The test will fail if the expected
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // text is not written, or if all the bytes are not read.
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<ClientSocketHandle> CreateClientSocketHandle(
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& expect_written,
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& return_to_read) {
37a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    socket_factory_maker_.SetExpectations(expect_written, return_to_read);
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_ptr<ClientSocketHandle> socket_handle(new ClientSocketHandle);
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    socket_handle->Init(
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        "a",
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        scoped_refptr<MockTransportSocketParams>(),
42a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        MEDIUM,
43a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        CompletionCallback(),
44a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        &pool_,
45a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        BoundNetLog());
46a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return socket_handle.Pass();
47a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
48a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
49a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
50a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WebSocketDeterministicMockClientSocketFactoryMaker socket_factory_maker_;
51a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  ClientSocketPoolHistograms histograms_;
52a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockTransportClientSocketPool pool_;
53a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
54a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(MockClientSocketHandleFactory);
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class WebSocketHandshakeStreamCreateHelperTest : public ::testing::Test {
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) protected:
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStream> CreateAndInitializeStream(
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_url,
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_path,
62a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::vector<std::string>& sub_protocols,
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& origin,
64a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& extra_request_headers,
65a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& extra_response_headers) {
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    WebSocketHandshakeStreamCreateHelper create_helper(sub_protocols);
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_ptr<ClientSocketHandle> socket_handle =
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        socket_handle_factory_.CreateClientSocketHandle(
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            WebSocketStandardRequest(
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                socket_path, origin, extra_request_headers),
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            WebSocketStandardResponse(extra_response_headers));
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    scoped_ptr<WebSocketHandshakeStreamBase> handshake(
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        create_helper.CreateBasicStream(socket_handle.Pass(), false));
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // If in future the implementation type returned by CreateBasicStream()
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // changes, this static_cast will be wrong. However, in that case the test
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // will fail and AddressSanitizer should identify the issue.
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    static_cast<WebSocketBasicHandshakeStream*>(handshake.get())
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ==");
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    HttpRequestInfo request_info;
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    request_info.url = GURL(socket_url);
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    request_info.method = "GET";
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    request_info.load_flags = LOAD_DISABLE_CACHE | LOAD_DO_NOT_PROMPT_FOR_LOGIN;
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    int rv = handshake->InitializeStream(
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        &request_info, DEFAULT_PRIORITY, BoundNetLog(), CompletionCallback());
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_EQ(OK, rv);
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    HttpRequestHeaders headers;
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("Host", "localhost");
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("Connection", "Upgrade");
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("Upgrade", "websocket");
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("Origin", origin);
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("Sec-WebSocket-Version", "13");
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("User-Agent", "");
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("Accept-Encoding", "gzip,deflate");
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    headers.SetHeader("Accept-Language", "en-us,fr");
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    HttpResponseInfo response;
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    TestCompletionCallback dummy;
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    rv = handshake->SendRequest(headers, &response, dummy.callback());
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_EQ(OK, rv);
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    rv = handshake->ReadResponseHeaders(dummy.callback());
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_EQ(OK, rv);
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_EQ(101, response.headers->response_code());
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_TRUE(response.headers->HasHeaderValue("Connection", "Upgrade"));
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    EXPECT_TRUE(response.headers->HasHeaderValue("Upgrade", "websocket"));
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return handshake->Upgrade();
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockClientSocketHandleFactory socket_handle_factory_;
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the basic case works as expected.
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketHandshakeStreamCreateHelperTest, BasicStream) {
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStream> stream =
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      CreateAndInitializeStream("ws://localhost/", "/",
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                std::vector<std::string>(), "http://localhost/",
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                "", "");
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ("", stream->GetExtensions());
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ("", stream->GetSubProtocol());
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Verify that the sub-protocols are passed through.
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketHandshakeStreamCreateHelperTest, SubProtocols) {
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chat");
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("superchat");
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStream> stream =
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      CreateAndInitializeStream("ws://localhost/", "/",
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                sub_protocols, "http://localhost/",
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                "Sec-WebSocket-Protocol: chat, superchat\r\n",
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                "Sec-WebSocket-Protocol: superchat\r\n");
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ("superchat", stream->GetSubProtocol());
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// TODO(ricea): Test extensions once they are implemented.
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace net
146