1 // Copyright (c) 2013 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 "android_webview/native/aw_contents_client_bridge.h" 6 7 #include "base/android/jni_android.h" 8 #include "base/android/jni_array.h" 9 #include "base/android/jni_string.h" 10 #include "base/callback.h" 11 #include "content/public/browser/browser_thread.h" 12 #include "jni/AwContentsClientBridge_jni.h" 13 #include "net/cert/x509_certificate.h" 14 #include "url/gurl.h" 15 16 using base::android::AttachCurrentThread; 17 using base::android::ConvertJavaStringToUTF16; 18 using base::android::ConvertUTF8ToJavaString; 19 using base::android::ConvertUTF16ToJavaString; 20 using base::android::JavaRef; 21 using base::android::ScopedJavaLocalRef; 22 using content::BrowserThread; 23 24 namespace android_webview { 25 26 AwContentsClientBridge::AwContentsClientBridge(JNIEnv* env, jobject obj) 27 : java_ref_(env, obj) { 28 DCHECK(obj); 29 Java_AwContentsClientBridge_setNativeContentsClientBridge( 30 env, obj, reinterpret_cast<intptr_t>(this)); 31 } 32 33 AwContentsClientBridge::~AwContentsClientBridge() { 34 JNIEnv* env = AttachCurrentThread(); 35 36 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 37 if (obj.is_null()) 38 return; 39 // Clear the weak reference from the java peer to the native object since 40 // it is possible that java object lifetime can exceed the AwContens. 41 Java_AwContentsClientBridge_setNativeContentsClientBridge(env, obj.obj(), 0); 42 } 43 44 void AwContentsClientBridge::AllowCertificateError( 45 int cert_error, 46 net::X509Certificate* cert, 47 const GURL& request_url, 48 const base::Callback<void(bool)>& callback, 49 bool* cancel_request) { 50 51 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 52 JNIEnv* env = AttachCurrentThread(); 53 54 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 55 if (obj.is_null()) 56 return; 57 58 std::string der_string; 59 net::X509Certificate::GetDEREncoded(cert->os_cert_handle(), &der_string); 60 ScopedJavaLocalRef<jbyteArray> jcert = base::android::ToJavaByteArray( 61 env, 62 reinterpret_cast<const uint8*>(der_string.data()), 63 der_string.length()); 64 ScopedJavaLocalRef<jstring> jurl(ConvertUTF8ToJavaString( 65 env, request_url.spec())); 66 // We need to add the callback before making the call to java side, 67 // as it may do a synchronous callback prior to returning. 68 int request_id = pending_cert_error_callbacks_.Add( 69 new CertErrorCallback(callback)); 70 *cancel_request = !Java_AwContentsClientBridge_allowCertificateError( 71 env, obj.obj(), cert_error, jcert.obj(), jurl.obj(), request_id); 72 // if the request is cancelled, then cancel the stored callback 73 if (*cancel_request) { 74 pending_cert_error_callbacks_.Remove(request_id); 75 } 76 } 77 78 void AwContentsClientBridge::ProceedSslError(JNIEnv* env, jobject obj, 79 jboolean proceed, jint id) { 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 81 CertErrorCallback* callback = pending_cert_error_callbacks_.Lookup(id); 82 if (!callback || callback->is_null()) { 83 LOG(WARNING) << "Ignoring unexpected ssl error proceed callback"; 84 return; 85 } 86 callback->Run(proceed); 87 pending_cert_error_callbacks_.Remove(id); 88 } 89 90 void AwContentsClientBridge::RunJavaScriptDialog( 91 content::JavaScriptMessageType message_type, 92 const GURL& origin_url, 93 const string16& message_text, 94 const string16& default_prompt_text, 95 const content::JavaScriptDialogManager::DialogClosedCallback& callback) { 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 97 JNIEnv* env = AttachCurrentThread(); 98 99 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 100 if (obj.is_null()) 101 return; 102 103 int callback_id = pending_js_dialog_callbacks_.Add( 104 new content::JavaScriptDialogManager::DialogClosedCallback(callback)); 105 ScopedJavaLocalRef<jstring> jurl( 106 ConvertUTF8ToJavaString(env, origin_url.spec())); 107 ScopedJavaLocalRef<jstring> jmessage( 108 ConvertUTF16ToJavaString(env, message_text)); 109 110 switch (message_type) { 111 case content::JAVASCRIPT_MESSAGE_TYPE_ALERT: 112 Java_AwContentsClientBridge_handleJsAlert( 113 env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id); 114 break; 115 case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM: 116 Java_AwContentsClientBridge_handleJsConfirm( 117 env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id); 118 break; 119 case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT: { 120 ScopedJavaLocalRef<jstring> jdefault_value( 121 ConvertUTF16ToJavaString(env, default_prompt_text)); 122 Java_AwContentsClientBridge_handleJsPrompt(env, 123 obj.obj(), 124 jurl.obj(), 125 jmessage.obj(), 126 jdefault_value.obj(), 127 callback_id); 128 break; 129 } 130 default: 131 NOTREACHED(); 132 } 133 } 134 135 void AwContentsClientBridge::RunBeforeUnloadDialog( 136 const GURL& origin_url, 137 const string16& message_text, 138 const content::JavaScriptDialogManager::DialogClosedCallback& callback) { 139 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 140 JNIEnv* env = AttachCurrentThread(); 141 142 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 143 if (obj.is_null()) 144 return; 145 146 int callback_id = pending_js_dialog_callbacks_.Add( 147 new content::JavaScriptDialogManager::DialogClosedCallback(callback)); 148 ScopedJavaLocalRef<jstring> jurl( 149 ConvertUTF8ToJavaString(env, origin_url.spec())); 150 ScopedJavaLocalRef<jstring> jmessage( 151 ConvertUTF16ToJavaString(env, message_text)); 152 153 Java_AwContentsClientBridge_handleJsBeforeUnload( 154 env, obj.obj(), jurl.obj(), jmessage.obj(), callback_id); 155 } 156 157 bool AwContentsClientBridge::ShouldOverrideUrlLoading( 158 const base::string16& url) { 159 JNIEnv* env = AttachCurrentThread(); 160 ScopedJavaLocalRef<jobject> obj = java_ref_.get(env); 161 if (obj.is_null()) 162 return false; 163 ScopedJavaLocalRef<jstring> jurl = ConvertUTF16ToJavaString(env, url); 164 return Java_AwContentsClientBridge_shouldOverrideUrlLoading( 165 env, obj.obj(), 166 jurl.obj()); 167 } 168 169 void AwContentsClientBridge::ConfirmJsResult(JNIEnv* env, 170 jobject, 171 int id, 172 jstring prompt) { 173 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 174 content::JavaScriptDialogManager::DialogClosedCallback* callback = 175 pending_js_dialog_callbacks_.Lookup(id); 176 if (!callback) { 177 LOG(WARNING) << "Unexpected JS dialog confirm. " << id; 178 return; 179 } 180 string16 prompt_text; 181 if (prompt) { 182 prompt_text = ConvertJavaStringToUTF16(env, prompt); 183 } 184 callback->Run(true, prompt_text); 185 pending_js_dialog_callbacks_.Remove(id); 186 } 187 188 void AwContentsClientBridge::CancelJsResult(JNIEnv*, jobject, int id) { 189 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 190 content::JavaScriptDialogManager::DialogClosedCallback* callback = 191 pending_js_dialog_callbacks_.Lookup(id); 192 if (!callback) { 193 LOG(WARNING) << "Unexpected JS dialog cancel. " << id; 194 return; 195 } 196 callback->Run(false, string16()); 197 pending_js_dialog_callbacks_.Remove(id); 198 } 199 200 bool RegisterAwContentsClientBridge(JNIEnv* env) { 201 return RegisterNativesImpl(env) >= 0; 202 } 203 204 } // namespace android_webview 205