blob: fdff1da37690cf11eb778b5c3e06fe2ef8740cac [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2015 The Chromium Authors
xunjieli11834f02015-12-22 04:27:082// 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
xunjielid4c21ab2016-04-28 22:44:477#include <string>
Bence Béky6d05ebd2017-05-16 00:09:018#include <utility>
danakj1fd259a02016-04-16 03:17:099
xunjieli11834f02015-12-22 04:27:0810#include "base/bind.h"
11#include "base/location.h"
12#include "base/logging.h"
xunjielid58621f2016-08-12 18:33:0013#include "base/metrics/histogram_macros.h"
Sean Maher5b9af51f2022-11-21 15:32:4714#include "base/task/single_thread_task_runner.h"
xunjieli11834f02015-12-22 04:27:0815#include "base/timer/timer.h"
xunjielid4c21ab2016-04-28 22:44:4716#include "base/values.h"
xunjieli11834f02015-12-22 04:27:0817#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"
xunjielib3a648e2016-03-22 03:39:5121#include "net/http/http_response_headers.h"
xunjieli11834f02015-12-22 04:27:0822#include "net/http/http_stream.h"
mikecironef22f9812016-10-04 03:40:1923#include "net/log/net_log.h"
xunjielid4c21ab2016-04-28 22:44:4724#include "net/log/net_log_capture_mode.h"
mikecirone8b85c432016-09-08 19:11:0025#include "net/log/net_log_event_type.h"
26#include "net/log/net_log_source_type.h"
Eric Roman06bd9742019-07-13 15:19:1327#include "net/log/net_log_values.h"
Bence Béky94658bf2018-05-11 19:22:5828#include "net/spdy/spdy_http_utils.h"
29#include "net/spdy/spdy_log_util.h"
xunjieli11834f02015-12-22 04:27:0830#include "net/ssl/ssl_cert_request_info.h"
31#include "net/ssl/ssl_config.h"
Bence Békyb7096dc2022-08-02 14:20:4032#include "net/third_party/quiche/src/quiche/spdy/core/http2_header_block.h"
Ramin Halavati3c96c6d2018-03-11 13:29:4433#include "net/traffic_annotation/network_traffic_annotation.h"
xunjieli11834f02015-12-22 04:27:0834#include "url/gurl.h"
35
36namespace net {
37
xunjielid4c21ab2016-04-28 22:44:4738namespace {
39
Bence Béky4c325e52020-10-22 20:48:0140base::Value NetLogHeadersParams(const spdy::Http2HeaderBlock* headers,
Eric Roman06bd9742019-07-13 15:19:1341 NetLogCaptureMode capture_mode) {
Matt Menkec9a0b382022-05-27 22:31:4742 base::Value::Dict dict;
43 dict.Set("headers", ElideHttp2HeaderBlockForNetLog(*headers, capture_mode));
44 return base::Value(std::move(dict));
xunjielid4c21ab2016-04-28 22:44:4745}
46
Eric Roman06bd9742019-07-13 15:19:1347base::Value NetLogParams(const GURL& url,
48 const std::string& method,
49 const HttpRequestHeaders* headers,
50 NetLogCaptureMode capture_mode) {
Matt Menkec9a0b382022-05-27 22:31:4751 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 base::Value(std::move(dict));
xunjielid4c21ab2016-04-28 22:44:4758}
59
60} // namespace
61
Chris Watkins7a41d3552017-12-01 02:13:2762BidirectionalStream::Delegate::Delegate() = default;
xunjieli11834f02015-12-22 04:27:0863
Chris Watkins7a41d3552017-12-01 02:13:2764BidirectionalStream::Delegate::~Delegate() = default;
xunjieli11834f02015-12-22 04:27:0865
66BidirectionalStream::BidirectionalStream(
danakj1fd259a02016-04-16 03:17:0967 std::unique_ptr<BidirectionalStreamRequestInfo> request_info,
xunjieli11834f02015-12-22 04:27:0868 HttpNetworkSession* session,
xunjielibcb0f86e2016-06-03 00:49:2969 bool send_request_headers_automatically,
xunjieli11834f02015-12-22 04:27:0870 Delegate* delegate)
71 : BidirectionalStream(std::move(request_info),
72 session,
xunjielibcb0f86e2016-06-03 00:49:2973 send_request_headers_automatically,
xunjieli11834f02015-12-22 04:27:0874 delegate,
tzik08d8d6e2018-07-09 04:11:4775 std::make_unique<base::OneShotTimer>()) {}
xunjieli11834f02015-12-22 04:27:0876
77BidirectionalStream::BidirectionalStream(
danakj1fd259a02016-04-16 03:17:0978 std::unique_ptr<BidirectionalStreamRequestInfo> request_info,
xunjieli11834f02015-12-22 04:27:0879 HttpNetworkSession* session,
xunjielibcb0f86e2016-06-03 00:49:2980 bool send_request_headers_automatically,
xunjieli11834f02015-12-22 04:27:0881 Delegate* delegate,
tzik08d8d6e2018-07-09 04:11:4782 std::unique_ptr<base::OneShotTimer> timer)
xunjieli11834f02015-12-22 04:27:0883 : request_info_(std::move(request_info)),
tfarina42834112016-09-22 13:38:2084 net_log_(NetLogWithSource::Make(session->net_log(),
85 NetLogSourceType::BIDIRECTIONAL_STREAM)),
xunjielib3a648e2016-03-22 03:39:5186 session_(session),
xunjielibcb0f86e2016-06-03 00:49:2987 send_request_headers_automatically_(send_request_headers_automatically),
xunjieli11834f02015-12-22 04:27:0888 delegate_(delegate),
Jeremy Romand54000b22019-07-08 18:40:1689 timer_(std::move(timer)) {
xunjieli11834f02015-12-22 04:27:0890 DCHECK(delegate_);
91 DCHECK(request_info_);
92
xunjieli369d0922016-09-23 18:45:0693 // 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
xunjielif88028e2016-06-01 19:27:1497 if (net_log_.IsCapturing()) {
Eric Roman06bd9742019-07-13 15:19:1398 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 });
xunjielif88028e2016-06-01 19:27:14104 }
105
xunjieli11834f02015-12-22 04:27:08106 if (!request_info_->url.SchemeIs(url::kHttpsScheme)) {
Sean Maher5b9af51f2022-11-21 15:32:47107 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
xunjieli11834f02015-12-22 04:27:08108 FROM_HERE,
kylecharf4fe5172019-02-15 18:53:49109 base::BindOnce(&BidirectionalStream::NotifyFailed,
110 weak_factory_.GetWeakPtr(), ERR_DISALLOWED_URL_SCHEME));
xunjieli11834f02015-12-22 04:27:08111 return;
112 }
113
David Benjamin830c58c32022-01-19 22:23:23114 StartRequest(SSLConfig());
xunjieli11834f02015-12-22 04:27:08115}
116
117BidirectionalStream::~BidirectionalStream() {
xunjielid4c21ab2016-04-28 22:44:47118 if (net_log_.IsCapturing()) {
mikecirone8b85c432016-09-08 19:11:00119 net_log_.EndEvent(NetLogEventType::BIDIRECTIONAL_STREAM_ALIVE);
xunjielid4c21ab2016-04-28 22:44:47120 }
xunjieli11834f02015-12-22 04:27:08121}
122
xunjielibcb0f86e2016-06-03 00:49:29123void BidirectionalStream::SendRequestHeaders() {
124 DCHECK(stream_impl_);
125 DCHECK(!request_headers_sent_);
126 DCHECK(!send_request_headers_automatically_);
127
128 stream_impl_->SendRequestHeaders();
129}
130
xunjieli11834f02015-12-22 04:27:08131int BidirectionalStream::ReadData(IOBuffer* buf, int buf_len) {
xunjieli5749218c2016-03-22 16:43:06132 DCHECK(stream_impl_);
xunjieli11834f02015-12-22 04:27:08133
xunjielibe07785e2016-04-14 21:15:29134 int rv = stream_impl_->ReadData(buf, buf_len);
135 if (rv > 0) {
xunjielid58621f2016-08-12 18:33:00136 read_end_time_ = base::TimeTicks::Now();
xunjielibe07785e2016-04-14 21:15:29137 net_log_.AddByteTransferEvent(
mikecirone8b85c432016-09-08 19:11:00138 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED, rv, buf->data());
xunjielibe07785e2016-04-14 21:15:29139 } else if (rv == ERR_IO_PENDING) {
140 read_buffer_ = buf;
141 // Bytes will be logged in OnDataRead().
142 }
xunjielie1780482016-07-01 21:22:54143 if (net_log_.IsCapturing()) {
Eric Roman06bd9742019-07-13 15:19:13144 net_log_.AddEventWithIntParams(
145 NetLogEventType::BIDIRECTIONAL_STREAM_READ_DATA, "rv", rv);
xunjielie1780482016-07-01 21:22:54146 }
xunjielibe07785e2016-04-14 21:15:29147 return rv;
xunjieli11834f02015-12-22 04:27:08148}
149
xunjieli2328a2682016-05-16 19:38:25150void BidirectionalStream::SendvData(
151 const std::vector<scoped_refptr<IOBuffer>>& buffers,
152 const std::vector<int>& lengths,
153 bool end_stream) {
xunjieli07a42ce2016-04-26 20:05:31154 DCHECK(stream_impl_);
155 DCHECK_EQ(buffers.size(), lengths.size());
156 DCHECK(write_buffer_list_.empty());
157 DCHECK(write_buffer_len_list_.empty());
158
xunjielie1780482016-07-01 21:22:54159 if (net_log_.IsCapturing()) {
Eric Roman06bd9742019-07-13 15:19:13160 net_log_.AddEventWithIntParams(
161 NetLogEventType::BIDIRECTIONAL_STREAM_SENDV_DATA, "num_buffers",
162 buffers.size());
xunjielie1780482016-07-01 21:22:54163 }
xunjieli07a42ce2016-04-26 20:05:31164 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 }
xunjieli11834f02015-12-22 04:27:08169}
170
xunjieli11834f02015-12-22 04:27:08171NextProto BidirectionalStream::GetProtocol() const {
xunjieli5749218c2016-03-22 16:43:06172 if (!stream_impl_)
xunjieli11834f02015-12-22 04:27:08173 return kProtoUnknown;
174
xunjieli5749218c2016-03-22 16:43:06175 return stream_impl_->GetProtocol();
xunjieli11834f02015-12-22 04:27:08176}
177
178int64_t BidirectionalStream::GetTotalReceivedBytes() const {
xunjieli5749218c2016-03-22 16:43:06179 if (!stream_impl_)
xunjieli11834f02015-12-22 04:27:08180 return 0;
181
xunjieli5749218c2016-03-22 16:43:06182 return stream_impl_->GetTotalReceivedBytes();
xunjieli11834f02015-12-22 04:27:08183}
184
185int64_t BidirectionalStream::GetTotalSentBytes() const {
xunjieli5749218c2016-03-22 16:43:06186 if (!stream_impl_)
xunjieli11834f02015-12-22 04:27:08187 return 0;
188
xunjieli5749218c2016-03-22 16:43:06189 return stream_impl_->GetTotalSentBytes();
xunjieli11834f02015-12-22 04:27:08190}
191
xunjieli369d0922016-09-23 18:45:06192void BidirectionalStream::GetLoadTimingInfo(
193 LoadTimingInfo* load_timing_info) const {
194 *load_timing_info = load_timing_info_;
195}
196
Brad Lassey5f488db42017-07-19 00:30:46197void BidirectionalStream::PopulateNetErrorDetails(NetErrorDetails* details) {
198 DCHECK(details);
199 if (stream_impl_)
200 stream_impl_->PopulateNetErrorDetails(details);
201}
202
Helen Li43e3bee2018-03-21 16:57:11203void 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, ssl_config,
213 this,
214 /* enable_ip_based_pooling = */ true,
215 /* enable_alternative_services = */ true, net_log_);
216 // Check that this call does not fail.
217 DCHECK(stream_request_);
218 // Check that HttpStreamFactory does not invoke OnBidirectionalStreamImplReady
219 // synchronously.
220 DCHECK(!stream_impl_);
221}
222
xunjielibcb0f86e2016-06-03 00:49:29223void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
224 request_headers_sent_ = request_headers_sent;
xunjieli2704f5d2016-06-10 16:02:23225 if (net_log_.IsCapturing()) {
Eric Roman06bd9742019-07-13 15:19:13226 net_log_.AddEntryWithBoolParams(
227 NetLogEventType::BIDIRECTIONAL_STREAM_READY, NetLogEventPhase::NONE,
228 "request_headers_sent", request_headers_sent);
xunjieli2704f5d2016-06-10 16:02:23229 }
xunjieli369d0922016-09-23 18:45:06230 load_timing_info_.send_start = base::TimeTicks::Now();
231 load_timing_info_.send_end = load_timing_info_.send_start;
xunjielibcb0f86e2016-06-03 00:49:29232 delegate_->OnStreamReady(request_headers_sent);
xunjieli11834f02015-12-22 04:27:08233}
234
235void BidirectionalStream::OnHeadersReceived(
Bence Béky4c325e52020-10-22 20:48:01236 const spdy::Http2HeaderBlock& response_headers) {
xunjielib3a648e2016-03-22 03:39:51237 HttpResponseInfo response_info;
Kenichi Ishibashie3708df2022-02-26 00:55:40238 if (SpdyHeadersToHttpResponse(response_headers, &response_info) != OK) {
xunjielib3a648e2016-03-22 03:39:51239 DLOG(WARNING) << "Invalid headers";
xunjieli3b6ac702016-06-06 21:36:28240 NotifyFailed(ERR_FAILED);
xunjielib3a648e2016-03-22 03:39:51241 return;
242 }
xunjielid4c21ab2016-04-28 22:44:47243 if (net_log_.IsCapturing()) {
mikecirone8b85c432016-09-08 19:11:00244 net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_RECV_HEADERS,
Eric Roman06bd9742019-07-13 15:19:13245 [&](NetLogCaptureMode capture_mode) {
246 return NetLogHeadersParams(&response_headers,
247 capture_mode);
248 });
xunjielid4c21ab2016-04-28 22:44:47249 }
xunjieli369d0922016-09-23 18:45:06250 // Impl should only provide |connect_timing| and |socket_reused| info,
251 // so use a copy to get these information only.
252 LoadTimingInfo impl_load_timing_info;
253 bool has_load_timing =
254 stream_impl_->GetLoadTimingInfo(&impl_load_timing_info);
255 if (has_load_timing) {
256 load_timing_info_.connect_timing = impl_load_timing_info.connect_timing;
257 load_timing_info_.socket_reused = impl_load_timing_info.socket_reused;
258 }
259 load_timing_info_.receive_headers_end = base::TimeTicks::Now();
260 read_end_time_ = load_timing_info_.receive_headers_end;
xunjielib3a648e2016-03-22 03:39:51261 session_->http_stream_factory()->ProcessAlternativeServices(
Brianna Goldsteinabb3aac2022-10-07 12:06:00262 session_, net::NetworkAnonymizationKey(), response_info.headers.get(),
zhongyi3d4a55e72016-04-22 20:36:46263 url::SchemeHostPort(request_info_->url));
xunjieli11834f02015-12-22 04:27:08264 delegate_->OnHeadersReceived(response_headers);
265}
266
267void BidirectionalStream::OnDataRead(int bytes_read) {
xunjielibe07785e2016-04-14 21:15:29268 DCHECK(read_buffer_);
269
xunjielid4c21ab2016-04-28 22:44:47270 if (net_log_.IsCapturing()) {
271 net_log_.AddByteTransferEvent(
mikecirone8b85c432016-09-08 19:11:00272 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_RECEIVED, bytes_read,
xunjielid4c21ab2016-04-28 22:44:47273 read_buffer_->data());
274 }
xunjielid58621f2016-08-12 18:33:00275 read_end_time_ = base::TimeTicks::Now();
xunjielibe07785e2016-04-14 21:15:29276 read_buffer_ = nullptr;
xunjieli11834f02015-12-22 04:27:08277 delegate_->OnDataRead(bytes_read);
278}
279
280void BidirectionalStream::OnDataSent() {
xunjieli07a42ce2016-04-26 20:05:31281 DCHECK(!write_buffer_list_.empty());
282 DCHECK_EQ(write_buffer_list_.size(), write_buffer_len_list_.size());
xunjielibe07785e2016-04-14 21:15:29283
xunjielid4c21ab2016-04-28 22:44:47284 if (net_log_.IsCapturing()) {
xunjieli2704f5d2016-06-10 16:02:23285 if (write_buffer_list_.size() > 1) {
286 net_log_.BeginEvent(
Eric Roman06bd9742019-07-13 15:19:13287 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED, [&] {
288 return NetLogParamsWithInt("num_buffers_coalesced",
289 write_buffer_list_.size());
290 });
xunjieli2704f5d2016-06-10 16:02:23291 }
xunjielid4c21ab2016-04-28 22:44:47292 for (size_t i = 0; i < write_buffer_list_.size(); ++i) {
293 net_log_.AddByteTransferEvent(
mikecirone8b85c432016-09-08 19:11:00294 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT,
xunjielid4c21ab2016-04-28 22:44:47295 write_buffer_len_list_[i], write_buffer_list_[i]->data());
296 }
xunjieli2704f5d2016-06-10 16:02:23297 if (write_buffer_list_.size() > 1) {
mikecirone8b85c432016-09-08 19:11:00298 net_log_.EndEvent(
299 NetLogEventType::BIDIRECTIONAL_STREAM_BYTES_SENT_COALESCED);
xunjieli2704f5d2016-06-10 16:02:23300 }
xunjieli07a42ce2016-04-26 20:05:31301 }
xunjieli369d0922016-09-23 18:45:06302 load_timing_info_.send_end = base::TimeTicks::Now();
xunjieli07a42ce2016-04-26 20:05:31303 write_buffer_list_.clear();
304 write_buffer_len_list_.clear();
xunjieli11834f02015-12-22 04:27:08305 delegate_->OnDataSent();
306}
307
Ryan Hamilton0239aac2018-05-19 00:03:13308void BidirectionalStream::OnTrailersReceived(
Bence Béky4c325e52020-10-22 20:48:01309 const spdy::Http2HeaderBlock& trailers) {
xunjielid4c21ab2016-04-28 22:44:47310 if (net_log_.IsCapturing()) {
mikecirone8b85c432016-09-08 19:11:00311 net_log_.AddEvent(NetLogEventType::BIDIRECTIONAL_STREAM_RECV_TRAILERS,
Eric Roman06bd9742019-07-13 15:19:13312 [&](NetLogCaptureMode capture_mode) {
313 return NetLogHeadersParams(&trailers, capture_mode);
314 });
xunjielid4c21ab2016-04-28 22:44:47315 }
xunjielid58621f2016-08-12 18:33:00316 read_end_time_ = base::TimeTicks::Now();
xunjieli11834f02015-12-22 04:27:08317 delegate_->OnTrailersReceived(trailers);
318}
319
320void BidirectionalStream::OnFailed(int status) {
xunjieli2704f5d2016-06-10 16:02:23321 if (net_log_.IsCapturing()) {
Eric Roman06bd9742019-07-13 15:19:13322 net_log_.AddEventWithIntParams(NetLogEventType::BIDIRECTIONAL_STREAM_FAILED,
323 "net_error", status);
xunjieli2704f5d2016-06-10 16:02:23324 }
xunjieli3b6ac702016-06-06 21:36:28325 NotifyFailed(status);
xunjieli11834f02015-12-22 04:27:08326}
327
328void BidirectionalStream::OnStreamReady(const SSLConfig& used_ssl_config,
329 const ProxyInfo& used_proxy_info,
bnc5029f4632017-06-08 16:19:00330 std::unique_ptr<HttpStream> stream) {
xunjieli11834f02015-12-22 04:27:08331 NOTREACHED();
332}
333
xunjieli5749218c2016-03-22 16:43:06334void BidirectionalStream::OnBidirectionalStreamImplReady(
xunjieli11834f02015-12-22 04:27:08335 const SSLConfig& used_ssl_config,
336 const ProxyInfo& used_proxy_info,
bnc5029f4632017-06-08 16:19:00337 std::unique_ptr<BidirectionalStreamImpl> stream) {
xunjieli5749218c2016-03-22 16:43:06338 DCHECK(!stream_impl_);
xunjieli11834f02015-12-22 04:27:08339
Ramin Halavati3c96c6d2018-03-11 13:29:44340 net::NetworkTrafficAnnotationTag traffic_annotation =
341 net::DefineNetworkTrafficAnnotation("bidirectional_stream", R"(
342 semantics {
343 sender: "Bidirectional Stream"
344 description:
345 "Bidirectional stream is used to exchange data with a server on "
346 "behalf of an RPC API."
347 trigger:
348 "When an application makes an RPC to the server."
349 data:
350 "Any arbitrary data."
351 destination: OTHER
352 destination_other:
353 "Any destination that the application chooses."
354 }
355 policy {
356 cookies_allowed: NO
357 setting: "This feature is not used in Chrome."
358 policy_exception_justification:
359 "This feature is not used in Chrome."
360 }
361 )");
362
xunjieli11834f02015-12-22 04:27:08363 stream_request_.reset();
bnc5029f4632017-06-08 16:19:00364 stream_impl_ = std::move(stream);
xunjielibcb0f86e2016-06-03 00:49:29365 stream_impl_->Start(request_info_.get(), net_log_,
366 send_request_headers_automatically_, this,
Ramin Halavati3c96c6d2018-03-11 13:29:44367 std::move(timer_), traffic_annotation);
xunjieli11834f02015-12-22 04:27:08368}
369
370void BidirectionalStream::OnWebSocketHandshakeStreamReady(
371 const SSLConfig& used_ssl_config,
372 const ProxyInfo& used_proxy_info,
bnc5029f4632017-06-08 16:19:00373 std::unique_ptr<WebSocketHandshakeStreamBase> stream) {
xunjieli11834f02015-12-22 04:27:08374 NOTREACHED();
375}
376
Ryan Hamilton75f197262017-08-17 14:00:07377void BidirectionalStream::OnStreamFailed(
378 int result,
379 const NetErrorDetails& net_error_details,
Wojciech Dzierżanowskiabdeeaf2019-04-01 20:16:22380 const SSLConfig& used_ssl_config,
dalyk6d7a8c52019-12-18 21:43:01381 const ProxyInfo& used_proxy_info,
382 ResolveErrorInfo resolve_error_info) {
xunjieli11834f02015-12-22 04:27:08383 DCHECK_LT(result, 0);
384 DCHECK_NE(result, ERR_IO_PENDING);
385 DCHECK(stream_request_);
386
xunjieli3b6ac702016-06-06 21:36:28387 NotifyFailed(result);
xunjieli11834f02015-12-22 04:27:08388}
389
390void BidirectionalStream::OnCertificateError(int result,
391 const SSLConfig& used_ssl_config,
392 const SSLInfo& ssl_info) {
393 DCHECK_LT(result, 0);
394 DCHECK_NE(result, ERR_IO_PENDING);
395 DCHECK(stream_request_);
396
xunjieli3b6ac702016-06-06 21:36:28397 NotifyFailed(result);
xunjieli11834f02015-12-22 04:27:08398}
399
400void BidirectionalStream::OnNeedsProxyAuth(
401 const HttpResponseInfo& proxy_response,
402 const SSLConfig& used_ssl_config,
403 const ProxyInfo& used_proxy_info,
404 HttpAuthController* auth_controller) {
405 DCHECK(stream_request_);
406
xunjieli3b6ac702016-06-06 21:36:28407 NotifyFailed(ERR_PROXY_AUTH_REQUESTED);
xunjieli11834f02015-12-22 04:27:08408}
409
410void BidirectionalStream::OnNeedsClientAuth(const SSLConfig& used_ssl_config,
411 SSLCertRequestInfo* cert_info) {
412 DCHECK(stream_request_);
413
Helen Li43e3bee2018-03-21 16:57:11414 // BidirectionalStream doesn't support client auth. It ignores client auth
415 // requests with null client cert and key.
416 SSLConfig ssl_config = used_ssl_config;
David Benjaminbac8dff2019-08-07 01:30:41417 session_->ssl_client_context()->SetClientCertificate(cert_info->host_and_port,
418 nullptr, nullptr);
Helen Li43e3bee2018-03-21 16:57:11419 stream_request_ = nullptr;
420 StartRequest(ssl_config);
xunjieli11834f02015-12-22 04:27:08421}
422
xunjieli11834f02015-12-22 04:27:08423void BidirectionalStream::OnQuicBroken() {}
424
xunjieli3b6ac702016-06-06 21:36:28425void BidirectionalStream::NotifyFailed(int error) {
426 delegate_->OnFailed(error);
427}
428
xunjieli11834f02015-12-22 04:27:08429} // namespace net