1 // Copyright 2015 The Chromium Authors
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/http/bidirectional_stream.h"
6
7 #include <string>
8 #include <utility>
9
10 #include "base/functional/bind.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/metrics/histogram_macros.h"
14 #include "base/task/single_thread_task_runner.h"
15 #include "base/timer/timer.h"
16 #include "base/values.h"
17 #include "net/base/load_flags.h"
18 #include "net/base/net_errors.h"
19 #include "net/http/bidirectional_stream_request_info.h"
20 #include "net/http/http_network_session.h"
21 #include "net/http/http_response_headers.h"
22 #include "net/http/http_stream.h"
23 #include "net/log/net_log.h"
24 #include "net/log/net_log_capture_mode.h"
25 #include "net/log/net_log_event_type.h"
26 #include "net/log/net_log_source_type.h"
27 #include "net/log/net_log_values.h"
28 #include "net/spdy/spdy_http_utils.h"
29 #include "net/spdy/spdy_log_util.h"
30 #include "net/ssl/ssl_cert_request_info.h"
31 #include "net/ssl/ssl_config.h"
32 #include "net/third_party/quiche/src/quiche/spdy/core/http2_header_block.h"
33 #include "net/traffic_annotation/network_traffic_annotation.h"
34 #include "url/gurl.h"
35
36 namespace net {
37
38 namespace {
39
NetLogHeadersParams(const spdy::Http2HeaderBlock * headers,NetLogCaptureMode capture_mode)40 base::Value::Dict NetLogHeadersParams(const spdy::Http2HeaderBlock* headers,
41 NetLogCaptureMode capture_mode) {
42 base::Value::Dict dict;
43 dict.Set("headers", ElideHttp2HeaderBlockForNetLog(*headers, capture_mode));
44 return dict;
45 }
46
NetLogParams(const GURL & url,const std::string & method,const HttpRequestHeaders * headers,NetLogCaptureMode capture_mode)47 base::Value::Dict NetLogParams(const GURL& url,
48 const std::string& method,
49 const HttpRequestHeaders* headers,
50 NetLogCaptureMode capture_mode) {
51 base::Value::Dict dict;
52 dict.Set("url", url.possibly_invalid_spec());
53 dict.Set("method", method);
54 base::Value headers_param(
55 headers->NetLogParams(/*request_line=*/std::string(), capture_mode));
56 dict.Set("headers", std::move(headers_param));
57 return dict;
58 }
59
60 } // namespace
61
62 BidirectionalStream::Delegate::Delegate() = default;
63
64 BidirectionalStream::Delegate::~Delegate() = default;
65
BidirectionalStream(std::unique_ptr<BidirectionalStreamRequestInfo> request_info,HttpNetworkSession * session,bool send_request_headers_automatically,Delegate * delegate)66 BidirectionalStream::BidirectionalStream(
67 std::unique_ptr<BidirectionalStreamRequestInfo> request_info,
68 HttpNetworkSession* session,
69 bool send_request_headers_automatically,
70 Delegate* delegate)
71 : BidirectionalStream(std::move(request_info),
72 session,
73 send_request_headers_automatically,
74 delegate,
75 std::make_unique<base::OneShotTimer>()) {}
76
BidirectionalStream(std::unique_ptr<BidirectionalStreamRequestInfo> request_info,HttpNetworkSession * session,bool send_request_headers_automatically,Delegate * delegate,std::unique_ptr<base::OneShotTimer> timer)77 BidirectionalStream::BidirectionalStream(
78 std::unique_ptr<BidirectionalStreamRequestInfo> request_info,
79 HttpNetworkSession* session,
80 bool send_request_headers_automatically,
81 Delegate* delegate,
82 std::unique_ptr<base::OneShotTimer> timer)
83 : request_info_(std::move(request_info)),
84 net_log_(NetLogWithSource::Make(session->net_log(),
85 NetLogSourceType::BIDIRECTIONAL_STREAM)),
86 session_(session),
87 send_request_headers_automatically_(send_request_headers_automatically),
88 delegate_(delegate),
89 timer_(std::move(timer)) {
90 DCHECK(delegate_);
91 DCHECK(request_info_);
92
93 // Start time should be measured before connect.
94 load_timing_info_.request_start_time = base::Time::Now();
95 load_timing_info_.request_start = base::TimeTicks::Now();
96
97 if (net_log_.IsCapturing()) {
98 net_log_.BeginEvent(NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE,
99 [&](NetLogCaptureMode capture_mode) {
100 return NetLogParams(
101 request_info_->url, request_info_->method,
102 &request_info_->extra_headers, capture_mode);
103 });
104 }
105
106 if (!request_info_->url.SchemeIs(url::kHttpsScheme)) {
107 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
108 FROM_HERE,
109 base::BindOnce(&BidirectionalStream::NotifyFailed,
110 weak_factory_.GetWeakPtr(), ERR_DISALLOWED_URL_SCHEME));
111 return;
112 }
113
114 StartRequest(SSLConfig());
115 }
116
~BidirectionalStream()117 BidirectionalStream::~BidirectionalStream() {
118 if (net_log_.IsCapturing()) {
119 net_log_.EndEvent(NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE);
120 }
121 }
122
SendRequestHeaders()123 void BidirectionalStream::SendRequestHeaders() {
124 DCHECK(stream_impl_);
125 DCHECK(!request_headers_sent_);
126 DCHECK(!send_request_headers_automatically_);
127
128 stream_impl_->SendRequestHeaders();
129 }
130
ReadData(IOBuffer * buf,int buf_len)131 int BidirectionalStream::ReadData(IOBuffer* buf, int buf_len) {
132 DCHECK(stream_impl_);
133
134 int rv = stream_impl_->ReadData(buf, buf_len);
135 if (rv > 0) {
136 read_end_time_ = base::TimeTicks::Now();
137 net_log_.AddByteTransferEvent(
138 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED, rv, buf->data());
139 } else if (rv == ERR_IO_PENDING) {
140 read_buffer_ = buf;
141 // Bytes will be logged in OnDataRead().
142 }
143 if (net_log_.IsCapturing()) {
144 net_log_.AddEventWithIntParams(
145 NetLogEventType::BIDIRECTIONAL_STREAM_READ_DATA, "rv", rv);
146 }
147 return rv;
148 }
149
SendvData(const std::vector<scoped_refptr<IOBuffer>> & buffers,const std::vector<int> & lengths,bool end_stream)150 void BidirectionalStream::SendvData(
151 const std::vector<scoped_refptr<IOBuffer>>& buffers,
152 const std::vector<int>& lengths,
153 bool end_stream) {
154 DCHECK(stream_impl_);
155 DCHECK_EQ(buffers.size(), lengths.size());
156 DCHECK(write_buffer_list_.empty());
157 DCHECK(write_buffer_len_list_.empty());
158
159 if (net_log_.IsCapturing()) {
160 net_log_.AddEventWithIntParams(
161 NetLogEventType::BIDIRECTIONAL_STREAM_SENDV_DATA, "num_buffers",
162 buffers.size());
163 }
164 stream_impl_->SendvData(buffers, lengths, end_stream);
165 for (size_t i = 0; i < buffers.size(); ++i) {
166 write_buffer_list_.push_back(buffers[i]);
167 write_buffer_len_list_.push_back(lengths[i]);
168 }
169 }
170
GetProtocol() const171 NextProto BidirectionalStream::GetProtocol() const {
172 if (!stream_impl_)
173 return kProtoUnknown;
174
175 return stream_impl_->GetProtocol();
176 }
177
GetTotalReceivedBytes() const178 int64_t BidirectionalStream::GetTotalReceivedBytes() const {
179 if (!stream_impl_)
180 return 0;
181
182 return stream_impl_->GetTotalReceivedBytes();
183 }
184
GetTotalSentBytes() const185 int64_t BidirectionalStream::GetTotalSentBytes() const {
186 if (!stream_impl_)
187 return 0;
188
189 return stream_impl_->GetTotalSentBytes();
190 }
191
GetLoadTimingInfo(LoadTimingInfo * load_timing_info) const192 void BidirectionalStream::GetLoadTimingInfo(
193 LoadTimingInfo* load_timing_info) const {
194 *load_timing_info = load_timing_info_;
195 }
196
PopulateNetErrorDetails(NetErrorDetails * details)197 void BidirectionalStream::PopulateNetErrorDetails(NetErrorDetails* details) {
198 DCHECK(details);
199 if (stream_impl_)
200 stream_impl_->PopulateNetErrorDetails(details);
201 }
202
StartRequest(const SSLConfig & ssl_config)203 void BidirectionalStream::StartRequest(const SSLConfig& ssl_config) {
204 DCHECK(!stream_request_);
205 HttpRequestInfo http_request_info;
206 http_request_info.url = request_info_->url;
207 http_request_info.method = request_info_->method;
208 http_request_info.extra_headers = request_info_->extra_headers;
209 http_request_info.socket_tag = request_info_->socket_tag;
210 stream_request_ =
211 session_->http_stream_factory()->RequestBidirectionalStreamImpl(
212 http_request_info, request_info_->priority, ssl_config, this,
213 /* enable_ip_based_pooling = */ true,
214 /* enable_alternative_services = */ true, net_log_);
215 // Check that this call does not fail.
216 DCHECK(stream_request_);
217 // Check that HttpStreamFactory does not invoke OnBidirectionalStreamImplReady
218 // synchronously.
219 DCHECK(!stream_impl_);
220 }
221
OnStreamReady(bool request_headers_sent)222 void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
223 request_headers_sent_ = request_headers_sent;
224 if (net_log_.IsCapturing()) {
225 net_log_.AddEntryWithBoolParams(
226 NetLogEventType::BIDIRECTIONAL_STREAM_READY, NetLogEventPhase::NONE,
227 "request_headers_sent", request_headers_sent);
228 }
229 load_timing_info_.send_start = base::TimeTicks::Now();
230 load_timing_info_.send_end = load_timing_info_.send_start;
231 delegate_->OnStreamReady(request_headers_sent);
232 }
233
OnHeadersReceived(const spdy::Http2HeaderBlock & response_headers)234 void BidirectionalStream::OnHeadersReceived(
235 const spdy::Http2HeaderBlock& response_headers) {
236 HttpResponseInfo response_info;
237 if (SpdyHeadersToHttpResponse(response_headers, &response_info) != OK) {
238 DLOG(WARNING) << "Invalid headers";
239 NotifyFailed(ERR_FAILED);
240 return;
241 }
242 if (net_log_.IsCapturing()) {
243 net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_RECV_HEADERS,
244 [&](NetLogCaptureMode capture_mode) {
245 return NetLogHeadersParams(&response_headers,
246 capture_mode);
247 });
248 }
249 // Impl should only provide |connect_timing| and |socket_reused| info,
250 // so use a copy to get these information only.
251 LoadTimingInfo impl_load_timing_info;
252 bool has_load_timing =
253 stream_impl_->GetLoadTimingInfo(&impl_load_timing_info);
254 if (has_load_timing) {
255 load_timing_info_.connect_timing = impl_load_timing_info.connect_timing;
256 load_timing_info_.socket_reused = impl_load_timing_info.socket_reused;
257 }
258 load_timing_info_.receive_headers_end = base::TimeTicks::Now();
259 read_end_time_ = load_timing_info_.receive_headers_end;
260 session_->http_stream_factory()->ProcessAlternativeServices(
261 session_, net::NetworkAnonymizationKey(), response_info.headers.get(),
262 url::SchemeHostPort(request_info_->url));
263 delegate_->OnHeadersReceived(response_headers);
264 }
265
OnDataRead(int bytes_read)266 void BidirectionalStream::OnDataRead(int bytes_read) {
267 DCHECK(read_buffer_);
268
269 if (net_log_.IsCapturing()) {
270 net_log_.AddByteTransferEvent(
271 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED, bytes_read,
272 read_buffer_->data());
273 }
274 read_end_time_ = base::TimeTicks::Now();
275 read_buffer_ = nullptr;
276 delegate_->OnDataRead(bytes_read);
277 }
278
OnDataSent()279 void BidirectionalStream::OnDataSent() {
280 DCHECK(!write_buffer_list_.empty());
281 DCHECK_EQ(write_buffer_list_.size(), write_buffer_len_list_.size());
282
283 if (net_log_.IsCapturing()) {
284 if (write_buffer_list_.size() > 1) {
285 net_log_.BeginEvent(
286 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED, [&] {
287 return NetLogParamsWithInt("num_buffers_coalesced",
288 write_buffer_list_.size());
289 });
290 }
291 for (size_t i = 0; i < write_buffer_list_.size(); ++i) {
292 net_log_.AddByteTransferEvent(
293 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
294 write_buffer_len_list_[i], write_buffer_list_[i]->data());
295 }
296 if (write_buffer_list_.size() > 1) {
297 net_log_.EndEvent(
298 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED);
299 }
300 }
301 load_timing_info_.send_end = base::TimeTicks::Now();
302 write_buffer_list_.clear();
303 write_buffer_len_list_.clear();
304 delegate_->OnDataSent();
305 }
306
OnTrailersReceived(const spdy::Http2HeaderBlock & trailers)307 void BidirectionalStream::OnTrailersReceived(
308 const spdy::Http2HeaderBlock& trailers) {
309 if (net_log_.IsCapturing()) {
310 net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_RECV_TRAILERS,
311 [&](NetLogCaptureMode capture_mode) {
312 return NetLogHeadersParams(&trailers, capture_mode);
313 });
314 }
315 read_end_time_ = base::TimeTicks::Now();
316 delegate_->OnTrailersReceived(trailers);
317 }
318
OnFailed(int status)319 void BidirectionalStream::OnFailed(int status) {
320 if (net_log_.IsCapturing()) {
321 net_log_.AddEventWithIntParams(NetLogEventType::BIDIRECTIONAL_STREAM_FAILED,
322 "net_error", status);
323 }
324 NotifyFailed(status);
325 }
326
OnStreamReady(const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,std::unique_ptr<HttpStream> stream)327 void BidirectionalStream::OnStreamReady(const SSLConfig& used_ssl_config,
328 const ProxyInfo& used_proxy_info,
329 std::unique_ptr<HttpStream> stream) {
330 NOTREACHED();
331 }
332
OnBidirectionalStreamImplReady(const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,std::unique_ptr<BidirectionalStreamImpl> stream)333 void BidirectionalStream::OnBidirectionalStreamImplReady(
334 const SSLConfig& used_ssl_config,
335 const ProxyInfo& used_proxy_info,
336 std::unique_ptr<BidirectionalStreamImpl> stream) {
337 DCHECK(!stream_impl_);
338
339 net::NetworkTrafficAnnotationTag traffic_annotation =
340 net::DefineNetworkTrafficAnnotation("bidirectional_stream", R"(
341 semantics {
342 sender: "Bidirectional Stream"
343 description:
344 "Bidirectional stream is used to exchange data with a server on "
345 "behalf of an RPC API."
346 trigger:
347 "When an application makes an RPC to the server."
348 data:
349 "Any arbitrary data."
350 destination: OTHER
351 destination_other:
352 "Any destination that the application chooses."
353 }
354 policy {
355 cookies_allowed: NO
356 setting: "This feature is not used in Chrome."
357 policy_exception_justification:
358 "This feature is not used in Chrome."
359 }
360 )");
361
362 stream_request_.reset();
363 stream_impl_ = std::move(stream);
364 stream_impl_->Start(request_info_.get(), net_log_,
365 send_request_headers_automatically_, this,
366 std::move(timer_), traffic_annotation);
367 }
368
OnWebSocketHandshakeStreamReady(const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,std::unique_ptr<WebSocketHandshakeStreamBase> stream)369 void BidirectionalStream::OnWebSocketHandshakeStreamReady(
370 const SSLConfig& used_ssl_config,
371 const ProxyInfo& used_proxy_info,
372 std::unique_ptr<WebSocketHandshakeStreamBase> stream) {
373 NOTREACHED();
374 }
375
OnStreamFailed(int result,const NetErrorDetails & net_error_details,const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,ResolveErrorInfo resolve_error_info)376 void BidirectionalStream::OnStreamFailed(
377 int result,
378 const NetErrorDetails& net_error_details,
379 const SSLConfig& used_ssl_config,
380 const ProxyInfo& used_proxy_info,
381 ResolveErrorInfo resolve_error_info) {
382 DCHECK_LT(result, 0);
383 DCHECK_NE(result, ERR_IO_PENDING);
384 DCHECK(stream_request_);
385
386 NotifyFailed(result);
387 }
388
OnCertificateError(int result,const SSLConfig & used_ssl_config,const SSLInfo & ssl_info)389 void BidirectionalStream::OnCertificateError(int result,
390 const SSLConfig& used_ssl_config,
391 const SSLInfo& ssl_info) {
392 DCHECK_LT(result, 0);
393 DCHECK_NE(result, ERR_IO_PENDING);
394 DCHECK(stream_request_);
395
396 NotifyFailed(result);
397 }
398
OnNeedsProxyAuth(const HttpResponseInfo & proxy_response,const SSLConfig & used_ssl_config,const ProxyInfo & used_proxy_info,HttpAuthController * auth_controller)399 void BidirectionalStream::OnNeedsProxyAuth(
400 const HttpResponseInfo& proxy_response,
401 const SSLConfig& used_ssl_config,
402 const ProxyInfo& used_proxy_info,
403 HttpAuthController* auth_controller) {
404 DCHECK(stream_request_);
405
406 NotifyFailed(ERR_PROXY_AUTH_REQUESTED);
407 }
408
OnNeedsClientAuth(const SSLConfig & used_ssl_config,SSLCertRequestInfo * cert_info)409 void BidirectionalStream::OnNeedsClientAuth(const SSLConfig& used_ssl_config,
410 SSLCertRequestInfo* cert_info) {
411 DCHECK(stream_request_);
412
413 // BidirectionalStream doesn't support client auth. It ignores client auth
414 // requests with null client cert and key.
415 SSLConfig ssl_config = used_ssl_config;
416 session_->ssl_client_context()->SetClientCertificate(cert_info->host_and_port,
417 nullptr, nullptr);
418 stream_request_ = nullptr;
419 StartRequest(ssl_config);
420 }
421
OnQuicBroken()422 void BidirectionalStream::OnQuicBroken() {}
423
NotifyFailed(int error)424 void BidirectionalStream::NotifyFailed(int error) {
425 delegate_->OnFailed(error);
426 }
427
428 } // namespace net
429