mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 1 | // 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 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 5 | #include "components/grpc_support/bidirectional_stream.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 6 | |
dcheng | fe3745e624 | 2016-04-21 23:49:58 | [diff] [blame] | 7 | #include <memory> |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 8 | #include <string> |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 9 | #include <utility> |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 10 | #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 Zhang | 52637ed | 2019-02-20 01:38:37 | [diff] [blame] | 16 | #include "base/single_thread_task_runner.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 17 | #include "base/strings/string_number_conversions.h" |
Matt Menke | d732ea4 | 2019-03-08 12:05:00 | [diff] [blame] | 18 | #include "net/base/http_user_agent_settings.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 19 | #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" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 29 | #include "net/ssl/ssl_info.h" |
Victor Vasiliev | 27cc771 | 2019-01-24 11:50:14 | [diff] [blame] | 30 | #include "net/third_party/quiche/src/spdy/core/spdy_header_block.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 31 | #include "net/url_request/url_request_context.h" |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 32 | #include "net/url_request/url_request_context_getter.h" |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 33 | #include "url/gurl.h" |
| 34 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 35 | namespace grpc_support { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 36 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 37 | BidirectionalStream::WriteBuffers::WriteBuffers() {} |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 38 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 39 | BidirectionalStream::WriteBuffers::~WriteBuffers() {} |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 40 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 41 | void BidirectionalStream::WriteBuffers::Clear() { |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 42 | write_buffer_list.clear(); |
| 43 | write_buffer_len_list.clear(); |
| 44 | } |
| 45 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 46 | void BidirectionalStream::WriteBuffers::AppendBuffer( |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 47 | 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 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 53 | void BidirectionalStream::WriteBuffers::MoveTo(WriteBuffers* target) { |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 54 | 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 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 61 | bool BidirectionalStream::WriteBuffers::Empty() const { |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 62 | return write_buffer_list.empty(); |
| 63 | } |
| 64 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 65 | BidirectionalStream::BidirectionalStream( |
| 66 | net::URLRequestContextGetter* request_context_getter, |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 67 | Delegate* delegate) |
| 68 | : read_state_(NOT_STARTED), |
| 69 | write_state_(NOT_STARTED), |
| 70 | write_end_of_stream_(false), |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 71 | request_headers_sent_(false), |
| 72 | disable_auto_flush_(false), |
| 73 | delay_headers_until_flush_(false), |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 74 | request_context_getter_(request_context_getter), |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 75 | pending_write_data_(new WriteBuffers()), |
| 76 | flushing_write_data_(new WriteBuffers()), |
| 77 | sending_write_data_(new WriteBuffers()), |
Jeremy Roman | 5c341f6d | 2019-07-15 15:56:10 | [diff] [blame] | 78 | delegate_(delegate) { |
mef | ce9fb50 | 2016-09-27 19:45:56 | [diff] [blame] | 79 | weak_this_ = weak_factory_.GetWeakPtr(); |
| 80 | } |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 81 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 82 | BidirectionalStream::~BidirectionalStream() { |
| 83 | DCHECK(IsOnNetworkThread()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 84 | } |
| 85 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 86 | int BidirectionalStream::Start(const char* url, |
| 87 | int priority, |
| 88 | const char* method, |
| 89 | const net::HttpRequestHeaders& headers, |
| 90 | bool end_of_stream) { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 91 | // Prepare request info here to be able to return the error. |
dcheng | fe3745e624 | 2016-04-21 23:49:58 | [diff] [blame] | 92 | std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info( |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 93 | 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; |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 103 | PostToNetworkThread(FROM_HERE, |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 104 | base::BindOnce(&BidirectionalStream::StartOnNetworkThread, |
Claudio DeSouza | 591a997 | 2018-02-21 17:27:16 | [diff] [blame] | 105 | weak_this_, std::move(request_info))); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 106 | return 0; |
| 107 | } |
| 108 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 109 | bool BidirectionalStream::ReadData(char* buffer, int capacity) { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 110 | if (!buffer) |
| 111 | return false; |
Victor Costan | 282536d | 2018-09-03 22:31:31 | [diff] [blame] | 112 | scoped_refptr<net::WrappedIOBuffer> read_buffer = |
| 113 | base::MakeRefCounted<net::WrappedIOBuffer>(buffer); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 114 | |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 115 | PostToNetworkThread( |
| 116 | FROM_HERE, base::BindOnce(&BidirectionalStream::ReadDataOnNetworkThread, |
Misha Efimov | a7fc344 | 2019-10-08 17:11:05 | [diff] [blame] | 117 | weak_this_, std::move(read_buffer), capacity)); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 118 | return true; |
| 119 | } |
| 120 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 121 | bool BidirectionalStream::WriteData(const char* buffer, |
| 122 | int count, |
| 123 | bool end_of_stream) { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 124 | if (!buffer) |
| 125 | return false; |
| 126 | |
Victor Costan | 282536d | 2018-09-03 22:31:31 | [diff] [blame] | 127 | scoped_refptr<net::WrappedIOBuffer> write_buffer = |
| 128 | base::MakeRefCounted<net::WrappedIOBuffer>(buffer); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 129 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 130 | PostToNetworkThread( |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 131 | FROM_HERE, |
| 132 | base::BindOnce(&BidirectionalStream::WriteDataOnNetworkThread, weak_this_, |
Misha Efimov | a7fc344 | 2019-10-08 17:11:05 | [diff] [blame] | 133 | std::move(write_buffer), count, end_of_stream)); |
| 134 | |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 135 | return true; |
| 136 | } |
| 137 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 138 | void BidirectionalStream::Flush() { |
| 139 | PostToNetworkThread( |
mef | ce9fb50 | 2016-09-27 19:45:56 | [diff] [blame] | 140 | FROM_HERE, |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 141 | base::BindOnce(&BidirectionalStream::FlushOnNetworkThread, weak_this_)); |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 142 | } |
| 143 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 144 | void BidirectionalStream::Cancel() { |
| 145 | PostToNetworkThread( |
| 146 | FROM_HERE, |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 147 | base::BindOnce(&BidirectionalStream::CancelOnNetworkThread, weak_this_)); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 148 | } |
| 149 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 150 | void BidirectionalStream::Destroy() { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 151 | // 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 Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 154 | PostToNetworkThread( |
| 155 | FROM_HERE, base::BindOnce(&BidirectionalStream::DestroyOnNetworkThread, |
| 156 | base::Unretained(this))); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 157 | } |
| 158 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 159 | void BidirectionalStream::OnStreamReady(bool request_headers_sent) { |
| 160 | DCHECK(IsOnNetworkThread()); |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 161 | DCHECK_EQ(STARTED, write_state_); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 162 | if (!bidi_stream_) |
| 163 | return; |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 164 | 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 | } |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 172 | write_state_ = WRITING_DONE; |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 173 | } |
xunjieli | 07a42ce | 2016-04-26 20:05:31 | [diff] [blame] | 174 | delegate_->OnStreamReady(); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 175 | } |
| 176 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 177 | void BidirectionalStream::OnHeadersReceived( |
Ryan Hamilton | 0239aac | 2018-05-19 00:03:13 | [diff] [blame] | 178 | const spdy::SpdyHeaderBlock& response_headers) { |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 179 | DCHECK(IsOnNetworkThread()); |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 180 | DCHECK_EQ(STARTED, read_state_); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 181 | if (!bidi_stream_) |
| 182 | return; |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 183 | 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; |
bnc | 401eb92 | 2016-10-21 16:49:35 | [diff] [blame] | 194 | case net::kProtoQUIC: |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 195 | protocol = "quic/1+spdy/3"; |
| 196 | break; |
| 197 | default: |
| 198 | break; |
| 199 | } |
| 200 | delegate_->OnHeadersReceived(response_headers, protocol); |
| 201 | } |
| 202 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 203 | void BidirectionalStream::OnDataRead(int bytes_read) { |
| 204 | DCHECK(IsOnNetworkThread()); |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 205 | DCHECK_EQ(READING, read_state_); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 206 | if (!bidi_stream_) |
| 207 | return; |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 208 | 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 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 218 | void BidirectionalStream::OnDataSent() { |
| 219 | DCHECK(IsOnNetworkThread()); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 220 | if (!bidi_stream_) |
| 221 | return; |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 222 | 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 | } |
mef | a3e2f52 | 2016-07-11 18:18:07 | [diff] [blame] | 234 | if (write_end_of_stream_ && pending_write_data_->Empty()) { |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 235 | write_state_ = WRITING_DONE; |
mef | a3e2f52 | 2016-07-11 18:18:07 | [diff] [blame] | 236 | MaybeOnSucceded(); |
| 237 | } |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 238 | } |
| 239 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 240 | void BidirectionalStream::OnTrailersReceived( |
Ryan Hamilton | 0239aac | 2018-05-19 00:03:13 | [diff] [blame] | 241 | const spdy::SpdyHeaderBlock& response_trailers) { |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 242 | DCHECK(IsOnNetworkThread()); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 243 | if (!bidi_stream_) |
| 244 | return; |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 245 | delegate_->OnTrailersReceived(response_trailers); |
| 246 | } |
| 247 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 248 | void BidirectionalStream::OnFailed(int error) { |
| 249 | DCHECK(IsOnNetworkThread()); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 250 | if (!bidi_stream_ && read_state_ != NOT_STARTED) |
| 251 | return; |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 252 | read_state_ = write_state_ = ERR; |
mef | ce9fb50 | 2016-09-27 19:45:56 | [diff] [blame] | 253 | weak_factory_.InvalidateWeakPtrs(); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 254 | // Delete underlying |bidi_stream_| asynchronously as it may still be used. |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 255 | PostToNetworkThread( |
| 256 | FROM_HERE, base::BindOnce(&base::DeletePointer<net::BidirectionalStream>, |
| 257 | bidi_stream_.release())); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 258 | delegate_->OnFailed(error); |
| 259 | } |
| 260 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 261 | void BidirectionalStream::StartOnNetworkThread( |
dcheng | fe3745e624 | 2016-04-21 23:49:58 | [diff] [blame] | 262 | std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info) { |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 263 | DCHECK(IsOnNetworkThread()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 264 | DCHECK(!bidi_stream_); |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 265 | DCHECK(request_context_getter_->GetURLRequestContext()); |
| 266 | net::URLRequestContext* request_context = |
| 267 | request_context_getter_->GetURLRequestContext(); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 268 | request_info->extra_headers.SetHeaderIfMissing( |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 269 | net::HttpRequestHeaders::kUserAgent, |
| 270 | request_context->http_user_agent_settings()->GetUserAgent()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 271 | bidi_stream_.reset(new net::BidirectionalStream( |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 272 | std::move(request_info), |
| 273 | request_context->http_transaction_factory()->GetSession(), |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 274 | !delay_headers_until_flush_, this)); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 275 | DCHECK(read_state_ == NOT_STARTED && write_state_ == NOT_STARTED); |
| 276 | read_state_ = write_state_ = STARTED; |
| 277 | } |
| 278 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 279 | void BidirectionalStream::ReadDataOnNetworkThread( |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 280 | scoped_refptr<net::WrappedIOBuffer> read_buffer, |
| 281 | int buffer_size) { |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 282 | DCHECK(IsOnNetworkThread()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 283 | DCHECK(read_buffer); |
| 284 | DCHECK(!read_buffer_); |
| 285 | if (read_state_ != WAITING_FOR_READ) { |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 286 | DLOG(ERROR) << "Unexpected Read Data in read_state " << read_state_; |
mef | 5ef58edc3 | 2016-04-29 22:34:53 | [diff] [blame] | 287 | // Invoke OnFailed unless it is already invoked. |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 288 | if (read_state_ != ERR) |
mef | 5ef58edc3 | 2016-04-29 22:34:53 | [diff] [blame] | 289 | OnFailed(net::ERR_UNEXPECTED); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 290 | 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 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 307 | void BidirectionalStream::WriteDataOnNetworkThread( |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 308 | scoped_refptr<net::WrappedIOBuffer> write_buffer, |
| 309 | int buffer_size, |
| 310 | bool end_of_stream) { |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 311 | DCHECK(IsOnNetworkThread()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 312 | DCHECK(write_buffer); |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 313 | DCHECK(!write_end_of_stream_); |
| 314 | if (!bidi_stream_ || write_end_of_stream_) { |
| 315 | DLOG(ERROR) << "Unexpected Flush Data in write_state " << write_state_; |
mef | 5ef58edc3 | 2016-04-29 22:34:53 | [diff] [blame] | 316 | // Invoke OnFailed unless it is already invoked. |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 317 | if (write_state_ != ERR) |
mef | 5ef58edc3 | 2016-04-29 22:34:53 | [diff] [blame] | 318 | OnFailed(net::ERR_UNEXPECTED); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 319 | return; |
| 320 | } |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 321 | pending_write_data_->AppendBuffer(write_buffer, buffer_size); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 322 | write_end_of_stream_ = end_of_stream; |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 323 | if (!disable_auto_flush_) |
| 324 | FlushOnNetworkThread(); |
| 325 | } |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 326 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 327 | void BidirectionalStream::FlushOnNetworkThread() { |
| 328 | DCHECK(IsOnNetworkThread()); |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 329 | 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 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 350 | void BidirectionalStream::SendFlushingWriteData() { |
mef | ce9fb50 | 2016-09-27 19:45:56 | [diff] [blame] | 351 | DCHECK(bidi_stream_); |
mef | 62d0ba2a | 2016-06-15 21:03:02 | [diff] [blame] | 352 | // 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(), |
mef | a3e2f52 | 2016-07-11 18:18:07 | [diff] [blame] | 359 | sending_write_data_->lengths(), |
| 360 | write_end_of_stream_ && pending_write_data_->Empty()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 361 | } |
| 362 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 363 | void BidirectionalStream::CancelOnNetworkThread() { |
| 364 | DCHECK(IsOnNetworkThread()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 365 | if (!bidi_stream_) |
| 366 | return; |
| 367 | read_state_ = write_state_ = CANCELED; |
| 368 | bidi_stream_.reset(); |
mef | ce9fb50 | 2016-09-27 19:45:56 | [diff] [blame] | 369 | weak_factory_.InvalidateWeakPtrs(); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 370 | delegate_->OnCanceled(); |
| 371 | } |
| 372 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 373 | void BidirectionalStream::DestroyOnNetworkThread() { |
| 374 | DCHECK(IsOnNetworkThread()); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 375 | delete this; |
| 376 | } |
| 377 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 378 | void BidirectionalStream::MaybeOnSucceded() { |
| 379 | DCHECK(IsOnNetworkThread()); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 380 | if (!bidi_stream_) |
| 381 | return; |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 382 | if (read_state_ == READING_DONE && write_state_ == WRITING_DONE) { |
| 383 | read_state_ = write_state_ = SUCCESS; |
mef | ce9fb50 | 2016-09-27 19:45:56 | [diff] [blame] | 384 | weak_factory_.InvalidateWeakPtrs(); |
mef | 210d6b6d | 2016-09-30 21:24:57 | [diff] [blame] | 385 | // Delete underlying |bidi_stream_| asynchronously as it may still be used. |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 386 | PostToNetworkThread( |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 387 | FROM_HERE, |
| 388 | base::BindOnce(&base::DeletePointer<net::BidirectionalStream>, |
| 389 | bidi_stream_.release())); |
mef | 06eab3e8 | 2016-04-14 22:45:49 | [diff] [blame] | 390 | delegate_->OnSucceeded(); |
| 391 | } |
| 392 | } |
| 393 | |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 394 | bool BidirectionalStream::IsOnNetworkThread() { |
| 395 | return request_context_getter_->GetNetworkTaskRunner() |
| 396 | ->BelongsToCurrentThread(); |
| 397 | } |
| 398 | |
Brett Wilson | 190fd2ac | 2017-09-12 05:04:30 | [diff] [blame] | 399 | void BidirectionalStream::PostToNetworkThread(const base::Location& from_here, |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 400 | base::OnceClosure task) { |
| 401 | request_context_getter_->GetNetworkTaskRunner()->PostTask(from_here, |
| 402 | std::move(task)); |
gcasto | 67ace93 | 2016-11-10 21:44:49 | [diff] [blame] | 403 | } |
| 404 | |
Misha Efimov | 9983c6bb | 2018-01-30 23:10:39 | [diff] [blame] | 405 | } // namespace grpc_support |