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