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

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

Issue 1858483002: Cronet for iOS with C API for GRPC support. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@small
Patch Set: Make it syncable Created 4 years, 8 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 <stdbool.h>
xunjieli 2016/04/08 14:43:15 Why do we need to include stdbool?
mef 2016/04/08 16:43:03 I think this is carry-over from when it used to be
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/macros.h"
xunjieli 2016/04/08 14:43:15 not needed?
mef 2016/04/08 16:43:02 Done.
15 #include "base/memory/ref_counted.h"
16 #include "base/memory/scoped_ptr.h"
17 #include "base/strings/string_number_conversions.h"
18 #include "components/cronet/ios/cronet_environment.h"
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"
xunjieli 2016/04/08 14:43:15 Not needed?
mef 2016/04/08 16:43:03 Needed.
xunjieli 2016/04/08 17:46:15 Acknowledged.
28 #include "net/http/http_util.h"
29 #include "net/spdy/spdy_header_block.h"
30 #include "net/ssl/ssl_info.h"
31 #include "net/url_request/http_user_agent_settings.h"
32 #include "net/url_request/url_request_context.h"
33 #include "url/gurl.h"
34
35 namespace cronet {
36
37 CronetBidirectionalStream::CronetBidirectionalStream(
38 CronetEnvironment* environment,
39 Delegate* delegate)
40 : read_state_(NOT_STARTED),
41 write_state_(NOT_STARTED),
42 write_end_of_stream_(false),
43 environment_(environment),
44 delegate_(delegate) {}
45
46 CronetBidirectionalStream::~CronetBidirectionalStream() {
47 DCHECK(environment_->IsOnNetworkThread());
48 }
49
50 int CronetBidirectionalStream::Start(const char* url,
51 int priority,
52 const char* method,
53 const net::HttpRequestHeaders& headers,
54 bool end_of_stream) {
55 // Prepare request info here to be able to return the error.
56 scoped_ptr<net::BidirectionalStreamRequestInfo> request_info(
57 new net::BidirectionalStreamRequestInfo());
58 request_info->url = GURL(url);
59 request_info->priority = static_cast<net::RequestPriority>(priority);
60 // Http method is a token, just as header name.
61 request_info->method = method;
62 if (!net::HttpUtil::IsValidHeaderName(request_info->method))
63 return -1;
64 request_info->extra_headers.CopyFrom(headers);
65 request_info->end_stream_on_headers = end_of_stream;
66 write_end_of_stream_ = end_of_stream;
67 DCHECK(environment_);
68 environment_->PostToNetworkThread(
69 FROM_HERE,
70 base::Bind(&CronetBidirectionalStream::StartOnNetworkThread,
71 base::Unretained(this), base::Passed(&request_info)));
72 return 0;
73 }
74
75 bool CronetBidirectionalStream::ReadData(char* buffer, int capacity) {
76 if (!buffer)
77 return false;
78 scoped_refptr<net::WrappedIOBuffer> read_buffer(
79 new net::WrappedIOBuffer(buffer));
xunjieli 2016/04/08 14:43:15 Should we write to |read_buffer_| here, and use th
mef 2016/04/08 16:43:02 I don't think so. By accessing |read_buffer_| only
xunjieli 2016/04/08 17:46:15 Acknowledged.
80
81 environment_->PostToNetworkThread(
82 FROM_HERE, base::Bind(&CronetBidirectionalStream::ReadDataOnNetworkThread,
83 base::Unretained(this), read_buffer, capacity));
84 return true;
85 }
86
87 bool CronetBidirectionalStream::WriteData(const char* buffer,
88 int count,
89 bool end_of_stream) {
90 if (!buffer)
91 return false;
92
93 scoped_refptr<net::WrappedIOBuffer> write_buffer(
94 new net::WrappedIOBuffer(buffer));
xunjieli 2016/04/08 14:43:15 Should we write to |write_buffer_| here, and use t
mef 2016/04/08 16:43:03 ditto.
95
96 environment_->PostToNetworkThread(
97 FROM_HERE,
98 base::Bind(&CronetBidirectionalStream::WriteDataOnNetworkThread,
99 base::Unretained(this), write_buffer, count, end_of_stream));
100 return true;
101 }
102
103 void CronetBidirectionalStream::Cancel() {
104 environment_->PostToNetworkThread(
105 FROM_HERE, base::Bind(&CronetBidirectionalStream::CancelOnNetworkThread,
106 base::Unretained(this)));
107 }
108
109 void CronetBidirectionalStream::Destroy() {
110 // Destroy could be called from any thread, including network thread (if
111 // posting task to executor throws an exception), but is posted, so |this|
112 // is valid until calling task is complete.
113 environment_->PostToNetworkThread(
114 FROM_HERE, base::Bind(&CronetBidirectionalStream::DestroyOnNetworkThread,
115 base::Unretained(this)));
116 }
117
118 void CronetBidirectionalStream::OnHeadersSent() {
119 DCHECK(environment_->IsOnNetworkThread());
120 DCHECK(write_state_ == STARTED);
121 write_state_ = WAITING_FOR_WRITE;
122 if (write_end_of_stream_)
123 write_state_ = WRITING_DONE;
124 delegate_->OnHeadersSent();
125 }
126
127 void CronetBidirectionalStream::OnHeadersReceived(
128 const net::SpdyHeaderBlock& response_headers) {
129 DCHECK(environment_->IsOnNetworkThread());
130 DCHECK(read_state_ == STARTED);
131 read_state_ = WAITING_FOR_READ;
132 // Get http status code from response headers.
133 int http_status_code = 0;
134 const auto http_status_header = response_headers.find(":status");
135 if (http_status_header != response_headers.end())
136 base::StringToInt(http_status_header->second, &http_status_code);
137 const char* protocol = "unknown";
138 switch (bidi_stream_->GetProtocol()) {
139 case net::kProtoHTTP2:
140 protocol = "h2";
141 break;
142 case net::kProtoQUIC1SPDY3:
143 protocol = "quic/1+spdy/3";
144 break;
145 default:
146 break;
147 }
148 delegate_->OnHeadersReceived(response_headers, protocol);
149 }
150
151 void CronetBidirectionalStream::OnDataRead(int bytes_read) {
152 DCHECK(environment_->IsOnNetworkThread());
153 DCHECK(read_state_ == READING);
154 read_state_ = WAITING_FOR_READ;
155 delegate_->OnDataRead(read_buffer_->data(), bytes_read);
156
157 // Free the read buffer.
158 read_buffer_ = nullptr;
159 if (bytes_read == 0)
160 read_state_ = READING_DONE;
161 MaybeOnSucceded();
162 }
163
164 void CronetBidirectionalStream::OnDataSent() {
165 DCHECK(environment_->IsOnNetworkThread());
166 DCHECK(write_state_ == WRITING);
167 write_state_ = WAITING_FOR_WRITE;
168 delegate_->OnDataSent(write_buffer_->data());
169 // Free the write buffer.
170 write_buffer_ = nullptr;
171 if (write_end_of_stream_)
172 write_state_ = WRITING_DONE;
173 MaybeOnSucceded();
174 }
175
176 void CronetBidirectionalStream::OnTrailersReceived(
177 const net::SpdyHeaderBlock& response_trailers) {
178 DCHECK(environment_->IsOnNetworkThread());
179 delegate_->OnTrailersReceived(response_trailers);
180 }
181
182 void CronetBidirectionalStream::OnFailed(int error) {
183 DCHECK(environment_->IsOnNetworkThread());
184 read_state_ = write_state_ = ERROR;
185 delegate_->OnFailed(error);
186 }
187
188 void CronetBidirectionalStream::StartOnNetworkThread(
189 scoped_ptr<net::BidirectionalStreamRequestInfo> request_info) {
190 DCHECK(environment_->IsOnNetworkThread());
191 DCHECK(!bidi_stream_);
192 DCHECK(environment_->GetURLRequestContext());
193 request_info->extra_headers.SetHeaderIfMissing(
194 net::HttpRequestHeaders::kUserAgent, environment_->user_agent());
195 bidi_stream_.reset(new net::BidirectionalStream(
196 std::move(request_info), environment_->GetURLRequestContext()
197 ->http_transaction_factory()
198 ->GetSession(),
199 this));
200 DCHECK(read_state_ == NOT_STARTED && write_state_ == NOT_STARTED);
201 read_state_ = write_state_ = STARTED;
202 }
203
204 void CronetBidirectionalStream::ReadDataOnNetworkThread(
205 scoped_refptr<net::WrappedIOBuffer> read_buffer,
206 int buffer_size) {
207 DCHECK(environment_->IsOnNetworkThread());
208 DCHECK(read_buffer);
209 DCHECK(!read_buffer_);
210 DCHECK(read_state_ == WAITING_FOR_READ);
211 read_state_ = READING;
212
213 read_buffer_ = read_buffer;
214
215 int bytes_read = bidi_stream_->ReadData(read_buffer_.get(), buffer_size);
216 // If IO is pending, wait for the BidirectionalStream to call OnDataRead.
217 if (bytes_read == net::ERR_IO_PENDING)
218 return;
219
220 if (bytes_read < 0) {
221 OnFailed(bytes_read);
222 return;
223 }
224 OnDataRead(bytes_read);
225 }
226
227 void CronetBidirectionalStream::WriteDataOnNetworkThread(
228 scoped_refptr<net::WrappedIOBuffer> write_buffer,
229 int buffer_size,
230 bool end_of_stream) {
231 DCHECK(environment_->IsOnNetworkThread());
232 DCHECK(write_buffer);
233 DCHECK(!write_buffer_);
234 DCHECK(write_state_ == WAITING_FOR_WRITE);
235 write_state_ = WRITING;
236 write_end_of_stream_ = end_of_stream;
237
238 write_buffer_ = write_buffer;
239 bidi_stream_->SendData(write_buffer_.get(), buffer_size, end_of_stream);
240 }
241
242 void CronetBidirectionalStream::CancelOnNetworkThread() {
243 DCHECK(environment_->IsOnNetworkThread());
244 read_state_ = write_state_ = CANCELED;
245 bidi_stream_.reset();
246 delegate_->OnCanceled();
247 }
248
249 void CronetBidirectionalStream::DestroyOnNetworkThread() {
250 DCHECK(environment_->IsOnNetworkThread());
251 delete this;
252 }
253
254 void CronetBidirectionalStream::MaybeOnSucceded() {
255 DCHECK(environment_->IsOnNetworkThread());
256 if (read_state_ == READING_DONE && write_state_ == WRITING_DONE) {
257 read_state_ = write_state_ = SUCCESS;
258 delegate_->OnSucceeded();
259 }
260 }
261
262 } // namespace cronet
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698