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 "net/http/http_request_headers.h"
10 #include "net/http/http_status_code.h"
11 #include "net/url_request/url_request.h"
12 #include "net/url_request/url_request_context.h"
13 #include "net/websockets/websocket_errors.h"
14 #include "net/websockets/websocket_handshake_constants.h"
15 #include "net/websockets/websocket_handshake_stream_base.h"
16 #include "net/websockets/websocket_handshake_stream_create_helper.h"
17 #include "net/websockets/websocket_test_util.h"
19 #include "url/origin.h"
24 class StreamRequestImpl
;
26 class Delegate
: public URLRequest::Delegate
{
28 explicit Delegate(StreamRequestImpl
* owner
) : owner_(owner
) {}
29 virtual ~Delegate() {}
31 // Implementation of URLRequest::Delegate methods.
32 virtual void OnResponseStarted(URLRequest
* request
) OVERRIDE
;
34 virtual void OnAuthRequired(URLRequest
* request
,
35 AuthChallengeInfo
* auth_info
) OVERRIDE
;
37 virtual void OnCertificateRequested(URLRequest
* request
,
38 SSLCertRequestInfo
* cert_request_info
)
41 virtual void OnSSLCertificateError(URLRequest
* request
,
42 const SSLInfo
& ssl_info
,
45 virtual void OnReadCompleted(URLRequest
* request
, int bytes_read
) OVERRIDE
;
48 StreamRequestImpl
* owner_
;
51 class StreamRequestImpl
: public WebSocketStreamRequest
{
55 const URLRequestContext
* context
,
56 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
,
57 WebSocketHandshakeStreamCreateHelper
* create_helper
)
58 : delegate_(new Delegate(this)),
59 url_request_(url
, DEFAULT_PRIORITY
, delegate_
.get(), context
),
60 connect_delegate_(connect_delegate
.Pass()),
61 create_helper_(create_helper
) {}
63 // Destroying this object destroys the URLRequest, which cancels the request
64 // and so terminates the handshake if it is incomplete.
65 virtual ~StreamRequestImpl() {}
67 URLRequest
* url_request() { return &url_request_
; }
69 void PerformUpgrade() {
70 connect_delegate_
->OnSuccess(create_helper_
->stream()->Upgrade());
73 void ReportFailure() {
74 std::string failure_message
;
75 if (create_helper_
->stream()) {
76 failure_message
= create_helper_
->stream()->GetFailureMessage();
78 switch (url_request_
.status().status()) {
79 case URLRequestStatus::SUCCESS
:
80 case URLRequestStatus::IO_PENDING
:
82 case URLRequestStatus::CANCELED
:
83 failure_message
= "WebSocket opening handshake was canceled";
85 case URLRequestStatus::FAILED
:
87 std::string("Error in connection establishment: ") +
88 ErrorToString(url_request_
.status().error());
92 connect_delegate_
->OnFailure(failure_message
);
96 // |delegate_| needs to be declared before |url_request_| so that it gets
98 scoped_ptr
<Delegate
> delegate_
;
100 // Deleting the StreamRequestImpl object deletes this URLRequest object,
101 // cancelling the whole connection.
102 URLRequest url_request_
;
104 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate_
;
106 // Owned by the URLRequest.
107 WebSocketHandshakeStreamCreateHelper
* create_helper_
;
110 void Delegate::OnResponseStarted(URLRequest
* request
) {
111 switch (request
->GetResponseCode()) {
112 case HTTP_SWITCHING_PROTOCOLS
:
113 owner_
->PerformUpgrade();
116 case HTTP_UNAUTHORIZED
:
117 case HTTP_PROXY_AUTHENTICATION_REQUIRED
:
121 owner_
->ReportFailure();
125 void Delegate::OnAuthRequired(URLRequest
* request
,
126 AuthChallengeInfo
* auth_info
) {
127 request
->CancelAuth();
130 void Delegate::OnCertificateRequested(URLRequest
* request
,
131 SSLCertRequestInfo
* cert_request_info
) {
132 request
->ContinueWithCertificate(NULL
);
135 void Delegate::OnSSLCertificateError(URLRequest
* request
,
136 const SSLInfo
& ssl_info
,
141 void Delegate::OnReadCompleted(URLRequest
* request
, int bytes_read
) {
145 // Internal implementation of CreateAndConnectStream and
146 // CreateAndConnectStreamForTesting.
147 scoped_ptr
<WebSocketStreamRequest
> CreateAndConnectStreamWithCreateHelper(
148 const GURL
& socket_url
,
149 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper
,
150 const url::Origin
& origin
,
151 URLRequestContext
* url_request_context
,
152 const BoundNetLog
& net_log
,
153 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
) {
154 scoped_ptr
<StreamRequestImpl
> request(
155 new StreamRequestImpl(socket_url
,
157 connect_delegate
.Pass(),
158 create_helper
.get()));
159 HttpRequestHeaders headers
;
160 headers
.SetHeader(websockets::kUpgrade
, websockets::kWebSocketLowercase
);
161 headers
.SetHeader(HttpRequestHeaders::kConnection
, websockets::kUpgrade
);
162 headers
.SetHeader(HttpRequestHeaders::kOrigin
, origin
.string());
163 headers
.SetHeader(websockets::kSecWebSocketVersion
,
164 websockets::kSupportedVersion
);
165 request
->url_request()->SetExtraRequestHeaders(headers
);
166 request
->url_request()->SetUserData(
167 WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
168 create_helper
.release());
169 request
->url_request()->SetLoadFlags(LOAD_DISABLE_CACHE
|
171 LOAD_DO_NOT_PROMPT_FOR_LOGIN
);
172 request
->url_request()->Start();
173 return request
.PassAs
<WebSocketStreamRequest
>();
178 WebSocketStreamRequest::~WebSocketStreamRequest() {}
180 WebSocketStream::WebSocketStream() {}
181 WebSocketStream::~WebSocketStream() {}
183 WebSocketStream::ConnectDelegate::~ConnectDelegate() {}
185 scoped_ptr
<WebSocketStreamRequest
> WebSocketStream::CreateAndConnectStream(
186 const GURL
& socket_url
,
187 const std::vector
<std::string
>& requested_subprotocols
,
188 const url::Origin
& origin
,
189 URLRequestContext
* url_request_context
,
190 const BoundNetLog
& net_log
,
191 scoped_ptr
<ConnectDelegate
> connect_delegate
) {
192 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper(
193 new WebSocketHandshakeStreamCreateHelper(connect_delegate
.get(),
194 requested_subprotocols
));
195 return CreateAndConnectStreamWithCreateHelper(socket_url
,
196 create_helper
.Pass(),
200 connect_delegate
.Pass());
203 // This is declared in websocket_test_util.h.
204 scoped_ptr
<WebSocketStreamRequest
> CreateAndConnectStreamForTesting(
205 const GURL
& socket_url
,
206 scoped_ptr
<WebSocketHandshakeStreamCreateHelper
> create_helper
,
207 const url::Origin
& origin
,
208 URLRequestContext
* url_request_context
,
209 const BoundNetLog
& net_log
,
210 scoped_ptr
<WebSocketStream::ConnectDelegate
> connect_delegate
) {
211 return CreateAndConnectStreamWithCreateHelper(socket_url
,
212 create_helper
.Pass(),
216 connect_delegate
.Pass());