Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(261)

Side by Side Diff: components/cronet/ios/cronet_bidirectional_stream.cc

Issue 2273403003: Moving gRPC support interfaces out of cronet and into a new component. (Closed)
Patch Set: Add cronet_c_for_graph back to sources. Might fix GN, probably won't compile Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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
5 #include "components/cronet/ios/cronet_bidirectional_stream.h"
6
7 #include <memory>
8 #include <string>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "components/cronet/ios/cronet_environment.h"
17 #include "net/base/io_buffer.h"
18 #include "net/base/net_errors.h"
19 #include "net/base/request_priority.h"
20 #include "net/http/bidirectional_stream.h"
21 #include "net/http/bidirectional_stream_request_info.h"
22 #include "net/http/http_network_session.h"
23 #include "net/http/http_response_headers.h"
24 #include "net/http/http_status_code.h"
25 #include "net/http/http_transaction_factory.h"
26 #include "net/http/http_util.h"
27 #include "net/spdy/spdy_header_block.h"
28 #include "net/ssl/ssl_info.h"
29 #include "net/url_request/http_user_agent_settings.h"
30 #include "net/url_request/url_request_context.h"
31 #include "url/gurl.h"
32
33 namespace cronet {
34
35 CronetBidirectionalStream::WriteBuffers::WriteBuffers() {}
36
37 CronetBidirectionalStream::WriteBuffers::~WriteBuffers() {}
38
39 void CronetBidirectionalStream::WriteBuffers::Clear() {
40 write_buffer_list.clear();
41 write_buffer_len_list.clear();
42 }
43
44 void CronetBidirectionalStream::WriteBuffers::AppendBuffer(
45 const scoped_refptr<net::IOBuffer>& buffer,
46 int buffer_size) {
47 write_buffer_list.push_back(buffer);
48 write_buffer_len_list.push_back(buffer_size);
49 }
50
51 void CronetBidirectionalStream::WriteBuffers::MoveTo(WriteBuffers* target) {
52 std::move(write_buffer_list.begin(), write_buffer_list.end(),
53 std::back_inserter(target->write_buffer_list));
54 std::move(write_buffer_len_list.begin(), write_buffer_len_list.end(),
55 std::back_inserter(target->write_buffer_len_list));
56 Clear();
57 }
58
59 bool CronetBidirectionalStream::WriteBuffers::Empty() const {
60 return write_buffer_list.empty();
61 }
62
63 CronetBidirectionalStream::CronetBidirectionalStream(
64 CronetEnvironment* environment,
65 Delegate* delegate)
66 : read_state_(NOT_STARTED),
67 write_state_(NOT_STARTED),
68 write_end_of_stream_(false),
69 request_headers_sent_(false),
70 disable_auto_flush_(false),
71 delay_headers_until_flush_(false),
72 environment_(environment),
73 pending_write_data_(new WriteBuffers()),
74 flushing_write_data_(new WriteBuffers()),
75 sending_write_data_(new WriteBuffers()),
76 delegate_(delegate) {}
77
78 CronetBidirectionalStream::~CronetBidirectionalStream() {
79 DCHECK(environment_->IsOnNetworkThread());
80 }
81
82 int CronetBidirectionalStream::Start(const char* url,
83 int priority,
84 const char* method,
85 const net::HttpRequestHeaders& headers,
86 bool end_of_stream) {
87 // Prepare request info here to be able to return the error.
88 std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info(
89 new net::BidirectionalStreamRequestInfo());
90 request_info->url = GURL(url);
91 request_info->priority = static_cast<net::RequestPriority>(priority);
92 // Http method is a token, just as header name.
93 request_info->method = method;
94 if (!net::HttpUtil::IsValidHeaderName(request_info->method))
95 return -1;
96 request_info->extra_headers.CopyFrom(headers);
97 request_info->end_stream_on_headers = end_of_stream;
98 write_end_of_stream_ = end_of_stream;
99 DCHECK(environment_);
100 environment_->PostToNetworkThread(
101 FROM_HERE,
102 base::Bind(&CronetBidirectionalStream::StartOnNetworkThread,
103 base::Unretained(this), base::Passed(&request_info)));
104 return 0;
105 }
106
107 bool CronetBidirectionalStream::ReadData(char* buffer, int capacity) {
108 if (!buffer)
109 return false;
110 scoped_refptr<net::WrappedIOBuffer> read_buffer(
111 new net::WrappedIOBuffer(buffer));
112
113 environment_->PostToNetworkThread(
114 FROM_HERE, base::Bind(&CronetBidirectionalStream::ReadDataOnNetworkThread,
115 base::Unretained(this), read_buffer, capacity));
116 return true;
117 }
118
119 bool CronetBidirectionalStream::WriteData(const char* buffer,
120 int count,
121 bool end_of_stream) {
122 if (!buffer)
123 return false;
124
125 scoped_refptr<net::WrappedIOBuffer> write_buffer(
126 new net::WrappedIOBuffer(buffer));
127
128 environment_->PostToNetworkThread(
129 FROM_HERE,
130 base::Bind(&CronetBidirectionalStream::WriteDataOnNetworkThread,
131 base::Unretained(this), write_buffer, count, end_of_stream));
132 return true;
133 }
134
135 void CronetBidirectionalStream::Flush() {
136 environment_->PostToNetworkThread(
137 FROM_HERE, base::Bind(&CronetBidirectionalStream::FlushOnNetworkThread,
138 base::Unretained(this)));
139 }
140
141 void CronetBidirectionalStream::Cancel() {
142 environment_->PostToNetworkThread(
143 FROM_HERE, base::Bind(&CronetBidirectionalStream::CancelOnNetworkThread,
144 base::Unretained(this)));
145 }
146
147 void CronetBidirectionalStream::Destroy() {
148 // Destroy could be called from any thread, including network thread (if
149 // posting task to executor throws an exception), but is posted, so |this|
150 // is valid until calling task is complete.
151 environment_->PostToNetworkThread(
152 FROM_HERE, base::Bind(&CronetBidirectionalStream::DestroyOnNetworkThread,
153 base::Unretained(this)));
154 }
155
156 void CronetBidirectionalStream::OnStreamReady(bool request_headers_sent) {
157 DCHECK(environment_->IsOnNetworkThread());
158 DCHECK_EQ(STARTED, write_state_);
159 request_headers_sent_ = request_headers_sent;
160 write_state_ = WAITING_FOR_FLUSH;
161 if (write_end_of_stream_) {
162 if (!request_headers_sent) {
163 // If there is no data to write, then just send headers explicitly.
164 bidi_stream_->SendRequestHeaders();
165 request_headers_sent_ = true;
166 }
167 write_state_ = WRITING_DONE;
168 }
169 delegate_->OnStreamReady();
170 }
171
172 void CronetBidirectionalStream::OnHeadersReceived(
173 const net::SpdyHeaderBlock& response_headers) {
174 DCHECK(environment_->IsOnNetworkThread());
175 DCHECK_EQ(STARTED, read_state_);
176 read_state_ = WAITING_FOR_READ;
177 // Get http status code from response headers.
178 int http_status_code = 0;
179 const auto http_status_header = response_headers.find(":status");
180 if (http_status_header != response_headers.end())
181 base::StringToInt(http_status_header->second, &http_status_code);
182 const char* protocol = "unknown";
183 switch (bidi_stream_->GetProtocol()) {
184 case net::kProtoHTTP2:
185 protocol = "h2";
186 break;
187 case net::kProtoQUIC1SPDY3:
188 protocol = "quic/1+spdy/3";
189 break;
190 default:
191 break;
192 }
193 delegate_->OnHeadersReceived(response_headers, protocol);
194 }
195
196 void CronetBidirectionalStream::OnDataRead(int bytes_read) {
197 DCHECK(environment_->IsOnNetworkThread());
198 DCHECK_EQ(READING, read_state_);
199 read_state_ = WAITING_FOR_READ;
200 delegate_->OnDataRead(read_buffer_->data(), bytes_read);
201
202 // Free the read buffer.
203 read_buffer_ = nullptr;
204 if (bytes_read == 0)
205 read_state_ = READING_DONE;
206 MaybeOnSucceded();
207 }
208
209 void CronetBidirectionalStream::OnDataSent() {
210 DCHECK(environment_->IsOnNetworkThread());
211 DCHECK_EQ(WRITING, write_state_);
212 write_state_ = WAITING_FOR_FLUSH;
213 for (const scoped_refptr<net::IOBuffer>& buffer :
214 sending_write_data_->buffers()) {
215 delegate_->OnDataSent(buffer->data());
216 }
217 sending_write_data_->Clear();
218 // Send data flushed while other data was sending.
219 if (!flushing_write_data_->Empty()) {
220 SendFlushingWriteData();
221 return;
222 }
223 if (write_end_of_stream_ && pending_write_data_->Empty()) {
224 write_state_ = WRITING_DONE;
225 MaybeOnSucceded();
226 }
227 }
228
229 void CronetBidirectionalStream::OnTrailersReceived(
230 const net::SpdyHeaderBlock& response_trailers) {
231 DCHECK(environment_->IsOnNetworkThread());
232 delegate_->OnTrailersReceived(response_trailers);
233 }
234
235 void CronetBidirectionalStream::OnFailed(int error) {
236 DCHECK(environment_->IsOnNetworkThread());
237 bidi_stream_.reset();
238 read_state_ = write_state_ = ERROR;
239 delegate_->OnFailed(error);
240 }
241
242 void CronetBidirectionalStream::StartOnNetworkThread(
243 std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info) {
244 DCHECK(environment_->IsOnNetworkThread());
245 DCHECK(!bidi_stream_);
246 DCHECK(environment_->GetURLRequestContext());
247 request_info->extra_headers.SetHeaderIfMissing(
248 net::HttpRequestHeaders::kUserAgent, environment_->user_agent());
249 bidi_stream_.reset(new net::BidirectionalStream(
250 std::move(request_info), environment_->GetURLRequestContext()
251 ->http_transaction_factory()
252 ->GetSession(),
253 !delay_headers_until_flush_, this));
254 DCHECK(read_state_ == NOT_STARTED && write_state_ == NOT_STARTED);
255 read_state_ = write_state_ = STARTED;
256 }
257
258 void CronetBidirectionalStream::ReadDataOnNetworkThread(
259 scoped_refptr<net::WrappedIOBuffer> read_buffer,
260 int buffer_size) {
261 DCHECK(environment_->IsOnNetworkThread());
262 DCHECK(read_buffer);
263 DCHECK(!read_buffer_);
264 if (read_state_ != WAITING_FOR_READ) {
265 DLOG(ERROR) << "Unexpected Read Data in read_state " << WAITING_FOR_READ;
266 // Invoke OnFailed unless it is already invoked.
267 if (read_state_ != ERROR)
268 OnFailed(net::ERR_UNEXPECTED);
269 return;
270 }
271 read_state_ = READING;
272 read_buffer_ = read_buffer;
273
274 int bytes_read = bidi_stream_->ReadData(read_buffer_.get(), buffer_size);
275 // If IO is pending, wait for the BidirectionalStream to call OnDataRead.
276 if (bytes_read == net::ERR_IO_PENDING)
277 return;
278
279 if (bytes_read < 0) {
280 OnFailed(bytes_read);
281 return;
282 }
283 OnDataRead(bytes_read);
284 }
285
286 void CronetBidirectionalStream::WriteDataOnNetworkThread(
287 scoped_refptr<net::WrappedIOBuffer> write_buffer,
288 int buffer_size,
289 bool end_of_stream) {
290 DCHECK(environment_->IsOnNetworkThread());
291 DCHECK(write_buffer);
292 DCHECK(!write_end_of_stream_);
293 if (!bidi_stream_ || write_end_of_stream_) {
294 DLOG(ERROR) << "Unexpected Flush Data in write_state " << write_state_;
295 // Invoke OnFailed unless it is already invoked.
296 if (write_state_ != ERROR)
297 OnFailed(net::ERR_UNEXPECTED);
298 return;
299 }
300 pending_write_data_->AppendBuffer(write_buffer, buffer_size);
301 write_end_of_stream_ = end_of_stream;
302 if (!disable_auto_flush_)
303 FlushOnNetworkThread();
304 }
305
306 void CronetBidirectionalStream::FlushOnNetworkThread() {
307 DCHECK(environment_->IsOnNetworkThread());
308 if (!bidi_stream_)
309 return;
310 // If there is no data to flush, may need to send headers.
311 if (pending_write_data_->Empty()) {
312 if (!request_headers_sent_) {
313 request_headers_sent_ = true;
314 bidi_stream_->SendRequestHeaders();
315 }
316 return;
317 }
318 // If request headers are not sent yet, they will be sent with the data.
319 if (!request_headers_sent_)
320 request_headers_sent_ = true;
321
322 // Move pending data to the flushing list.
323 pending_write_data_->MoveTo(flushing_write_data_.get());
324 DCHECK(pending_write_data_->Empty());
325 if (write_state_ != WRITING)
326 SendFlushingWriteData();
327 }
328
329 void CronetBidirectionalStream::SendFlushingWriteData() {
330 // If previous send is not done, or there is nothing to flush, then exit.
331 if (write_state_ == WRITING || flushing_write_data_->Empty())
332 return;
333 DCHECK(sending_write_data_->Empty());
334 write_state_ = WRITING;
335 flushing_write_data_->MoveTo(sending_write_data_.get());
336 bidi_stream_->SendvData(sending_write_data_->buffers(),
337 sending_write_data_->lengths(),
338 write_end_of_stream_ && pending_write_data_->Empty());
339 }
340
341 void CronetBidirectionalStream::CancelOnNetworkThread() {
342 DCHECK(environment_->IsOnNetworkThread());
343 if (!bidi_stream_)
344 return;
345 read_state_ = write_state_ = CANCELED;
346 bidi_stream_.reset();
347 delegate_->OnCanceled();
348 }
349
350 void CronetBidirectionalStream::DestroyOnNetworkThread() {
351 DCHECK(environment_->IsOnNetworkThread());
352 delete this;
353 }
354
355 void CronetBidirectionalStream::MaybeOnSucceded() {
356 DCHECK(environment_->IsOnNetworkThread());
357 if (read_state_ == READING_DONE && write_state_ == WRITING_DONE) {
358 read_state_ = write_state_ = SUCCESS;
359 bidi_stream_.reset();
360 delegate_->OnSucceeded();
361 }
362 }
363
364 } // namespace cronet
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698