OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "components/cronet/android/cronet_url_request.h" | |
6 | |
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" | |
19 | |
20 using base::android::ConvertUTF8ToJavaString; | |
21 | |
22 // This file contains all the plumbing to handle the bidirectional communication | |
23 // between the Java CronetURLRequest and C++ CronetURLRequestAdapter. | |
24 | |
25 namespace cronet { | |
26 namespace { | |
27 | |
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 | |
30 // Network thread. | |
31 class JniCronetURLRequestAdapterDelegate | |
32 : public CronetURLRequestAdapter::CronetURLRequestAdapterDelegate { | |
33 public: | |
34 JniCronetURLRequestAdapterDelegate(JNIEnv* env, jobject owner) { | |
35 owner_.Reset(env, owner); | |
36 } | |
37 | |
38 // CronetURLRequestAdapter::CronetURLRequestAdapterDelegate implementation. | |
39 | |
40 void OnRedirect(const GURL& new_location, int http_status_code) override { | |
41 JNIEnv* env = base::android::AttachCurrentThread(); | |
42 cronet::Java_CronetUrlRequest_onRedirect( | |
43 env, | |
44 owner_.obj(), | |
45 ConvertUTF8ToJavaString(env, new_location.spec()).obj(), | |
46 http_status_code); | |
47 } | |
48 | |
49 void OnResponseStarted(int http_status_code) override { | |
50 JNIEnv* env = base::android::AttachCurrentThread(); | |
51 cronet::Java_CronetUrlRequest_onResponseStarted(env, | |
52 owner_.obj(), | |
53 http_status_code); | |
54 } | |
55 | |
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()); | |
63 } | |
64 | |
65 void OnRequestFinished() override { | |
66 JNIEnv* env = base::android::AttachCurrentThread(); | |
67 cronet::Java_CronetUrlRequest_onSucceeded(env, owner_.obj()); | |
68 } | |
69 | |
70 void OnError(int net_error) override { | |
71 JNIEnv* env = base::android::AttachCurrentThread(); | |
72 cronet::Java_CronetUrlRequest_onError( | |
73 env, | |
74 owner_.obj(), | |
75 net_error, | |
76 ConvertUTF8ToJavaString(env, net::ErrorToString(net_error)).obj()); | |
77 } | |
78 | |
79 private: | |
80 ~JniCronetURLRequestAdapterDelegate() override { | |
81 } | |
82 | |
83 // Java object that owns the CronetURLRequestContextAdapter, which owns this | |
84 // delegate. | |
85 base::android::ScopedJavaGlobalRef<jobject> owner_; | |
86 | |
87 DISALLOW_COPY_AND_ASSIGN(JniCronetURLRequestAdapterDelegate); | |
88 }; | |
89 | |
90 } // namespace | |
91 | |
92 // Explicitly register static JNI functions. | |
93 bool CronetUrlRequestRegisterJni(JNIEnv* env) { | |
94 return RegisterNativesImpl(env); | |
95 } | |
96 | |
97 static jlong CreateRequestAdapter(JNIEnv* env, | |
98 jobject jurl_request, | |
99 jlong jurl_request_context_adapter, | |
100 jstring jurl_string, | |
101 jint jpriority) { | |
102 CronetURLRequestContextAdapter* context_adapter = | |
103 reinterpret_cast<CronetURLRequestContextAdapter*>( | |
104 jurl_request_context_adapter); | |
105 DCHECK(context_adapter); | |
106 | |
107 GURL url(base::android::ConvertJavaStringToUTF8(env, jurl_string)); | |
108 | |
109 VLOG(1) << "New chromium network request_adapter: " | |
110 << url.possibly_invalid_spec(); | |
111 | |
112 scoped_ptr<CronetURLRequestAdapter::CronetURLRequestAdapterDelegate> delegate( | |
113 new JniCronetURLRequestAdapterDelegate(env, jurl_request)); | |
114 | |
115 CronetURLRequestAdapter* adapter = new CronetURLRequestAdapter( | |
116 context_adapter, | |
117 delegate.Pass(), | |
118 url, | |
119 static_cast<net::RequestPriority>(jpriority)); | |
120 | |
121 return reinterpret_cast<jlong>(adapter); | |
122 } | |
123 | |
124 static jboolean SetHttpMethod(JNIEnv* env, | |
125 jobject jurl_request, | |
126 jlong jurl_request_adapter, | |
127 jstring jmethod) { | |
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)) | |
135 return JNI_FALSE; | |
136 request_adapter->set_method(method); | |
137 return JNI_TRUE; | |
138 } | |
139 | |
140 static jboolean AddHeader(JNIEnv* env, | |
141 jobject jurl_request, | |
142 jlong jurl_request_adapter, | |
143 jstring jname, | |
144 jstring jvalue) { | |
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)) { | |
153 return JNI_FALSE; | |
154 } | |
155 request_adapter->AddRequestHeader(name, value); | |
156 return JNI_TRUE; | |
157 } | |
158 | |
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( | |
167 FROM_HERE, | |
168 base::Bind(&CronetURLRequestAdapter::Start, | |
169 base::Unretained(request_adapter))); | |
170 } | |
171 | |
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( | |
180 FROM_HERE, | |
181 base::Bind(&CronetURLRequestAdapter::Destroy, | |
182 base::Unretained(request_adapter))); | |
183 } | |
184 | |
185 static void ReceiveData(JNIEnv* env, | |
186 jobject jcaller, | |
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( | |
193 FROM_HERE, | |
194 base::Bind(&CronetURLRequestAdapter::ReadData, | |
195 base::Unretained(request_adapter))); | |
196 } | |
197 | |
198 static void FollowDeferredRedirect(JNIEnv* env, | |
199 jobject jcaller, | |
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( | |
206 FROM_HERE, | |
207 base::Bind(&CronetURLRequestAdapter::FollowDeferredRedirect, | |
208 base::Unretained(request_adapter))); | |
209 } | |
210 | |
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(); | |
219 } | |
220 | |
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()); | |
229 | |
230 const net::HttpResponseHeaders* headers = | |
231 request_adapter->GetResponseHeaders(); | |
232 if (headers == nullptr) | |
233 return; | |
234 | |
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()); | |
245 } | |
246 } | |
247 | |
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(); | |
257 } | |
258 | |
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; | |
267 } | |
268 | |
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(); | |
277 } | |
278 | |
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 if (headers == NULL) | |
289 return ConvertUTF8ToJavaString(env, "").Release(); | |
290 return ConvertUTF8ToJavaString(env, headers->GetStatusText()).Release(); | |
291 } | |
292 | |
293 } // namespace cronet | |
OLD | NEW |