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"
23 class StreamRequestImpl;
25 class Delegate : public URLRequest::Delegate {
27 explicit Delegate(StreamRequestImpl* owner) : owner_(owner) {}
28 virtual ~Delegate() {}
30 // Implementation of URLRequest::Delegate methods.
31 virtual void OnResponseStarted(URLRequest* request) OVERRIDE;
33 virtual void OnAuthRequired(URLRequest* request,
34 AuthChallengeInfo* auth_info) OVERRIDE;
36 virtual void OnCertificateRequested(URLRequest* request,
37 SSLCertRequestInfo* cert_request_info)
40 virtual void OnSSLCertificateError(URLRequest* request,
41 const SSLInfo& ssl_info,
44 virtual void OnReadCompleted(URLRequest* request, int bytes_read) OVERRIDE;
47 StreamRequestImpl* owner_;
50 class StreamRequestImpl : public WebSocketStreamRequest {
54 const URLRequestContext* context,
55 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate,
56 WebSocketHandshakeStreamCreateHelper* create_helper)
57 : delegate_(new Delegate(this)),
58 url_request_(url, DEFAULT_PRIORITY, delegate_.get(), context),
59 connect_delegate_(connect_delegate.Pass()),
60 create_helper_(create_helper) {}
62 // Destroying this object destroys the URLRequest, which cancels the request
63 // and so terminates the handshake if it is incomplete.
64 virtual ~StreamRequestImpl() {}
66 URLRequest* url_request() { return &url_request_; }
68 void PerformUpgrade() {
69 connect_delegate_->OnSuccess(create_helper_->stream()->Upgrade());
72 void ReportFailure() {
73 std::string failure_message;
74 if (create_helper_->stream()) {
75 failure_message = create_helper_->stream()->GetFailureMessage();
77 switch (url_request_.status().status()) {
78 case URLRequestStatus::SUCCESS:
79 case URLRequestStatus::IO_PENDING:
81 case URLRequestStatus::CANCELED:
82 failure_message = "WebSocket opening handshake was canceled";
84 case URLRequestStatus::FAILED:
86 std::string("Error in connection establishment: ") +
87 ErrorToString(url_request_.status().error());
91 connect_delegate_->OnFailure(failure_message);
95 // |delegate_| needs to be declared before |url_request_| so that it gets
97 scoped_ptr<Delegate> delegate_;
99 // Deleting the StreamRequestImpl object deletes this URLRequest object,
100 // cancelling the whole connection.
101 URLRequest url_request_;
103 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate_;
105 // Owned by the URLRequest.
106 WebSocketHandshakeStreamCreateHelper* create_helper_;
109 void Delegate::OnResponseStarted(URLRequest* request) {
110 switch (request->GetResponseCode()) {
111 case HTTP_SWITCHING_PROTOCOLS:
112 owner_->PerformUpgrade();
115 case HTTP_UNAUTHORIZED:
116 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
120 owner_->ReportFailure();
124 void Delegate::OnAuthRequired(URLRequest* request,
125 AuthChallengeInfo* auth_info) {
126 request->CancelAuth();
129 void Delegate::OnCertificateRequested(URLRequest* request,
130 SSLCertRequestInfo* cert_request_info) {
131 request->ContinueWithCertificate(NULL);
134 void Delegate::OnSSLCertificateError(URLRequest* request,
135 const SSLInfo& ssl_info,
140 void Delegate::OnReadCompleted(URLRequest* request, int bytes_read) {
144 // Internal implementation of CreateAndConnectStream and
145 // CreateAndConnectStreamForTesting.
146 scoped_ptr<WebSocketStreamRequest> CreateAndConnectStreamWithCreateHelper(
147 const GURL& socket_url,
148 scoped_ptr<WebSocketHandshakeStreamCreateHelper> create_helper,
150 URLRequestContext* url_request_context,
151 const BoundNetLog& net_log,
152 scoped_ptr<WebSocketStream::ConnectDelegate> connect_delegate) {
153 scoped_ptr<StreamRequestImpl> request(
154 new StreamRequestImpl(socket_url,
156 connect_delegate.Pass(),
157 create_helper.get()));
158 HttpRequestHeaders headers;
159 headers.SetHeader(websockets::kUpgrade, websockets::kWebSocketLowercase);
160 headers.SetHeader(HttpRequestHeaders::kConnection, websockets::kUpgrade);
161 headers.SetHeader(HttpRequestHeaders::kOrigin, origin.spec());
162 // TODO(ricea): Move the version number to websocket_handshake_constants.h
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,
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,
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());