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 PopulateResponseHeaders(JNIEnv* env, |
| 212 jobject jurl_request, |
| 213 jlong jurl_request_adapter, |
| 214 jobject jheaders_map) { |
| 215 DCHECK(jurl_request_adapter); |
| 216 CronetURLRequestAdapter* request_adapter = |
| 217 reinterpret_cast<CronetURLRequestAdapter*>(jurl_request_adapter); |
| 218 DCHECK(request_adapter->IsOnNetworkThread()); |
| 219 |
| 220 const net::HttpResponseHeaders* headers = |
| 221 request_adapter->GetResponseHeaders(); |
| 222 if (headers == nullptr) |
| 223 return; |
| 224 |
| 225 void* iter = nullptr; |
| 226 std::string header_name; |
| 227 std::string header_value; |
| 228 while (headers->EnumerateHeaderLines(&iter, &header_name, &header_value)) { |
| 229 ScopedJavaLocalRef<jstring> name = |
| 230 ConvertUTF8ToJavaString(env, header_name); |
| 231 ScopedJavaLocalRef<jstring> value = |
| 232 ConvertUTF8ToJavaString(env, header_value); |
| 233 Java_CronetUrlRequest_onAppendResponseHeader( |
| 234 env, jurl_request, jheaders_map, name.obj(), value.obj()); |
| 235 } |
| 236 } |
| 237 |
| 238 static jstring GetNegotiatedProtocol(JNIEnv* env, |
| 239 jobject jurl_request, |
| 240 jlong jurl_request_adapter) { |
| 241 DCHECK(jurl_request_adapter); |
| 242 CronetURLRequestAdapter* request_adapter = |
| 243 reinterpret_cast<CronetURLRequestAdapter*>(jurl_request_adapter); |
| 244 DCHECK(request_adapter->IsOnNetworkThread()); |
| 245 return ConvertUTF8ToJavaString( |
| 246 env, request_adapter->GetNegotiatedProtocol()).Release(); |
| 247 } |
| 248 |
| 249 static jboolean GetWasCached(JNIEnv* env, |
| 250 jobject jurl_request, |
| 251 jlong jurl_request_adapter) { |
| 252 DCHECK(jurl_request_adapter); |
| 253 CronetURLRequestAdapter* request_adapter = |
| 254 reinterpret_cast<CronetURLRequestAdapter*>(jurl_request_adapter); |
| 255 DCHECK(request_adapter->IsOnNetworkThread()); |
| 256 return request_adapter->GetWasCached() ? JNI_TRUE : JNI_FALSE; |
| 257 } |
| 258 |
| 259 static jlong GetTotalReceivedBytes(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->GetTotalReceivedBytes(); |
| 267 } |
| 268 |
| 269 } // namespace cronet |
OLD | NEW |