1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/websockets/websocket_stream.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/metrics/histogram.h"
10 #include "net/http/http_request_headers.h"
11 #include "net/http/http_status_code.h"
12 #include "net/url_request/url_request.h"
13 #include "net/url_request/url_request_context.h"
14 #include "net/websockets/websocket_errors.h"
15 #include "net/websockets/websocket_handshake_constants.h"
16 #include "net/websockets/websocket_handshake_stream_base.h"
17 #include "net/websockets/websocket_handshake_stream_create_helper.h"
18 #include "net/websockets/websocket_test_util.h"
20 #include "url/origin.h"
25 class StreamRequestImpl
;
27 class Delegate
: public URLRequest::Delegate
{
29 enum HandshakeResult
{
33 NUM_HANDSHAKE_RESULT_TYPES
,
36 explicit Delegate(StreamRequestImpl
* owner
)
37 : owner_(owner
), result_(INCOMPLETE
) {}
39 UMA_HISTOGRAM_ENUMERATION(
40 "Net.WebSocket.HandshakeResult", result_
, NUM_HANDSHAKE_RESULT_TYPES
);
43 // Implementation of URLRequest::Delegate methods.
44 virtual void OnResponseStarted(URLRequest
* request
) OVERRIDE
;
46 virtual void OnAuthRequired(URLRequest
* request
,
47 AuthChallengeInfo
* auth_info
) OVERRIDE
;
49 virtual void OnCertificateRequested(URLRequest
* request
,
50 SSLCertRequestInfo
* cert_request_info
)
53 virtual void OnSSLCertificateError(URLRequest
* request
,
54 const SSLInfo
& ssl_info
,
57 virtual void OnReadCompleted(URLRequest
* request
, int bytes_read
) OVERRIDE
;
60 StreamRequestImpl
* owner_
;
61 HandshakeResult result_
;
64 class StreamRequestImpl
: public WebSocketStreamRequest
{
68 const URLRequestContext
* context
,
69 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
,
70 WebSocketHandshakeStreamCreateHelper
* create_helper
)
71 : delegate_(new Delegate(this)),
72 url_request_(url
, DEFAULT_PRIORITY
, delegate_
.get(), context
),
73 connect_delegate_(connect_delegate
.Pass()),
74 create_helper_(create_helper
) {}
76 // Destroying this object destroys the URLRequest, which cancels the request
77 // and so terminates the handshake if it is incomplete.
78 virtual ~StreamRequestImpl() {}
80 URLRequest
* url_request() { return &url_request_
; }
82 void PerformUpgrade() {
83 connect_delegate_
->OnSuccess(create_helper_
->stream()->Upgrade());
86 void ReportFailure() {
87 std::string failure_message
;
88 if (create_helper_
->stream()) {
89 failure_message
= create_helper_
->stream()->GetFailureMessage();
91 switch (url_request_
.status().status()) {
92 case URLRequestStatus::SUCCESS
:
93 case URLRequestStatus::IO_PENDING
:
95 case URLRequestStatus::CANCELED
:
96 failure_message
= "WebSocket opening handshake was canceled";
98 case URLRequestStatus::FAILED
:
100 std::string("Error in connection establishment: ") +
101 ErrorToString(url_request_
.status().error());
105 connect_delegate_
->OnFailure(failure_message
);
109 // |delegate_| needs to be declared before |url_request_| so that it gets
110 // initialised first.
111 scoped_ptr
<Delegate
> delegate_
;
113 // Deleting the StreamRequestImpl object deletes this URLRequest object,
114 // cancelling the whole connection.
115 URLRequest url_request_
;
117 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate_
;
119 // Owned by the URLRequest.
120 WebSocketHandshakeStreamCreateHelper
* create_helper_
;
123 void Delegate::OnResponseStarted(URLRequest
* request
) {
124 switch (request
->GetResponseCode()) {
125 case HTTP_SWITCHING_PROTOCOLS
:
127 owner_
->PerformUpgrade();
130 case HTTP_UNAUTHORIZED
:
131 case HTTP_PROXY_AUTHENTICATION_REQUIRED
:
136 owner_
->ReportFailure();
140 void Delegate::OnAuthRequired(URLRequest
* request
,
141 AuthChallengeInfo
* auth_info
) {
142 request
->CancelAuth();
145 void Delegate::OnCertificateRequested(URLRequest
* request
,
146 SSLCertRequestInfo
* cert_request_info
) {
147 request
->ContinueWithCertificate(NULL
);
150 void Delegate::OnSSLCertificateError(URLRequest
* request
,
151 const SSLInfo
& ssl_info
,
156 void Delegate::OnReadCompleted(URLRequest
* request
, int bytes_read
) {
160 // Internal implementation of CreateAndConnectStream and
161 // CreateAndConnectStreamForTesting.
162 scoped_ptr
<WebSocketStreamRequest
> CreateAndConnectStreamWithCreateHelper(
163 const GURL
& socket_url
,
164 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper
,
165 const url::Origin
& origin
,
166 URLRequestContext
* url_request_context
,
167 const BoundNetLog
& net_log
,
168 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
) {
169 scoped_ptr
<StreamRequestImpl
> request(
170 new StreamRequestImpl(socket_url
,
172 connect_delegate
.Pass(),
173 create_helper
.get()));
174 HttpRequestHeaders headers
;
175 headers
.SetHeader(websockets::kUpgrade
, websockets::kWebSocketLowercase
);
176 headers
.SetHeader(HttpRequestHeaders::kConnection
, websockets::kUpgrade
);
177 headers
.SetHeader(HttpRequestHeaders::kOrigin
, origin
.string());
178 headers
.SetHeader(websockets::kSecWebSocketVersion
,
179 websockets::kSupportedVersion
);
180 request
->url_request()->SetExtraRequestHeaders(headers
);
181 request
->url_request()->SetUserData(
182 WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
183 create_helper
.release());
184 request
->url_request()->SetLoadFlags(LOAD_DISABLE_CACHE
|
186 LOAD_DO_NOT_PROMPT_FOR_LOGIN
);
187 request
->url_request()->Start();
188 return request
.PassAs
<WebSocketStreamRequest
>();
193 WebSocketStreamRequest::~WebSocketStreamRequest() {}
195 WebSocketStream::WebSocketStream() {}
196 WebSocketStream::~WebSocketStream() {}
198 WebSocketStream::ConnectDelegate::~ConnectDelegate() {}
200 scoped_ptr
<WebSocketStreamRequest
> WebSocketStream::CreateAndConnectStream(
201 const GURL
& socket_url
,
202 const std::vector
<std::string
>& requested_subprotocols
,
203 const url::Origin
& origin
,
204 URLRequestContext
* url_request_context
,
205 const BoundNetLog
& net_log
,
206 scoped_ptr
<ConnectDelegate
> connect_delegate
) {
207 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper(
208 new WebSocketHandshakeStreamCreateHelper(connect_delegate
.get(),
209 requested_subprotocols
));
210 return CreateAndConnectStreamWithCreateHelper(socket_url
,
211 create_helper
.Pass(),
215 connect_delegate
.Pass());
218 // This is declared in websocket_test_util.h.
219 scoped_ptr
<WebSocketStreamRequest
> CreateAndConnectStreamForTesting(
220 const GURL
& socket_url
,
221 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper
,
222 const url::Origin
& origin
,
223 URLRequestContext
* url_request_context
,
224 const BoundNetLog
& net_log
,
225 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
) {
226 return CreateAndConnectStreamWithCreateHelper(socket_url
,
227 create_helper
.Pass(),
231 connect_delegate
.Pass());