blob: 99910c99b8d26018c768bf50744de1b82d857e18 [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"
11#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),
Jeremy Romand54000b22019-07-08 18:40:1656 response_headers_complete_(false) {
Bence Béky46bfbc12018-02-22 19:28:2057 DCHECK(connect_delegate);
58 DCHECK(request);
59}
60
61WebSocketHttp2HandshakeStream::~WebSocketHttp2HandshakeStream() {
62 spdy_stream_request_.reset();
Bence Békyde0be312018-03-13 17:51:5863 RecordHandshakeResult(result_);
Bence Béky46bfbc12018-02-22 19:28:2064}
65
66int WebSocketHttp2HandshakeStream::InitializeStream(
67 const HttpRequestInfo* request_info,
68 bool can_send_early,
69 RequestPriority priority,
70 const NetLogWithSource& net_log,
71 CompletionOnceCallback callback) {
Ramin Halavati5ac4c912018-03-13 18:52:1972 DCHECK(request_info->traffic_annotation.is_valid());
Bence Béky46bfbc12018-02-22 19:28:2073 request_info_ = request_info;
74 priority_ = priority;
75 net_log_ = net_log;
76 return OK;
77}
78
79int WebSocketHttp2HandshakeStream::SendRequest(
80 const HttpRequestHeaders& headers,
81 HttpResponseInfo* response,
82 CompletionOnceCallback callback) {
83 DCHECK(!headers.HasHeader(websockets::kSecWebSocketKey));
84 DCHECK(!headers.HasHeader(websockets::kSecWebSocketProtocol));
85 DCHECK(!headers.HasHeader(websockets::kSecWebSocketExtensions));
86 DCHECK(headers.HasHeader(HttpRequestHeaders::kOrigin));
87 DCHECK(headers.HasHeader(websockets::kUpgrade));
88 DCHECK(headers.HasHeader(HttpRequestHeaders::kConnection));
89 DCHECK(headers.HasHeader(websockets::kSecWebSocketVersion));
90
91 if (!session_) {
92 OnFailure("Connection closed before sending request.");
93 return ERR_CONNECTION_CLOSED;
94 }
95
96 http_response_info_ = response;
97
98 IPEndPoint address;
99 int result = session_->GetPeerAddress(&address);
100 if (result != OK) {
101 OnFailure("Error getting IP address.");
102 return result;
103 }
Tsuyoshi Horo01faed62019-02-20 22:11:37104 http_response_info_->remote_endpoint = address;
Bence Béky46bfbc12018-02-22 19:28:20105
106 auto request = std::make_unique<WebSocketHandshakeRequestInfo>(
107 request_info_->url, base::Time::Now());
108 request->headers.CopyFrom(headers);
109
110 AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketExtensions,
111 requested_extensions_, &request->headers);
112 AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketProtocol,
113 requested_sub_protocols_, &request->headers);
114
115 CreateSpdyHeadersFromHttpRequestForWebSocket(
116 request_info_->url, request->headers, &http2_request_headers_);
117
118 connect_delegate_->OnStartOpeningHandshake(std::move(request));
119
120 callback_ = std::move(callback);
121 spdy_stream_request_ = std::make_unique<SpdyStreamRequest>();
Steven Valdez1c1859172019-04-10 15:33:28122 // The initial request for the WebSocket is a CONNECT, so there is no need to
123 // call ConfirmHandshake().
Bence Béky46bfbc12018-02-22 19:28:20124 int rv = spdy_stream_request_->StartRequest(
Steven Valdez1c1859172019-04-10 15:33:28125 SPDY_BIDIRECTIONAL_STREAM, session_, request_info_->url, true, priority_,
Paul Jensen94cde5f2018-03-01 04:38:13126 request_info_->socket_tag, net_log_,
Bence Béky46bfbc12018-02-22 19:28:20127 base::BindOnce(&WebSocketHttp2HandshakeStream::StartRequestCallback,
Ramin Halavatiead42712018-02-28 18:41:27128 base::Unretained(this)),
Ramin Halavati5ac4c912018-03-13 18:52:19129 NetworkTrafficAnnotationTag(request_info_->traffic_annotation));
Bence Béky46bfbc12018-02-22 19:28:20130 if (rv == OK) {
131 StartRequestCallback(rv);
132 return ERR_IO_PENDING;
133 }
134 return rv;
135}
136
137int WebSocketHttp2HandshakeStream::ReadResponseHeaders(
138 CompletionOnceCallback callback) {
139 if (stream_closed_)
140 return stream_error_;
141
142 if (response_headers_complete_)
143 return ValidateResponse();
144
145 callback_ = std::move(callback);
146 return ERR_IO_PENDING;
147}
148
149int WebSocketHttp2HandshakeStream::ReadResponseBody(
150 IOBuffer* buf,
151 int buf_len,
152 CompletionOnceCallback callback) {
153 // Callers should instead call Upgrade() to get a WebSocketStream
154 // and call ReadFrames() on that.
155 NOTREACHED();
156 return OK;
157}
158
159void WebSocketHttp2HandshakeStream::Close(bool not_reusable) {
160 spdy_stream_request_.reset();
161 if (stream_) {
162 stream_ = nullptr;
163 stream_closed_ = true;
164 stream_error_ = ERR_CONNECTION_CLOSED;
165 }
166 stream_adapter_.reset();
167}
168
169bool WebSocketHttp2HandshakeStream::IsResponseBodyComplete() const {
170 return false;
171}
172
173bool WebSocketHttp2HandshakeStream::IsConnectionReused() const {
174 return true;
175}
176
177void WebSocketHttp2HandshakeStream::SetConnectionReused() {}
178
179bool WebSocketHttp2HandshakeStream::CanReuseConnection() const {
180 return false;
181}
182
183int64_t WebSocketHttp2HandshakeStream::GetTotalReceivedBytes() const {
184 return stream_ ? stream_->raw_received_bytes() : 0;
185}
186
187int64_t WebSocketHttp2HandshakeStream::GetTotalSentBytes() const {
188 return stream_ ? stream_->raw_sent_bytes() : 0;
189}
190
191bool WebSocketHttp2HandshakeStream::GetAlternativeService(
192 AlternativeService* alternative_service) const {
193 return false;
194}
195
196bool WebSocketHttp2HandshakeStream::GetLoadTimingInfo(
197 LoadTimingInfo* load_timing_info) const {
198 return stream_ && stream_->GetLoadTimingInfo(load_timing_info);
199}
200
201void WebSocketHttp2HandshakeStream::GetSSLInfo(SSLInfo* ssl_info) {
202 if (stream_)
203 stream_->GetSSLInfo(ssl_info);
204}
205
206void WebSocketHttp2HandshakeStream::GetSSLCertRequestInfo(
207 SSLCertRequestInfo* cert_request_info) {
208 // A multiplexed stream cannot request client certificates. Client
209 // authentication may only occur during the initial SSL handshake.
210 NOTREACHED();
211}
212
213bool WebSocketHttp2HandshakeStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
214 return session_ && session_->GetRemoteEndpoint(endpoint);
215}
216
217void WebSocketHttp2HandshakeStream::PopulateNetErrorDetails(
218 NetErrorDetails* /*details*/) {
219 return;
220}
221
Bence Béky46bfbc12018-02-22 19:28:20222void WebSocketHttp2HandshakeStream::Drain(HttpNetworkSession* session) {
223 Close(true /* not_reusable */);
224}
225
226void WebSocketHttp2HandshakeStream::SetPriority(RequestPriority priority) {
227 priority_ = priority;
228 if (stream_)
Bence Béky7a4836c2018-05-08 03:52:48229 stream_->SetPriority(priority_);
Bence Béky46bfbc12018-02-22 19:28:20230}
231
232HttpStream* WebSocketHttp2HandshakeStream::RenewStreamForAuth() {
233 // Renewing the stream is not supported.
234 return nullptr;
235}
236
237std::unique_ptr<WebSocketStream> WebSocketHttp2HandshakeStream::Upgrade() {
238 DCHECK(extension_params_.get());
239
240 stream_adapter_->DetachDelegate();
241 std::unique_ptr<WebSocketStream> basic_stream =
242 std::make_unique<WebSocketBasicStream>(
243 std::move(stream_adapter_), nullptr, sub_protocol_, extensions_);
244
245 if (!extension_params_->deflate_enabled)
246 return basic_stream;
247
Bence Béky46bfbc12018-02-22 19:28:20248 return std::make_unique<WebSocketDeflateStream>(
249 std::move(basic_stream), extension_params_->deflate_parameters,
250 std::make_unique<WebSocketDeflatePredictorImpl>());
251}
252
Bence Békyca0da432019-01-24 15:03:20253base::WeakPtr<WebSocketHandshakeStreamBase>
254WebSocketHttp2HandshakeStream::GetWeakPtr() {
255 return weak_ptr_factory_.GetWeakPtr();
256}
257
Bence Béky46bfbc12018-02-22 19:28:20258void WebSocketHttp2HandshakeStream::OnHeadersSent() {
Daniel Chengcac5f4c62019-04-25 22:39:27259 std::move(callback_).Run(OK);
Bence Béky46bfbc12018-02-22 19:28:20260}
261
262void WebSocketHttp2HandshakeStream::OnHeadersReceived(
Ryan Hamilton0239aac2018-05-19 00:03:13263 const spdy::SpdyHeaderBlock& response_headers) {
Bence Béky46bfbc12018-02-22 19:28:20264 DCHECK(!response_headers_complete_);
265 DCHECK(http_response_info_);
266
267 response_headers_complete_ = true;
268
269 const bool headers_valid =
270 SpdyHeadersToHttpResponse(response_headers, http_response_info_);
271 DCHECK(headers_valid);
272
273 http_response_info_->response_time = stream_->response_time();
274 // Do not store SSLInfo in the response here, HttpNetworkTransaction will take
275 // care of that part.
276 http_response_info_->was_alpn_negotiated = true;
277 http_response_info_->request_time = stream_->GetRequestTime();
278 http_response_info_->connection_info =
279 HttpResponseInfo::CONNECTION_INFO_HTTP2;
280 http_response_info_->alpn_negotiated_protocol =
281 HttpResponseInfo::ConnectionInfoToString(
282 http_response_info_->connection_info);
283 http_response_info_->vary_data.Init(*request_info_,
284 *http_response_info_->headers.get());
285
286 if (callback_)
Daniel Chengcac5f4c62019-04-25 22:39:27287 std::move(callback_).Run(ValidateResponse());
Bence Béky46bfbc12018-02-22 19:28:20288}
289
290void WebSocketHttp2HandshakeStream::OnClose(int status) {
291 DCHECK(stream_adapter_);
292 DCHECK_GT(ERR_IO_PENDING, status);
293
294 stream_closed_ = true;
295 stream_error_ = status;
296 stream_ = nullptr;
297
298 stream_adapter_.reset();
299
Bence Békyde0be312018-03-13 17:51:58300 // If response headers have already been received,
301 // then ValidateResponse() sets |result_|.
302 if (!response_headers_complete_)
303 result_ = HandshakeResult::HTTP2_FAILED;
304
Bence Béky46bfbc12018-02-22 19:28:20305 OnFailure(std::string("Stream closed with error: ") + ErrorToString(status));
306
307 if (callback_)
Daniel Chengcac5f4c62019-04-25 22:39:27308 std::move(callback_).Run(status);
Bence Béky46bfbc12018-02-22 19:28:20309}
310
311void WebSocketHttp2HandshakeStream::StartRequestCallback(int rv) {
312 DCHECK(callback_);
313 if (rv != OK) {
314 spdy_stream_request_.reset();
Daniel Chengcac5f4c62019-04-25 22:39:27315 std::move(callback_).Run(rv);
Bence Béky46bfbc12018-02-22 19:28:20316 return;
317 }
318 stream_ = spdy_stream_request_->ReleaseStream();
319 spdy_stream_request_.reset();
320 stream_adapter_ =
321 std::make_unique<WebSocketSpdyStreamAdapter>(stream_, this, net_log_);
322 rv = stream_->SendRequestHeaders(std::move(http2_request_headers_),
323 MORE_DATA_TO_SEND);
324 // SendRequestHeaders() always returns asynchronously,
325 // and instead of taking a callback, it calls OnHeadersSent().
326 DCHECK_EQ(ERR_IO_PENDING, rv);
327}
328
329int WebSocketHttp2HandshakeStream::ValidateResponse() {
330 DCHECK(http_response_info_);
331 const HttpResponseHeaders* headers = http_response_info_->headers.get();
332 const int response_code = headers->response_code();
333 switch (response_code) {
334 case HTTP_OK:
335 OnFinishOpeningHandshake();
336 return ValidateUpgradeResponse(headers);
337
338 // We need to pass these through for authentication to work.
339 case HTTP_UNAUTHORIZED:
340 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
341 return OK;
342
343 // Other status codes are potentially risky (see the warnings in the
344 // WHATWG WebSocket API spec) and so are dropped by default.
345 default:
346 OnFailure(base::StringPrintf(
347 "Error during WebSocket handshake: Unexpected response code: %d",
348 headers->response_code()));
349 OnFinishOpeningHandshake();
Bence Békyde0be312018-03-13 17:51:58350 result_ = HandshakeResult::HTTP2_INVALID_STATUS;
Bence Béky46bfbc12018-02-22 19:28:20351 return ERR_INVALID_RESPONSE;
352 }
353}
354
355int WebSocketHttp2HandshakeStream::ValidateUpgradeResponse(
356 const HttpResponseHeaders* headers) {
357 extension_params_ = std::make_unique<WebSocketExtensionParams>();
358 std::string failure_message;
Bence Békyde0be312018-03-13 17:51:58359 if (!ValidateStatus(headers)) {
360 result_ = HandshakeResult::HTTP2_INVALID_STATUS;
361 } else if (!ValidateSubProtocol(headers, requested_sub_protocols_,
362 &sub_protocol_, &failure_message)) {
363 result_ = HandshakeResult::HTTP2_FAILED_SUBPROTO;
364 } else if (!ValidateExtensions(headers, &extensions_, &failure_message,
365 extension_params_.get())) {
366 result_ = HandshakeResult::HTTP2_FAILED_EXTENSIONS;
367 } else {
368 result_ = HandshakeResult::HTTP2_CONNECTED;
Bence Béky46bfbc12018-02-22 19:28:20369 return OK;
370 }
371 OnFailure("Error during WebSocket handshake: " + failure_message);
372 return ERR_INVALID_RESPONSE;
373}
374
375void WebSocketHttp2HandshakeStream::OnFinishOpeningHandshake() {
376 DCHECK(http_response_info_);
377 WebSocketDispatchOnFinishOpeningHandshake(
378 connect_delegate_, request_info_->url, http_response_info_->headers,
Tsuyoshi Horo01faed62019-02-20 22:11:37379 http_response_info_->remote_endpoint, http_response_info_->response_time);
Bence Béky46bfbc12018-02-22 19:28:20380}
381
382void WebSocketHttp2HandshakeStream::OnFailure(const std::string& message) {
383 stream_request_->OnFailure(message);
384}
385
386} // namespace net