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

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: Address comments, bundle libboringssl.a into libcronet.a 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 <string>
8 #include <vector>
9
10 #include "base/bind.h"
11 #include "base/location.h"
12 #include "base/logging.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.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::CronetBidirectionalStream(
36 CronetEnvironment* environment,
37 Delegate* delegate)
38 : read_state_(NOT_STARTED),
39 write_state_(NOT_STARTED),
40 write_end_of_stream_(false),
41 environment_(environment),
42 delegate_(delegate) {}
43
44 CronetBidirectionalStream::~CronetBidirectionalStream() {
45 DCHECK(environment_->IsOnNetworkThread());
46 }
47
48 int CronetBidirectionalStream::Start(const char* url,
49 int priority,
50 const char* method,
51 const net::HttpRequestHeaders& headers,
52 bool end_of_stream) {
53 // Prepare request info here to be able to return the error.
54 scoped_ptr<net::BidirectionalStreamRequestInfo> request_info(
55 new net::BidirectionalStreamRequestInfo());
56 request_info->url = GURL(url);
57 request_info->priority = static_cast<net::RequestPriority>(priority);
58 // Http method is a token, just as header name.
59 request_info->method = method;
60 if (!net::HttpUtil::IsValidHeaderName(request_info->method))
61 return -1;
62 request_info->extra_headers.CopyFrom(headers);
63 request_info->end_stream_on_headers = end_of_stream;
64 write_end_of_stream_ = end_of_stream;
65 DCHECK(environment_);
66 environment_->PostToNetworkThread(
67 FROM_HERE,
68 base::Bind(&CronetBidirectionalStream::StartOnNetworkThread,
69 base::Unretained(this), base::Passed(&request_info)));
70 return 0;
71 }
72
73 bool CronetBidirectionalStream::ReadData(char* buffer, int capacity) {
74 if (!buffer)
75 return false;
76 scoped_refptr<net::WrappedIOBuffer> read_buffer(
77 new net::WrappedIOBuffer(buffer));
78
79 environment_->PostToNetworkThread(
80 FROM_HERE, base::Bind(&CronetBidirectionalStream::ReadDataOnNetworkThread,
81 base::Unretained(this), read_buffer, capacity));
82 return true;
83 }
84
85 bool CronetBidirectionalStream::WriteData(const char* buffer,
86 int count,
87 bool end_of_stream) {
88 if (!buffer)
89 return false;
90
91 scoped_refptr<net::WrappedIOBuffer> write_buffer(
92 new net::WrappedIOBuffer(buffer));
93
94 environment_->PostToNetworkThread(
95 FROM_HERE,
96 base::Bind(&CronetBidirectionalStream::WriteDataOnNetworkThread,
97 base::Unretained(this), write_buffer, count, end_of_stream));
98 return true;
99 }
100
101 void CronetBidirectionalStream::Cancel() {
102 environment_->PostToNetworkThread(
103 FROM_HERE, base::Bind(&CronetBidirectionalStream::CancelOnNetworkThread,
104 base::Unretained(this)));
105 }
106
107 void CronetBidirectionalStream::Destroy() {
108 // Destroy could be called from any thread, including network thread (if
109 // posting task to executor throws an exception), but is posted, so |this|
110 // is valid until calling task is complete.
111 environment_->PostToNetworkThread(
112 FROM_HERE, base::Bind(&CronetBidirectionalStream::DestroyOnNetworkThread,
113 base::Unretained(this)));
114 }
115
116 void CronetBidirectionalStream::OnHeadersSent() {
117 DCHECK(environment_->IsOnNetworkThread());
118 DCHECK(write_state_ == STARTED);
119 write_state_ = WAITING_FOR_WRITE;
120 if (write_end_of_stream_)
121 write_state_ = WRITING_DONE;
122 delegate_->OnHeadersSent();
123 }
124
125 void CronetBidirectionalStream::OnHeadersReceived(
126 const net::SpdyHeaderBlock& response_headers) {
127 DCHECK(environment_->IsOnNetworkThread());
128 DCHECK(read_state_ == STARTED);
129 read_state_ = WAITING_FOR_READ;
130 // Get http status code from response headers.
131 int http_status_code = 0;
132 const auto http_status_header = response_headers.find(":status");
133 if (http_status_header != response_headers.end())
134 base::StringToInt(http_status_header->second, &http_status_code);
135 const char* protocol = "unknown";
136 switch (bidi_stream_->GetProtocol()) {
137 case net::kProtoHTTP2:
138 protocol = "h2";
139 break;
140 case net::kProtoQUIC1SPDY3:
141 protocol = "quic/1+spdy/3";
142 break;
143 default:
144 break;
145 }
146 delegate_->OnHeadersReceived(response_headers, protocol);
147 }
148
149 void CronetBidirectionalStream::OnDataRead(int bytes_read) {
150 DCHECK(environment_->IsOnNetworkThread());
151 DCHECK(read_state_ == READING);
152 read_state_ = WAITING_FOR_READ;
153 delegate_->OnDataRead(read_buffer_->data(), bytes_read);
154
155 // Free the read buffer.
156 read_buffer_ = nullptr;
157 if (bytes_read == 0)
158 read_state_ = READING_DONE;
159 MaybeOnSucceded();
160 }
161
162 void CronetBidirectionalStream::OnDataSent() {
163 DCHECK(environment_->IsOnNetworkThread());
164 DCHECK(write_state_ == WRITING);
165 write_state_ = WAITING_FOR_WRITE;
166 delegate_->OnDataSent(write_buffer_->data());
167 // Free the write buffer.
168 write_buffer_ = nullptr;
169 if (write_end_of_stream_)
170 write_state_ = WRITING_DONE;
171 MaybeOnSucceded();
172 }
173
174 void CronetBidirectionalStream::OnTrailersReceived(
175 const net::SpdyHeaderBlock& response_trailers) {
176 DCHECK(environment_->IsOnNetworkThread());
177 delegate_->OnTrailersReceived(response_trailers);
178 }
179
180 void CronetBidirectionalStream::OnFailed(int error) {
181 DCHECK(environment_->IsOnNetworkThread());
182 bidi_stream_.reset();
183 read_state_ = write_state_ = ERROR;
184 delegate_->OnFailed(error);
185 }
186
187 void CronetBidirectionalStream::StartOnNetworkThread(
188 scoped_ptr<net::BidirectionalStreamRequestInfo> request_info) {
189 DCHECK(environment_->IsOnNetworkThread());
190 DCHECK(!bidi_stream_);
191 DCHECK(environment_->GetURLRequestContext());
192 request_info->extra_headers.SetHeaderIfMissing(
193 net::HttpRequestHeaders::kUserAgent, environment_->user_agent());
194 bidi_stream_.reset(new net::BidirectionalStream(
195 std::move(request_info), environment_->GetURLRequestContext()
196 ->http_transaction_factory()
197 ->GetSession(),
198 this));
199 DCHECK(read_state_ == NOT_STARTED && write_state_ == NOT_STARTED);
200 read_state_ = write_state_ = STARTED;
201 }
202
203 void CronetBidirectionalStream::ReadDataOnNetworkThread(
204 scoped_refptr<net::WrappedIOBuffer> read_buffer,
205 int buffer_size) {
206 DCHECK(environment_->IsOnNetworkThread());
207 DCHECK(read_buffer);
208 DCHECK(!read_buffer_);
209 if (read_state_ != WAITING_FOR_READ) {
210 DLOG(ERROR) << "Unexpected Read Data in read_state " << WAITING_FOR_READ;
211 OnFailed(net::ERR_UNEXPECTED);
212 return;
213 }
214 read_state_ = READING;
215 read_buffer_ = read_buffer;
216
217 int bytes_read = bidi_stream_->ReadData(read_buffer_.get(), buffer_size);
218 // If IO is pending, wait for the BidirectionalStream to call OnDataRead.
219 if (bytes_read == net::ERR_IO_PENDING)
220 return;
221
222 if (bytes_read < 0) {
223 OnFailed(bytes_read);
224 return;
225 }
226 OnDataRead(bytes_read);
227 }
228
229 void CronetBidirectionalStream::WriteDataOnNetworkThread(
230 scoped_refptr<net::WrappedIOBuffer> write_buffer,
231 int buffer_size,
232 bool end_of_stream) {
233 DCHECK(environment_->IsOnNetworkThread());
234 DCHECK(write_buffer);
235 DCHECK(!write_buffer_);
236 if (write_state_ != WAITING_FOR_WRITE) {
237 DLOG(ERROR) << "Unexpected Write Data in write_state " << write_state_;
238 OnFailed(net::ERR_UNEXPECTED);
239 return;
240 }
241 write_state_ = WRITING;
242 write_end_of_stream_ = end_of_stream;
243
244 write_buffer_ = write_buffer;
245 bidi_stream_->SendData(write_buffer_.get(), buffer_size, end_of_stream);
246 }
247
248 void CronetBidirectionalStream::CancelOnNetworkThread() {
249 DCHECK(environment_->IsOnNetworkThread());
250 if (!bidi_stream_)
251 return;
252 read_state_ = write_state_ = CANCELED;
253 bidi_stream_.reset();
254 delegate_->OnCanceled();
255 }
256
257 void CronetBidirectionalStream::DestroyOnNetworkThread() {
258 DCHECK(environment_->IsOnNetworkThread());
259 delete this;
260 }
261
262 void CronetBidirectionalStream::MaybeOnSucceded() {
263 DCHECK(environment_->IsOnNetworkThread());
264 if (read_state_ == READING_DONE && write_state_ == WRITING_DONE) {
265 read_state_ = write_state_ = SUCCESS;
266 bidi_stream_.reset();
267 delegate_->OnSucceeded();
268 }
269 }
270
271 } // namespace cronet
OLDNEW
« no previous file with comments | « components/cronet/ios/cronet_bidirectional_stream.h ('k') | components/cronet/ios/cronet_c_for_grpc.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698