1eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Copyright 2013 The Chromium Authors. All rights reserved.
2eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Use of this source code is governed by a BSD-style license that can be
3eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// found in the LICENSE file.
4eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
5eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "net/websockets/websocket_stream.h"
6eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "base/logging.h"
8a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "base/memory/scoped_ptr.h"
9c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "base/metrics/histogram.h"
106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)#include "base/metrics/sparse_histogram.h"
111320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/time/time.h"
121320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci#include "base/timer/timer.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "net/base/load_flags.h"
14a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/http/http_request_headers.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "net/http/http_response_headers.h"
16a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/http/http_status_code.h"
176e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "net/url_request/redirect_info.h"
18a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/url_request/url_request.h"
19a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/url_request/url_request_context.h"
20a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_errors.h"
2146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)#include "net/websockets/websocket_event_interface.h"
22a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_handshake_constants.h"
23a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_handshake_stream_base.h"
24a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_handshake_stream_create_helper.h"
25a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "net/websockets/websocket_test_util.h"
26a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)#include "url/gurl.h"
27a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "url/origin.h"
28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochnamespace net {
30a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)namespace {
31a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// The timeout duration of WebSocket handshake.
331320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// It is defined as the same value as the TCP connection timeout value in
341320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// net/socket/websocket_transport_client_socket_pool.cc to make it hard for
351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci// JavaScript programs to recognize the timeout cause.
361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucciconst int kHandshakeTimeoutIntervalInSeconds = 240;
371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
38a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class StreamRequestImpl;
39a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
40a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class Delegate : public URLRequest::Delegate {
41a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
42c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  enum HandshakeResult {
43c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    INCOMPLETE,
44c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    CONNECTED,
45c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    FAILED,
46c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    NUM_HANDSHAKE_RESULT_TYPES,
47c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  };
48c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch
49c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  explicit Delegate(StreamRequestImpl* owner)
50c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      : owner_(owner), result_(INCOMPLETE) {}
51c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  virtual ~Delegate() {
52c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch    UMA_HISTOGRAM_ENUMERATION(
53c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch        "Net.WebSocket.HandshakeResult", result_, NUM_HANDSHAKE_RESULT_TYPES);
54c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  }
55a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
56a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Implementation of URLRequest::Delegate methods.
5746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual void OnReceivedRedirect(URLRequest* request,
586e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)                                  const RedirectInfo& redirect_info,
5946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)                                  bool* defer_redirect) OVERRIDE {
6046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // HTTP status codes returned by HttpStreamParser are filtered by
6146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // WebSocketBasicHandshakeStream, and only 101, 401 and 407 are permitted
6246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // back up the stack to HttpNetworkTransaction. In particular, redirect
6346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // codes are never allowed, and so URLRequest never sees a redirect on a
6446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    // WebSocket request.
6546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    NOTREACHED();
6646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
6746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
68a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnResponseStarted(URLRequest* request) OVERRIDE;
69a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
70a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnAuthRequired(URLRequest* request,
71a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              AuthChallengeInfo* auth_info) OVERRIDE;
72a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
73a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnCertificateRequested(URLRequest* request,
74a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      SSLCertRequestInfo* cert_request_info)
75a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      OVERRIDE;
76a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
77a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnSSLCertificateError(URLRequest* request,
78a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     const SSLInfo& ssl_info,
79a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     bool fatal) OVERRIDE;
80a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
81a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual void OnReadCompleted(URLRequest* request, int bytes_read) OVERRIDE;
82a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
83a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
84a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  StreamRequestImpl* owner_;
85c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch  HandshakeResult result_;
86a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
87a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
88a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)class StreamRequestImpl : public WebSocketStreamRequest {
89a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) public:
90a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  StreamRequestImpl(
91a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const GURL& url,
92a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      const URLRequestContext* context,
93cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      const url::Origin& origin,
94a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
95cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper)
96a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      : delegate_(new Delegate(this)),
9703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)        url_request_(context->CreateRequest(url, DEFAULT_PRIORITY,
9803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                            delegate_.get(), NULL)),
99a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        connect_delegate_(connect_delegate.Pass()),
100cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        create_helper_(create_helper.release()) {
101116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    create_helper_->set_failure_message(&failure_message_);
102cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    HttpRequestHeaders headers;
103cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    headers.SetHeader(websockets::kUpgrade, websockets::kWebSocketLowercase);
104cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    headers.SetHeader(HttpRequestHeaders::kConnection, websockets::kUpgrade);
105cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    headers.SetHeader(HttpRequestHeaders::kOrigin, origin.string());
106cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    headers.SetHeader(websockets::kSecWebSocketVersion,
107cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                      websockets::kSupportedVersion);
10803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    url_request_->SetExtraRequestHeaders(headers);
109cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
110cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // This passes the ownership of |create_helper_| to |url_request_|.
11103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    url_request_->SetUserData(
112cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
113cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        create_helper_);
11403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    url_request_->SetLoadFlags(LOAD_DISABLE_CACHE |
11503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               LOAD_BYPASS_CACHE |
11603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                               LOAD_DO_NOT_PROMPT_FOR_LOGIN);
117cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Destroying this object destroys the URLRequest, which cancels the request
120a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // and so terminates the handshake if it is incomplete.
121a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  virtual ~StreamRequestImpl() {}
122a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
1231320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void Start(scoped_ptr<base::Timer> timer) {
1241320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(timer);
1251320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    TimeDelta timeout(TimeDelta::FromSeconds(
1261320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        kHandshakeTimeoutIntervalInSeconds));
1271320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    timer_ = timer.Pass();
1281320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    timer_->Start(FROM_HERE, timeout,
1291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                  base::Bind(&StreamRequestImpl::OnTimeout,
1301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                             base::Unretained(this)));
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    url_request_->Start();
132cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  }
133a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
134a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void PerformUpgrade() {
1351320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(timer_);
1361320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    timer_->Stop();
137116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    connect_delegate_->OnSuccess(create_helper_->Upgrade());
138a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
139a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
140a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  void ReportFailure() {
1411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    DCHECK(timer_);
1421320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    timer_->Stop();
143116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch    if (failure_message_.empty()) {
14403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      switch (url_request_->status().status()) {
1455d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        case URLRequestStatus::SUCCESS:
1465d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        case URLRequestStatus::IO_PENDING:
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
1485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        case URLRequestStatus::CANCELED:
1491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          if (url_request_->status().error() == ERR_TIMED_OUT)
1501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            failure_message_ = "WebSocket opening handshake timed out";
1511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci          else
1521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            failure_message_ = "WebSocket opening handshake was canceled";
1535d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
1545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        case URLRequestStatus::FAILED:
155116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch          failure_message_ =
1565d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)              std::string("Error in connection establishment: ") +
15703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)              ErrorToString(url_request_->status().error());
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          break;
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      }
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    }
1615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    ReportFailureWithMessage(failure_message_);
1625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void ReportFailureWithMessage(const std::string& failure_message) {
1655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    connect_delegate_->OnFailure(failure_message);
1665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  void OnFinishOpeningHandshake() {
1695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebSocketDispatchOnFinishOpeningHandshake(connect_delegate(),
17003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                              url_request_->url(),
17103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                              url_request_->response_headers(),
17203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                              url_request_->response_time());
173a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
174a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
17546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  WebSocketStream::ConnectDelegate* connect_delegate() const {
17646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return connect_delegate_.get();
17746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
17846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
1791320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  void OnTimeout() {
1801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    url_request_->CancelWithError(ERR_TIMED_OUT);
1811320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  }
1821320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
183a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles) private:
184a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // |delegate_| needs to be declared before |url_request_| so that it gets
185a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // initialised first.
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<Delegate> delegate_;
187a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
188a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Deleting the StreamRequestImpl object deletes this URLRequest object,
189a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // cancelling the whole connection.
19003b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<URLRequest> url_request_;
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
192a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate_;
193a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  // Owned by the URLRequest.
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  WebSocketHandshakeStreamCreateHelper* create_helper_;
196116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch
197116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  // The failure message supplied by WebSocketBasicHandshakeStream, if any.
198116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  std::string failure_message_;
1991320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
2001320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  // A timer for handshake timeout.
2011320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  scoped_ptr<base::Timer> timer_;
202a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)};
203a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
20446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)class SSLErrorCallbacks : public WebSocketEventInterface::SSLErrorCallbacks {
20546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) public:
20646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  explicit SSLErrorCallbacks(URLRequest* url_request)
20746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      : url_request_(url_request) {}
20846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
20946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual void CancelSSLRequest(int error, const SSLInfo* ssl_info) OVERRIDE {
21046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    if (ssl_info) {
21146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      url_request_->CancelWithSSLError(error, *ssl_info);
21246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    } else {
21346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      url_request_->CancelWithError(error);
21446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    }
21546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
21646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
21746d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  virtual void ContinueSSLRequest() OVERRIDE {
21846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    url_request_->ContinueDespiteLastError();
21946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
22046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
22146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) private:
22246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  URLRequest* url_request_;
22346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)};
22446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)
225a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Delegate::OnResponseStarted(URLRequest* request) {
2266d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // All error codes, including OK and ABORTED, as with
2276d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  // Net.ErrorCodesForMainFrame3
2286d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ErrorCodes",
2296d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)                              -request->status().error());
23046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  if (!request->status().is_success()) {
23146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    DVLOG(3) << "OnResponseStarted (request failed)";
23246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    owner_->ReportFailure();
23346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)    return;
23446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  }
2356d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  const int response_code = request->GetResponseCode();
2366d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  DVLOG(3) << "OnResponseStarted (response code " << response_code << ")";
2376d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles)  switch (response_code) {
238a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case HTTP_SWITCHING_PROTOCOLS:
239c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      result_ = CONNECTED;
240a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      owner_->PerformUpgrade();
241a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return;
242a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
243a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case HTTP_UNAUTHORIZED:
2445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result_ = FAILED;
2455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      owner_->OnFinishOpeningHandshake();
2465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      owner_->ReportFailureWithMessage(
2475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)          "HTTP Authentication failed; no valid credentials available");
2485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      return;
2495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
250a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    case HTTP_PROXY_AUTHENTICATION_REQUIRED:
2515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result_ = FAILED;
2525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      owner_->OnFinishOpeningHandshake();
2535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      owner_->ReportFailureWithMessage("Proxy authentication failed");
254a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      return;
255a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
256a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    default:
257c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch      result_ = FAILED;
258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      owner_->ReportFailure();
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  }
260a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
261a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
262a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Delegate::OnAuthRequired(URLRequest* request,
263a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                              AuthChallengeInfo* auth_info) {
26446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // This should only be called if credentials are not already stored.
265a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  request->CancelAuth();
266a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
267a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
268a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Delegate::OnCertificateRequested(URLRequest* request,
269a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                      SSLCertRequestInfo* cert_request_info) {
27046d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // This method is called when a client certificate is requested, and the
27146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // request context does not already contain a client certificate selection for
27246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // the endpoint. In this case, a main frame resource request would pop-up UI
27346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // to permit selection of a client certificate, but since WebSockets are
27446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // sub-resources they should not pop-up UI and so there is nothing more we can
27546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  // do.
27646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  request->Cancel();
277a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
278a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Delegate::OnSSLCertificateError(URLRequest* request,
280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     const SSLInfo& ssl_info,
281a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                     bool fatal) {
28246d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)  owner_->connect_delegate()->OnSSLCertificateError(
28346d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      scoped_ptr<WebSocketEventInterface::SSLErrorCallbacks>(
28446d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)          new SSLErrorCallbacks(request)),
28546d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      ssl_info,
28646d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)      fatal);
287a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
288a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)void Delegate::OnReadCompleted(URLRequest* request, int bytes_read) {
290a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  NOTREACHED();
291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}  // namespace
294eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
295eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochWebSocketStreamRequest::~WebSocketStreamRequest() {}
296eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
297eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochWebSocketStream::WebSocketStream() {}
298eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochWebSocketStream::~WebSocketStream() {}
299eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
300eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochWebSocketStream::ConnectDelegate::~ConnectDelegate() {}
301eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
302eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochscoped_ptr<WebSocketStreamRequest> WebSocketStream::CreateAndConnectStream(
303eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const GURL& socket_url,
304eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const std::vector<std::string>& requested_subprotocols,
305a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const url::Origin& origin,
306eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    URLRequestContext* url_request_context,
307eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    const BoundNetLog& net_log,
308eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    scoped_ptr<ConnectDelegate> connect_delegate) {
309a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper(
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      new WebSocketHandshakeStreamCreateHelper(connect_delegate.get(),
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)                                               requested_subprotocols));
312cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<StreamRequestImpl> request(
313cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new StreamRequestImpl(socket_url,
314cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            url_request_context,
315cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            origin,
316cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            connect_delegate.Pass(),
317cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            create_helper.Pass()));
3181320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  request->Start(scoped_ptr<base::Timer>(new base::Timer(false, false)));
319cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return request.PassAs<WebSocketStreamRequest>();
320a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)}
321a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)
322a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)// This is declared in websocket_test_util.h.
323a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)scoped_ptr<WebSocketStreamRequest> CreateAndConnectStreamForTesting(
324a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const GURL& socket_url,
325a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
326a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const url::Origin& origin,
327a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    URLRequestContext* url_request_context,
328a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    const BoundNetLog& net_log,
3291320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
3301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    scoped_ptr<base::Timer> timer) {
331cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  scoped_ptr<StreamRequestImpl> request(
332cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      new StreamRequestImpl(socket_url,
333cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            url_request_context,
334cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            origin,
335cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            connect_delegate.Pass(),
336cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                            create_helper.Pass()));
3371320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  request->Start(timer.Pass());
338cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)  return request.PassAs<WebSocketStreamRequest>();
339eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
340eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
3415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void WebSocketDispatchOnFinishOpeningHandshake(
3425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    WebSocketStream::ConnectDelegate* connect_delegate,
3435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const GURL& url,
3445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const scoped_refptr<HttpResponseHeaders>& headers,
3455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    base::Time response_time) {
3465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  DCHECK(connect_delegate);
3471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  if (headers.get()) {
3485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    connect_delegate->OnFinishOpeningHandshake(make_scoped_ptr(
3495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new WebSocketHandshakeResponseInfo(url,
3505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                           headers->response_code(),
3515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                           headers->GetStatusText(),
3525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                           headers,
3535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                           response_time)));
3545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
3555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
3565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
357eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}  // namespace net
358