Disable failing PartnerDisableIncognitoModeIntegrationTest#testEnabledParentalControl...
[chromium-blink-merge.git] / components / cronet / android / cronet_url_request_adapter.cc
blobff8e70392dd73ea60b774286811db088709c41c8
1 // Copyright 2014 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.
5 #include "cronet_url_request_adapter.h"
7 #include <limits>
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/logging.h"
12 #include "components/cronet/android/cronet_url_request_context_adapter.h"
13 #include "jni/CronetUrlRequest_jni.h"
14 #include "net/base/io_buffer.h"
15 #include "net/base/load_flags.h"
16 #include "net/base/net_errors.h"
17 #include "net/base/request_priority.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/http/http_status_code.h"
20 #include "net/http/http_util.h"
21 #include "net/url_request/redirect_info.h"
22 #include "net/url_request/url_request_context.h"
24 using base::android::ConvertUTF8ToJavaString;
26 namespace cronet {
28 // Explicitly register static JNI functions.
29 bool CronetUrlRequestAdapterRegisterJni(JNIEnv* env) {
30 return RegisterNativesImpl(env);
33 static jlong CreateRequestAdapter(JNIEnv* env,
34 jobject jurl_request,
35 jlong jurl_request_context_adapter,
36 jstring jurl_string,
37 jint jpriority) {
38 CronetURLRequestContextAdapter* context_adapter =
39 reinterpret_cast<CronetURLRequestContextAdapter*>(
40 jurl_request_context_adapter);
41 DCHECK(context_adapter);
43 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl_string));
45 VLOG(1) << "New chromium network request_adapter: "
46 << url.possibly_invalid_spec();
48 CronetURLRequestAdapter* adapter =
49 new CronetURLRequestAdapter(context_adapter, env, jurl_request, url,
50 static_cast<net::RequestPriority>(jpriority));
52 return reinterpret_cast<jlong>(adapter);
55 // net::WrappedIOBuffer subclass for a buffer owned by a Java ByteBuffer. Keeps
56 // the ByteBuffer alive until destroyed. Uses WrappedIOBuffer because data() is
57 // owned by the embedder.
58 class CronetURLRequestAdapter::IOBufferWithByteBuffer
59 : public net::WrappedIOBuffer {
60 public:
61 // Creates a buffer wrapping the Java ByteBuffer |jbyte_buffer|. |data| points
62 // to the memory backed by the ByteBuffer, and position is the location to
63 // start writing.
64 IOBufferWithByteBuffer(
65 JNIEnv* env,
66 jobject jbyte_buffer,
67 void* data,
68 int position)
69 : net::WrappedIOBuffer(static_cast<char*>(data) + position),
70 initial_position_(position) {
71 DCHECK(data);
72 DCHECK_EQ(env->GetDirectBufferAddress(jbyte_buffer), data);
73 byte_buffer_.Reset(env, jbyte_buffer);
76 int initial_position() const { return initial_position_; }
78 jobject byte_buffer() const { return byte_buffer_.obj(); }
80 private:
81 ~IOBufferWithByteBuffer() override {}
83 base::android::ScopedJavaGlobalRef<jobject> byte_buffer_;
85 const int initial_position_;
88 CronetURLRequestAdapter::CronetURLRequestAdapter(
89 CronetURLRequestContextAdapter* context,
90 JNIEnv* env,
91 jobject jurl_request,
92 const GURL& url,
93 net::RequestPriority priority)
94 : context_(context),
95 initial_url_(url),
96 initial_priority_(priority),
97 initial_method_("GET"),
98 load_flags_(context->default_load_flags()) {
99 DCHECK(!context_->IsOnNetworkThread());
100 owner_.Reset(env, jurl_request);
103 CronetURLRequestAdapter::~CronetURLRequestAdapter() {
104 DCHECK(context_->IsOnNetworkThread());
107 jboolean CronetURLRequestAdapter::SetHttpMethod(JNIEnv* env,
108 jobject jcaller,
109 jstring jmethod) {
110 DCHECK(!context_->IsOnNetworkThread());
111 std::string method(base::android::ConvertJavaStringToUTF8(env, jmethod));
112 // Http method is a token, just as header name.
113 if (!net::HttpUtil::IsValidHeaderName(method))
114 return JNI_FALSE;
115 initial_method_ = method;
116 return JNI_TRUE;
119 jboolean CronetURLRequestAdapter::AddRequestHeader(JNIEnv* env,
120 jobject jcaller,
121 jstring jname,
122 jstring jvalue) {
123 DCHECK(!context_->IsOnNetworkThread());
124 std::string name(base::android::ConvertJavaStringToUTF8(env, jname));
125 std::string value(base::android::ConvertJavaStringToUTF8(env, jvalue));
126 if (!net::HttpUtil::IsValidHeaderName(name) ||
127 !net::HttpUtil::IsValidHeaderValue(value)) {
128 return JNI_FALSE;
130 initial_request_headers_.SetHeader(name, value);
131 return JNI_TRUE;
134 void CronetURLRequestAdapter::DisableCache(JNIEnv* env, jobject jcaller) {
135 DCHECK(!context_->IsOnNetworkThread());
136 load_flags_ |= net::LOAD_DISABLE_CACHE;
139 void CronetURLRequestAdapter::SetUpload(
140 scoped_ptr<net::UploadDataStream> upload) {
141 DCHECK(!context_->IsOnNetworkThread());
142 DCHECK(!upload_);
143 upload_ = upload.Pass();
146 void CronetURLRequestAdapter::Start(JNIEnv* env, jobject jcaller) {
147 DCHECK(!context_->IsOnNetworkThread());
148 context_->PostTaskToNetworkThread(
149 FROM_HERE, base::Bind(&CronetURLRequestAdapter::StartOnNetworkThread,
150 base::Unretained(this)));
153 void CronetURLRequestAdapter::GetStatus(JNIEnv* env,
154 jobject jcaller,
155 jobject jstatus_listener) const {
156 DCHECK(!context_->IsOnNetworkThread());
157 base::android::ScopedJavaGlobalRef<jobject> status_listener_ref;
158 status_listener_ref.Reset(env, jstatus_listener);
159 context_->PostTaskToNetworkThread(
160 FROM_HERE, base::Bind(&CronetURLRequestAdapter::GetStatusOnNetworkThread,
161 base::Unretained(this), status_listener_ref));
164 void CronetURLRequestAdapter::FollowDeferredRedirect(JNIEnv* env,
165 jobject jcaller) {
166 DCHECK(!context_->IsOnNetworkThread());
167 context_->PostTaskToNetworkThread(
168 FROM_HERE,
169 base::Bind(
170 &CronetURLRequestAdapter::FollowDeferredRedirectOnNetworkThread,
171 base::Unretained(this)));
174 jboolean CronetURLRequestAdapter::ReadData(
175 JNIEnv* env, jobject jcaller, jobject jbyte_buffer, jint jposition,
176 jint jcapacity) {
177 DCHECK(!context_->IsOnNetworkThread());
178 DCHECK_LT(jposition, jcapacity);
180 void* data = env->GetDirectBufferAddress(jbyte_buffer);
181 if (!data)
182 return JNI_FALSE;
184 scoped_refptr<IOBufferWithByteBuffer> read_buffer(
185 new IOBufferWithByteBuffer(env, jbyte_buffer, data, jposition));
187 int remaining_capacity = jcapacity - jposition;
189 context_->PostTaskToNetworkThread(
190 FROM_HERE, base::Bind(&CronetURLRequestAdapter::ReadDataOnNetworkThread,
191 base::Unretained(this),
192 read_buffer,
193 remaining_capacity));
194 return JNI_TRUE;
197 void CronetURLRequestAdapter::Destroy(JNIEnv* env, jobject jcaller) {
198 // Destroy could be called from any thread, including network thread (if
199 // posting task to executor throws an exception), but is posted, so |this|
200 // is valid until calling task is complete. Destroy() is always called from
201 // within a synchronized java block that guarantees no future posts to the
202 // network thread with the adapter pointer.
203 context_->PostTaskToNetworkThread(
204 FROM_HERE, base::Bind(&CronetURLRequestAdapter::DestroyOnNetworkThread,
205 base::Unretained(this)));
208 void CronetURLRequestAdapter::PopulateResponseHeaders(JNIEnv* env,
209 jobject jurl_request,
210 jobject jheaders_list) {
211 DCHECK(context_->IsOnNetworkThread());
212 const net::HttpResponseHeaders* headers = url_request_->response_headers();
213 if (headers == nullptr)
214 return;
216 void* iter = nullptr;
217 std::string header_name;
218 std::string header_value;
219 while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) {
220 base::android::ScopedJavaLocalRef<jstring> name =
221 ConvertUTF8ToJavaString(env, header_name);
222 base::android::ScopedJavaLocalRef<jstring> value =
223 ConvertUTF8ToJavaString(env, header_value);
224 Java_CronetUrlRequest_onAppendResponseHeader(
225 env, jurl_request, jheaders_list, name.obj(), value.obj());
229 base::android::ScopedJavaLocalRef<jstring>
230 CronetURLRequestAdapter::GetHttpStatusText(JNIEnv* env, jobject jcaller) const {
231 DCHECK(context_->IsOnNetworkThread());
232 const net::HttpResponseHeaders* headers = url_request_->response_headers();
233 return ConvertUTF8ToJavaString(env, headers->GetStatusText());
236 base::android::ScopedJavaLocalRef<jstring>
237 CronetURLRequestAdapter::GetNegotiatedProtocol(JNIEnv* env,
238 jobject jcaller) const {
239 DCHECK(context_->IsOnNetworkThread());
240 return ConvertUTF8ToJavaString(
241 env, url_request_->response_info().npn_negotiated_protocol);
244 base::android::ScopedJavaLocalRef<jstring>
245 CronetURLRequestAdapter::GetProxyServer(JNIEnv* env,
246 jobject jcaller) const {
247 DCHECK(context_->IsOnNetworkThread());
248 return ConvertUTF8ToJavaString(
249 env, url_request_->response_info().proxy_server.ToString());
252 jboolean CronetURLRequestAdapter::GetWasCached(JNIEnv* env,
253 jobject jcaller) const {
254 DCHECK(context_->IsOnNetworkThread());
255 return url_request_->response_info().was_cached;
258 // net::URLRequest::Delegate overrides (called on network thread).
260 void CronetURLRequestAdapter::OnReceivedRedirect(
261 net::URLRequest* request,
262 const net::RedirectInfo& redirect_info,
263 bool* defer_redirect) {
264 DCHECK(context_->IsOnNetworkThread());
265 DCHECK(request->status().is_success());
266 JNIEnv* env = base::android::AttachCurrentThread();
267 cronet::Java_CronetUrlRequest_onReceivedRedirect(
268 env, owner_.obj(),
269 ConvertUTF8ToJavaString(env, redirect_info.new_url.spec()).obj(),
270 redirect_info.status_code);
271 *defer_redirect = true;
274 void CronetURLRequestAdapter::OnResponseStarted(net::URLRequest* request) {
275 DCHECK(context_->IsOnNetworkThread());
276 if (MaybeReportError(request))
277 return;
278 JNIEnv* env = base::android::AttachCurrentThread();
279 cronet::Java_CronetUrlRequest_onResponseStarted(env, owner_.obj(),
280 request->GetResponseCode());
283 void CronetURLRequestAdapter::OnReadCompleted(net::URLRequest* request,
284 int bytes_read) {
285 DCHECK(context_->IsOnNetworkThread());
286 if (MaybeReportError(request))
287 return;
288 if (bytes_read != 0) {
289 JNIEnv* env = base::android::AttachCurrentThread();
290 cronet::Java_CronetUrlRequest_onReadCompleted(
291 env, owner_.obj(), read_buffer_->byte_buffer(), bytes_read,
292 read_buffer_->initial_position());
293 // Free the read buffer. This lets the Java ByteBuffer be freed, if the
294 // embedder releases it, too.
295 read_buffer_ = nullptr;
296 } else {
297 JNIEnv* env = base::android::AttachCurrentThread();
298 cronet::Java_CronetUrlRequest_onSucceeded(
299 env, owner_.obj(), url_request_->GetTotalReceivedBytes());
303 void CronetURLRequestAdapter::StartOnNetworkThread() {
304 DCHECK(context_->IsOnNetworkThread());
305 VLOG(1) << "Starting chromium request: "
306 << initial_url_.possibly_invalid_spec().c_str()
307 << " priority: " << RequestPriorityToString(initial_priority_);
308 url_request_ = context_->GetURLRequestContext()->CreateRequest(
309 initial_url_, net::DEFAULT_PRIORITY, this);
310 url_request_->SetLoadFlags(load_flags_);
311 url_request_->set_method(initial_method_);
312 url_request_->SetExtraRequestHeaders(initial_request_headers_);
313 url_request_->SetPriority(initial_priority_);
314 if (upload_)
315 url_request_->set_upload(upload_.Pass());
316 url_request_->Start();
319 void CronetURLRequestAdapter::GetStatusOnNetworkThread(
320 const base::android::ScopedJavaGlobalRef<jobject>& status_listener_ref)
321 const {
322 DCHECK(context_->IsOnNetworkThread());
323 JNIEnv* env = base::android::AttachCurrentThread();
324 cronet::Java_CronetUrlRequest_onStatus(env, owner_.obj(),
325 status_listener_ref.obj(),
326 url_request_->GetLoadState().state);
329 void CronetURLRequestAdapter::FollowDeferredRedirectOnNetworkThread() {
330 DCHECK(context_->IsOnNetworkThread());
331 url_request_->FollowDeferredRedirect();
334 void CronetURLRequestAdapter::ReadDataOnNetworkThread(
335 scoped_refptr<IOBufferWithByteBuffer> read_buffer,
336 int buffer_size) {
337 DCHECK(context_->IsOnNetworkThread());
338 DCHECK(read_buffer);
339 DCHECK(!read_buffer_);
341 read_buffer_ = read_buffer;
343 int bytes_read = 0;
344 url_request_->Read(read_buffer_.get(), buffer_size, &bytes_read);
345 // If IO is pending, wait for the URLRequest to call OnReadCompleted.
346 if (url_request_->status().is_io_pending())
347 return;
349 OnReadCompleted(url_request_.get(), bytes_read);
352 void CronetURLRequestAdapter::DestroyOnNetworkThread() {
353 DCHECK(context_->IsOnNetworkThread());
354 delete this;
357 bool CronetURLRequestAdapter::MaybeReportError(net::URLRequest* request) const {
358 DCHECK_NE(net::URLRequestStatus::IO_PENDING, url_request_->status().status());
359 DCHECK_EQ(request, url_request_);
360 if (url_request_->status().is_success())
361 return false;
362 int net_error = url_request_->status().error();
363 VLOG(1) << "Error " << net::ErrorToString(net_error)
364 << " on chromium request: " << initial_url_.possibly_invalid_spec();
365 JNIEnv* env = base::android::AttachCurrentThread();
366 cronet::Java_CronetUrlRequest_onError(
367 env, owner_.obj(), net_error,
368 ConvertUTF8ToJavaString(env, net::ErrorToString(net_error)).obj());
369 return true;
372 } // namespace cronet