OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cronet_bidirectional_stream_adapter.h" | 5 #include "cronet_bidirectional_stream_adapter.h" |
6 | 6 |
7 #include <string> | 7 #include <string> |
8 #include <vector> | 8 #include <vector> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "net/ssl/ssl_info.h" | 27 #include "net/ssl/ssl_info.h" |
28 #include "net/url_request/http_user_agent_settings.h" | 28 #include "net/url_request/http_user_agent_settings.h" |
29 #include "net/url_request/url_request_context.h" | 29 #include "net/url_request/url_request_context.h" |
30 #include "url/gurl.h" | 30 #include "url/gurl.h" |
31 | 31 |
32 using base::android::ConvertUTF8ToJavaString; | 32 using base::android::ConvertUTF8ToJavaString; |
33 using base::android::ConvertJavaStringToUTF8; | 33 using base::android::ConvertJavaStringToUTF8; |
34 | 34 |
35 namespace cronet { | 35 namespace cronet { |
36 | 36 |
| 37 namespace { |
| 38 |
| 39 // As |GetArrayLength| makes no guarantees about the returned value (e.g., it |
| 40 // may be -1 if |array| is not a valid Java array), provide a safe wrapper |
| 41 // that always returns a valid, non-negative size. |
| 42 template <typename JavaArrayType> |
| 43 size_t SafeGetArrayLength(JNIEnv* env, JavaArrayType jarray) { |
| 44 DCHECK(jarray); |
| 45 jsize length = env->GetArrayLength(jarray); |
| 46 DCHECK_GE(length, 0) << "Invalid array length: " << length; |
| 47 return static_cast<size_t>(std::max(0, length)); |
| 48 } |
| 49 |
| 50 } // namespace |
| 51 |
37 static jlong CreateBidirectionalStream( | 52 static jlong CreateBidirectionalStream( |
38 JNIEnv* env, | 53 JNIEnv* env, |
39 const JavaParamRef<jobject>& jbidi_stream, | 54 const base::android::JavaParamRef<jobject>& jbidi_stream, |
40 jlong jurl_request_context_adapter) { | 55 jlong jurl_request_context_adapter, |
| 56 jboolean jdisable_auto_flush) { |
41 CronetURLRequestContextAdapter* context_adapter = | 57 CronetURLRequestContextAdapter* context_adapter = |
42 reinterpret_cast<CronetURLRequestContextAdapter*>( | 58 reinterpret_cast<CronetURLRequestContextAdapter*>( |
43 jurl_request_context_adapter); | 59 jurl_request_context_adapter); |
44 DCHECK(context_adapter); | 60 DCHECK(context_adapter); |
45 | 61 |
46 CronetBidirectionalStreamAdapter* adapter = | 62 CronetBidirectionalStreamAdapter* adapter = |
47 new CronetBidirectionalStreamAdapter(context_adapter, env, jbidi_stream); | 63 new CronetBidirectionalStreamAdapter(context_adapter, env, jbidi_stream, |
| 64 jdisable_auto_flush); |
48 | 65 |
49 return reinterpret_cast<jlong>(adapter); | 66 return reinterpret_cast<jlong>(adapter); |
50 } | 67 } |
51 | 68 |
52 // static | 69 // static |
53 bool CronetBidirectionalStreamAdapter::RegisterJni(JNIEnv* env) { | 70 bool CronetBidirectionalStreamAdapter::RegisterJni(JNIEnv* env) { |
54 return RegisterNativesImpl(env); | 71 return RegisterNativesImpl(env); |
55 } | 72 } |
56 | 73 |
57 CronetBidirectionalStreamAdapter::CronetBidirectionalStreamAdapter( | 74 CronetBidirectionalStreamAdapter::CronetBidirectionalStreamAdapter( |
58 CronetURLRequestContextAdapter* context, | 75 CronetURLRequestContextAdapter* context, |
59 JNIEnv* env, | 76 JNIEnv* env, |
60 const JavaParamRef<jobject>& jbidi_stream) | 77 const base::android::JavaParamRef<jobject>& jbidi_stream, |
61 : context_(context), owner_(env, jbidi_stream), stream_failed_(false) {} | 78 bool disable_auto_flush) |
| 79 : context_(context), |
| 80 owner_(env, jbidi_stream), |
| 81 disable_auto_flush_(disable_auto_flush), |
| 82 write_end_of_stream_(false), |
| 83 stream_failed_(false) {} |
62 | 84 |
63 CronetBidirectionalStreamAdapter::~CronetBidirectionalStreamAdapter() { | 85 CronetBidirectionalStreamAdapter::~CronetBidirectionalStreamAdapter() { |
64 DCHECK(context_->IsOnNetworkThread()); | 86 DCHECK(context_->IsOnNetworkThread()); |
65 } | 87 } |
66 | 88 |
67 jint CronetBidirectionalStreamAdapter::Start( | 89 jint CronetBidirectionalStreamAdapter::Start( |
68 JNIEnv* env, | 90 JNIEnv* env, |
69 const JavaParamRef<jobject>& jcaller, | 91 const base::android::JavaParamRef<jobject>& jcaller, |
70 const JavaParamRef<jstring>& jurl, | 92 const base::android::JavaParamRef<jstring>& jurl, |
71 jint jpriority, | 93 jint jpriority, |
72 const JavaParamRef<jstring>& jmethod, | 94 const base::android::JavaParamRef<jstring>& jmethod, |
73 const JavaParamRef<jobjectArray>& jheaders, | 95 const base::android::JavaParamRef<jobjectArray>& jheaders, |
74 jboolean jend_of_stream) { | 96 jboolean jend_of_stream) { |
75 // Prepare request info here to be able to return the error. | 97 // Prepare request info here to be able to return the error. |
76 std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info( | 98 std::unique_ptr<net::BidirectionalStreamRequestInfo> request_info( |
77 new net::BidirectionalStreamRequestInfo()); | 99 new net::BidirectionalStreamRequestInfo()); |
78 request_info->url = GURL(ConvertJavaStringToUTF8(env, jurl)); | 100 request_info->url = GURL(ConvertJavaStringToUTF8(env, jurl)); |
79 request_info->priority = static_cast<net::RequestPriority>(jpriority); | 101 request_info->priority = static_cast<net::RequestPriority>(jpriority); |
80 // Http method is a token, just as header name. | 102 // Http method is a token, just as header name. |
81 request_info->method = ConvertJavaStringToUTF8(env, jmethod); | 103 request_info->method = ConvertJavaStringToUTF8(env, jmethod); |
82 if (!net::HttpUtil::IsValidHeaderName(request_info->method)) | 104 if (!net::HttpUtil::IsValidHeaderName(request_info->method)) |
83 return -1; | 105 return -1; |
(...skipping 13 matching lines...) Expand all Loading... |
97 | 119 |
98 context_->PostTaskToNetworkThread( | 120 context_->PostTaskToNetworkThread( |
99 FROM_HERE, | 121 FROM_HERE, |
100 base::Bind(&CronetBidirectionalStreamAdapter::StartOnNetworkThread, | 122 base::Bind(&CronetBidirectionalStreamAdapter::StartOnNetworkThread, |
101 base::Unretained(this), base::Passed(&request_info))); | 123 base::Unretained(this), base::Passed(&request_info))); |
102 return 0; | 124 return 0; |
103 } | 125 } |
104 | 126 |
105 jboolean CronetBidirectionalStreamAdapter::ReadData( | 127 jboolean CronetBidirectionalStreamAdapter::ReadData( |
106 JNIEnv* env, | 128 JNIEnv* env, |
107 const JavaParamRef<jobject>& jcaller, | 129 const base::android::JavaParamRef<jobject>& jcaller, |
108 const JavaParamRef<jobject>& jbyte_buffer, | 130 const base::android::JavaParamRef<jobject>& jbyte_buffer, |
109 jint jposition, | 131 jint jposition, |
110 jint jlimit) { | 132 jint jlimit) { |
111 DCHECK_LT(jposition, jlimit); | 133 DCHECK_LT(jposition, jlimit); |
112 | 134 |
113 void* data = env->GetDirectBufferAddress(jbyte_buffer); | 135 void* data = env->GetDirectBufferAddress(jbyte_buffer); |
114 if (!data) | 136 if (!data) |
115 return JNI_FALSE; | 137 return JNI_FALSE; |
116 | 138 |
117 scoped_refptr<IOBufferWithByteBuffer> read_buffer( | 139 scoped_refptr<IOBufferWithByteBuffer> read_buffer( |
118 new IOBufferWithByteBuffer(env, jbyte_buffer, data, jposition, jlimit)); | 140 new IOBufferWithByteBuffer(env, jbyte_buffer, data, jposition, jlimit)); |
119 | 141 |
120 int remaining_capacity = jlimit - jposition; | 142 int remaining_capacity = jlimit - jposition; |
121 | 143 |
122 context_->PostTaskToNetworkThread( | 144 context_->PostTaskToNetworkThread( |
123 FROM_HERE, | 145 FROM_HERE, |
124 base::Bind(&CronetBidirectionalStreamAdapter::ReadDataOnNetworkThread, | 146 base::Bind(&CronetBidirectionalStreamAdapter::ReadDataOnNetworkThread, |
125 base::Unretained(this), read_buffer, remaining_capacity)); | 147 base::Unretained(this), read_buffer, remaining_capacity)); |
126 return JNI_TRUE; | 148 return JNI_TRUE; |
127 } | 149 } |
128 | 150 |
129 jboolean CronetBidirectionalStreamAdapter::WriteData( | 151 jboolean CronetBidirectionalStreamAdapter::WritevData( |
130 JNIEnv* env, | 152 JNIEnv* env, |
131 const JavaParamRef<jobject>& jcaller, | 153 const base::android::JavaParamRef<jobject>& jcaller, |
132 const JavaParamRef<jobject>& jbyte_buffer, | 154 const base::android::JavaParamRef<jobjectArray>& jbyte_buffers, |
133 jint jposition, | 155 const base::android::JavaParamRef<jintArray>& jbyte_buffers_pos, |
134 jint jlimit, | 156 const base::android::JavaParamRef<jintArray>& jbyte_buffers_limit, |
135 jboolean jend_of_stream) { | 157 jboolean jend_of_stream) { |
136 DCHECK_LE(jposition, jlimit); | 158 size_t buffers_array_size = SafeGetArrayLength(env, jbyte_buffers.obj()); |
| 159 size_t pos_array_size = SafeGetArrayLength(env, jbyte_buffers.obj()); |
| 160 size_t limit_array_size = SafeGetArrayLength(env, jbyte_buffers.obj()); |
| 161 if (buffers_array_size != pos_array_size || |
| 162 buffers_array_size != limit_array_size) { |
| 163 DLOG(ERROR) << "Illegal arguments."; |
| 164 return JNI_FALSE; |
| 165 } |
137 | 166 |
138 void* data = env->GetDirectBufferAddress(jbyte_buffer); | 167 IOByteBufferList buffers; |
139 if (!data) | 168 for (size_t i = 0; i < buffers_array_size; ++i) { |
140 return JNI_FALSE; | 169 ScopedJavaLocalRef<jobject> jbuffer( |
141 | 170 env, env->GetObjectArrayElement(jbyte_buffers, i)); |
142 scoped_refptr<IOBufferWithByteBuffer> write_buffer( | 171 void* data = env->GetDirectBufferAddress(jbuffer.obj()); |
143 new IOBufferWithByteBuffer(env, jbyte_buffer, data, jposition, jlimit)); | 172 if (!data) |
144 | 173 return JNI_FALSE; |
145 int remaining_capacity = jlimit - jposition; | 174 jint pos; |
146 | 175 env->GetIntArrayRegion(jbyte_buffers_pos.obj(), i, 1, &pos); |
| 176 jint limit; |
| 177 env->GetIntArrayRegion(jbyte_buffers_limit.obj(), i, 1, &limit); |
| 178 DCHECK_LE(pos, limit); |
| 179 scoped_refptr<IOBufferWithByteBuffer> write_buffer( |
| 180 new IOBufferWithByteBuffer( |
| 181 env, base::android::JavaParamRef<jobject>(env, jbuffer.Release()), |
| 182 data, pos, limit)); |
| 183 buffers.push_back(write_buffer); |
| 184 } |
147 context_->PostTaskToNetworkThread( | 185 context_->PostTaskToNetworkThread( |
148 FROM_HERE, | 186 FROM_HERE, |
149 base::Bind(&CronetBidirectionalStreamAdapter::WriteDataOnNetworkThread, | 187 base::Bind(&CronetBidirectionalStreamAdapter::WritevDataOnNetworkThread, |
150 base::Unretained(this), write_buffer, remaining_capacity, | 188 base::Unretained(this), buffers, jend_of_stream)); |
151 jend_of_stream)); | 189 |
152 return JNI_TRUE; | 190 return JNI_TRUE; |
153 } | 191 } |
154 | 192 |
155 void CronetBidirectionalStreamAdapter::Destroy( | 193 void CronetBidirectionalStreamAdapter::Destroy( |
156 JNIEnv* env, | 194 JNIEnv* env, |
157 const JavaParamRef<jobject>& jcaller, | 195 const base::android::JavaParamRef<jobject>& jcaller, |
158 jboolean jsend_on_canceled) { | 196 jboolean jsend_on_canceled) { |
159 // Destroy could be called from any thread, including network thread (if | 197 // Destroy could be called from any thread, including network thread (if |
160 // posting task to executor throws an exception), but is posted, so |this| | 198 // posting task to executor throws an exception), but is posted, so |this| |
161 // is valid until calling task is complete. Destroy() is always called from | 199 // is valid until calling task is complete. Destroy() is always called from |
162 // within a synchronized java block that guarantees no future posts to the | 200 // within a synchronized java block that guarantees no future posts to the |
163 // network thread with the adapter pointer. | 201 // network thread with the adapter pointer. |
164 context_->PostTaskToNetworkThread( | 202 context_->PostTaskToNetworkThread( |
165 FROM_HERE, | 203 FROM_HERE, |
166 base::Bind(&CronetBidirectionalStreamAdapter::DestroyOnNetworkThread, | 204 base::Bind(&CronetBidirectionalStreamAdapter::DestroyOnNetworkThread, |
167 base::Unretained(this), jsend_on_canceled)); | 205 base::Unretained(this), jsend_on_canceled)); |
168 } | 206 } |
169 | 207 |
170 void CronetBidirectionalStreamAdapter::OnHeadersSent() { | 208 void CronetBidirectionalStreamAdapter::OnStreamReady() { |
171 DCHECK(context_->IsOnNetworkThread()); | 209 DCHECK(context_->IsOnNetworkThread()); |
172 JNIEnv* env = base::android::AttachCurrentThread(); | 210 JNIEnv* env = base::android::AttachCurrentThread(); |
173 cronet::Java_CronetBidirectionalStream_onRequestHeadersSent(env, | 211 cronet::Java_CronetBidirectionalStream_onStreamReady(env, owner_.obj()); |
174 owner_.obj()); | |
175 } | 212 } |
176 | 213 |
177 void CronetBidirectionalStreamAdapter::OnHeadersReceived( | 214 void CronetBidirectionalStreamAdapter::OnHeadersReceived( |
178 const net::SpdyHeaderBlock& response_headers) { | 215 const net::SpdyHeaderBlock& response_headers) { |
179 DCHECK(context_->IsOnNetworkThread()); | 216 DCHECK(context_->IsOnNetworkThread()); |
180 JNIEnv* env = base::android::AttachCurrentThread(); | 217 JNIEnv* env = base::android::AttachCurrentThread(); |
181 // Get http status code from response headers. | 218 // Get http status code from response headers. |
182 jint http_status_code = 0; | 219 jint http_status_code = 0; |
183 const auto http_status_header = response_headers.find(":status"); | 220 const auto http_status_header = response_headers.find(":status"); |
184 if (http_status_header != response_headers.end()) | 221 if (http_status_header != response_headers.end()) |
(...skipping 25 matching lines...) Expand all Loading... |
210 env, owner_.obj(), read_buffer_->byte_buffer(), bytes_read, | 247 env, owner_.obj(), read_buffer_->byte_buffer(), bytes_read, |
211 read_buffer_->initial_position(), read_buffer_->initial_limit(), | 248 read_buffer_->initial_position(), read_buffer_->initial_limit(), |
212 bidi_stream_->GetTotalReceivedBytes()); | 249 bidi_stream_->GetTotalReceivedBytes()); |
213 // Free the read buffer. This lets the Java ByteBuffer be freed, if the | 250 // Free the read buffer. This lets the Java ByteBuffer be freed, if the |
214 // embedder releases it, too. | 251 // embedder releases it, too. |
215 read_buffer_ = nullptr; | 252 read_buffer_ = nullptr; |
216 } | 253 } |
217 | 254 |
218 void CronetBidirectionalStreamAdapter::OnDataSent() { | 255 void CronetBidirectionalStreamAdapter::OnDataSent() { |
219 DCHECK(context_->IsOnNetworkThread()); | 256 DCHECK(context_->IsOnNetworkThread()); |
| 257 DCHECK(!write_buffer_list_.empty()); |
| 258 |
220 JNIEnv* env = base::android::AttachCurrentThread(); | 259 JNIEnv* env = base::android::AttachCurrentThread(); |
221 cronet::Java_CronetBidirectionalStream_onWriteCompleted( | 260 base::android::ScopedJavaLocalRef<jclass> byte_buffer_clazz( |
222 env, owner_.obj(), write_buffer_->byte_buffer(), | 261 env, env->GetObjectClass(write_buffer_list_[0]->byte_buffer())); |
223 write_buffer_->initial_position(), write_buffer_->initial_limit()); | 262 size_t size = write_buffer_list_.size(); |
224 // Free the write buffer. This lets the Java ByteBuffer be freed, if the | 263 jobjectArray jbuffers = |
| 264 env->NewObjectArray(size, byte_buffer_clazz.obj(), NULL); |
| 265 base::android::CheckException(env); |
| 266 std::vector<int> initial_positions; |
| 267 std::vector<int> initial_limits; |
| 268 for (size_t i = 0; i < size; ++i) { |
| 269 env->SetObjectArrayElement(jbuffers, i, |
| 270 write_buffer_list_[i]->byte_buffer()); |
| 271 initial_positions.push_back(write_buffer_list_[i]->initial_position()); |
| 272 initial_limits.push_back(write_buffer_list_[i]->initial_limit()); |
| 273 } |
| 274 ScopedJavaLocalRef<jintArray> jinitial_positions = |
| 275 base::android::ToJavaIntArray(env, initial_positions); |
| 276 ScopedJavaLocalRef<jintArray> jinitial_limits = |
| 277 base::android::ToJavaIntArray(env, initial_limits); |
| 278 // Call into Java. |
| 279 cronet::Java_CronetBidirectionalStream_onWritevCompleted( |
| 280 env, owner_.obj(), jbuffers, jinitial_positions.obj(), |
| 281 jinitial_limits.obj(), write_end_of_stream_); |
| 282 // Free the write buffers. This lets the Java ByteBuffer be freed, if the |
225 // embedder releases it, too. | 283 // embedder releases it, too. |
226 write_buffer_ = nullptr; | 284 write_buffer_list_.clear(); |
227 } | 285 } |
228 | 286 |
229 void CronetBidirectionalStreamAdapter::OnTrailersReceived( | 287 void CronetBidirectionalStreamAdapter::OnTrailersReceived( |
230 const net::SpdyHeaderBlock& response_trailers) { | 288 const net::SpdyHeaderBlock& response_trailers) { |
231 DCHECK(context_->IsOnNetworkThread()); | 289 DCHECK(context_->IsOnNetworkThread()); |
232 JNIEnv* env = base::android::AttachCurrentThread(); | 290 JNIEnv* env = base::android::AttachCurrentThread(); |
233 cronet::Java_CronetBidirectionalStream_onResponseTrailersReceived( | 291 cronet::Java_CronetBidirectionalStream_onResponseTrailersReceived( |
234 env, owner_.obj(), GetHeadersArray(env, response_trailers).obj()); | 292 env, owner_.obj(), GetHeadersArray(env, response_trailers).obj()); |
235 } | 293 } |
236 | 294 |
(...skipping 12 matching lines...) Expand all Loading... |
249 DCHECK(context_->IsOnNetworkThread()); | 307 DCHECK(context_->IsOnNetworkThread()); |
250 DCHECK(!bidi_stream_); | 308 DCHECK(!bidi_stream_); |
251 request_info->extra_headers.SetHeaderIfMissing( | 309 request_info->extra_headers.SetHeaderIfMissing( |
252 net::HttpRequestHeaders::kUserAgent, context_->GetURLRequestContext() | 310 net::HttpRequestHeaders::kUserAgent, context_->GetURLRequestContext() |
253 ->http_user_agent_settings() | 311 ->http_user_agent_settings() |
254 ->GetUserAgent()); | 312 ->GetUserAgent()); |
255 bidi_stream_.reset(new net::BidirectionalStream( | 313 bidi_stream_.reset(new net::BidirectionalStream( |
256 std::move(request_info), context_->GetURLRequestContext() | 314 std::move(request_info), context_->GetURLRequestContext() |
257 ->http_transaction_factory() | 315 ->http_transaction_factory() |
258 ->GetSession(), | 316 ->GetSession(), |
259 this)); | 317 disable_auto_flush_, this)); |
260 } | 318 } |
261 | 319 |
262 void CronetBidirectionalStreamAdapter::ReadDataOnNetworkThread( | 320 void CronetBidirectionalStreamAdapter::ReadDataOnNetworkThread( |
263 scoped_refptr<IOBufferWithByteBuffer> read_buffer, | 321 scoped_refptr<IOBufferWithByteBuffer> read_buffer, |
264 int buffer_size) { | 322 int buffer_size) { |
265 DCHECK(context_->IsOnNetworkThread()); | 323 DCHECK(context_->IsOnNetworkThread()); |
266 DCHECK(read_buffer); | 324 DCHECK(read_buffer); |
267 DCHECK(!read_buffer_); | 325 DCHECK(!read_buffer_); |
268 | 326 |
269 read_buffer_ = read_buffer; | 327 read_buffer_ = read_buffer; |
270 | 328 |
271 int bytes_read = bidi_stream_->ReadData(read_buffer_.get(), buffer_size); | 329 int bytes_read = bidi_stream_->ReadData(read_buffer_.get(), buffer_size); |
272 // If IO is pending, wait for the BidirectionalStream to call OnDataRead. | 330 // If IO is pending, wait for the BidirectionalStream to call OnDataRead. |
273 if (bytes_read == net::ERR_IO_PENDING) | 331 if (bytes_read == net::ERR_IO_PENDING) |
274 return; | 332 return; |
275 | 333 |
276 if (bytes_read < 0) { | 334 if (bytes_read < 0) { |
277 OnFailed(bytes_read); | 335 OnFailed(bytes_read); |
278 return; | 336 return; |
279 } | 337 } |
280 OnDataRead(bytes_read); | 338 OnDataRead(bytes_read); |
281 } | 339 } |
282 | 340 |
283 void CronetBidirectionalStreamAdapter::WriteDataOnNetworkThread( | 341 void CronetBidirectionalStreamAdapter::WritevDataOnNetworkThread( |
284 scoped_refptr<IOBufferWithByteBuffer> write_buffer, | 342 const IOByteBufferList& write_buffer_list, |
285 int buffer_size, | |
286 bool end_of_stream) { | 343 bool end_of_stream) { |
287 DCHECK(context_->IsOnNetworkThread()); | 344 DCHECK(context_->IsOnNetworkThread()); |
288 DCHECK(write_buffer); | 345 DCHECK(write_buffer_list_.empty()); |
289 DCHECK(!write_buffer_); | 346 DCHECK(!write_buffer_list.empty()); |
| 347 DCHECK(!write_end_of_stream_); |
290 | 348 |
291 if (stream_failed_) { | 349 if (stream_failed_) { |
292 // If stream failed between the time when WriteData is invoked and | 350 // If stream failed between the time when WriteData is invoked and |
293 // WriteDataOnNetworkThread is executed, do not call into |bidi_stream_| | 351 // WriteDataOnNetworkThread is executed, do not call into |bidi_stream_| |
294 // since the underlying stream might have been destroyed. Do not invoke | 352 // since the underlying stream might have been destroyed. Do not invoke |
295 // Java callback either, since onError is posted when |stream_failed_| is | 353 // Java callback either, since onError is posted when |stream_failed_| is |
296 // set to true. | 354 // set to true. |
297 return; | 355 return; |
298 } | 356 } |
299 write_buffer_ = write_buffer; | 357 |
300 bidi_stream_->SendData(write_buffer_.get(), buffer_size, end_of_stream); | 358 write_end_of_stream_ = end_of_stream; |
| 359 std::vector<net::IOBuffer*> buffers; |
| 360 std::vector<int> lengths; |
| 361 for (const auto& buffer : write_buffer_list) { |
| 362 write_buffer_list_.push_back(buffer); |
| 363 buffers.push_back(buffer.get()); |
| 364 lengths.push_back(buffer->initial_limit() - buffer->initial_position()); |
| 365 } |
| 366 if (buffers.size() == 1) { |
| 367 bidi_stream_->SendData(buffers[0], lengths[0], end_of_stream); |
| 368 } else { |
| 369 bidi_stream_->SendvData(buffers, lengths, end_of_stream); |
| 370 } |
301 } | 371 } |
302 | 372 |
303 void CronetBidirectionalStreamAdapter::DestroyOnNetworkThread( | 373 void CronetBidirectionalStreamAdapter::DestroyOnNetworkThread( |
304 bool send_on_canceled) { | 374 bool send_on_canceled) { |
305 DCHECK(context_->IsOnNetworkThread()); | 375 DCHECK(context_->IsOnNetworkThread()); |
306 if (send_on_canceled) { | 376 if (send_on_canceled) { |
307 JNIEnv* env = base::android::AttachCurrentThread(); | 377 JNIEnv* env = base::android::AttachCurrentThread(); |
308 cronet::Java_CronetBidirectionalStream_onCanceled(env, owner_.obj()); | 378 cronet::Java_CronetBidirectionalStream_onCanceled(env, owner_.obj()); |
309 } | 379 } |
310 delete this; | 380 delete this; |
311 } | 381 } |
312 | 382 |
313 base::android::ScopedJavaLocalRef<jobjectArray> | 383 base::android::ScopedJavaLocalRef<jobjectArray> |
314 CronetBidirectionalStreamAdapter::GetHeadersArray( | 384 CronetBidirectionalStreamAdapter::GetHeadersArray( |
315 JNIEnv* env, | 385 JNIEnv* env, |
316 const net::SpdyHeaderBlock& header_block) { | 386 const net::SpdyHeaderBlock& header_block) { |
317 DCHECK(context_->IsOnNetworkThread()); | 387 DCHECK(context_->IsOnNetworkThread()); |
318 | 388 |
319 std::vector<std::string> headers; | 389 std::vector<std::string> headers; |
320 for (const auto& header : header_block) { | 390 for (const auto& header : header_block) { |
321 headers.push_back(header.first.as_string()); | 391 headers.push_back(header.first.as_string()); |
322 headers.push_back(header.second.as_string()); | 392 headers.push_back(header.second.as_string()); |
323 } | 393 } |
324 return base::android::ToJavaArrayOfStrings(env, headers); | 394 return base::android::ToJavaArrayOfStrings(env, headers); |
325 } | 395 } |
326 | 396 |
327 } // namespace cronet | 397 } // namespace cronet |
OLD | NEW |