blob: bd99b759532751fa7efcb81891ada1bd4434e27d [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"
14#include "net/http/http_request_headers.h"
15#include "net/http/http_request_info.h"
16#include "net/http/http_response_headers.h"
17#include "net/http/http_status_code.h"
18#include "net/spdy/chromium/spdy_http_utils.h"
19#include "net/spdy/chromium/spdy_session.h"
20#include "net/traffic_annotation/network_traffic_annotation.h"
21#include "net/websockets/websocket_basic_stream.h"
22#include "net/websockets/websocket_deflate_parameters.h"
23#include "net/websockets/websocket_deflate_predictor_impl.h"
24#include "net/websockets/websocket_deflate_stream.h"
25#include "net/websockets/websocket_deflater.h"
Bence Béky46bfbc12018-02-22 19:28:2026#include "net/websockets/websocket_handshake_constants.h"
27#include "net/websockets/websocket_handshake_request_info.h"
28
29namespace net {
30
Bence Béky46bfbc12018-02-22 19:28:2031namespace {
32
Bence Béky46bfbc12018-02-22 19:28:2033bool ValidateStatus(const HttpResponseHeaders* headers) {
34 return headers->GetStatusLine() == "HTTP/1.1 200";
35}
36
Bence Béky46bfbc12018-02-22 19:28:2037} // namespace
38
39WebSocketHttp2HandshakeStream::WebSocketHttp2HandshakeStream(
40 base::WeakPtr<SpdySession> session,
41 WebSocketStream::ConnectDelegate* connect_delegate,
42 std::vector<std::string> requested_sub_protocols,
43 std::vector<std::string> requested_extensions,
44 WebSocketStreamRequest* request)
Bence Békyde0be312018-03-13 17:51:5845 : result_(HandshakeResult::HTTP2_INCOMPLETE),
46 session_(session),
Bence Béky46bfbc12018-02-22 19:28:2047 connect_delegate_(connect_delegate),
48 http_response_info_(nullptr),
49 requested_sub_protocols_(requested_sub_protocols),
50 requested_extensions_(requested_extensions),
51 stream_request_(request),
52 request_info_(nullptr),
53 stream_closed_(false),
54 stream_error_(OK),
55 response_headers_complete_(false) {
56 DCHECK(connect_delegate);
57 DCHECK(request);
58}
59
60WebSocketHttp2HandshakeStream::~WebSocketHttp2HandshakeStream() {
61 spdy_stream_request_.reset();
Bence Békyde0be312018-03-13 17:51:5862 RecordHandshakeResult(result_);
Bence Béky46bfbc12018-02-22 19:28:2063}
64
65int WebSocketHttp2HandshakeStream::InitializeStream(
66 const HttpRequestInfo* request_info,
67 bool can_send_early,
68 RequestPriority priority,
69 const NetLogWithSource& net_log,
70 CompletionOnceCallback callback) {
Ramin Halavati5ac4c912018-03-13 18:52:1971 DCHECK(request_info->traffic_annotation.is_valid());
Bence Béky46bfbc12018-02-22 19:28:2072 request_info_ = request_info;
73 priority_ = priority;
74 net_log_ = net_log;
75 return OK;
76}
77
78int WebSocketHttp2HandshakeStream::SendRequest(
79 const HttpRequestHeaders& headers,
80 HttpResponseInfo* response,
81 CompletionOnceCallback callback) {
82 DCHECK(!headers.HasHeader(websockets::kSecWebSocketKey));
83 DCHECK(!headers.HasHeader(websockets::kSecWebSocketProtocol));
84 DCHECK(!headers.HasHeader(websockets::kSecWebSocketExtensions));
85 DCHECK(headers.HasHeader(HttpRequestHeaders::kOrigin));
86 DCHECK(headers.HasHeader(websockets::kUpgrade));
87 DCHECK(headers.HasHeader(HttpRequestHeaders::kConnection));
88 DCHECK(headers.HasHeader(websockets::kSecWebSocketVersion));
89
90 if (!session_) {
91 OnFailure("Connection closed before sending request.");
92 return ERR_CONNECTION_CLOSED;
93 }
94
95 http_response_info_ = response;
96
97 IPEndPoint address;
98 int result = session_->GetPeerAddress(&address);
99 if (result != OK) {
100 OnFailure("Error getting IP address.");
101 return result;
102 }
103 http_response_info_->socket_address = HostPortPair::FromIPEndPoint(address);
104
105 auto request = std::make_unique<WebSocketHandshakeRequestInfo>(
106 request_info_->url, base::Time::Now());
107 request->headers.CopyFrom(headers);
108
109 AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketExtensions,
110 requested_extensions_, &request->headers);
111 AddVectorHeaderIfNonEmpty(websockets::kSecWebSocketProtocol,
112 requested_sub_protocols_, &request->headers);
113
114 CreateSpdyHeadersFromHttpRequestForWebSocket(
115 request_info_->url, request->headers, &http2_request_headers_);
116
117 connect_delegate_->OnStartOpeningHandshake(std::move(request));
118
119 callback_ = std::move(callback);
120 spdy_stream_request_ = std::make_unique<SpdyStreamRequest>();
121 int rv = spdy_stream_request_->StartRequest(
122 SPDY_BIDIRECTIONAL_STREAM, session_, request_info_->url, priority_,
Paul Jensen94cde5f2018-03-01 04:38:13123 request_info_->socket_tag, net_log_,
Bence Béky46bfbc12018-02-22 19:28:20124 base::BindOnce(&WebSocketHttp2HandshakeStream::StartRequestCallback,
Ramin Halavatiead42712018-02-28 18:41:27125 base::Unretained(this)),
Ramin Halavati5ac4c912018-03-13 18:52:19126 NetworkTrafficAnnotationTag(request_info_->traffic_annotation));
Bence Béky46bfbc12018-02-22 19:28:20127 if (rv == OK) {
128 StartRequestCallback(rv);
129 return ERR_IO_PENDING;
130 }
131 return rv;
132}
133
134int WebSocketHttp2HandshakeStream::ReadResponseHeaders(
135 CompletionOnceCallback callback) {
136 if (stream_closed_)
137 return stream_error_;
138
139 if (response_headers_complete_)
140 return ValidateResponse();
141
142 callback_ = std::move(callback);
143 return ERR_IO_PENDING;
144}
145
146int WebSocketHttp2HandshakeStream::ReadResponseBody(
147 IOBuffer* buf,
148 int buf_len,
149 CompletionOnceCallback callback) {
150 // Callers should instead call Upgrade() to get a WebSocketStream
151 // and call ReadFrames() on that.
152 NOTREACHED();
153 return OK;
154}
155
156void WebSocketHttp2HandshakeStream::Close(bool not_reusable) {
157 spdy_stream_request_.reset();
158 if (stream_) {
159 stream_ = nullptr;
160 stream_closed_ = true;
161 stream_error_ = ERR_CONNECTION_CLOSED;
162 }
163 stream_adapter_.reset();
164}
165
166bool WebSocketHttp2HandshakeStream::IsResponseBodyComplete() const {
167 return false;
168}
169
170bool WebSocketHttp2HandshakeStream::IsConnectionReused() const {
171 return true;
172}
173
174void WebSocketHttp2HandshakeStream::SetConnectionReused() {}
175
176bool WebSocketHttp2HandshakeStream::CanReuseConnection() const {
177 return false;
178}
179
180int64_t WebSocketHttp2HandshakeStream::GetTotalReceivedBytes() const {
181 return stream_ ? stream_->raw_received_bytes() : 0;
182}
183
184int64_t WebSocketHttp2HandshakeStream::GetTotalSentBytes() const {
185 return stream_ ? stream_->raw_sent_bytes() : 0;
186}
187
188bool WebSocketHttp2HandshakeStream::GetAlternativeService(
189 AlternativeService* alternative_service) const {
190 return false;
191}
192
193bool WebSocketHttp2HandshakeStream::GetLoadTimingInfo(
194 LoadTimingInfo* load_timing_info) const {
195 return stream_ && stream_->GetLoadTimingInfo(load_timing_info);
196}
197
198void WebSocketHttp2HandshakeStream::GetSSLInfo(SSLInfo* ssl_info) {
199 if (stream_)
200 stream_->GetSSLInfo(ssl_info);
201}
202
203void WebSocketHttp2HandshakeStream::GetSSLCertRequestInfo(
204 SSLCertRequestInfo* cert_request_info) {
205 // A multiplexed stream cannot request client certificates. Client
206 // authentication may only occur during the initial SSL handshake.
207 NOTREACHED();
208}
209
210bool WebSocketHttp2HandshakeStream::GetRemoteEndpoint(IPEndPoint* endpoint) {
211 return session_ && session_->GetRemoteEndpoint(endpoint);
212}
213
214void WebSocketHttp2HandshakeStream::PopulateNetErrorDetails(
215 NetErrorDetails* /*details*/) {
216 return;
217}
218
219Error WebSocketHttp2HandshakeStream::GetTokenBindingSignature(
220 crypto::ECPrivateKey* key,
221 TokenBindingType tb_type,
222 std::vector<uint8_t>* out) {
223 NOTREACHED();
224 return ERR_NOT_IMPLEMENTED;
225}
226
227void WebSocketHttp2HandshakeStream::Drain(HttpNetworkSession* session) {
228 Close(true /* not_reusable */);
229}
230
231void WebSocketHttp2HandshakeStream::SetPriority(RequestPriority priority) {
232 priority_ = priority;
233 if (stream_)
234 stream_->set_priority(priority_);
235}
236
237HttpStream* WebSocketHttp2HandshakeStream::RenewStreamForAuth() {
238 // Renewing the stream is not supported.
239 return nullptr;
240}
241
242std::unique_ptr<WebSocketStream> WebSocketHttp2HandshakeStream::Upgrade() {
243 DCHECK(extension_params_.get());
244
245 stream_adapter_->DetachDelegate();
246 std::unique_ptr<WebSocketStream> basic_stream =
247 std::make_unique<WebSocketBasicStream>(
248 std::move(stream_adapter_), nullptr, sub_protocol_, extensions_);
249
250 if (!extension_params_->deflate_enabled)
251 return basic_stream;
252
Bence Békyde0be312018-03-13 17:51:58253 RecordDeflateMode(
254 extension_params_->deflate_parameters.client_context_take_over_mode());
Bence Béky46bfbc12018-02-22 19:28:20255
256 return std::make_unique<WebSocketDeflateStream>(
257 std::move(basic_stream), extension_params_->deflate_parameters,
258 std::make_unique<WebSocketDeflatePredictorImpl>());
259}
260
261void WebSocketHttp2HandshakeStream::OnHeadersSent() {
262 base::ResetAndReturn(&callback_).Run(OK);
263}
264
265void WebSocketHttp2HandshakeStream::OnHeadersReceived(
266 const SpdyHeaderBlock& response_headers) {
267 DCHECK(!response_headers_complete_);
268 DCHECK(http_response_info_);
269
270 response_headers_complete_ = true;
271
272 const bool headers_valid =
273 SpdyHeadersToHttpResponse(response_headers, http_response_info_);
274 DCHECK(headers_valid);
275
276 http_response_info_->response_time = stream_->response_time();
277 // Do not store SSLInfo in the response here, HttpNetworkTransaction will take
278 // care of that part.
279 http_response_info_->was_alpn_negotiated = true;
280 http_response_info_->request_time = stream_->GetRequestTime();
281 http_response_info_->connection_info =
282 HttpResponseInfo::CONNECTION_INFO_HTTP2;
283 http_response_info_->alpn_negotiated_protocol =
284 HttpResponseInfo::ConnectionInfoToString(
285 http_response_info_->connection_info);
286 http_response_info_->vary_data.Init(*request_info_,
287 *http_response_info_->headers.get());
288
289 if (callback_)
290 base::ResetAndReturn(&callback_).Run(ValidateResponse());
291}
292
293void WebSocketHttp2HandshakeStream::OnClose(int status) {
294 DCHECK(stream_adapter_);
295 DCHECK_GT(ERR_IO_PENDING, status);
296
297 stream_closed_ = true;
298 stream_error_ = status;
299 stream_ = nullptr;
300
301 stream_adapter_.reset();
302
Bence Békyde0be312018-03-13 17:51:58303 // If response headers have already been received,
304 // then ValidateResponse() sets |result_|.
305 if (!response_headers_complete_)
306 result_ = HandshakeResult::HTTP2_FAILED;
307
Bence Béky46bfbc12018-02-22 19:28:20308 OnFailure(std::string("Stream closed with error: ") + ErrorToString(status));
309
310 if (callback_)
311 base::ResetAndReturn(&callback_).Run(status);
312}
313
314void WebSocketHttp2HandshakeStream::StartRequestCallback(int rv) {
315 DCHECK(callback_);
316 if (rv != OK) {
317 spdy_stream_request_.reset();
318 base::ResetAndReturn(&callback_).Run(rv);
319 return;
320 }
321 stream_ = spdy_stream_request_->ReleaseStream();
322 spdy_stream_request_.reset();
323 stream_adapter_ =
324 std::make_unique<WebSocketSpdyStreamAdapter>(stream_, this, net_log_);
325 rv = stream_->SendRequestHeaders(std::move(http2_request_headers_),
326 MORE_DATA_TO_SEND);
327 // SendRequestHeaders() always returns asynchronously,
328 // and instead of taking a callback, it calls OnHeadersSent().
329 DCHECK_EQ(ERR_IO_PENDING, rv);
330}
331
332int WebSocketHttp2HandshakeStream::ValidateResponse() {
333 DCHECK(http_response_info_);
334 const HttpResponseHeaders* headers = http_response_info_->headers.get();
335 const int response_code = headers->response_code();
336 switch (response_code) {
337 case HTTP_OK:
338 OnFinishOpeningHandshake();
339 return ValidateUpgradeResponse(headers);
340
341 // We need to pass these through for authentication to work.
342 case HTTP_UNAUTHORIZED:
343 case HTTP_PROXY_AUTHENTICATION_REQUIRED:
344 return OK;
345
346 // Other status codes are potentially risky (see the warnings in the
347 // WHATWG WebSocket API spec) and so are dropped by default.
348 default:
349 OnFailure(base::StringPrintf(
350 "Error during WebSocket handshake: Unexpected response code: %d",
351 headers->response_code()));
352 OnFinishOpeningHandshake();
Bence Békyde0be312018-03-13 17:51:58353 result_ = HandshakeResult::HTTP2_INVALID_STATUS;
Bence Béky46bfbc12018-02-22 19:28:20354 return ERR_INVALID_RESPONSE;
355 }
356}
357
358int WebSocketHttp2HandshakeStream::ValidateUpgradeResponse(
359 const HttpResponseHeaders* headers) {
360 extension_params_ = std::make_unique<WebSocketExtensionParams>();
361 std::string failure_message;
Bence Békyde0be312018-03-13 17:51:58362 if (!ValidateStatus(headers)) {
363 result_ = HandshakeResult::HTTP2_INVALID_STATUS;
364 } else if (!ValidateSubProtocol(headers, requested_sub_protocols_,
365 &sub_protocol_, &failure_message)) {
366 result_ = HandshakeResult::HTTP2_FAILED_SUBPROTO;
367 } else if (!ValidateExtensions(headers, &extensions_, &failure_message,
368 extension_params_.get())) {
369 result_ = HandshakeResult::HTTP2_FAILED_EXTENSIONS;
370 } else {
371 result_ = HandshakeResult::HTTP2_CONNECTED;
Bence Béky46bfbc12018-02-22 19:28:20372 return OK;
373 }
374 OnFailure("Error during WebSocket handshake: " + failure_message);
375 return ERR_INVALID_RESPONSE;
376}
377
378void WebSocketHttp2HandshakeStream::OnFinishOpeningHandshake() {
379 DCHECK(http_response_info_);
380 WebSocketDispatchOnFinishOpeningHandshake(
381 connect_delegate_, request_info_->url, http_response_info_->headers,
382 http_response_info_->response_time);
383}
384
385void WebSocketHttp2HandshakeStream::OnFailure(const std::string& message) {
386 stream_request_->OnFailure(message);
387}
388
389} // namespace net