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