| 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 |