blob: 055c4d5064a08b9ef9ddb3b6414e7b38d93cd1e2 [file] [log] [blame]
Bence Béky46bfbc12018-02-22 19:28:201// Copyright 2018 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_http2_handshake_stream.h"
6
7#include <cstddef>
Bence Béky46bfbc12018-02-22 19:28:208#include <utility>
9
10#include "base/bind.h"
Bence Béky46bfbc12018-02-22 19:28:2011#include "base/logging.h"
Bence Béky46bfbc12018-02-22 19:28:2012#include "base/strings/stringprintf.h"
13#include "base/time/time.h"
Tsuyoshi Horo01faed62019-02-20 22:11:3714#include "net/base/ip_endpoint.h"
Bence Béky46bfbc12018-02-22 19:28:2015#include "net/http/http_request_headers.h"
16#include "net/http/http_request_info.h"
17#include "net/http/http_response_headers.h"
18#include "net/http/http_status_code.h"
Bence Béky94658bf2018-05-11 19:22:5819#include "net/spdy/spdy_http_utils.h"
20#include "net/spdy/spdy_session.h"
Bence Béky46bfbc12018-02-22 19:28:2021#include "net/traffic_annotation/network_traffic_annotation.h"
22#include "net/websockets/websocket_basic_stream.h"
23#include "net/websockets/websocket_deflate_parameters.h"
24#include "net/websockets/websocket_deflate_predictor_impl.h"
25#include "net/websockets/websocket_deflate_stream.h"
26#include "net/websockets/websocket_deflater.h"
Bence Béky46bfbc12018-02-22 19:28:2027#include "net/websockets/websocket_handshake_constants.h"
28#include "net/websockets/websocket_handshake_request_info.h"
29
30namespace net {
31
Bence Béky46bfbc12018-02-22 19:28:2032namespace {
33
Bence Béky46bfbc12018-02-22 19:28:2034bool ValidateStatus(const HttpResponseHeaders* headers) {
35 return headers->GetStatusLine() == "HTTP/1.1 200";
36}
37
Bence Béky46bfbc12018-02-22 19:28:2038} // namespace
39
40WebSocketHttp2HandshakeStream::WebSocketHttp2HandshakeStream(
41 base::WeakPtr<SpdySession> session,
42 WebSocketStream::ConnectDelegate* connect_delegate,
43 std::vector<std::string> requested_sub_protocols,
44 std::vector<std::string> requested_extensions,
Adam Rice6f75c0f2018-06-04 08:00:0545 WebSocketStreamRequestAPI* request)
Bence Békyde0be312018-03-13 17:51:5846 : result_(HandshakeResult::HTTP2_INCOMPLETE),
47 session_(session),
Bence Béky46bfbc12018-02-22 19:28:2048 connect_delegate_(connect_delegate),
49 http_response_info_(nullptr),
50 requested_sub_protocols_(requested_sub_protocols),
51 requested_extensions_(requested_extensions),
52 stream_request_(request),
53 request_info_(nullptr),
54 stream_closed_(false),
55 stream_error_(OK),
Bence Békyca0da432019-01-24 15:03:2056 response_headers_complete_(false),
57 weak_ptr_factory_(this) {
Bence Béky46bfbc12018-02-22 19:28:2058 DCHECK(connect_delegate);
59 DCHECK(request);
60}
61
62WebSocketHttp2HandshakeStream::~WebSocketHttp2HandshakeStream() {
63 spdy_stream_request_.reset();
Bence Békyde0be312018-03-13 17:51:5864 RecordHandshakeResult(result_);
Bence Béky46bfbc12018-02-22 19:28:2065}
66
67int WebSocketHttp2HandshakeStream::InitializeStream(
68 const HttpRequestInfo* request_info,
69 bool can_send_early,
70 RequestPriority priority,
71 const NetLogWithSource& net_log,
72 CompletionOnceCallback callback) {
Ramin Halavati5ac4c912018-03-13 18:52:1973 DCHECK(request_info->traffic_annotation.is_valid());
Bence Béky46bfbc12018-02-22 19:28:2074 request_info_ = request_info;
75 priority_ = priority;
76 net_log_ = net_log;
77 return OK;
78}
79
80int WebSocketHttp2HandshakeStream::SendRequest(
81 const HttpRequestHeaders& headers,
82 HttpResponseInfo* response,
83 CompletionOnceCallback callback) {
84 DCHECK(!headers.HasHeader(websockets::kSecWebSocketKey));
85 DCHECK(!headers.HasHeader(websockets::kSecWebSocketProtocol));
86 DCHECK(!headers.HasHeader(websockets::kSecWebSocketExtensions));
87 DCHECK(headers.HasHeader(HttpRequestHeaders::kOrigin));
88 DCHECK(headers.HasHeader(websockets::kUpgrade));
89 DCHECK(headers.HasHeader(HttpRequestHeaders::kConnection));
90 DCHECK(headers.HasHeader(websockets::kSecWebSocketVersion));
91
92 if (!session_) {
93 OnFailure("Connection closed before sending request.");
94 return ERR_CONNECTION_CLOSED;
95 }
96
97 http_response_info_ = response;
98
99 IPEndPoint address;
100 int result = session_->GetPeerAddress(&address);
101 if (result != OK) {
102 OnFailure("Error getting IP address.");
103 return result;
104 }
Tsuyoshi Horo01faed62019-02-20 22:11:37105 http_response_info_->remote_endpoint = address;
Bence Béky46bfbc12018-02-22 19:28:20106
107 auto request = std::make_unique<WebSocketHandshakeRequestInfo>(
108 request_info_->url, base::Time::Now());
109 request->headers.CopyFrom(headers);
110
111 AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketExtensions,
112 requested_extensions_, &request->headers);
113 AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketProtocol,
114 requested_sub_protocols_, &request->headers);
115
116 CreateSpdyHeadersFromHttpRequestForWebSocket(
117 request_info_->url, request->headers, &http2_request_headers_);
118
119 connect_delegate_->OnStartOpeningHandshake(std::move(request));
120
121 callback_ = std::move(callback);
122 spdy_stream_request_ = std::make_unique<SpdyStreamRequest>();
Steven Valdez1c1859172019-04-10 15:33:28123 // The initial request for the WebSocket is a CONNECT, so there is no need to
124 // call ConfirmHandshake().
Bence Béky46bfbc12018-02-22 19:28:20125 int rv = spdy_stream_request_->StartRequest(
Steven Valdez1c1859172019-04-10 15:33:28126 SPDY_BIDIRECTIONAL_STREAM, session_, request_info_->url, true, priority_,
Paul Jensen94cde5f2018-03-01 04:38:13127 request_info_->socket_tag, net_log_,
Bence Béky46bfbc12018-02-22 19:28:20128 base::BindOnce(&WebSocketHttp2HandshakeStream::StartRequestCallback,
Ramin Halavatiead42712018-02-28 18:41:27129 base::Unretained(this)),
Ramin Halavati5ac4c912018-03-13 18:52:19130 NetworkTrafficAnnotationTag(request_info_->traffic_annotation));
Bence Béky46bfbc12018-02-22 19:28:20131 if (rv == OK) {
132 StartRequestCallback(rv);
133 return ERR_IO_PENDING;
134 }
135 return rv;
136}
137
138int WebSocketHttp2HandshakeStream::ReadResponseHeaders(
139 CompletionOnceCallback callback) {
140 if (stream_closed_)
141 return stream_error_;
142
143 if (response_headers_complete_)
144 return ValidateResponse();
145
146 callback_ = std::move(callback);
147 return ERR_IO_PENDING;
148}
149
150int WebSocketHttp2HandshakeStream::ReadResponseBody(
151 IOBuffer* buf,
152 int buf_len,
153 CompletionOnceCallback callback) {
154 // Callers should instead call Upgrade() to get a WebSocketStream
155 // and call ReadFrames() on that.
156 NOTREACHED();
157 return OK;
158}
159
160void WebSocketHttp2HandshakeStream::Close(bool not_reusable) {
161 spdy_stream_request_.reset();
162 if (stream_) {
163 stream_ = nullptr;
164 stream_closed_ = true;
165 stream_error_ = ERR_CONNECTION_CLOSED;
166 }
167 stream_adapter_.reset();
168}
169
170bool WebSocketHttp2HandshakeStream::IsResponseBodyComplete() const {
171 return false;
172}
173
174bool WebSocketHttp2HandshakeStream::IsConnectionReused() const {
175 return true;
176}
177
178void WebSocketHttp2HandshakeStream::SetConnectionReused() {}
179
180bool WebSocketHttp2HandshakeStream::CanReuseConnection() const {
181 return false;
182}
183
184int64_t WebSocketHttp2HandshakeStream::GetTotalReceivedBytes() const {
185 return stream_ ? stream_->raw_received_bytes() : 0;
186}
187
188int64_t WebSocketHttp2HandshakeStream::GetTotalSentBytes() const {
189 return stream_ ? stream_->raw_sent_bytes() : 0;
190}
191
192bool WebSocketHttp2HandshakeStream::GetAlternativeService(
193 AlternativeService* alternative_service) const {
194 return false;
195}
196
197bool WebSocketHttp2HandshakeStream::GetLoadTimingInfo(
198 LoadTimingInfo* load_timing_info) const {
199 return stream_ && stream_->GetLoadTimingInfo(load_timing_info);
200}
201
202void WebSocketHttp2HandshakeStream::GetSSLInfo(SSLInfo* ssl_info) {
203 if (stream_)
204 stream_->GetSSLInfo(ssl_info);
205}
206
207void WebSocketHttp2HandshakeStream::GetSSLCertRequestInfo(
208 SSLCertRequestInfo* cert_request_info) {
209 // A multiplexed stream cannot request client certificates. Client
210 // authentication may only occur during the initial SSL handshake.
211 NOTREACHED();
212}
213
214bool WebSocketHttp2HandshakeStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
215 return session_ && session_->GetRemoteEndpoint(endpoint);
216}
217
218void WebSocketHttp2HandshakeStream::PopulateNetErrorDetails(
219 NetErrorDetails* /*details*/) {
220 return;
221}
222
Bence Béky46bfbc12018-02-22 19:28:20223void WebSocketHttp2HandshakeStream::Drain(HttpNetworkSession* session) {
224 Close(true /* not_reusable */);
225}
226
227void WebSocketHttp2HandshakeStream::SetPriority(RequestPriority priority) {
228 priority_ = priority;
229 if (stream_)
Bence Béky7a4836c2018-05-08 03:52:48230 stream_->SetPriority(priority_);
Bence Béky46bfbc12018-02-22 19:28:20231}
232
233HttpStream* WebSocketHttp2HandshakeStream::RenewStreamForAuth() {
234 // Renewing the stream is not supported.
235 return nullptr;
236}
237
238std::unique_ptr<WebSocketStream> WebSocketHttp2HandshakeStream::Upgrade() {
239 DCHECK(extension_params_.get());
240
241 stream_adapter_->DetachDelegate();
242 std::unique_ptr<WebSocketStream> basic_stream =
243 std::make_unique<WebSocketBasicStream>(
244 std::move(stream_adapter_), nullptr, sub_protocol_, extensions_);
245
246 if (!extension_params_->deflate_enabled)
247 return basic_stream;
248
Bence Békyde0be312018-03-13 17:51:58249 RecordDeflateMode(
250 extension_params_->deflate_parameters.client_context_take_over_mode());
Bence Béky46bfbc12018-02-22 19:28:20251
252 return std::make_unique<WebSocketDeflateStream>(
253 std::move(basic_stream), extension_params_->deflate_parameters,
254 std::make_unique<WebSocketDeflatePredictorImpl>());
255}
256
Bence Békyca0da432019-01-24 15:03:20257base::WeakPtr<WebSocketHandshakeStreamBase>
258WebSocketHttp2HandshakeStream::GetWeakPtr() {
259 return weak_ptr_factory_.GetWeakPtr();
260}
261
Bence Béky46bfbc12018-02-22 19:28:20262void WebSocketHttp2HandshakeStream::OnHeadersSent() {
Daniel Chengcac5f4c62019-04-25 22:39:27263 std::move(callback_).Run(OK);
Bence Béky46bfbc12018-02-22 19:28:20264}
265
266void WebSocketHttp2HandshakeStream::OnHeadersReceived(
Ryan Hamilton0239aac2018-05-19 00:03:13267 const spdy::SpdyHeaderBlock& response_headers) {
Bence Béky46bfbc12018-02-22 19:28:20268 DCHECK(!response_headers_complete_);
269 DCHECK(http_response_info_);
270
271 response_headers_complete_ = true;
272
273 const bool headers_valid =
274 SpdyHeadersToHttpResponse(response_headers, http_response_info_);
275 DCHECK(headers_valid);
276
277 http_response_info_->response_time = stream_->response_time();
278 // Do not store SSLInfo in the response here, HttpNetworkTransaction will take
279 // care of that part.
280 http_response_info_->was_alpn_negotiated = true;
281 http_response_info_->request_time = stream_->GetRequestTime();
282 http_response_info_->connection_info =
283 HttpResponseInfo::CONNECTION_INFO_HTTP2;
284 http_response_info_->alpn_negotiated_protocol =
285 HttpResponseInfo::ConnectionInfoToString(
286 http_response_info_->connection_info);
287 http_response_info_->vary_data.Init(*request_info_,
288 *http_response_info_->headers.get());
289
290 if (callback_)
Daniel Chengcac5f4c62019-04-25 22:39:27291 std::move(callback_).Run(ValidateResponse());
Bence Béky46bfbc12018-02-22 19:28:20292}
293
294void WebSocketHttp2HandshakeStream::OnClose(int status) {
295 DCHECK(stream_adapter_);
296 DCHECK_GT(ERR_IO_PENDING, status);
297
298 stream_closed_ = true;
299 stream_error_ = status;
300 stream_ = nullptr;
301
302 stream_adapter_.reset();
303
Bence Békyde0be312018-03-13 17:51:58304 // If response headers have already been received,
305 // then ValidateResponse() sets |result_|.
306 if (!response_headers_complete_)
307 result_ = HandshakeResult::HTTP2_FAILED;
308
Bence Béky46bfbc12018-02-22 19:28:20309 OnFailure(std::string("Stream closed with error: ") + ErrorToString(status));
310
311 if (callback_)
Daniel Chengcac5f4c62019-04-25 22:39:27312 std::move(callback_).Run(status);
Bence Béky46bfbc12018-02-22 19:28:20313}
314
315void WebSocketHttp2HandshakeStream::StartRequestCallback(int rv) {
316 DCHECK(callback_);
317 if (rv != OK) {
318 spdy_stream_request_.reset();
Daniel Chengcac5f4c62019-04-25 22:39:27319 std::move(callback_).Run(rv);
Bence Béky46bfbc12018-02-22 19:28:20320 return;
321 }
322 stream_ = spdy_stream_request_->ReleaseStream();
323 spdy_stream_request_.reset();
324 stream_adapter_ =
325 std::make_unique<WebSocketSpdyStreamAdapter>(stream_, this, net_log_);
326 rv = stream_->SendRequestHeaders(std::move(http2_request_headers_),
327 MORE_DATA_TO_SEND);
328 // SendRequestHeaders() always returns asynchronously,
329 // and instead of taking a callback, it calls OnHeadersSent().
330 DCHECK_EQ(ERR_IO_PENDING, rv);
331}
332
333int WebSocketHttp2HandshakeStream::ValidateResponse() {
334 DCHECK(http_response_info_);
335 const HttpResponseHeaders* headers = http_response_info_->headers.get();
336 const int response_code = headers->response_code();
337 switch (response_code) {
338 case HTTP_OK:
339 OnFinishOpeningHandshake();
340 return ValidateUpgradeResponse(headers);
341
342 // We need to pass these through for authentication to work.
343 case HTTP_UNAUTHORIZED:
344 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
345 return OK;
346
347 // Other status codes are potentially risky (see the warnings in the
348 // WHATWG WebSocket API spec) and so are dropped by default.
349 default:
350 OnFailure(base::StringPrintf(
351 "Error during WebSocket handshake: Unexpected response code: %d",
352 headers->response_code()));
353 OnFinishOpeningHandshake();
Bence Békyde0be312018-03-13 17:51:58354 result_ = HandshakeResult::HTTP2_INVALID_STATUS;
Bence Béky46bfbc12018-02-22 19:28:20355 return ERR_INVALID_RESPONSE;
356 }
357}
358
359int WebSocketHttp2HandshakeStream::ValidateUpgradeResponse(
360 const HttpResponseHeaders* headers) {
361 extension_params_ = std::make_unique<WebSocketExtensionParams>();
362 std::string failure_message;
Bence Békyde0be312018-03-13 17:51:58363 if (!ValidateStatus(headers)) {
364 result_ = HandshakeResult::HTTP2_INVALID_STATUS;
365 } else if (!ValidateSubProtocol(headers, requested_sub_protocols_,
366 &sub_protocol_, &failure_message)) {
367 result_ = HandshakeResult::HTTP2_FAILED_SUBPROTO;
368 } else if (!ValidateExtensions(headers, &extensions_, &failure_message,
369 extension_params_.get())) {
370 result_ = HandshakeResult::HTTP2_FAILED_EXTENSIONS;
371 } else {
372 result_ = HandshakeResult::HTTP2_CONNECTED;
Bence Béky46bfbc12018-02-22 19:28:20373 return OK;
374 }
375 OnFailure("Error during WebSocket handshake: " + failure_message);
376 return ERR_INVALID_RESPONSE;
377}
378
379void WebSocketHttp2HandshakeStream::OnFinishOpeningHandshake() {
380 DCHECK(http_response_info_);
381 WebSocketDispatchOnFinishOpeningHandshake(
382 connect_delegate_, request_info_->url, http_response_info_->headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37383 http_response_info_->remote_endpoint, http_response_info_->response_time);
Bence Béky46bfbc12018-02-22 19:28:20384}
385
386void WebSocketHttp2HandshakeStream::OnFailure(const std::string& message) {
387 stream_request_->OnFailure(message);
388}
389
390} // namespace net