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)
12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include "base/compiler_specific.h"
135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/memory/scoped_vector.h"
14c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/metrics/histogram.h"
15c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/metrics/histogram_samples.h"
16c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/metrics/statistics_recorder.h"
17a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/run_loop.h"
185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/strings/stringprintf.h"
191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/timer/mock_timer.h"
201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/timer/timer.h"
21a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/base/net_errors.h"
2246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "net/base/test_data_directory.h"
235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_request_headers.h"
245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/http/http_response_headers.h"
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/client_socket_handle.h"
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/socket/socket_test_util.h"
2746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "net/test/cert_test_util.h"
28a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/url_request/url_request_test_util.h"
29a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_basic_handshake_stream.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_frame.h"
315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_request_info.h"
325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "net/websockets/websocket_handshake_response_info.h"
33a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_handshake_stream_create_helper.h"
34a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_test_util.h"
35a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
36a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h"
37a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "url/origin.h"
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace net {
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)typedef std::pair<std::string, std::string> HeaderKeyValuePair;
435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<HeaderKeyValuePair> ToVector(const HttpRequestHeaders& headers) {
455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  HttpRequestHeaders::Iterator it(headers);
465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> result;
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (it.GetNext())
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.push_back(HeaderKeyValuePair(it.name(), it.value()));
495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)std::vector<HeaderKeyValuePair> ToVector(const HttpResponseHeaders& headers) {
535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void* iter = NULL;
545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string name, value;
555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> result;
565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  while (headers.EnumerateHeaderLines(&iter, &name, &value))
575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    result.push_back(HeaderKeyValuePair(name, value));
585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  return result;
595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Simple builder for a DeterministicSocketData object to save repetitive code.
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// It always sets the connect data to MockConnect(SYNCHRONOUS, OK), so it cannot
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// be used in tests where the connect fails. In practice, those tests never have
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// any read/write data and so can't benefit from it anyway.  The arrays are not
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// copied. It is up to the caller to ensure they stay in scope until the test
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// ends.
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)template <size_t reads_count, size_t writes_count>
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)scoped_ptr<DeterministicSocketData> BuildSocketData(
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    MockRead (&reads)[reads_count],
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    MockWrite (&writes)[writes_count]) {
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new DeterministicSocketData(reads, reads_count, writes, writes_count));
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  socket_data->SetStop(reads_count + writes_count);
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return socket_data.Pass();
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Builder for a DeterministicSocketData that expects nothing. This does not
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// set the connect data, so the calling code must do that explicitly.
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)scoped_ptr<DeterministicSocketData> BuildNullSocketData() {
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  return make_scoped_ptr(new DeterministicSocketData(NULL, 0, NULL, 0));
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciclass MockWeakTimer : public base::MockTimer,
851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                      public base::SupportsWeakPtr<MockWeakTimer> {
861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci public:
871320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  MockWeakTimer(bool retain_user_task, bool is_repeating)
881320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      : MockTimer(retain_user_task, is_repeating) {}
891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci};
901320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// A sub-class of WebSocketHandshakeStreamCreateHelper which always sets a
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// deterministic key to use in the WebSocket handshake.
93a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class DeterministicKeyWebSocketHandshakeStreamCreateHelper
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    : public WebSocketHandshakeStreamCreateHelper {
95a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DeterministicKeyWebSocketHandshakeStreamCreateHelper(
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      WebSocketStream::ConnectDelegate* connect_delegate,
98a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::vector<std::string>& requested_subprotocols)
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      : WebSocketHandshakeStreamCreateHelper(connect_delegate,
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                             requested_subprotocols) {}
101a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
102116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void OnStreamCreated(WebSocketBasicHandshakeStream* stream) OVERRIDE {
103116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    stream->SetWebSocketKeyForTesting("dGhlIHNhbXBsZSBub25jZQ==");
104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
107a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class WebSocketStreamCreateTest : public ::testing::Test {
108c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch public:
10946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  WebSocketStreamCreateTest() : has_failed_(false), ssl_fatal_(false) {}
110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
111a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectCustomResponse(
112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_url,
113a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_path,
114a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::vector<std::string>& sub_protocols,
115a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& origin,
116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& extra_request_headers,
1171320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      const std::string& response_body,
1181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      scoped_ptr<base::Timer> timer = scoped_ptr<base::Timer>()) {
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    url_request_context_host_.SetExpectations(
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        WebSocketStandardRequest(socket_path, origin, extra_request_headers),
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        response_body);
1221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CreateAndConnectStream(socket_url, sub_protocols, origin, timer.Pass());
123a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
124a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
125a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |extra_request_headers| and |extra_response_headers| must end in "\r\n" or
126a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // errors like "Unable to perform synchronous IO while stopped" will occur.
127a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectStandard(const std::string& socket_url,
128a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::string& socket_path,
129a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::vector<std::string>& sub_protocols,
130a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::string& origin,
131a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                const std::string& extra_request_headers,
1321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                const std::string& extra_response_headers,
1331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                scoped_ptr<base::Timer> timer =
1341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                scoped_ptr<base::Timer>()) {
135a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    CreateAndConnectCustomResponse(
136a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        socket_url,
137a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        socket_path,
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        sub_protocols,
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        origin,
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        extra_request_headers,
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        WebSocketStandardResponse(extra_response_headers),
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        timer.Pass());
143a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
144a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
145a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectRawExpectations(
146a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& socket_url,
147a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::vector<std::string>& sub_protocols,
148a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const std::string& origin,
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      scoped_ptr<DeterministicSocketData> socket_data,
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      scoped_ptr<base::Timer> timer = scoped_ptr<base::Timer>()) {
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    AddRawExpectations(socket_data.Pass());
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    CreateAndConnectStream(socket_url, sub_protocols, origin, timer.Pass());
153a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
154a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Add additional raw expectations for sockets created before the final one.
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void AddRawExpectations(scoped_ptr<DeterministicSocketData> socket_data) {
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    url_request_context_host_.AddRawExpectations(socket_data.Pass());
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
160a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // A wrapper for CreateAndConnectStreamForTesting that knows about our default
161a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // parameters.
162a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void CreateAndConnectStream(const std::string& socket_url,
163a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              const std::vector<std::string>& sub_protocols,
1641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              const std::string& origin,
1651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              scoped_ptr<base::Timer> timer) {
16646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    for (size_t i = 0; i < ssl_data_.size(); ++i) {
16746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<SSLSocketDataProvider> ssl_data(ssl_data_[i]);
16846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ssl_data_[i] = NULL;
16946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      url_request_context_host_.AddSSLSocketDataProvider(ssl_data.Pass());
17046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
17146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    ssl_data_.clear();
1725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate(
1735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        new TestConnectDelegate(this));
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    WebSocketStream::ConnectDelegate* delegate = connect_delegate.get();
175116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper(
176116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        new DeterministicKeyWebSocketHandshakeStreamCreateHelper(
177116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch            delegate, sub_protocols));
178a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    stream_request_ = ::net::CreateAndConnectStreamForTesting(
179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        GURL(socket_url),
180116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch        create_helper.Pass(),
181a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        url::Origin(origin),
182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        url_request_context_host_.GetURLRequestContext(),
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        BoundNetLog(),
1841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        connect_delegate.Pass(),
1851320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        timer ? timer.Pass() : scoped_ptr<base::Timer>(
1861320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            new base::Timer(false, false)));
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static void RunUntilIdle() { base::RunLoop().RunUntilIdle(); }
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // A simple function to make the tests more readable. Creates an empty vector.
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static std::vector<std::string> NoSubProtocols() {
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    return std::vector<std::string>();
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  const std::string& failure_message() const { return failure_message_; }
1975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool has_failed() const { return has_failed_; }
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  class TestConnectDelegate : public WebSocketStream::ConnectDelegate {
200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   public:
2015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    explicit TestConnectDelegate(WebSocketStreamCreateTest* owner)
2025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        : owner_(owner) {}
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    virtual void OnSuccess(scoped_ptr<WebSocketStream> stream) OVERRIDE {
205a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      stream.swap(owner_->stream_);
206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual void OnFailure(const std::string& message) OVERRIDE {
2095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->has_failed_ = true;
2105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->failure_message_ = message;
2115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual void OnStartOpeningHandshake(
2145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scoped_ptr<WebSocketHandshakeRequestInfo> request) OVERRIDE {
2155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // Can be called multiple times (in the case of HTTP auth). Last call
2165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      // wins.
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->request_info_ = request.Pass();
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
2195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    virtual void OnFinishOpeningHandshake(
2205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        scoped_ptr<WebSocketHandshakeResponseInfo> response) OVERRIDE {
2215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (owner_->response_info_)
2225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        ADD_FAILURE();
2235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      owner_->response_info_ = response.Pass();
224a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    }
22546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    virtual void OnSSLCertificateError(
22646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks>
22746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)            ssl_error_callbacks,
22846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        const SSLInfo& ssl_info,
22946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)        bool fatal) OVERRIDE {
23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      owner_->ssl_error_callbacks_ = ssl_error_callbacks.Pass();
23146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      owner_->ssl_info_ = ssl_info;
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      owner_->ssl_fatal_ = fatal;
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
234a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
235a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)   private:
236a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    WebSocketStreamCreateTest* owner_;
237a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  };
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
239a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WebSocketTestURLRequestContextHost url_request_context_host_;
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStreamRequest> stream_request_;
241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Only set if the connection succeeded.
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStream> stream_;
2435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Only set if the connection failed.
2445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string failure_message_;
2455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  bool has_failed_;
2465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeRequestInfo> request_info_;
2475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeResponseInfo> response_info_;
24846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks> ssl_error_callbacks_;
24946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  SSLInfo ssl_info_;
25046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  bool ssl_fatal_;
25146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ScopedVector<SSLSocketDataProvider> ssl_data_;
2525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)};
2535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// There are enough tests of the Sec-WebSocket-Extensions header that they
2555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// deserve their own test fixture.
2565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)class WebSocketStreamCreateExtensionTest : public WebSocketStreamCreateTest {
2575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public:
2585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Performs a standard connect, with the value of the Sec-WebSocket-Extensions
2595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // header in the response set to |extensions_header_value|. Runs the event
2605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // loop to allow the connect to complete.
2615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void CreateAndConnectWithExtensions(
2625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      const std::string& extensions_header_value) {
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    CreateAndConnectStandard(
2645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "ws://localhost/testing_path",
2655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "/testing_path",
2665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        NoSubProtocols(),
267a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)        "http://localhost",
2685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "",
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        "Sec-WebSocket-Extensions: " + extensions_header_value + "\r\n");
2705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    RunUntilIdle();
2715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
272a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
2745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Common code to construct expectations for authentication tests that receive
2755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// the auth challenge on one connection and then create a second connection to
2765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// send the authenticated request on.
2775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class CommonAuthTestHelper {
2785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) public:
2795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CommonAuthTestHelper() : reads1_(), writes1_(), reads2_(), writes2_() {}
2805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> BuildSocketData1(
2825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const std::string& response) {
2835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    request1_ = WebSocketStandardRequest("/", "http://localhost", "");
2845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    writes1_[0] = MockWrite(SYNCHRONOUS, 0, request1_.c_str());
2855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    response1_ = response;
2865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    reads1_[0] = MockRead(SYNCHRONOUS, 1, response1_.c_str());
2875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    reads1_[1] = MockRead(SYNCHRONOUS, OK, 2);  // Close connection
2885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return BuildSocketData(reads1_, writes1_);
2905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
2915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
2925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> BuildSocketData2(
2935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const std::string& request,
2945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      const std::string& response) {
2955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    request2_ = request;
2965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    response2_ = response;
2975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    writes2_[0] = MockWrite(SYNCHRONOUS, 0, request2_.c_str());
2985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    reads2_[0] = MockRead(SYNCHRONOUS, 1, response2_.c_str());
2995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return BuildSocketData(reads2_, writes2_);
3005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) private:
3035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // These need to be object-scoped since they have to remain valid until all
3045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // socket operations in the test are complete.
3055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string request1_;
3065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string request2_;
3075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string response1_;
3085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::string response2_;
3095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MockRead reads1_[2];
3105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MockWrite writes1_[1];
3115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MockRead reads2_[1];
3125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  MockWrite writes2_[1];
3135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(CommonAuthTestHelper);
3155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
3165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Data and methods for BasicAuth tests.
3185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class WebSocketStreamCreateBasicAuthTest : public WebSocketStreamCreateTest {
3195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) protected:
3205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void CreateAndConnectAuthHandshake(const std::string& url,
3215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                     const std::string& base64_user_pass,
3225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                     const std::string& response2) {
3235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    AddRawExpectations(helper_.BuildSocketData1(kUnauthorizedResponse));
3245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    static const char request2format[] =
3265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "GET / HTTP/1.1\r\n"
3275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Host: localhost\r\n"
3285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Connection: Upgrade\r\n"
3295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Pragma: no-cache\r\n"
3305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Cache-Control: no-cache\r\n"
3315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Authorization: Basic %s\r\n"
3325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Upgrade: websocket\r\n"
3335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Origin: http://localhost\r\n"
3345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Sec-WebSocket-Version: 13\r\n"
3355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "User-Agent:\r\n"
3361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        "Accept-Encoding: gzip, deflate\r\n"
3375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Accept-Language: en-us,fr\r\n"
3385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
3395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "Sec-WebSocket-Extensions: permessage-deflate; "
3405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "client_max_window_bits\r\n"
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "\r\n";
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string request =
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        base::StringPrintf(request2format, base64_user_pass.c_str());
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    CreateAndConnectRawExpectations(
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        url,
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        NoSubProtocols(),
3475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        "http://localhost",
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        helper_.BuildSocketData2(request, response2));
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  static const char kUnauthorizedResponse[];
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CommonAuthTestHelper helper_;
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)class WebSocketStreamCreateDigestAuthTest : public WebSocketStreamCreateTest {
3575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) protected:
3585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  static const char kUnauthorizedResponse[];
3595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  static const char kAuthorizedRequest[];
3605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CommonAuthTestHelper helper_;
3625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)};
3635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char WebSocketStreamCreateBasicAuthTest::kUnauthorizedResponse[] =
3655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "HTTP/1.1 401 Unauthorized\r\n"
3665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Content-Length: 0\r\n"
3675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "WWW-Authenticate: Basic realm=\"camelot\"\r\n"
3685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "\r\n";
3695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// These negotiation values are borrowed from
3715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// http_auth_handler_digest_unittest.cc. Feel free to come up with new ones if
3725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// you are bored. Only the weakest (no qop) variants of Digest authentication
3735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// can be tested by this method, because the others involve random input.
3745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char WebSocketStreamCreateDigestAuthTest::kUnauthorizedResponse[] =
3755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "HTTP/1.1 401 Unauthorized\r\n"
3765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Content-Length: 0\r\n"
3775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "WWW-Authenticate: Digest realm=\"Oblivion\", nonce=\"nonce-value\"\r\n"
3785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "\r\n";
3795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
3805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)const char WebSocketStreamCreateDigestAuthTest::kAuthorizedRequest[] =
3815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "GET / HTTP/1.1\r\n"
3825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Host: localhost\r\n"
3835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Connection: Upgrade\r\n"
3845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Pragma: no-cache\r\n"
3855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Cache-Control: no-cache\r\n"
3865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Authorization: Digest username=\"FooBar\", realm=\"Oblivion\", "
3875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "nonce=\"nonce-value\", uri=\"/\", "
3885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "response=\"f72ff54ebde2f928860f806ec04acd1b\"\r\n"
3895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Upgrade: websocket\r\n"
3905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Origin: http://localhost\r\n"
3915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Sec-WebSocket-Version: 13\r\n"
3925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "User-Agent:\r\n"
3931320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    "Accept-Encoding: gzip, deflate\r\n"
3945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Accept-Language: en-us,fr\r\n"
3955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
3965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "Sec-WebSocket-Extensions: permessage-deflate; "
3975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "client_max_window_bits\r\n"
3985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    "\r\n";
3995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdochclass WebSocketStreamCreateUMATest : public ::testing::Test {
401c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch public:
402c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  // This enum should match with the enum in Delegate in websocket_stream.cc.
403c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  enum HandshakeResult {
404c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    INCOMPLETE,
405c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    CONNECTED,
406c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    FAILED,
407c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    NUM_HANDSHAKE_RESULT_TYPES,
408c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  };
409c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
410c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  class StreamCreation : public WebSocketStreamCreateTest {
411c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    virtual void TestBody() OVERRIDE {}
412c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  };
413c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
414c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> GetSamples(const std::string& name) {
415c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    base::HistogramBase* histogram =
416c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        base::StatisticsRecorder::FindHistogram(name);
417c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    return histogram ? histogram->SnapshotSamples()
418c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                     : scoped_ptr<base::HistogramSamples>();
419c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
420c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch};
421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
422a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the basic case works as expected.
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SimpleSuccess) {
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
425a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "");
4265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
4275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
428a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
4295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
430a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
4315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(request_info_);
4325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(response_info_);
4335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
4345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, HandshakeInfo) {
4365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char kResponse[] =
4375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
4385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Upgrade: websocket\r\n"
4395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Connection: Upgrade\r\n"
4405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
4415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "foo: bar, baz\r\n"
4425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "hoge: fuga\r\n"
4435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "hoge: piyo\r\n"
4445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "\r\n";
4455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse(
4475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "ws://localhost/",
4485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "/",
4495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NoSubProtocols(),
450a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
4515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "",
4525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      kResponse);
4535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
4545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
4555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
4565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(stream_);
4575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(request_info_);
4585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(response_info_);
4595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> request_headers =
4605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ToVector(request_info_->headers);
4615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // We examine the contents of request_info_ and response_info_
4625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // mainly only in this test case.
4635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(GURL("ws://localhost/"), request_info_->url);
4645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(GURL("ws://localhost/"), response_info_->url);
4655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(101, response_info_->status_code);
4665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Switching Protocols", response_info_->status_text);
4675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(12u, request_headers.size());
4685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Host", "localhost"), request_headers[0]);
4695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), request_headers[1]);
4705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Pragma", "no-cache"), request_headers[2]);
4715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Cache-Control", "no-cache"),
4725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[3]);
4735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), request_headers[4]);
474a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Origin", "http://localhost"),
4755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[5]);
4765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Version", "13"),
4775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[6]);
4785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("User-Agent", ""), request_headers[7]);
4791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ(HeaderKeyValuePair("Accept-Encoding", "gzip, deflate"),
4805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[8]);
4815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Accept-Language", "en-us,fr"),
4825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[9]);
4835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Sec-WebSocket-Key",  request_headers[10].first);
4845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Sec-WebSocket-Extensions",
4855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                               "permessage-deflate; client_max_window_bits"),
4865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            request_headers[11]);
4875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<HeaderKeyValuePair> response_headers =
4891320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      ToVector(*response_info_->headers.get());
4905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(6u, response_headers.size());
4915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  // Sort the headers for ease of verification.
4925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::sort(response_headers.begin(), response_headers.end());
4935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
4945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Connection", "Upgrade"), response_headers[0]);
4955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Sec-WebSocket-Accept", response_headers[1].first);
4965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("Upgrade", "websocket"), response_headers[2]);
4975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("foo", "bar, baz"), response_headers[3]);
4985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("hoge", "fuga"), response_headers[4]);
4995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(HeaderKeyValuePair("hoge", "piyo"), response_headers[5]);
500a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
501a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
502a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Confirm that the stream isn't established until the message loop runs.
503a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, NeedsToRunLoop) {
504a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
505a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "");
5065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
507a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
508a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
509a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
510a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check the path is used.
511a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, PathIsUsed) {
512a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
513a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
514a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           NoSubProtocols(),
515a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://localhost",
516a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "",
517a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "");
518a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
5195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
520a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
521a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
522a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
523a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that the origin is used.
524a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, OriginIsUsed) {
525a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
526a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
527a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           NoSubProtocols(),
528a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
529a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "",
530a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "");
531a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
5325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
533a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
534a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
535a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
536a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Check that sub-protocols are sent and parsed.
537a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SubProtocolIsUsed) {
538a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
539a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv11.chromium.org");
540a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv20.chromium.org");
541a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
542a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
543a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           sub_protocols,
544a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
545a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
546a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "chatv20.chromium.org\r\n",
547a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n");
548a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
549a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
5505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
551a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_EQ("chatv20.chromium.org", stream_->GetSubProtocol());
552a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
553a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
554a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Unsolicited sub-protocols are rejected.
555a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnsolicitedSubProtocol) {
556a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
557a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
558a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           NoSubProtocols(),
559a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
560a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "",
561a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv20.chromium.org\r\n");
562a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
563a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
5665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Response must not include 'Sec-WebSocket-Protocol' header "
5675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "if not present in request: chatv20.chromium.org",
5685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
569a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
570a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
571a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Missing sub-protocol response is rejected.
572a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnacceptedSubProtocol) {
5735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
5745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sub_protocols.push_back("chat.example.com");
575a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
576a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
5775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           sub_protocols,
578a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://localhost",
579a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chat.example.com\r\n",
580a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "");
581a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
582a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
5835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
5845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
5855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Sent non-empty 'Sec-WebSocket-Protocol' header "
5865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "but no response was received",
5875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
588a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
589a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
590a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Only one sub-protocol can be accepted.
591a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MultipleSubProtocolsInResponse) {
592a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
593a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv11.chromium.org");
594a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  sub_protocols.push_back("chatv20.chromium.org");
595a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
596a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
597a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           sub_protocols,
598a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
599a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
600a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "chatv20.chromium.org\r\n",
601a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
602a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "chatv20.chromium.org\r\n");
603a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
604a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
6075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Protocol' header must not appear "
6085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "more than once in a response",
6095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
610a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
611a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
6125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Unmatched sub-protocol should be rejected.
6135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, UnmatchedSubProtocolInResponse) {
6145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::vector<std::string> sub_protocols;
6155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sub_protocols.push_back("chatv11.chromium.org");
6165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  sub_protocols.push_back("chatv20.chromium.org");
617a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/testing_path",
618a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                           "/testing_path",
6195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           sub_protocols,
620a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://google.com",
6215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv11.chromium.org, "
6225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           "chatv20.chromium.org\r\n",
6235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                           "Sec-WebSocket-Protocol: chatv21.chromium.org\r\n");
6245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
6255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
6285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Protocol' header value 'chatv21.chromium.org' "
6295d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "in response does not match any of sent values",
6305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
6315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate extension basic success case.
6345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateSuccess) {
6355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions("permessage-deflate");
6365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(stream_);
6375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
6385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate extensions success with all parameters.
6415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateParamsSuccess) {
6425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
6435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_no_context_takeover; "
6445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "server_max_window_bits=11; client_max_window_bits=13; "
6455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "server_no_context_takeover");
6465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(stream_);
6475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
6485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Verify that incoming messages are actually decompressed with
6515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate enabled.
6525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, PerMessageDeflateInflates) {
6535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse(
6545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "ws://localhost/testing_path",
6555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "/testing_path",
6565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      NoSubProtocols(),
657a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
6585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "",
6595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      WebSocketStandardResponse(
6605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          "Sec-WebSocket-Extensions: permessage-deflate\r\n") +
6615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          std::string(
6625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              "\xc1\x07"  // WebSocket header (FIN + RSV1, Text payload 7 bytes)
6635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              "\xf2\x48\xcd\xc9\xc9\x07\x00",  // "Hello" DEFLATE compressed
6645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              9));
665a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
6665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_TRUE(stream_);
6685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ScopedVector<WebSocketFrame> frames;
6695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CompletionCallback callback;
6705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(OK, stream_->ReadFrames(&frames, callback));
6715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(1U, frames.size());
6725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  ASSERT_EQ(5U, frames[0]->header.payload_length);
6735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Hello", std::string(frames[0]->data->data(), 5));
6745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Unknown extension in the response is rejected
6775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, UnknownExtension) {
6785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions("x-unknown-extension");
6795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6805d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
6825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Found an unsupported extension 'x-unknown-extension' "
6835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "in 'Sec-WebSocket-Extensions' header",
6845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
6855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Malformed extensions are rejected (this file does not cover all possible
6885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// parse failures, as the parser is covered thoroughly by its own unit tests).
6895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MalformedExtension) {
6905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(";");
6915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
6925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
6935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
6945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Error during WebSocket handshake: 'Sec-WebSocket-Extensions' header "
6955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "value is rejected by the parser: ;",
6965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
6975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
6985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
6995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// The permessage-deflate extension may only be specified once.
7005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, OnlyOnePerMessageDeflateAllowed) {
7015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
7025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate, permessage-deflate; client_max_window_bits=10");
7035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
706a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: "
707a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received duplicate permessage-deflate response",
7085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
7095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters may not be duplicated.
7125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, NoDuplicateParameters) {
7135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
7145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_no_context_takeover; "
7155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "client_no_context_takeover");
7165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
719a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
720a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received duplicate permessage-deflate extension parameter "
721a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "client_no_context_takeover",
7225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
7235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters must start with "client_" or "server_"
7265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterPrefix) {
7275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
7285d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; absurd_no_context_takeover");
729a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
732a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
733a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received an unexpected permessage-deflate extension parameter",
7345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
735a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
736a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
7375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// permessage-deflate parameters must be either *_no_context_takeover or
7385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits
7395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterSuffix) {
7405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
7415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_max_content_bits=5");
7425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
745a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
746a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received an unexpected permessage-deflate extension parameter",
7475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
7485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_no_context_takeover parameters must not have an argument
7515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, BadParameterValue) {
7525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
7535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_no_context_takeover=true");
7545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
757a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
758a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid client_no_context_takeover parameter",
7595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
7605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must have an argument
7635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, NoMaxWindowBitsArgument) {
7645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions("permessage-deflate; client_max_window_bits");
7655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
768a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
769a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "client_max_window_bits must have value",
7705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
7715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be an integer
7745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueInteger) {
7755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
7765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; server_max_window_bits=banana");
7775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
780a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
781a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid server_max_window_bits parameter",
7825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
7835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be >= 8
7865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooSmall) {
7875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
7885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; server_max_window_bits=7");
7895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
7905d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
7915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
792a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
793a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid server_max_window_bits parameter",
7945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
7955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
7965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
7975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must be <= 15
7985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueTooBig) {
7995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
8005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_max_window_bits=16");
8015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
8025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
804a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
805a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid client_max_window_bits parameter",
8065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
8075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must not start with 0
8105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithZero) {
8115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
8125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; client_max_window_bits=08");
8135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
8145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
816a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
817a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid client_max_window_bits parameter",
8185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
8195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8205d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// *_max_window_bits must not start with +
8225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateExtensionTest, MaxWindowBitsValueStartsWithPlus) {
8235d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectWithExtensions(
8245d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "permessage-deflate; server_max_window_bits=+9");
8255d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
8265d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8275d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ(
828a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Error during WebSocket handshake: Error in permessage-deflate: "
829a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "Received invalid server_max_window_bits parameter",
8305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      failure_message());
8315d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
8325d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
8335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// TODO(ricea): Check that WebSocketDeflateStream is initialised with the
8345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// arguments from the server. This is difficult because the data written to the
8355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// socket is randomly masked.
8365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
837a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Additional Sec-WebSocket-Accept headers should be rejected.
838a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleAccept) {
839a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
840a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "ws://localhost/",
841a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "/",
842a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NoSubProtocols(),
843a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
844a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "",
845a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n");
846a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
847a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
8485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
8505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Accept' header must not appear "
8515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "more than once in a response",
8525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
853a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
854a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
855a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Response code 200 must be rejected.
856a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, InvalidStatusCode) {
857a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kInvalidStatusCodeResponse[] =
858a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 200 OK\r\n"
859a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
860a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
861a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
862a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
863a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
864a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
865a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
866a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
867a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
868a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kInvalidStatusCodeResponse);
869a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
8705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 200",
8725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
873a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
874a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
875a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Redirects are not followed (according to the WHATWG WebSocket API, which
876a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// overrides RFC6455 for browser applications).
877a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, RedirectsRejected) {
878a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kRedirectResponse[] =
879a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 302 Moved Temporarily\r\n"
880a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Content-Type: text/html\r\n"
881a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Content-Length: 34\r\n"
882a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: keep-alive\r\n"
883a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Location: ws://localhost/other\r\n"
884a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n"
885a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "<title>Moved</title><h1>Moved</h1>";
886a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
887a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
888a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
889a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
890a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
891a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kRedirectResponse);
892a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
8935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
8945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: Unexpected response code: 302",
8955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
896a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
897a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
898a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Malformed responses should be rejected. HttpStreamParser will accept just
899a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// about any garbage in the middle of the headers. To make it give up, the junk
900a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// has to be at the start of the response. Even then, it just gets treated as an
901a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// HTTP/0.9 response.
902a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MalformedResponse) {
903a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMalformedResponse[] =
904a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "220 mx.google.com ESMTP\r\n"
905a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 OK\r\n"
906a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
907a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
908a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
909a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
910a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
911a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
912a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
913a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
914a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
915a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMalformedResponse);
916a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
918a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: Invalid status line",
9195d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
920a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
921a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
922a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Upgrade header must be present.
923a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingUpgradeHeader) {
924a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMissingUpgradeResponse[] =
925a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
926a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
927a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
928a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
929a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
930a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
931a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
932a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
933a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
934a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMissingUpgradeResponse);
935a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
9375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: 'Upgrade' header is missing",
9385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
939a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
940a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
941a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// There must only be one upgrade header.
942a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, DoubleUpgradeHeader) {
943a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
944a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "ws://localhost/",
945a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "/",
946a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      NoSubProtocols(),
947a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "http://localhost",
948a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "", "Upgrade: HTTP/2.0\r\n");
949a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
9515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
9525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Upgrade' header must not appear more than once in a response",
9535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
9545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// There must only be one correct upgrade header.
9575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, IncorrectUpgradeHeader) {
9585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char kMissingUpgradeResponse[] =
9595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
9605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Connection: Upgrade\r\n"
9615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
9625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Upgrade: hogefuga\r\n"
9635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "\r\n";
9645d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
9655d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "/",
9665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 NoSubProtocols(),
967a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
9685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "",
9695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 kMissingUpgradeResponse);
9705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
9715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
9725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
9735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Upgrade' header value is not 'WebSocket': hogefuga",
9745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
975a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
976a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
977a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header must be present.
978a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingConnectionHeader) {
979a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMissingConnectionResponse[] =
980a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
981a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
982a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
983a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
984a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
985a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
986a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
987a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
988a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
989a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMissingConnectionResponse);
990a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
9915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
9925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
9935d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Connection' header is missing",
9945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
9955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
9965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
9975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Connection header must contain "Upgrade".
9985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, IncorrectConnectionHeader) {
9995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  static const char kMissingConnectionResponse[] =
10005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
10015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Upgrade: websocket\r\n"
10025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
10035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "Connection: hogefuga\r\n"
10045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      "\r\n";
10055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
10065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "/",
10075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 NoSubProtocols(),
1008a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
10095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 "",
10105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                 kMissingConnectionResponse);
10115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
10125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
10135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
10145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Connection' header value must contain 'Upgrade'",
10155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
1016a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1017a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1018a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connection header is permitted to contain other tokens.
1019a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, AdditionalTokenInConnectionHeader) {
1020a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kAdditionalConnectionTokenResponse[] =
1021a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
1022a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
1023a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade, Keep-Alive\r\n"
1024a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
1025a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
1026a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
1027a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
1028a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
1029a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
1030a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
1031a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kAdditionalConnectionTokenResponse);
1032a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
10335d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
1034a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_TRUE(stream_);
1035a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1036a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1037a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must be present.
1038a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, MissingSecWebSocketAccept) {
1039a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kMissingAcceptResponse[] =
1040a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
1041a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
1042a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
1043a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
1044a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
1045a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
1046a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
1047a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
1048a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
1049a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kMissingAcceptResponse);
1050a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
10515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
10525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
10535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "'Sec-WebSocket-Accept' header is missing",
10545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
1055a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1056a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1057a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Sec-WebSocket-Accept header must match the key that was sent.
1058a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, WrongSecWebSocketAccept) {
1059a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  static const char kIncorrectAcceptResponse[] =
1060a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "HTTP/1.1 101 Switching Protocols\r\n"
1061a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Upgrade: websocket\r\n"
1062a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Connection: Upgrade\r\n"
1063a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "Sec-WebSocket-Accept: x/byyPZ2tOFvJCGkkugcKvqhhPk=\r\n"
1064a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      "\r\n";
1065a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
1066a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "/",
1067a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 NoSubProtocols(),
1068a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                 "http://localhost",
1069a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 "",
1070a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                 kIncorrectAcceptResponse);
1071a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
10725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
10735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error during WebSocket handshake: "
10745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            "Incorrect 'Sec-WebSocket-Accept' header value",
10755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
1076a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1077a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1078a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation works.
1079a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, Cancellation) {
1080a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectStandard(
1081a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)      "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "");
1082a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
1083a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
10845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
1085a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
10865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
10875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
1088a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1089a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1090a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect failure must look just like negotiation failure.
1091a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionFailure) {
10925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
1093a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(
1094a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
1095a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
1096a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost", socket_data.Pass());
1097a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
10985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
10995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
11005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
11015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(request_info_);
11025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
1103a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1104a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1105a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Connect timeout must look just like any other failure.
1106a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, ConnectionTimeout) {
11075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
1108a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(
1109a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      MockConnect(ASYNC, ERR_CONNECTION_TIMED_OUT));
1110a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
1111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost", socket_data.Pass());
1112a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
11135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
11145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_TIMED_OUT",
11155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
1116a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1117a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
11181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// The server doesn't respond to the opening handshake.
11191320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(WebSocketStreamCreateTest, HandshakeTimeout) {
11201320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
11211320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
11221320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
11231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
11241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
11251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  "http://localhost", socket_data.Pass(),
11261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  timer.PassAs<base::Timer>());
11271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(has_failed());
11281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(weak_timer.get());
11291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(weak_timer->IsRunning());
11301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  weak_timer->Fire();
11321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RunUntilIdle();
11331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(has_failed());
11351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ("WebSocket opening handshake timed out", failure_message());
11361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(weak_timer.get());
11371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(weak_timer->IsRunning());
11381320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
11391320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11401320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// When the connection establishes the timer should be stopped.
11411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(WebSocketStreamCreateTest, HandshakeTimerOnSuccess) {
11421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
11431320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
11441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CreateAndConnectStandard(
11461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      "ws://localhost/", "/", NoSubProtocols(), "http://localhost", "", "",
11471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      timer.PassAs<base::Timer>());
11481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(weak_timer);
11491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(weak_timer->IsRunning());
11501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RunUntilIdle();
11521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(has_failed());
11531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(stream_);
11541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(weak_timer);
11551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(weak_timer->IsRunning());
11561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
11571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// When the connection fails the timer should be stopped.
11591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano TucciTEST_F(WebSocketStreamCreateTest, HandshakeTimerOnFailure) {
11601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
11611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  socket_data->set_connect_data(
11621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      MockConnect(SYNCHRONOUS, ERR_CONNECTION_REFUSED));
11631320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<MockWeakTimer> timer(new MockWeakTimer(false, false));
11641320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  base::WeakPtr<MockWeakTimer> weak_timer = timer->AsWeakPtr();
11651320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  CreateAndConnectRawExpectations("ws://localhost/", NoSubProtocols(),
11661320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  "http://localhost", socket_data.Pass(),
11671320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                                  timer.PassAs<base::Timer>());
11681320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(weak_timer.get());
11691320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(weak_timer->IsRunning());
11701320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
11711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  RunUntilIdle();
11721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_TRUE(has_failed());
11731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_EQ("Error in connection establishment: net::ERR_CONNECTION_REFUSED",
11741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            failure_message());
11751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(weak_timer.get());
11761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  EXPECT_FALSE(weak_timer->IsRunning());
11771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci}
11781320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
1179a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during connect works.
1180a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringConnect) {
11815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(BuildNullSocketData());
1182a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, ERR_IO_PENDING));
1183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
1184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  NoSubProtocols(),
1185a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
1186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  socket_data.Pass());
1187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
1188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
11895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
1190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
1191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during write of the request headers works.
1194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringWrite) {
1195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // We seem to need at least two operations in order to use SetStop().
1196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockWrite writes[] = {MockWrite(ASYNC, 0, "GET / HTTP/"),
1197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                        MockWrite(ASYNC, 1, "1.1\r\n")};
1198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // We keep a copy of the pointer so that we can call RunFor() on it later.
1199a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  DeterministicSocketData* socket_data(
1200a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      new DeterministicSocketData(NULL, 0, writes, arraysize(writes)));
1201a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
1202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->SetStop(1);
1203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
1204a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  NoSubProtocols(),
1205a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
1206a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  make_scoped_ptr(socket_data));
1207a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->Run();
1208a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
1209a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
12105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
1211a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
12125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(request_info_);
12135d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
1214a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1215a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1216a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// Cancellation during read of the response headers works.
1217a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, CancellationDuringRead) {
1218a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string request = WebSocketStandardRequest("/", "http://localhost", "");
1219a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockWrite writes[] = {MockWrite(ASYNC, 0, request.c_str())};
1220a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  MockRead reads[] = {
1221a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    MockRead(ASYNC, 1, "HTTP/1.1 101 Switching Protocols\r\nUpgr"),
1222a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  };
12235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(
12245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BuildSocketData(reads, writes));
1225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  socket_data->SetStop(1);
12265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DeterministicSocketData* socket_data_raw_ptr = socket_data.get();
1227a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
1228a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                  NoSubProtocols(),
1229a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
12305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  socket_data.Pass());
12315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  socket_data_raw_ptr->Run();
1232a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  stream_request_.reset();
1233a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  RunUntilIdle();
12345d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(has_failed());
12355d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(stream_);
12365d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(request_info_);
12375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
12385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
12395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12405d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// Over-size response headers (> 256KB) should not cause a crash.  This is a
12415d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// regression test for crbug.com/339456. It is based on the layout test
12425d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// "cookie-flood.html".
12435d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, VeryLargeResponseHeaders) {
12445d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  std::string set_cookie_headers;
12455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  set_cookie_headers.reserve(45 * 10000);
12465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  for (int i = 0; i < 10000; ++i) {
12475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    set_cookie_headers +=
12485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        base::StringPrintf("Set-Cookie: WK-websocket-test-flood-%d=1\r\n", i);
12495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
12505d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectStandard("ws://localhost/", "/", NoSubProtocols(),
1251a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                           "http://localhost", "", set_cookie_headers);
12525d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  RunUntilIdle();
12535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
12545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
12555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)}
12565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
12575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// If the remote host closes the connection without sending headers, we should
12585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// log the console message "Connection closed before receiving a handshake
12595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)// response".
12605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)TEST_F(WebSocketStreamCreateTest, NoResponse) {
1261a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  std::string request = WebSocketStandardRequest("/", "http://localhost", "");
12625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MockWrite writes[] = {MockWrite(ASYNC, request.data(), request.size(), 0)};
12635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  MockRead reads[] = {MockRead(ASYNC, 0, 1)};
12645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> socket_data(
12655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      BuildSocketData(reads, writes));
12665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DeterministicSocketData* socket_data_raw_ptr = socket_data.get();
12675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  CreateAndConnectRawExpectations("ws://localhost/",
12685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                  NoSubProtocols(),
1269a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)                                  "http://localhost",
12705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                  socket_data.Pass());
12715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  socket_data_raw_ptr->RunFor(2);
12725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_TRUE(has_failed());
1273a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  EXPECT_FALSE(stream_);
12745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_FALSE(response_info_);
12755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  EXPECT_EQ("Connection closed before receiving a handshake response",
12765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)            failure_message());
1277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
1278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
127946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SelfSignedCertificateFailure) {
128046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_data_.push_back(
128146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new SSLSocketDataProvider(ASYNC, ERR_CERT_AUTHORITY_INVALID));
128246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_data_[0]->cert =
128346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
12841320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(ssl_data_[0]->cert.get());
12855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  scoped_ptr<DeterministicSocketData> raw_socket_data(BuildNullSocketData());
128646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  CreateAndConnectRawExpectations("wss://localhost/",
128746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  NoSubProtocols(),
128846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  "http://localhost",
128946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  raw_socket_data.Pass());
129046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RunUntilIdle();
129146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_FALSE(has_failed());
129246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ASSERT_TRUE(ssl_error_callbacks_);
129346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_error_callbacks_->CancelSSLRequest(ERR_CERT_AUTHORITY_INVALID,
129446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                         &ssl_info_);
129546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RunUntilIdle();
129646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(has_failed());
129746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
129846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
129946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)TEST_F(WebSocketStreamCreateTest, SelfSignedCertificateSuccess) {
130046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  scoped_ptr<SSLSocketDataProvider> ssl_data(
130146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      new SSLSocketDataProvider(ASYNC, ERR_CERT_AUTHORITY_INVALID));
130246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_data->cert =
130346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ImportCertFromFile(GetTestCertsDirectory(), "unittest.selfsigned.der");
13041320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  ASSERT_TRUE(ssl_data->cert.get());
130546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_data_.push_back(ssl_data.release());
130646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_data.reset(new SSLSocketDataProvider(ASYNC, OK));
130746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_data_.push_back(ssl_data.release());
13085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  url_request_context_host_.AddRawExpectations(BuildNullSocketData());
130946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  CreateAndConnectStandard(
131046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      "wss://localhost/", "/", NoSubProtocols(), "http://localhost", "", "");
131146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RunUntilIdle();
131246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ASSERT_TRUE(ssl_error_callbacks_);
131346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  ssl_error_callbacks_->ContinueSSLRequest();
131446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  RunUntilIdle();
131546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_FALSE(has_failed());
131646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_TRUE(stream_);
131746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)}
131846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
13195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// If the server requests authorisation, but we have no credentials, the
13205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// connection should fail cleanly.
13215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST_F(WebSocketStreamCreateBasicAuthTest, FailureNoCredentials) {
13225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CreateAndConnectCustomResponse("ws://localhost/",
13235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 "/",
13245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 NoSubProtocols(),
13255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 "http://localhost",
13265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 "",
13275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                 kUnauthorizedResponse);
13285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  RunUntilIdle();
13295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(has_failed());
13305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ("HTTP Authentication failed; no valid credentials available",
13315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)            failure_message());
13325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(response_info_);
13335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
13345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST_F(WebSocketStreamCreateBasicAuthTest, SuccessPasswordInUrl) {
13365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CreateAndConnectAuthHandshake("ws://foo:bar@localhost/",
13375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                "Zm9vOmJhcg==",
13385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                WebSocketStandardResponse(std::string()));
13395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  RunUntilIdle();
13405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(has_failed());
13415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(stream_);
13425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_TRUE(response_info_);
13435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(101, response_info_->status_code);
13445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
13455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST_F(WebSocketStreamCreateBasicAuthTest, FailureIncorrectPasswordInUrl) {
13475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CreateAndConnectAuthHandshake(
13485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "ws://foo:baz@localhost/", "Zm9vOmJheg==", kUnauthorizedResponse);
13495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  RunUntilIdle();
13505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(has_failed());
13515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(response_info_);
13525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
13535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Digest auth has the same connection semantics as Basic auth, so we can
13555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// generally assume that whatever works for Basic auth will also work for
13565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Digest. There's just one test here, to confirm that it works at all.
13575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)TEST_F(WebSocketStreamCreateDigestAuthTest, DigestPasswordInUrl) {
13585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  AddRawExpectations(helper_.BuildSocketData1(kUnauthorizedResponse));
13595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
13605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CreateAndConnectRawExpectations(
13615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "ws://FooBar:pass@localhost/",
13625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      NoSubProtocols(),
13635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      "http://localhost",
13645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      helper_.BuildSocketData2(kAuthorizedRequest,
13655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                               WebSocketStandardResponse(std::string())));
13665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  RunUntilIdle();
13675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_FALSE(has_failed());
13685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_TRUE(stream_);
13695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  ASSERT_TRUE(response_info_);
13705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  EXPECT_EQ(101, response_info_->status_code);
13715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
13725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1373c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(WebSocketStreamCreateUMATest, Incomplete) {
1374c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::string name("Net.WebSocket.HandshakeResult");
1375c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> original(GetSamples(name));
1376c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1377c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  {
1378c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StreamCreation creation;
1379c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.CreateAndConnectStandard("ws://localhost/",
1380c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "/",
1381c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      creation.NoSubProtocols(),
1382c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "http://localhost",
1383c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "",
1384c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "");
1385c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1386c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1387c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> samples(GetSamples(name));
1388c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_TRUE(samples);
1389c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (original) {
1390c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    samples->Subtract(*original);  // Cancel the original values.
1391c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1392c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(1, samples->GetCount(INCOMPLETE));
1393c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(CONNECTED));
1394c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(FAILED));
1395c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
1396c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1397c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(WebSocketStreamCreateUMATest, Connected) {
1398c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::string name("Net.WebSocket.HandshakeResult");
1399c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> original(GetSamples(name));
1400c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1401c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  {
1402c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StreamCreation creation;
1403c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.CreateAndConnectStandard("ws://localhost/",
1404c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "/",
1405c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      creation.NoSubProtocols(),
1406c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "http://localhost",
1407c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "",
1408c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                      "");
1409c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.RunUntilIdle();
1410c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1411c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1412c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> samples(GetSamples(name));
1413c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_TRUE(samples);
1414c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (original) {
1415c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    samples->Subtract(*original);  // Cancel the original values.
1416c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1417c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(INCOMPLETE));
1418c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(1, samples->GetCount(CONNECTED));
1419c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(FAILED));
1420c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
1421c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1422c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen MurdochTEST_F(WebSocketStreamCreateUMATest, Failed) {
1423c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  const std::string name("Net.WebSocket.HandshakeResult");
1424c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> original(GetSamples(name));
1425c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1426c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  {
1427c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    StreamCreation creation;
1428c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    static const char kInvalidStatusCodeResponse[] =
1429c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "HTTP/1.1 200 OK\r\n"
1430c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Upgrade: websocket\r\n"
1431c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Connection: Upgrade\r\n"
1432c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
1433c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "\r\n";
1434c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.CreateAndConnectCustomResponse("ws://localhost/",
1435c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            "/",
1436c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            creation.NoSubProtocols(),
1437c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            "http://localhost",
1438c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            "",
1439c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch                                            kInvalidStatusCodeResponse);
1440c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    creation.RunUntilIdle();
1441c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
1442c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1443c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  scoped_ptr<base::HistogramSamples> samples(GetSamples(name));
1444c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  ASSERT_TRUE(samples);
1445c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  if (original) {
1446c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    samples->Subtract(*original);  // Cancel the original values.
1447c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
144846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(1, samples->GetCount(INCOMPLETE));
1449c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  EXPECT_EQ(0, samples->GetCount(CONNECTED));
145046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  EXPECT_EQ(0, samples->GetCount(FAILED));
1451c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch}
1452c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
1453a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
1454a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace net
1455