blob: defabbf76db4d861d1e3d602969c514bd33e24bd [file] [log] [blame]
mef06eab3e82016-04-14 22:45:491// Copyright 2016 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
gcasto67ace932016-11-10 21:44:495#include "components/grpc_support/bidirectional_stream.h"
mef06eab3e82016-04-14 22:45:496
dchengfe3745e6242016-04-21 23:49:587#include <memory>
mef06eab3e82016-04-14 22:45:498#include <string>
Misha Efimov9983c6bb2018-01-30 23:10:399#include <utility>
mef06eab3e82016-04-14 22:45:4910#include <vector>
11
12#include "base/bind.h"
13#include "base/location.h"
14#include "base/logging.h"
15#include "base/memory/ref_counted.h"
Lei Zhang52637ed2019-02-20 01:38:3716#include "base/single_thread_task_runner.h"
mef06eab3e82016-04-14 22:45:4917#include "base/strings/string_number_conversions.h"
Matt Menked732ea42019-03-08 12:05:0018#include "net/base/http_user_agent_settings.h"
mef06eab3e82016-04-14 22:45:4919#include "net/base/io_buffer.h"
20#include "net/base/net_errors.h"
21#include "net/base/request_priority.h"
22#include "net/http/bidirectional_stream.h"
23#include "net/http/bidirectional_stream_request_info.h"
24#include "net/http/http_network_session.h"
25#include "net/http/http_response_headers.h"
26#include "net/http/http_status_code.h"
27#include "net/http/http_transaction_factory.h"
28#include "net/http/http_util.h"
mef06eab3e82016-04-14 22:45:4929#include "net/ssl/ssl_info.h"
Victor Vasiliev27cc7712019-01-24 11:50:1430#include "net/third_party/quiche/src/spdy/core/spdy_header_block.h"
mef06eab3e82016-04-14 22:45:4931#include "net/url_request/url_request_context.h"
gcasto67ace932016-11-10 21:44:4932#include "net/url_request/url_request_context_getter.h"
mef06eab3e82016-04-14 22:45:4933#include "url/gurl.h"
34
gcasto67ace932016-11-10 21:44:4935namespace grpc_support {
mef06eab3e82016-04-14 22:45:4936
gcasto67ace932016-11-10 21:44:4937BidirectionalStream::WriteBuffers::WriteBuffers() {}
mef62d0ba2a2016-06-15 21:03:0238
gcasto67ace932016-11-10 21:44:4939BidirectionalStream::WriteBuffers::~WriteBuffers() {}
mef62d0ba2a2016-06-15 21:03:0240
gcasto67ace932016-11-10 21:44:4941void BidirectionalStream::WriteBuffers::Clear() {
mef62d0ba2a2016-06-15 21:03:0242 write_buffer_list.clear();
43 write_buffer_len_list.clear();
44}
45
gcasto67ace932016-11-10 21:44:4946void BidirectionalStream::WriteBuffers::AppendBuffer(
mef62d0ba2a2016-06-15 21:03:0247 const scoped_refptr<net::IOBuffer>& buffer,
48 int buffer_size) {
49 write_buffer_list.push_back(buffer);
50 write_buffer_len_list.push_back(buffer_size);
51}
52
gcasto67ace932016-11-10 21:44:4953void BidirectionalStream::WriteBuffers::MoveTo(WriteBuffers* target) {
mef62d0ba2a2016-06-15 21:03:0254 std::move(write_buffer_list.begin(), write_buffer_list.end(),
55 std::back_inserter(target->write_buffer_list));
56 std::move(write_buffer_len_list.begin(), write_buffer_len_list.end(),
57 std::back_inserter(target->write_buffer_len_list));
58 Clear();
59}
60
gcasto67ace932016-11-10 21:44:4961bool BidirectionalStream::WriteBuffers::Empty() const {
mef62d0ba2a2016-06-15 21:03:0262 return write_buffer_list.empty();
63}
64
gcasto67ace932016-11-10 21:44:4965BidirectionalStream::BidirectionalStream(
66 net::URLRequestContextGetter* request_context_getter,
mef06eab3e82016-04-14 22:45:4967 Delegate* delegate)
68 : read_state_(NOT_STARTED),
69 write_state_(NOT_STARTED),
70 write_end_of_stream_(false),
mef62d0ba2a2016-06-15 21:03:0271 request_headers_sent_(false),
72 disable_auto_flush_(false),
73 delay_headers_until_flush_(false),
gcasto67ace932016-11-10 21:44:4974 request_context_getter_(request_context_getter),
mef62d0ba2a2016-06-15 21:03:0275 pending_write_data_(new WriteBuffers()),
76 flushing_write_data_(new WriteBuffers()),
77 sending_write_data_(new WriteBuffers()),
Jeremy Roman5c341f6d2019-07-15 15:56:1078 delegate_(delegate) {
mefce9fb502016-09-27 19:45:5679 weak_this_ = weak_factory_.GetWeakPtr();
80}
mef06eab3e82016-04-14 22:45:4981
gcasto67ace932016-11-10 21:44:4982BidirectionalStream::~BidirectionalStream() {
83 DCHECK(IsOnNetworkThread());
mef06eab3e82016-04-14 22:45:4984}
85
gcasto67ace932016-11-10 21:44:4986int BidirectionalStream::Start(const char* url,
87 int priority,
88 const char* method,
89 const net::HttpRequestHeaders& headers,
90 bool end_of_stream) {
mef06eab3e82016-04-14 22:45:4991 // Prepare request info here to be able to return the error.
dchengfe3745e6242016-04-21 23:49:5892 std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info(
mef06eab3e82016-04-14 22:45:4993 new net::BidirectionalStreamRequestInfo());
94 request_info->url = GURL(url);
95 request_info->priority = static_cast<net::RequestPriority>(priority);
96 // Http method is a token, just as header name.
97 request_info->method = method;
98 if (!net::HttpUtil::IsValidHeaderName(request_info->method))
99 return -1;
100 request_info->extra_headers.CopyFrom(headers);
101 request_info->end_stream_on_headers = end_of_stream;
102 write_end_of_stream_ = end_of_stream;
gcasto67ace932016-11-10 21:44:49103 PostToNetworkThread(FROM_HERE,
Misha Efimov9983c6bb2018-01-30 23:10:39104 base::BindOnce(&BidirectionalStream::StartOnNetworkThread,
Claudio DeSouza591a9972018-02-21 17:27:16105 weak_this_, std::move(request_info)));
mef06eab3e82016-04-14 22:45:49106 return 0;
107}
108
gcasto67ace932016-11-10 21:44:49109bool BidirectionalStream::ReadData(char* buffer, int capacity) {
mef06eab3e82016-04-14 22:45:49110 if (!buffer)
111 return false;
Victor Costan282536d2018-09-03 22:31:31112 scoped_refptr<net::WrappedIOBuffer> read_buffer =
113 base::MakeRefCounted<net::WrappedIOBuffer>(buffer);
mef06eab3e82016-04-14 22:45:49114
Misha Efimov9983c6bb2018-01-30 23:10:39115 PostToNetworkThread(
116 FROM_HERE, base::BindOnce(&BidirectionalStream::ReadDataOnNetworkThread,
Misha Efimova7fc3442019-10-08 17:11:05117 weak_this_, std::move(read_buffer), capacity));
mef06eab3e82016-04-14 22:45:49118 return true;
119}
120
gcasto67ace932016-11-10 21:44:49121bool BidirectionalStream::WriteData(const char* buffer,
122 int count,
123 bool end_of_stream) {
mef06eab3e82016-04-14 22:45:49124 if (!buffer)
125 return false;
126
Victor Costan282536d2018-09-03 22:31:31127 scoped_refptr<net::WrappedIOBuffer> write_buffer =
128 base::MakeRefCounted<net::WrappedIOBuffer>(buffer);
mef06eab3e82016-04-14 22:45:49129
gcasto67ace932016-11-10 21:44:49130 PostToNetworkThread(
Misha Efimov9983c6bb2018-01-30 23:10:39131 FROM_HERE,
132 base::BindOnce(&BidirectionalStream::WriteDataOnNetworkThread, weak_this_,
Misha Efimova7fc3442019-10-08 17:11:05133 std::move(write_buffer), count, end_of_stream));
134
mef06eab3e82016-04-14 22:45:49135 return true;
136}
137
gcasto67ace932016-11-10 21:44:49138void BidirectionalStream::Flush() {
139 PostToNetworkThread(
mefce9fb502016-09-27 19:45:56140 FROM_HERE,
Misha Efimov9983c6bb2018-01-30 23:10:39141 base::BindOnce(&BidirectionalStream::FlushOnNetworkThread, weak_this_));
mef62d0ba2a2016-06-15 21:03:02142}
143
gcasto67ace932016-11-10 21:44:49144void BidirectionalStream::Cancel() {
145 PostToNetworkThread(
146 FROM_HERE,
Misha Efimov9983c6bb2018-01-30 23:10:39147 base::BindOnce(&BidirectionalStream::CancelOnNetworkThread, weak_this_));
mef06eab3e82016-04-14 22:45:49148}
149
gcasto67ace932016-11-10 21:44:49150void BidirectionalStream::Destroy() {
mef06eab3e82016-04-14 22:45:49151 // Destroy could be called from any thread, including network thread (if
152 // posting task to executor throws an exception), but is posted, so |this|
153 // is valid until calling task is complete.
Misha Efimov9983c6bb2018-01-30 23:10:39154 PostToNetworkThread(
155 FROM_HERE, base::BindOnce(&BidirectionalStream::DestroyOnNetworkThread,
156 base::Unretained(this)));
mef06eab3e82016-04-14 22:45:49157}
158
gcasto67ace932016-11-10 21:44:49159void BidirectionalStream::OnStreamReady(bool request_headers_sent) {
160 DCHECK(IsOnNetworkThread());
mef62d0ba2a2016-06-15 21:03:02161 DCHECK_EQ(STARTED, write_state_);
mef210d6b6d2016-09-30 21:24:57162 if (!bidi_stream_)
163 return;
mef62d0ba2a2016-06-15 21:03:02164 request_headers_sent_ = request_headers_sent;
165 write_state_ = WAITING_FOR_FLUSH;
166 if (write_end_of_stream_) {
167 if (!request_headers_sent) {
168 // If there is no data to write, then just send headers explicitly.
169 bidi_stream_->SendRequestHeaders();
170 request_headers_sent_ = true;
171 }
mef06eab3e82016-04-14 22:45:49172 write_state_ = WRITING_DONE;
mef62d0ba2a2016-06-15 21:03:02173 }
xunjieli07a42ce2016-04-26 20:05:31174 delegate_->OnStreamReady();
mef06eab3e82016-04-14 22:45:49175}
176
gcasto67ace932016-11-10 21:44:49177void BidirectionalStream::OnHeadersReceived(
Ryan Hamilton0239aac2018-05-19 00:03:13178 const spdy::SpdyHeaderBlock& response_headers) {
gcasto67ace932016-11-10 21:44:49179 DCHECK(IsOnNetworkThread());
mef62d0ba2a2016-06-15 21:03:02180 DCHECK_EQ(STARTED, read_state_);
mef210d6b6d2016-09-30 21:24:57181 if (!bidi_stream_)
182 return;
mef06eab3e82016-04-14 22:45:49183 read_state_ = WAITING_FOR_READ;
184 // Get http status code from response headers.
185 int http_status_code = 0;
186 const auto http_status_header = response_headers.find(":status");
187 if (http_status_header != response_headers.end())
188 base::StringToInt(http_status_header->second, &http_status_code);
189 const char* protocol = "unknown";
190 switch (bidi_stream_->GetProtocol()) {
191 case net::kProtoHTTP2:
192 protocol = "h2";
193 break;
bnc401eb922016-10-21 16:49:35194 case net::kProtoQUIC:
mef06eab3e82016-04-14 22:45:49195 protocol = "quic/1+spdy/3";
196 break;
197 default:
198 break;
199 }
200 delegate_->OnHeadersReceived(response_headers, protocol);
201}
202
gcasto67ace932016-11-10 21:44:49203void BidirectionalStream::OnDataRead(int bytes_read) {
204 DCHECK(IsOnNetworkThread());
mef62d0ba2a2016-06-15 21:03:02205 DCHECK_EQ(READING, read_state_);
mef210d6b6d2016-09-30 21:24:57206 if (!bidi_stream_)
207 return;
mef06eab3e82016-04-14 22:45:49208 read_state_ = WAITING_FOR_READ;
209 delegate_->OnDataRead(read_buffer_->data(), bytes_read);
210
211 // Free the read buffer.
212 read_buffer_ = nullptr;
213 if (bytes_read == 0)
214 read_state_ = READING_DONE;
215 MaybeOnSucceded();
216}
217
gcasto67ace932016-11-10 21:44:49218void BidirectionalStream::OnDataSent() {
219 DCHECK(IsOnNetworkThread());
mef210d6b6d2016-09-30 21:24:57220 if (!bidi_stream_)
221 return;
mef62d0ba2a2016-06-15 21:03:02222 DCHECK_EQ(WRITING, write_state_);
223 write_state_ = WAITING_FOR_FLUSH;
224 for (const scoped_refptr<net::IOBuffer>& buffer :
225 sending_write_data_->buffers()) {
226 delegate_->OnDataSent(buffer->data());
227 }
228 sending_write_data_->Clear();
229 // Send data flushed while other data was sending.
230 if (!flushing_write_data_->Empty()) {
231 SendFlushingWriteData();
232 return;
233 }
mefa3e2f522016-07-11 18:18:07234 if (write_end_of_stream_ && pending_write_data_->Empty()) {
mef06eab3e82016-04-14 22:45:49235 write_state_ = WRITING_DONE;
mefa3e2f522016-07-11 18:18:07236 MaybeOnSucceded();
237 }
mef06eab3e82016-04-14 22:45:49238}
239
gcasto67ace932016-11-10 21:44:49240void BidirectionalStream::OnTrailersReceived(
Ryan Hamilton0239aac2018-05-19 00:03:13241 const spdy::SpdyHeaderBlock& response_trailers) {
gcasto67ace932016-11-10 21:44:49242 DCHECK(IsOnNetworkThread());
mef210d6b6d2016-09-30 21:24:57243 if (!bidi_stream_)
244 return;
mef06eab3e82016-04-14 22:45:49245 delegate_->OnTrailersReceived(response_trailers);
246}
247
gcasto67ace932016-11-10 21:44:49248void BidirectionalStream::OnFailed(int error) {
249 DCHECK(IsOnNetworkThread());
mef210d6b6d2016-09-30 21:24:57250 if (!bidi_stream_ && read_state_ != NOT_STARTED)
251 return;
gcasto67ace932016-11-10 21:44:49252 read_state_ = write_state_ = ERR;
mefce9fb502016-09-27 19:45:56253 weak_factory_.InvalidateWeakPtrs();
mef210d6b6d2016-09-30 21:24:57254 // Delete underlying |bidi_stream_| asynchronously as it may still be used.
Misha Efimov9983c6bb2018-01-30 23:10:39255 PostToNetworkThread(
256 FROM_HERE, base::BindOnce(&base::DeletePointer<net::BidirectionalStream>,
257 bidi_stream_.release()));
mef06eab3e82016-04-14 22:45:49258 delegate_->OnFailed(error);
259}
260
gcasto67ace932016-11-10 21:44:49261void BidirectionalStream::StartOnNetworkThread(
dchengfe3745e6242016-04-21 23:49:58262 std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info) {
gcasto67ace932016-11-10 21:44:49263 DCHECK(IsOnNetworkThread());
mef06eab3e82016-04-14 22:45:49264 DCHECK(!bidi_stream_);
gcasto67ace932016-11-10 21:44:49265 DCHECK(request_context_getter_->GetURLRequestContext());
266 net::URLRequestContext* request_context =
267 request_context_getter_->GetURLRequestContext();
mef06eab3e82016-04-14 22:45:49268 request_info->extra_headers.SetHeaderIfMissing(
gcasto67ace932016-11-10 21:44:49269 net::HttpRequestHeaders::kUserAgent,
270 request_context->http_user_agent_settings()->GetUserAgent());
mef06eab3e82016-04-14 22:45:49271 bidi_stream_.reset(new net::BidirectionalStream(
gcasto67ace932016-11-10 21:44:49272 std::move(request_info),
273 request_context->http_transaction_factory()->GetSession(),
mef62d0ba2a2016-06-15 21:03:02274 !delay_headers_until_flush_, this));
mef06eab3e82016-04-14 22:45:49275 DCHECK(read_state_ == NOT_STARTED && write_state_ == NOT_STARTED);
276 read_state_ = write_state_ = STARTED;
277}
278
gcasto67ace932016-11-10 21:44:49279void BidirectionalStream::ReadDataOnNetworkThread(
mef06eab3e82016-04-14 22:45:49280 scoped_refptr<net::WrappedIOBuffer> read_buffer,
281 int buffer_size) {
gcasto67ace932016-11-10 21:44:49282 DCHECK(IsOnNetworkThread());
mef06eab3e82016-04-14 22:45:49283 DCHECK(read_buffer);
284 DCHECK(!read_buffer_);
285 if (read_state_ != WAITING_FOR_READ) {
mef210d6b6d2016-09-30 21:24:57286 DLOG(ERROR) << "Unexpected Read Data in read_state " << read_state_;
mef5ef58edc32016-04-29 22:34:53287 // Invoke OnFailed unless it is already invoked.
gcasto67ace932016-11-10 21:44:49288 if (read_state_ != ERR)
mef5ef58edc32016-04-29 22:34:53289 OnFailed(net::ERR_UNEXPECTED);
mef06eab3e82016-04-14 22:45:49290 return;
291 }
292 read_state_ = READING;
293 read_buffer_ = read_buffer;
294
295 int bytes_read = bidi_stream_->ReadData(read_buffer_.get(), buffer_size);
296 // If IO is pending, wait for the BidirectionalStream to call OnDataRead.
297 if (bytes_read == net::ERR_IO_PENDING)
298 return;
299
300 if (bytes_read < 0) {
301 OnFailed(bytes_read);
302 return;
303 }
304 OnDataRead(bytes_read);
305}
306
gcasto67ace932016-11-10 21:44:49307void BidirectionalStream::WriteDataOnNetworkThread(
mef06eab3e82016-04-14 22:45:49308 scoped_refptr<net::WrappedIOBuffer> write_buffer,
309 int buffer_size,
310 bool end_of_stream) {
gcasto67ace932016-11-10 21:44:49311 DCHECK(IsOnNetworkThread());
mef06eab3e82016-04-14 22:45:49312 DCHECK(write_buffer);
mef62d0ba2a2016-06-15 21:03:02313 DCHECK(!write_end_of_stream_);
314 if (!bidi_stream_ || write_end_of_stream_) {
315 DLOG(ERROR) << "Unexpected Flush Data in write_state " << write_state_;
mef5ef58edc32016-04-29 22:34:53316 // Invoke OnFailed unless it is already invoked.
gcasto67ace932016-11-10 21:44:49317 if (write_state_ != ERR)
mef5ef58edc32016-04-29 22:34:53318 OnFailed(net::ERR_UNEXPECTED);
mef06eab3e82016-04-14 22:45:49319 return;
320 }
mef62d0ba2a2016-06-15 21:03:02321 pending_write_data_->AppendBuffer(write_buffer, buffer_size);
mef06eab3e82016-04-14 22:45:49322 write_end_of_stream_ = end_of_stream;
mef62d0ba2a2016-06-15 21:03:02323 if (!disable_auto_flush_)
324 FlushOnNetworkThread();
325}
mef06eab3e82016-04-14 22:45:49326
gcasto67ace932016-11-10 21:44:49327void BidirectionalStream::FlushOnNetworkThread() {
328 DCHECK(IsOnNetworkThread());
mef62d0ba2a2016-06-15 21:03:02329 if (!bidi_stream_)
330 return;
331 // If there is no data to flush, may need to send headers.
332 if (pending_write_data_->Empty()) {
333 if (!request_headers_sent_) {
334 request_headers_sent_ = true;
335 bidi_stream_->SendRequestHeaders();
336 }
337 return;
338 }
339 // If request headers are not sent yet, they will be sent with the data.
340 if (!request_headers_sent_)
341 request_headers_sent_ = true;
342
343 // Move pending data to the flushing list.
344 pending_write_data_->MoveTo(flushing_write_data_.get());
345 DCHECK(pending_write_data_->Empty());
346 if (write_state_ != WRITING)
347 SendFlushingWriteData();
348}
349
gcasto67ace932016-11-10 21:44:49350void BidirectionalStream::SendFlushingWriteData() {
mefce9fb502016-09-27 19:45:56351 DCHECK(bidi_stream_);
mef62d0ba2a2016-06-15 21:03:02352 // If previous send is not done, or there is nothing to flush, then exit.
353 if (write_state_ == WRITING || flushing_write_data_->Empty())
354 return;
355 DCHECK(sending_write_data_->Empty());
356 write_state_ = WRITING;
357 flushing_write_data_->MoveTo(sending_write_data_.get());
358 bidi_stream_->SendvData(sending_write_data_->buffers(),
mefa3e2f522016-07-11 18:18:07359 sending_write_data_->lengths(),
360 write_end_of_stream_ && pending_write_data_->Empty());
mef06eab3e82016-04-14 22:45:49361}
362
gcasto67ace932016-11-10 21:44:49363void BidirectionalStream::CancelOnNetworkThread() {
364 DCHECK(IsOnNetworkThread());
mef06eab3e82016-04-14 22:45:49365 if (!bidi_stream_)
366 return;
367 read_state_ = write_state_ = CANCELED;
368 bidi_stream_.reset();
mefce9fb502016-09-27 19:45:56369 weak_factory_.InvalidateWeakPtrs();
mef06eab3e82016-04-14 22:45:49370 delegate_->OnCanceled();
371}
372
gcasto67ace932016-11-10 21:44:49373void BidirectionalStream::DestroyOnNetworkThread() {
374 DCHECK(IsOnNetworkThread());
mef06eab3e82016-04-14 22:45:49375 delete this;
376}
377
gcasto67ace932016-11-10 21:44:49378void BidirectionalStream::MaybeOnSucceded() {
379 DCHECK(IsOnNetworkThread());
mef210d6b6d2016-09-30 21:24:57380 if (!bidi_stream_)
381 return;
mef06eab3e82016-04-14 22:45:49382 if (read_state_ == READING_DONE && write_state_ == WRITING_DONE) {
383 read_state_ = write_state_ = SUCCESS;
mefce9fb502016-09-27 19:45:56384 weak_factory_.InvalidateWeakPtrs();
mef210d6b6d2016-09-30 21:24:57385 // Delete underlying |bidi_stream_| asynchronously as it may still be used.
gcasto67ace932016-11-10 21:44:49386 PostToNetworkThread(
Misha Efimov9983c6bb2018-01-30 23:10:39387 FROM_HERE,
388 base::BindOnce(&base::DeletePointer<net::BidirectionalStream>,
389 bidi_stream_.release()));
mef06eab3e82016-04-14 22:45:49390 delegate_->OnSucceeded();
391 }
392}
393
gcasto67ace932016-11-10 21:44:49394bool BidirectionalStream::IsOnNetworkThread() {
395 return request_context_getter_->GetNetworkTaskRunner()
396 ->BelongsToCurrentThread();
397}
398
Brett Wilson190fd2ac2017-09-12 05:04:30399void BidirectionalStream::PostToNetworkThread(const base::Location& from_here,
Misha Efimov9983c6bb2018-01-30 23:10:39400 base::OnceClosure task) {
401 request_context_getter_->GetNetworkTaskRunner()->PostTask(from_here,
402 std::move(task));
gcasto67ace932016-11-10 21:44:49403}
404
Misha Efimov9983c6bb2018-01-30 23:10:39405} // namespace grpc_support