websocket_stream_test.cc revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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"
13c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/metrics/histogram.h"
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/metrics/histogram_samples.h"
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/metrics/statistics_recorder.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/run_loop.h"
175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/base/net_errors.h"
195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_request_headers.h"
205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_response_headers.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/client_socket_handle.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/socket_test_util.h"
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/url_request/url_request_test_util.h"
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_basic_handshake_stream.h"
255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_frame.h"
265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_request_info.h"
275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_response_info.h"
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_handshake_stream_create_helper.h"
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_test_util.h"
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h"
32a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "url/origin.h"
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace net {
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef std::pair<std::string, std::string> HeaderKeyValuePair;
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<HeaderKeyValuePair> ToVector(const HttpRequestHeaders& headers) {
405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HttpRequestHeaders::Iterator it(headers);
415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> result;
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (it.GetNext())
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.push_back(HeaderKeyValuePair(it.name(), it.value()));
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<HeaderKeyValuePair> ToVector(const HttpResponseHeaders& headers) {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void* iter = NULL;
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string name, value;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> result;
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (headers.EnumerateHeaderLines(&iter, &name, &value))
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.push_back(HeaderKeyValuePair(name, value));
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a
57a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// deterministic key to use in the WebSocket handshake.
58a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class DeterministicKeyWebSocketHandshakeStreamCreateHelper
59a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : public WebSocketHandshakeStreamCreateHelper {
60a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
61a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DeterministicKeyWebSocketHandshakeStreamCreateHelper(
625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      WebSocketStream::ConnectDelegate* connect_delegate,
63a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::vector<std::string>& requested_subprotocols)
645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : WebSocketHandshakeStreamCreateHelper(connect_delegate,
655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             requested_subprotocols) {}
66a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
67a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual WebSocketHandshakeStreamBase* CreateBasicStream(
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      scoped_ptr<ClientSocketHandle> connection,
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      bool using_proxy) OVERRIDE {
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    WebSocketHandshakeStreamCreateHelper::CreateBasicStream(connection.Pass(),
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                            using_proxy);
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // This will break in an obvious way if the type created by
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    // CreateBasicStream() changes.
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    static_cast<WebSocketBasicHandshakeStream*>(stream())
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        ->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ==");
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return stream();
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class WebSocketStreamCreateTest : public ::testing::Test {
81c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch public:
825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  WebSocketStreamCreateTest(): has_failed_(false) {}
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectCustomResponse(
85a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_url,
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_path,
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::vector<std::string>& sub_protocols,
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& origin,
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& extra_request_headers,
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& response_body) {
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    url_request_context_host_.SetExpectations(
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        WebSocketStandardRequest(socket_path, origin, extra_request_headers),
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        response_body);
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    CreateAndConnectStream(socket_url, sub_protocols, origin);
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
97a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |extra_request_headers| and |extra_response_headers| must end in "\r\n" or
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // errors like "Unable to perform synchronous IO while stopped" will occur.
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectStandard(const std::string& socket_url,
100a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::string& socket_path,
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::vector<std::string>& sub_protocols,
102a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::string& origin,
103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::string& extra_request_headers,
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::string& extra_response_headers) {
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    CreateAndConnectCustomResponse(
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        socket_url,
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        socket_path,
108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        sub_protocols,
109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        origin,
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        extra_request_headers,
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        WebSocketStandardResponse(extra_response_headers));
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectRawExpectations(
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_url,
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::vector<std::string>& sub_protocols,
117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& origin,
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      scoped_ptr<DeterministicSocketData> socket_data) {
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    url_request_context_host_.SetRawExpectations(socket_data.Pass());
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    CreateAndConnectStream(socket_url, sub_protocols, origin);
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // A wrapper for CreateAndConnectStreamForTesting that knows about our default
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // parameters.
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectStream(const std::string& socket_url,
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              const std::vector<std::string>& sub_protocols,
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              const std::string& origin) {
1285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
1295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        new TestConnectDelegate(this));
1305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WebSocketStream::ConnectDelegate* delegate = connect_delegate.get();
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    stream_request_ = ::net::CreateAndConnectStreamForTesting(
132a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        GURL(socket_url),
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        scoped_ptr<WebSocketHandshakeStreamCreateHelper>(
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            new DeterministicKeyWebSocketHandshakeStreamCreateHelper(
1355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                delegate, sub_protocols)),
136a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        url::Origin(origin),
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        url_request_context_host_.GetURLRequestContext(),
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        BoundNetLog(),
1395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        connect_delegate.Pass());
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
141a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
142a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // A simple function to make the tests more readable. Creates an empty vector.
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static std::vector<std::string> NoSubProtocols() {
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return std::vector<std::string>();
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& failure_message() const { return failure_message_; }
1505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool has_failed() const { return has_failed_; }
151a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
152a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  class TestConnectDelegate : public WebSocketStream::ConnectDelegate {
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   public:
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    explicit TestConnectDelegate(WebSocketStreamCreateTest* owner)
1555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        : owner_(owner) {}
156a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
157a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE {
158a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      stream.swap(owner_->stream_);
159a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual void OnFailure(const std::string& message) OVERRIDE {
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->has_failed_ = true;
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->failure_message_ = message;
1645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual void OnStartOpeningHandshake(
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (owner_->request_info_)
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ADD_FAILURE();
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->request_info_ = request.Pass();
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual void OnFinishOpeningHandshake(
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (owner_->response_info_)
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ADD_FAILURE();
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->response_info_ = response.Pass();
177a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   private:
180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    WebSocketStreamCreateTest* owner_;
181a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  };
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WebSocketTestURLRequestContextHost url_request_context_host_;
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStreamRequest> stream_request_;
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Only set if the connection succeeded.
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStream> stream_;
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only set if the connection failed.
1885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string failure_message_;
1895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool has_failed_;
1905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeRequestInfo> request_info_;
1915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeResponseInfo> response_info_;
1925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
1935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// There are enough tests of the Sec-WebSocket-Extensions header that they
1955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// deserve their own test fixture.
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class WebSocketStreamCreateExtensionTest : public WebSocketStreamCreateTest {
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
1985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Performs a standard connect, with the value of the Sec-WebSocket-Extensions
1995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // header in the response set to |extensions_header_value|. Runs the event
2005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // loop to allow the connect to complete.
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void CreateAndConnectWithExtensions(
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& extensions_header_value) {
2035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CreateAndConnectStandard(
2045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "ws://localhost/testing_path",
2055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "/testing_path",
2065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        NoSubProtocols(),
207a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        "http://localhost",
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "",
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n");
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RunUntilIdle();
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
212a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
213a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
214c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass WebSocketStreamCreateUMATest : public ::testing::Test {
215c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch public:
216c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // This enum should match with the enum in Delegate in websocket_stream.cc.
217c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  enum HandshakeResult {
218c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    INCOMPLETE,
219c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    CONNECTED,
220c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    FAILED,
221c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    NUM_HANDSHAKE_RESULT_TYPES,
222c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  };
223c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
224c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  class StreamCreation : public WebSocketStreamCreateTest {
225c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    virtual void TestBody() OVERRIDE {}
226c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  };
227c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
228c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> GetSamples(const std::string& name) {
229c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    base::HistogramBase* histogram =
230c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        base::StatisticsRecorder::FindHistogram(name);
231c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return histogram ? histogram->SnapshotSamples()
232c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     : scoped_ptr<base::HistogramSamples>();
233c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
234c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch};
235c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the basic case works as expected.
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SimpleSuccess) {
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
239a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "");
2405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
2415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
244a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(request_info_);
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(response_info_);
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
2485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, HandshakeInfo) {
2505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char kResponse[] =
2515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Upgrade: websocket\r\n"
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Connection: Upgrade\r\n"
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "foo: bar, baz\r\n"
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "hoge: fuga\r\n"
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "hoge: piyo\r\n"
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "\r\n";
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse(
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "ws://localhost/",
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "/",
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NoSubProtocols(),
264a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "",
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kResponse);
2675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(stream_);
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(request_info_);
2725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(response_info_);
2735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> request_headers =
2745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ToVector(request_info_->headers);
2755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We examine the contents of request_info_ and response_info_
2765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // mainly only in this test case.
2775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(GURL("ws://localhost/"), request_info_->url);
2785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(GURL("ws://localhost/"), response_info_->url);
2795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(101, response_info_->status_code);
2805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Switching Protocols", response_info_->status_text);
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(12u, request_headers.size());
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]);
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]);
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]);
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"),
2865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[3]);
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]);
288a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"),
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[5]);
2905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"),
2915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[6]);
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[7]);
2935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip,deflate"),
2945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[8]);
2955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"),
2965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[9]);
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Sec-WebSocket-Key",  request_headers[10].first);
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions",
2995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               "permessage-deflate; client_max_window_bits"),
3005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[11]);
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> response_headers =
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ToVector(*response_info_->headers);
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(6u, response_headers.size());
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Sort the headers for ease of verification.
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::sort(response_headers.begin(), response_headers.end());
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), response_headers[0]);
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first);
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]);
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("foo", "bar, baz"), response_headers[3]);
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("hoge", "fuga"), response_headers[4]);
3135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("hoge", "piyo"), response_headers[5]);
314a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
315a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
316a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the stream isn't established until the message loop runs.
317a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) {
318a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
319a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "");
3205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
322a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
324a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check the path is used.
325a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, PathIsUsed) {
326a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
327a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
328a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           NoSubProtocols(),
329a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://localhost",
330a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "",
331a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "");
332a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
3335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
334a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
335a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
336a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
337a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that the origin is used.
338a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, OriginIsUsed) {
339a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
340a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
341a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           NoSubProtocols(),
342a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
343a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "",
344a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "");
345a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
3465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
347a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
348a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
349a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
350a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that sub-protocols are sent and parsed.
351a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) {
352a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
353a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv11.chromium.org");
354a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv20.chromium.org");
355a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
356a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
357a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           sub_protocols,
358a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
359a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "chatv20.chromium.org\r\n",
361a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n");
362a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
363a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
3645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
365a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol());
366a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
367a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
368a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Unsolicited sub-protocols are rejected.
369a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) {
370a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
371a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
372a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           NoSubProtocols(),
373a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
374a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "",
375a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n");
376a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
377a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
3805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Response must not include 'Sec-WebSocket-Protocol' header "
3815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "if not present in request: chatv20.chromium.org",
3825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
383a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
384a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
385a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Missing sub-protocol response is rejected.
386a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) {
3875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
3885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sub_protocols.push_back("chat.example.com");
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
3915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           sub_protocols,
392a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://localhost",
393a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chat.example.com\r\n",
394a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "");
395a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
396a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
3975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
3985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
3995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Sent non-empty 'Sec-WebSocket-Protocol' header "
4005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "but no response was received",
4015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
402a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
403a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Only one sub-protocol can be accepted.
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) {
406a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
407a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv11.chromium.org");
408a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv20.chromium.org");
409a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
410a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
411a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           sub_protocols,
412a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
413a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
414a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "chatv20.chromium.org\r\n",
415a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
416a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "chatv20.chromium.org\r\n");
417a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
418a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
4195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
4205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Protocol' header must not appear "
4225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "more than once in a response",
4235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
425a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Unmatched sub-protocol should be rejected.
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnmatchedSubProtocolInResponse) {
4285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sub_protocols.push_back("chatv11.chromium.org");
4305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sub_protocols.push_back("chatv20.chromium.org");
431a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
432a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           sub_protocols,
434a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           "chatv20.chromium.org\r\n",
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n");
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' "
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "in response does not match any of sent values",
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate extension basic success case.
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateSuccess) {
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions("permessage-deflate");
4505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(stream_);
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate extensions success with all parameters.
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateParamsSuccess) {
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_no_context_takeover; "
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "server_max_window_bits=11; client_max_window_bits=13; "
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "server_no_context_takeover");
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(stream_);
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Verify that incoming messages are actually decompressed with
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate enabled.
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) {
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse(
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "ws://localhost/testing_path",
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "/testing_path",
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NoSubProtocols(),
471a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "",
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      WebSocketStandardResponse(
4745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "Sec-WebSocket-Extensions: permessage-deflate\r\n") +
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          std::string(
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              "\xc1\x07"  // WebSocket header (FIN + RSV1, Text payload 7 bytes)
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              "\xf2\x48\xcd\xc9\xc9\x07\x00",  // "Hello" DEFLATE compressed
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              9));
479a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(stream_);
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedVector<WebSocketFrame> frames;
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CompletionCallback callback;
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(OK, stream_->ReadFrames(&frames, callback));
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(1U, frames.size());
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(5U, frames[0]->header.payload_length);
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Hello", std::string(frames[0]->data->data(), 5));
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Unknown extension in the response is rejected
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, UnknownExtension) {
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions("x-unknown-extension");
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Found an unsupported extension 'x-unknown-extension' "
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "in 'Sec-WebSocket-Extensions' header",
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Malformed extensions are rejected (this file does not cover all possible
5025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// parse failures, as the parser is covered thoroughly by its own unit tests).
5035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MalformedExtension) {
5045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(";");
5055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
5085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Error during WebSocket handshake: 'Sec-WebSocket-Extensions' header "
5095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "value is rejected by the parser: ;",
5105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
5115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The permessage-deflate extension may only be specified once.
5145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, OnlyOnePerMessageDeflateAllowed) {
5155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
5165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate, permessage-deflate; client_max_window_bits=10");
5175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
520a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: "
521a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received duplicate permessage-deflate response",
5225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
5235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters may not be duplicated.
5265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, NoDuplicateParameters) {
5275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
5285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_no_context_takeover; "
5295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "client_no_context_takeover");
5305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
533a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
534a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received duplicate permessage-deflate extension parameter "
535a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "client_no_context_takeover",
5365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
5375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters must start with "client_" or "server_"
5405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterPrefix) {
5415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
5425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; absurd_no_context_takeover");
543a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (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 an unexpected permessage-deflate extension parameter",
5485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
549a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
550a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
5515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters must be either *_no_context_takeover or
5525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits
5535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterSuffix) {
5545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
5555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_max_content_bits=5");
5565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
559a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
560a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received an unexpected permessage-deflate extension parameter",
5615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
5625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_no_context_takeover parameters must not have an argument
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterValue) {
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_no_context_takeover=true");
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
571a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
572a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid client_no_context_takeover parameter",
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must have an argument
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, NoMaxWindowBitsArgument) {
5785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions("permessage-deflate; client_max_window_bits");
5795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
582a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
583a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "client_max_window_bits must have value",
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be an integer
5885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueInteger) {
5895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
5905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; server_max_window_bits=banana");
5915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
594a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
595a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid server_max_window_bits parameter",
5965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
5975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
5985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
5995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be >= 8
6005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooSmall) {
6015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
6025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; server_max_window_bits=7");
6035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
606a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
607a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid server_max_window_bits parameter",
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be <= 15
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooBig) {
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_max_window_bits=16");
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
618a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
619a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid client_max_window_bits parameter",
6205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must not start with 0
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithZero) {
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_max_window_bits=08");
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
630a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
631a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid client_max_window_bits parameter",
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must not start with +
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithPlus) {
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; server_max_window_bits=+9");
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
642a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
643a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid server_max_window_bits parameter",
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(ricea): Check that WebSocketDeflateStream is initialised with the
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// arguments from the server. This is difficult because the data written to the
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// socket is randomly masked.
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
651a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Additional Sec-WebSocket-Accept headers should be rejected.
652a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleAccept) {
653a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
654a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "ws://localhost/",
655a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "/",
656a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NoSubProtocols(),
657a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
658a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "",
659a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n");
660a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
661a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
6645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Accept' header must not appear "
6655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "more than once in a response",
6665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
667a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
668a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
669a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Response code 200 must be rejected.
670a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) {
671a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kInvalidStatusCodeResponse[] =
672a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 200 OK\r\n"
673a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
674a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
675a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
676a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
677a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
678a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
679a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
680a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
681a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
682a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kInvalidStatusCodeResponse);
683a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 200",
6865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
687a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
688a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
689a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Redirects are not followed (according to the WHATWG WebSocket API, which
690a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// overrides RFC6455 for browser applications).
691a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, RedirectsRejected) {
692a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kRedirectResponse[] =
693a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 302 Moved Temporarily\r\n"
694a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Content-Type: text/html\r\n"
695a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Content-Length: 34\r\n"
696a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: keep-alive\r\n"
697a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Location: ws://localhost/other\r\n"
698a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n"
699a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "<title>Moved</title><h1>Moved</h1>";
700a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
701a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
702a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
703a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
704a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
705a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kRedirectResponse);
706a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
7075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 302",
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
710a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
711a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
712a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Malformed responses should be rejected. HttpStreamParser will accept just
713a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// about any garbage in the middle of the headers. To make it give up, the junk
714a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// has to be at the start of the response. Even then, it just gets treated as an
715a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// HTTP/0.9 response.
716a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MalformedResponse) {
717a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMalformedResponse[] =
718a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "220 mx.google.com ESMTP\r\n"
719a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 OK\r\n"
720a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
721a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
722a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
723a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
724a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
725a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
726a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
727a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
728a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMalformedResponse);
730a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
732a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: Invalid status line",
7335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
734a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
736a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Upgrade header must be present.
737a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) {
738a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMissingUpgradeResponse[] =
739a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
740a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
741a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
742a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
743a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
744a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
745a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
746a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
747a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
748a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMissingUpgradeResponse);
749a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing",
7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
753a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
754a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
755a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// There must only be one upgrade header.
756a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) {
757a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
758a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "ws://localhost/",
759a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "/",
760a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NoSubProtocols(),
761a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
762a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "", "Upgrade: HTTP/2.0\r\n");
763a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
7645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
7665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Upgrade' header must not appear more than once in a response",
7675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
7685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// There must only be one correct upgrade header.
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, IncorrectUpgradeHeader) {
7725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char kMissingUpgradeResponse[] =
7735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Connection: Upgrade\r\n"
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
7765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Upgrade: hogefuga\r\n"
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "\r\n";
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "/",
7805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 NoSubProtocols(),
781a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "",
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 kMissingUpgradeResponse);
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Upgrade' header value is not 'WebSocket': hogefuga",
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
789a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
790a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
791a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header must be present.
792a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) {
793a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMissingConnectionResponse[] =
794a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
795a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
796a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
797a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
798a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
799a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
800a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
801a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
802a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
803a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMissingConnectionResponse);
804a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
8055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Connection' header is missing",
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Connection header must contain "Upgrade".
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, IncorrectConnectionHeader) {
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char kMissingConnectionResponse[] =
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Upgrade: websocket\r\n"
8165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
8175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Connection: hogefuga\r\n"
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "\r\n";
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "/",
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 NoSubProtocols(),
822a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "",
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 kMissingConnectionResponse);
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
8285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Connection' header value must contain 'Upgrade'",
8295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
830a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
831a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
832a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header is permitted to contain other tokens.
833a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) {
834a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kAdditionalConnectionTokenResponse[] =
835a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
836a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
837a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade, Keep-Alive\r\n"
838a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
839a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
840a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
841a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
843a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
844a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
845a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kAdditionalConnectionTokenResponse);
846a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
8475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
848a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
849a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
850a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
851a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must be present.
852a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) {
853a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMissingAcceptResponse[] =
854a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
855a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
856a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
857a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
858a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
859a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
860a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
861a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
862a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
863a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMissingAcceptResponse);
864a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
8655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
8675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Accept' header is missing",
8685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
869a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
870a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
871a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must match the key that was sent.
872a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) {
873a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kIncorrectAcceptResponse[] =
874a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
875a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
876a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
877a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n"
878a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
879a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
880a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
881a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
882a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
883a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
884a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kIncorrectAcceptResponse);
885a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
8865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
8885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Incorrect 'Sec-WebSocket-Accept' header value",
8895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
890a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
891a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
892a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation works.
893a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, Cancellation) {
894a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
895a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "");
896a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
897a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
8985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
899a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
9005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
9015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
902a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
903a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
904a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect failure must look just like negotiation failure.
905a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionFailure) {
906a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(
907a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new DeterministicSocketData(NULL, 0, NULL, 0));
908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(
909a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
910a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
911a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost", socket_data.Pass());
912a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
9145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
9155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
9165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
918a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
919a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
920a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect timeout must look just like any other failure.
921a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) {
922a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(
923a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new DeterministicSocketData(NULL, 0, NULL, 0));
924a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(
925a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT));
926a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
927a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost", socket_data.Pass());
928a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
9305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT",
9315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
932a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
933a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
934a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during connect works.
935a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) {
936a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(
937a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new DeterministicSocketData(NULL, 0, NULL, 0));
938a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
939a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
940a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  NoSubProtocols(),
941a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
942a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  socket_data.Pass());
943a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
944a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
946a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
947a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
948a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
949a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during write of the request headers works.
950a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) {
951a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // We seem to need at least two operations in order to use SetStop().
952a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"),
953a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        MockWrite(ASYNC, 1, "1.1\r\n")};
954a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // We keep a copy of the pointer so that we can call RunFor() on it later.
955a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DeterministicSocketData* socket_data(
956a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new DeterministicSocketData(NULL, 0, writes, arraysize(writes)));
957a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
958a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->SetStop(1);
959a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
960a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  NoSubProtocols(),
961a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
962a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  make_scoped_ptr(socket_data));
963a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->Run();
964a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
965a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
967a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
9685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(request_info_);
9695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
970a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
971a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
972a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during read of the response headers works.
973a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) {
974a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string request = WebSocketStandardRequest("/", "http://localhost", "");
975a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())};
976a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockRead reads[] = {
977a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"),
978a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  };
979a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DeterministicSocketData* socket_data(new DeterministicSocketData(
980a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      reads, arraysize(reads), writes, arraysize(writes)));
981a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
982a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->SetStop(1);
983a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
984a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  NoSubProtocols(),
985a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
986a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  make_scoped_ptr(socket_data));
987a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->Run();
988a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
989a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
9915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
9925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(request_info_);
9935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
9945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Over-size response headers (> 256KB) should not cause a crash.  This is a
9975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// regression test for crbug.com/339456. It is based on the layout test
9985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// "cookie-flood.html".
9995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, VeryLargeResponseHeaders) {
10005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string set_cookie_headers;
10015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_cookie_headers.reserve(45 * 10000);
10025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < 10000; ++i) {
10035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    set_cookie_headers +=
10045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::StringPrintf("Set-Cookie: WK-websocket-test-flood-%d=1\r\n", i);
10055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
10065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/", "/", NoSubProtocols(),
1007a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://localhost", "", set_cookie_headers);
10085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
10095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
10105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
10115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
10125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
10135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If the remote host closes the connection without sending headers, we should
10145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// log the console message "Connection closed before receiving a handshake
10155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// response".
10165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, NoResponse) {
1017a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string request = WebSocketStandardRequest("/", "http://localhost", "");
10185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)};
10195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MockRead reads[] = {MockRead(ASYNC, 0, 1)};
10205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  DeterministicSocketData* socket_data(new DeterministicSocketData(
10215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      reads, arraysize(reads), writes, arraysize(writes)));
10225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
10235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
10245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  NoSubProtocols(),
1025a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
10265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  make_scoped_ptr(socket_data));
10275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  socket_data->RunFor(2);
10285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
1029a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
10305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
10315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Connection closed before receiving a handshake response",
10325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
1033a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1034a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1035c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(WebSocketStreamCreateUMATest, Incomplete) {
1036c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::string name("Net.WebSocket.HandshakeResult");
1037c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> original(GetSamples(name));
1038c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1039c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  {
1040c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StreamCreation creation;
1041c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.CreateAndConnectStandard("ws://localhost/",
1042c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "/",
1043c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      creation.NoSubProtocols(),
1044c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "http://localhost",
1045c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "",
1046c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "");
1047c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1048c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1049c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> samples(GetSamples(name));
1050c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_TRUE(samples);
1051c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (original) {
1052c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    samples->Subtract(*original);  // Cancel the original values.
1053c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1054c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(1, samples->GetCount(INCOMPLETE));
1055c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(CONNECTED));
1056c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(FAILED));
1057c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
1058c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1059c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(WebSocketStreamCreateUMATest, Connected) {
1060c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::string name("Net.WebSocket.HandshakeResult");
1061c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> original(GetSamples(name));
1062c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1063c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  {
1064c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StreamCreation creation;
1065c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.CreateAndConnectStandard("ws://localhost/",
1066c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "/",
1067c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      creation.NoSubProtocols(),
1068c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "http://localhost",
1069c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "",
1070c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "");
1071c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.RunUntilIdle();
1072c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1073c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1074c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> samples(GetSamples(name));
1075c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_TRUE(samples);
1076c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (original) {
1077c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    samples->Subtract(*original);  // Cancel the original values.
1078c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1079c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(INCOMPLETE));
1080c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(1, samples->GetCount(CONNECTED));
1081c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(FAILED));
1082c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
1083c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1084c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(WebSocketStreamCreateUMATest, Failed) {
1085c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::string name("Net.WebSocket.HandshakeResult");
1086c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> original(GetSamples(name));
1087c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1088c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  {
1089c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StreamCreation creation;
1090c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    static const char kInvalidStatusCodeResponse[] =
1091c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "HTTP/1.1 200 OK\r\n"
1092c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Upgrade: websocket\r\n"
1093c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Connection: Upgrade\r\n"
1094c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
1095c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "\r\n";
1096c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.CreateAndConnectCustomResponse("ws://localhost/",
1097c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            "/",
1098c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            creation.NoSubProtocols(),
1099c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            "http://localhost",
1100c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            "",
1101c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            kInvalidStatusCodeResponse);
1102c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.RunUntilIdle();
1103c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1104c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1105c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> samples(GetSamples(name));
1106c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_TRUE(samples);
1107c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (original) {
1108c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    samples->Subtract(*original);  // Cancel the original values.
1109c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1110c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(INCOMPLETE));
1111c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(CONNECTED));
1112c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(1, samples->GetCount(FAILED));
1113c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
1114c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
1116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace net
1117