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/base/load_flags.h"
11 #include "net/http/http_request_headers.h"
12 #include "net/http/http_status_code.h"
13 #include "net/url_request/url_request.h"
14 #include "net/url_request/url_request_context.h"
15 #include "net/websockets/websocket_errors.h"
16 #include "net/websockets/websocket_handshake_constants.h"
17 #include "net/websockets/websocket_handshake_stream_base.h"
18 #include "net/websockets/websocket_handshake_stream_create_helper.h"
19 #include "net/websockets/websocket_test_util.h"
21 #include "url/origin.h"
26 class StreamRequestImpl
;
28 class Delegate
: public URLRequest::Delegate
{
30 enum HandshakeResult
{
34 NUM_HANDSHAKE_RESULT_TYPES
,
37 explicit Delegate(StreamRequestImpl
* owner
)
38 : owner_(owner
), result_(INCOMPLETE
) {}
40 UMA_HISTOGRAM_ENUMERATION(
41 "Net.WebSocket.HandshakeResult", result_
, NUM_HANDSHAKE_RESULT_TYPES
);
44 // Implementation of URLRequest::Delegate methods.
45 virtual void OnResponseStarted(URLRequest
* request
) OVERRIDE
;
47 virtual void OnAuthRequired(URLRequest
* request
,
48 AuthChallengeInfo
* auth_info
) OVERRIDE
;
50 virtual void OnCertificateRequested(URLRequest
* request
,
51 SSLCertRequestInfo
* cert_request_info
)
54 virtual void OnSSLCertificateError(URLRequest
* request
,
55 const SSLInfo
& ssl_info
,
58 virtual void OnReadCompleted(URLRequest
* request
, int bytes_read
) OVERRIDE
;
61 StreamRequestImpl
* owner_
;
62 HandshakeResult result_
;
65 class StreamRequestImpl
: public WebSocketStreamRequest
{
69 const URLRequestContext
* context
,
70 const url::Origin
& origin
,
71 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
,
72 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper
)
73 : delegate_(new Delegate(this)),
74 url_request_(url
, DEFAULT_PRIORITY
, delegate_
.get(), context
),
75 connect_delegate_(connect_delegate
.Pass()),
76 create_helper_(create_helper
.release()) {
77 HttpRequestHeaders headers
;
78 headers
.SetHeader(websockets::kUpgrade
, websockets::kWebSocketLowercase
);
79 headers
.SetHeader(HttpRequestHeaders::kConnection
, websockets::kUpgrade
);
80 headers
.SetHeader(HttpRequestHeaders::kOrigin
, origin
.string());
81 headers
.SetHeader(websockets::kSecWebSocketVersion
,
82 websockets::kSupportedVersion
);
83 url_request_
.SetExtraRequestHeaders(headers
);
85 // This passes the ownership of |create_helper_| to |url_request_|.
86 url_request_
.SetUserData(
87 WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
89 url_request_
.SetLoadFlags(LOAD_DISABLE_CACHE
|
91 LOAD_DO_NOT_PROMPT_FOR_LOGIN
);
94 // Destroying this object destroys the URLRequest, which cancels the request
95 // and so terminates the handshake if it is incomplete.
96 virtual ~StreamRequestImpl() {}
102 void PerformUpgrade() {
103 connect_delegate_
->OnSuccess(create_helper_
->stream()->Upgrade());
106 void ReportFailure() {
107 std::string failure_message
;
108 if (create_helper_
->stream()) {
109 failure_message
= create_helper_
->stream()->GetFailureMessage();
111 switch (url_request_
.status().status()) {
112 case URLRequestStatus::SUCCESS
:
113 case URLRequestStatus::IO_PENDING
:
115 case URLRequestStatus::CANCELED
:
116 failure_message
= "WebSocket opening handshake was canceled";
118 case URLRequestStatus::FAILED
:
120 std::string("Error in connection establishment: ") +
121 ErrorToString(url_request_
.status().error());
125 connect_delegate_
->OnFailure(failure_message
);
129 // |delegate_| needs to be declared before |url_request_| so that it gets
130 // initialised first.
131 scoped_ptr
<Delegate
> delegate_
;
133 // Deleting the StreamRequestImpl object deletes this URLRequest object,
134 // cancelling the whole connection.
135 URLRequest url_request_
;
137 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate_
;
139 // Owned by the URLRequest.
140 WebSocketHandshakeStreamCreateHelper
* create_helper_
;
143 void Delegate::OnResponseStarted(URLRequest
* request
) {
144 switch (request
->GetResponseCode()) {
145 case HTTP_SWITCHING_PROTOCOLS
:
147 owner_
->PerformUpgrade();
150 case HTTP_UNAUTHORIZED
:
151 case HTTP_PROXY_AUTHENTICATION_REQUIRED
:
156 owner_
->ReportFailure();
160 void Delegate::OnAuthRequired(URLRequest
* request
,
161 AuthChallengeInfo
* auth_info
) {
162 request
->CancelAuth();
165 void Delegate::OnCertificateRequested(URLRequest
* request
,
166 SSLCertRequestInfo
* cert_request_info
) {
167 request
->ContinueWithCertificate(NULL
);
170 void Delegate::OnSSLCertificateError(URLRequest
* request
,
171 const SSLInfo
& ssl_info
,
176 void Delegate::OnReadCompleted(URLRequest
* request
, int bytes_read
) {
182 WebSocketStreamRequest::~WebSocketStreamRequest() {}
184 WebSocketStream::WebSocketStream() {}
185 WebSocketStream::~WebSocketStream() {}
187 WebSocketStream::ConnectDelegate::~ConnectDelegate() {}
189 scoped_ptr
<WebSocketStreamRequest
> WebSocketStream::CreateAndConnectStream(
190 const GURL
& socket_url
,
191 const std::vector
<std::string
>& requested_subprotocols
,
192 const url::Origin
& origin
,
193 URLRequestContext
* url_request_context
,
194 const BoundNetLog
& net_log
,
195 scoped_ptr
<ConnectDelegate
> connect_delegate
) {
196 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper(
197 new WebSocketHandshakeStreamCreateHelper(connect_delegate
.get(),
198 requested_subprotocols
));
199 scoped_ptr
<StreamRequestImpl
> request(
200 new StreamRequestImpl(socket_url
,
203 connect_delegate
.Pass(),
204 create_helper
.Pass()));
206 return request
.PassAs
<WebSocketStreamRequest
>();
209 // This is declared in websocket_test_util.h.
210 scoped_ptr
<WebSocketStreamRequest
> CreateAndConnectStreamForTesting(
211 const GURL
& socket_url
,
212 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper
,
213 const url::Origin
& origin
,
214 URLRequestContext
* url_request_context
,
215 const BoundNetLog
& net_log
,
216 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
) {
217 scoped_ptr
<StreamRequestImpl
> request(
218 new StreamRequestImpl(socket_url
,
221 connect_delegate
.Pass(),
222 create_helper
.Pass()));
224 return request
.PassAs
<WebSocketStreamRequest
>();