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 "components/cronet/android/cronet_url_request.h"
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_string.h"
9 #include "base/android/scoped_java_ref.h"
10 #include "base/logging.h"
11 #include "base/macros.h"
12 #include "components/cronet/android/cronet_url_request_adapter.h"
13 #include "components/cronet/android/cronet_url_request_context_adapter.h"
14 #include "jni/CronetUrlRequest_jni.h"
15 #include "net/base/net_errors.h"
16 #include "net/base/request_priority.h"
17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_util.h"
20 using base::android::ConvertUTF8ToJavaString
;
22 // This file contains all the plumbing to handle the bidirectional communication
23 // between the Java CronetURLRequest and C++ CronetURLRequestAdapter.
28 // A delegate of CronetURLRequestAdapter that delivers callbacks to the Java
29 // layer. Created on a Java thread, but always called and destroyed on the
31 class JniCronetURLRequestAdapterDelegate
32 : public CronetURLRequestAdapter::CronetURLRequestAdapterDelegate
{
34 JniCronetURLRequestAdapterDelegate(JNIEnv
* env
, jobject owner
) {
35 owner_
.Reset(env
, owner
);
38 // CronetURLRequestAdapter::CronetURLRequestAdapterDelegate implementation.
40 void OnRedirect(const GURL
& new_location
, int http_status_code
) override
{
41 JNIEnv
* env
= base::android::AttachCurrentThread();
42 cronet::Java_CronetUrlRequest_onRedirect(
45 ConvertUTF8ToJavaString(env
, new_location
.spec()).obj(),
49 void OnResponseStarted(int http_status_code
) override
{
50 JNIEnv
* env
= base::android::AttachCurrentThread();
51 cronet::Java_CronetUrlRequest_onResponseStarted(env
,
56 void OnBytesRead(unsigned char* bytes
,
57 int bytes_read
) override
{
58 JNIEnv
* env
= base::android::AttachCurrentThread();
59 base::android::ScopedJavaLocalRef
<jobject
> java_buffer(
60 env
, env
->NewDirectByteBuffer(bytes
, bytes_read
));
61 cronet::Java_CronetUrlRequest_onDataReceived(
62 env
, owner_
.obj(), java_buffer
.obj());
65 void OnRequestFinished() override
{
66 JNIEnv
* env
= base::android::AttachCurrentThread();
67 cronet::Java_CronetUrlRequest_onSucceeded(env
, owner_
.obj());
70 void OnError(int net_error
) override
{
71 JNIEnv
* env
= base::android::AttachCurrentThread();
72 cronet::Java_CronetUrlRequest_onError(
76 ConvertUTF8ToJavaString(env
, net::ErrorToString(net_error
)).obj());
80 ~JniCronetURLRequestAdapterDelegate() override
{
83 // Java object that owns the CronetURLRequestContextAdapter, which owns this
85 base::android::ScopedJavaGlobalRef
<jobject
> owner_
;
87 DISALLOW_COPY_AND_ASSIGN(JniCronetURLRequestAdapterDelegate
);
92 // Explicitly register static JNI functions.
93 bool CronetUrlRequestRegisterJni(JNIEnv
* env
) {
94 return RegisterNativesImpl(env
);
97 static jlong
CreateRequestAdapter(JNIEnv
* env
,
99 jlong jurl_request_context_adapter
,
102 CronetURLRequestContextAdapter
* context_adapter
=
103 reinterpret_cast<CronetURLRequestContextAdapter
*>(
104 jurl_request_context_adapter
);
105 DCHECK(context_adapter
);
107 GURL
url(base::android::ConvertJavaStringToUTF8(env
, jurl_string
));
109 VLOG(1) << "New chromium network request_adapter: "
110 << url
.possibly_invalid_spec();
112 scoped_ptr
<CronetURLRequestAdapter::CronetURLRequestAdapterDelegate
> delegate(
113 new JniCronetURLRequestAdapterDelegate(env
, jurl_request
));
115 CronetURLRequestAdapter
* adapter
= new CronetURLRequestAdapter(
119 static_cast<net::RequestPriority
>(jpriority
));
121 return reinterpret_cast<jlong
>(adapter
);
124 static jboolean
SetHttpMethod(JNIEnv
* env
,
125 jobject jurl_request
,
126 jlong jurl_request_adapter
,
128 DCHECK(jurl_request_adapter
);
129 CronetURLRequestAdapter
* request_adapter
=
130 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
131 DCHECK(!request_adapter
->IsOnNetworkThread());
132 std::string
method(base::android::ConvertJavaStringToUTF8(env
, jmethod
));
133 // Http method is a token, just as header name.
134 if (!net::HttpUtil::IsValidHeaderName(method
))
136 request_adapter
->set_method(method
);
140 static jboolean
AddHeader(JNIEnv
* env
,
141 jobject jurl_request
,
142 jlong jurl_request_adapter
,
145 DCHECK(jurl_request_adapter
);
146 CronetURLRequestAdapter
* request_adapter
=
147 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
148 DCHECK(!request_adapter
->IsOnNetworkThread());
149 std::string
name(base::android::ConvertJavaStringToUTF8(env
, jname
));
150 std::string
value(base::android::ConvertJavaStringToUTF8(env
, jvalue
));
151 if (!net::HttpUtil::IsValidHeaderName(name
) ||
152 !net::HttpUtil::IsValidHeaderValue(value
)) {
155 request_adapter
->AddRequestHeader(name
, value
);
159 static void Start(JNIEnv
* env
,
160 jobject jurl_request
,
161 jlong jurl_request_adapter
) {
162 DCHECK(jurl_request_adapter
);
163 CronetURLRequestAdapter
* request_adapter
=
164 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
165 DCHECK(!request_adapter
->IsOnNetworkThread());
166 request_adapter
->PostTaskToNetworkThread(
168 base::Bind(&CronetURLRequestAdapter::Start
,
169 base::Unretained(request_adapter
)));
172 static void DestroyRequestAdapter(JNIEnv
* env
,
173 jobject jurl_request
,
174 jlong jurl_request_adapter
) {
175 DCHECK(jurl_request_adapter
);
176 CronetURLRequestAdapter
* request_adapter
=
177 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
178 DCHECK(!request_adapter
->IsOnNetworkThread());
179 request_adapter
->PostTaskToNetworkThread(
181 base::Bind(&CronetURLRequestAdapter::Destroy
,
182 base::Unretained(request_adapter
)));
185 static void ReceiveData(JNIEnv
* env
,
187 jlong jurl_request_adapter
) {
188 DCHECK(jurl_request_adapter
);
189 CronetURLRequestAdapter
* request_adapter
=
190 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
191 DCHECK(!request_adapter
->IsOnNetworkThread());
192 request_adapter
->PostTaskToNetworkThread(
194 base::Bind(&CronetURLRequestAdapter::ReadData
,
195 base::Unretained(request_adapter
)));
198 static void FollowDeferredRedirect(JNIEnv
* env
,
200 jlong jurl_request_adapter
) {
201 DCHECK(jurl_request_adapter
);
202 CronetURLRequestAdapter
* request_adapter
=
203 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
204 DCHECK(!request_adapter
->IsOnNetworkThread());
205 request_adapter
->PostTaskToNetworkThread(
207 base::Bind(&CronetURLRequestAdapter::FollowDeferredRedirect
,
208 base::Unretained(request_adapter
)));
211 static void DisableCache(JNIEnv
* env
,
212 jobject jurl_request
,
213 jlong jurl_request_adapter
) {
214 DCHECK(jurl_request_adapter
);
215 CronetURLRequestAdapter
* request_adapter
=
216 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
217 DCHECK(!request_adapter
->IsOnNetworkThread());
218 request_adapter
->DisableCache();
221 static void PopulateResponseHeaders(JNIEnv
* env
,
222 jobject jurl_request
,
223 jlong jurl_request_adapter
,
224 jobject jheaders_list
) {
225 DCHECK(jurl_request_adapter
);
226 CronetURLRequestAdapter
* request_adapter
=
227 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
228 DCHECK(request_adapter
->IsOnNetworkThread());
230 const net::HttpResponseHeaders
* headers
=
231 request_adapter
->GetResponseHeaders();
232 if (headers
== nullptr)
235 void* iter
= nullptr;
236 std::string header_name
;
237 std::string header_value
;
238 while (headers
->EnumerateHeaderLines(&iter
, &header_name
, &header_value
)) {
239 ScopedJavaLocalRef
<jstring
> name
=
240 ConvertUTF8ToJavaString(env
, header_name
);
241 ScopedJavaLocalRef
<jstring
> value
=
242 ConvertUTF8ToJavaString(env
, header_value
);
243 Java_CronetUrlRequest_onAppendResponseHeader(
244 env
, jurl_request
, jheaders_list
, name
.obj(), value
.obj());
248 static jstring
GetNegotiatedProtocol(JNIEnv
* env
,
249 jobject jurl_request
,
250 jlong jurl_request_adapter
) {
251 DCHECK(jurl_request_adapter
);
252 CronetURLRequestAdapter
* request_adapter
=
253 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
254 DCHECK(request_adapter
->IsOnNetworkThread());
255 return ConvertUTF8ToJavaString(
256 env
, request_adapter
->GetNegotiatedProtocol()).Release();
259 static jboolean
GetWasCached(JNIEnv
* env
,
260 jobject jurl_request
,
261 jlong jurl_request_adapter
) {
262 DCHECK(jurl_request_adapter
);
263 CronetURLRequestAdapter
* request_adapter
=
264 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
265 DCHECK(request_adapter
->IsOnNetworkThread());
266 return request_adapter
->GetWasCached() ? JNI_TRUE
: JNI_FALSE
;
269 static jlong
GetTotalReceivedBytes(JNIEnv
* env
,
270 jobject jurl_request
,
271 jlong jurl_request_adapter
) {
272 DCHECK(jurl_request_adapter
);
273 CronetURLRequestAdapter
* request_adapter
=
274 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
275 DCHECK(request_adapter
->IsOnNetworkThread());
276 return request_adapter
->GetTotalReceivedBytes();
279 static jstring
GetHttpStatusText(JNIEnv
* env
,
280 jobject jurl_request
,
281 jlong jurl_request_adapter
) {
282 DCHECK(jurl_request_adapter
);
283 CronetURLRequestAdapter
* request_adapter
=
284 reinterpret_cast<CronetURLRequestAdapter
*>(jurl_request_adapter
);
285 DCHECK(request_adapter
->IsOnNetworkThread());
286 const net::HttpResponseHeaders
* headers
=
287 request_adapter
->GetResponseHeaders();
288 return ConvertUTF8ToJavaString(env
, headers
->GetStatusText()).Release();
291 } // namespace cronet