blob: 546e01b852cb4a10230110b177a9aa4112d041e1 [file] [log] [blame]
[email protected]473282d2013-07-02 11:57:071// 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.
4
5#include "net/websockets/websocket_stream.h"
6
7#include "base/logging.h"
[email protected]efa9e732013-11-29 02:55:058#include "base/memory/scoped_ptr.h"
[email protected]1e0a16a2014-04-04 16:18:049#include "base/metrics/histogram.h"
[email protected]d7599122014-05-24 03:37:2310#include "net/base/load_flags.h"
[email protected]efa9e732013-11-29 02:55:0511#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"
20#include "url/gurl.h"
[email protected]7824cf82014-03-13 10:22:5721#include "url/origin.h"
[email protected]473282d2013-07-02 11:57:0722
23namespace net {
[email protected]efa9e732013-11-29 02:55:0524namespace {
25
26class StreamRequestImpl;
27
28class Delegate : public URLRequest::Delegate {
29 public:
[email protected]1e0a16a2014-04-04 16:18:0430 enum HandshakeResult {
31 INCOMPLETE,
32 CONNECTED,
33 FAILED,
34 NUM_HANDSHAKE_RESULT_TYPES,
35 };
36
37 explicit Delegate(StreamRequestImpl* owner)
38 : owner_(owner), result_(INCOMPLETE) {}
39 virtual ~Delegate() {
40 UMA_HISTOGRAM_ENUMERATION(
41 "Net.WebSocket.HandshakeResult", result_, NUM_HANDSHAKE_RESULT_TYPES);
42 }
[email protected]efa9e732013-11-29 02:55:0543
44 // Implementation of URLRequest::Delegate methods.
45 virtual void OnResponseStarted(URLRequest* request) OVERRIDE;
46
47 virtual void OnAuthRequired(URLRequest* request,
48 AuthChallengeInfo* auth_info) OVERRIDE;
49
50 virtual void OnCertificateRequested(URLRequest* request,
51 SSLCertRequestInfo* cert_request_info)
52 OVERRIDE;
53
54 virtual void OnSSLCertificateError(URLRequest* request,
55 const SSLInfo& ssl_info,
56 bool fatal) OVERRIDE;
57
58 virtual void OnReadCompleted(URLRequest* request, int bytes_read) OVERRIDE;
59
60 private:
61 StreamRequestImpl* owner_;
[email protected]1e0a16a2014-04-04 16:18:0462 HandshakeResult result_;
[email protected]efa9e732013-11-29 02:55:0563};
64
65class StreamRequestImpl : public WebSocketStreamRequest {
66 public:
67 StreamRequestImpl(
68 const GURL& url,
69 const URLRequestContext* context,
[email protected]490e38f42014-05-26 23:44:1670 const url::Origin& origin,
[email protected]efa9e732013-11-29 02:55:0571 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
[email protected]490e38f42014-05-26 23:44:1672 scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper)
[email protected]efa9e732013-11-29 02:55:0573 : delegate_(new Delegate(this)),
74 url_request_(url, DEFAULT_PRIORITY, delegate_.get(), context),
75 connect_delegate_(connect_delegate.Pass()),
[email protected]490e38f42014-05-26 23:44:1676 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);
84
85 // This passes the ownership of |create_helper_| to |url_request_|.
86 url_request_.SetUserData(
87 WebSocketHandshakeStreamBase::CreateHelper::DataKey(),
88 create_helper_);
89 url_request_.SetLoadFlags(LOAD_DISABLE_CACHE |
90 LOAD_BYPASS_CACHE |
91 LOAD_DO_NOT_PROMPT_FOR_LOGIN);
92 }
[email protected]efa9e732013-11-29 02:55:0593
94 // Destroying this object destroys the URLRequest, which cancels the request
95 // and so terminates the handshake if it is incomplete.
96 virtual ~StreamRequestImpl() {}
97
[email protected]490e38f42014-05-26 23:44:1698 void Start() {
99 url_request_.Start();
100 }
[email protected]efa9e732013-11-29 02:55:05101
102 void PerformUpgrade() {
103 connect_delegate_->OnSuccess(create_helper_->stream()->Upgrade());
104 }
105
106 void ReportFailure() {
[email protected]96868202014-01-09 10:38:04107 std::string failure_message;
108 if (create_helper_->stream()) {
109 failure_message = create_helper_->stream()->GetFailureMessage();
110 } else {
111 switch (url_request_.status().status()) {
112 case URLRequestStatus::SUCCESS:
113 case URLRequestStatus::IO_PENDING:
114 break;
115 case URLRequestStatus::CANCELED:
116 failure_message = "WebSocket opening handshake was canceled";
117 break;
118 case URLRequestStatus::FAILED:
119 failure_message =
120 std::string("Error in connection establishment: ") +
121 ErrorToString(url_request_.status().error());
122 break;
123 }
124 }
125 connect_delegate_->OnFailure(failure_message);
[email protected]efa9e732013-11-29 02:55:05126 }
127
128 private:
129 // |delegate_| needs to be declared before |url_request_| so that it gets
130 // initialised first.
131 scoped_ptr<Delegate> delegate_;
132
133 // Deleting the StreamRequestImpl object deletes this URLRequest object,
134 // cancelling the whole connection.
135 URLRequest url_request_;
136
137 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate_;
138
139 // Owned by the URLRequest.
140 WebSocketHandshakeStreamCreateHelper* create_helper_;
141};
142
143void Delegate::OnResponseStarted(URLRequest* request) {
144 switch (request->GetResponseCode()) {
145 case HTTP_SWITCHING_PROTOCOLS:
[email protected]1e0a16a2014-04-04 16:18:04146 result_ = CONNECTED;
[email protected]efa9e732013-11-29 02:55:05147 owner_->PerformUpgrade();
148 return;
149
150 case HTTP_UNAUTHORIZED:
151 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
152 return;
153
154 default:
[email protected]1e0a16a2014-04-04 16:18:04155 result_ = FAILED;
[email protected]efa9e732013-11-29 02:55:05156 owner_->ReportFailure();
157 }
158}
159
160void Delegate::OnAuthRequired(URLRequest* request,
161 AuthChallengeInfo* auth_info) {
162 request->CancelAuth();
163}
164
165void Delegate::OnCertificateRequested(URLRequest* request,
166 SSLCertRequestInfo* cert_request_info) {
167 request->ContinueWithCertificate(NULL);
168}
169
170void Delegate::OnSSLCertificateError(URLRequest* request,
171 const SSLInfo& ssl_info,
172 bool fatal) {
173 request->Cancel();
174}
175
176void Delegate::OnReadCompleted(URLRequest* request, int bytes_read) {
177 NOTREACHED();
178}
179
[email protected]efa9e732013-11-29 02:55:05180} // namespace
[email protected]473282d2013-07-02 11:57:07181
182WebSocketStreamRequest::~WebSocketStreamRequest() {}
183
184WebSocketStream::WebSocketStream() {}
185WebSocketStream::~WebSocketStream() {}
186
187WebSocketStream::ConnectDelegate::~ConnectDelegate() {}
188
[email protected]473282d2013-07-02 11:57:07189scoped_ptr<WebSocketStreamRequest> WebSocketStream::CreateAndConnectStream(
190 const GURL& socket_url,
191 const std::vector<std::string>& requested_subprotocols,
[email protected]7824cf82014-03-13 10:22:57192 const url::Origin& origin,
[email protected]473282d2013-07-02 11:57:07193 URLRequestContext* url_request_context,
194 const BoundNetLog& net_log,
195 scoped_ptr<ConnectDelegate> connect_delegate) {
[email protected]efa9e732013-11-29 02:55:05196 scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper(
[email protected]cd48ed12014-01-22 14:34:22197 new WebSocketHandshakeStreamCreateHelper(connect_delegate.get(),
198 requested_subprotocols));
[email protected]490e38f42014-05-26 23:44:16199 scoped_ptr<StreamRequestImpl> request(
200 new StreamRequestImpl(socket_url,
201 url_request_context,
202 origin,
203 connect_delegate.Pass(),
204 create_helper.Pass()));
205 request->Start();
206 return request.PassAs<WebSocketStreamRequest>();
[email protected]efa9e732013-11-29 02:55:05207}
208
209// This is declared in websocket_test_util.h.
210scoped_ptr<WebSocketStreamRequest> CreateAndConnectStreamForTesting(
[email protected]7824cf82014-03-13 10:22:57211 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) {
[email protected]490e38f42014-05-26 23:44:16217 scoped_ptr<StreamRequestImpl> request(
218 new StreamRequestImpl(socket_url,
219 url_request_context,
220 origin,
221 connect_delegate.Pass(),
222 create_helper.Pass()));
223 request->Start();
224 return request.PassAs<WebSocketStreamRequest>();
[email protected]473282d2013-07-02 11:57:07225}
226
[email protected]473282d2013-07-02 11:57:07227} // namespace net