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