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/browser/aw_contents_client_bridge.h"
6 
7 #include <memory>
8 #include <utility>
9 
10 #include "android_webview/browser_jni_headers/AwContentsClientBridge_jni.h"
11 #include "android_webview/common/devtools_instrumentation.h"
12 #include "android_webview/grit/components_strings.h"
13 #include "base/android/jni_android.h"
14 #include "base/android/jni_array.h"
15 #include "base/android/jni_string.h"
16 #include "base/macros.h"
17 #include "base/memory/ref_counted.h"
18 #include "base/task/current_thread.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/client_certificate_delegate.h"
21 #include "content/public/browser/render_frame_host.h"
22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/web_contents.h"
24 #include "net/cert/x509_certificate.h"
25 #include "net/cert/x509_util.h"
26 #include "net/http/http_response_headers.h"
27 #include "net/ssl/ssl_cert_request_info.h"
28 #include "net/ssl/ssl_client_cert_type.h"
29 #include "net/ssl/ssl_platform_key_android.h"
30 #include "net/ssl/ssl_private_key.h"
31 #include "ui/base/l10n/l10n_util.h"
32 #include "url/gurl.h"
33 
34 using base::android::AttachCurrentThread;
35 using base::android::ConvertJavaStringToUTF16;
36 using base::android::ConvertUTF8ToJavaString;
37 using base::android::ConvertUTF16ToJavaString;
38 using base::android::HasException;
39 using base::android::JavaRef;
40 using base::android::ScopedJavaLocalRef;
41 using base::android::ToJavaArrayOfStrings;
42 using content::BrowserThread;
43 using content::WebContents;
44 using std::vector;
45 
46 namespace android_webview {
47 
48 namespace {
49 
50 const void* const kAwContentsClientBridge = &kAwContentsClientBridge;
51 
52 // This class is invented so that the UserData registry that we inject the
53 // AwContentsClientBridge object does not own and destroy it.
54 class UserData : public base::SupportsUserData::Data {
55  public:
GetContents(content::WebContents * web_contents)56   static AwContentsClientBridge* GetContents(
57       content::WebContents* web_contents) {
58     if (!web_contents)
59       return NULL;
60     UserData* data = static_cast<UserData*>(
61         web_contents->GetUserData(kAwContentsClientBridge));
62     return data ? data->contents_ : NULL;
63   }
64 
UserData(AwContentsClientBridge * ptr)65   explicit UserData(AwContentsClientBridge* ptr) : contents_(ptr) {}
66 
67  private:
68   AwContentsClientBridge* contents_;
69 
70   DISALLOW_COPY_AND_ASSIGN(UserData);
71 };
72 
73 }  // namespace
74 
HttpErrorInfo()75 AwContentsClientBridge::HttpErrorInfo::HttpErrorInfo() : status_code(0) {}
76 
~HttpErrorInfo()77 AwContentsClientBridge::HttpErrorInfo::~HttpErrorInfo() {}
78 
79 // static
Associate(WebContents * web_contents,AwContentsClientBridge * handler)80 void AwContentsClientBridge::Associate(WebContents* web_contents,
81                                        AwContentsClientBridge* handler) {
82   web_contents->SetUserData(kAwContentsClientBridge,
83                             std::make_unique<UserData>(handler));
84 }
85 
86 // static
Dissociate(WebContents * web_contents)87 void AwContentsClientBridge::Dissociate(WebContents* web_contents) {
88   web_contents->RemoveUserData(kAwContentsClientBridge);
89 }
90 
91 // static
FromWebContents(WebContents * web_contents)92 AwContentsClientBridge* AwContentsClientBridge::FromWebContents(
93     WebContents* web_contents) {
94   return UserData::GetContents(web_contents);
95 }
96 
97 // static
FromWebContentsGetter(const content::WebContents::Getter & web_contents_getter)98 AwContentsClientBridge* AwContentsClientBridge::FromWebContentsGetter(
99     const content::WebContents::Getter& web_contents_getter) {
100   DCHECK_CURRENTLY_ON(BrowserThread::UI);
101   WebContents* web_contents = web_contents_getter.Run();
102   return UserData::GetContents(web_contents);
103 }
104 
105 // static
FromID(int render_process_id,int render_frame_id)106 AwContentsClientBridge* AwContentsClientBridge::FromID(int render_process_id,
107                                                        int render_frame_id) {
108   DCHECK_CURRENTLY_ON(BrowserThread::UI);
109   content::RenderFrameHost* rfh =
110       content::RenderFrameHost::FromID(render_process_id, render_frame_id);
111   content::WebContents* web_contents =
112       content::WebContents::FromRenderFrameHost(rfh);
113   return UserData::GetContents(web_contents);
114 }
115 
AwContentsClientBridge(JNIEnv * env,const JavaRef<jobject> & obj)116 AwContentsClientBridge::AwContentsClientBridge(JNIEnv* env,
117                                                const JavaRef<jobject>& obj)
118     : java_ref_(env, obj) {
119   DCHECK(obj);
120   Java_AwContentsClientBridge_setNativeContentsClientBridge(
121       env, obj, reinterpret_cast<intptr_t>(this));
122 }
123 
~AwContentsClientBridge()124 AwContentsClientBridge::~AwContentsClientBridge() {
125   JNIEnv* env = AttachCurrentThread();
126 
127   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
128   if (obj) {
129     // Clear the weak reference from the java peer to the native object since
130     // it is possible that java object lifetime can exceed the AwContens.
131     Java_AwContentsClientBridge_setNativeContentsClientBridge(env, obj, 0);
132   }
133 }
134 
AllowCertificateError(int cert_error,net::X509Certificate * cert,const GURL & request_url,CertErrorCallback callback,bool * cancel_request)135 void AwContentsClientBridge::AllowCertificateError(int cert_error,
136                                                    net::X509Certificate* cert,
137                                                    const GURL& request_url,
138                                                    CertErrorCallback callback,
139                                                    bool* cancel_request) {
140   DCHECK_CURRENTLY_ON(BrowserThread::UI);
141   JNIEnv* env = AttachCurrentThread();
142 
143   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
144   if (!obj)
145     return;
146 
147   base::StringPiece der_string =
148       net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer());
149   ScopedJavaLocalRef<jbyteArray> jcert = base::android::ToJavaByteArray(
150       env, reinterpret_cast<const uint8_t*>(der_string.data()),
151       der_string.length());
152   ScopedJavaLocalRef<jstring> jurl(
153       ConvertUTF8ToJavaString(env, request_url.spec()));
154   // We need to add the callback before making the call to java side,
155   // as it may do a synchronous callback prior to returning.
156   int request_id = pending_cert_error_callbacks_.Add(
157       std::make_unique<CertErrorCallback>(std::move(callback)));
158   *cancel_request = !Java_AwContentsClientBridge_allowCertificateError(
159       env, obj, cert_error, jcert, jurl, request_id);
160   // if the request is cancelled, then cancel the stored callback
161   if (*cancel_request) {
162     pending_cert_error_callbacks_.Remove(request_id);
163   }
164 }
165 
ProceedSslError(JNIEnv * env,const JavaRef<jobject> & obj,jboolean proceed,jint id)166 void AwContentsClientBridge::ProceedSslError(JNIEnv* env,
167                                              const JavaRef<jobject>& obj,
168                                              jboolean proceed,
169                                              jint id) {
170   DCHECK_CURRENTLY_ON(BrowserThread::UI);
171   CertErrorCallback* callback = pending_cert_error_callbacks_.Lookup(id);
172   if (!callback || callback->is_null()) {
173     LOG(WARNING) << "Ignoring unexpected ssl error proceed callback";
174     return;
175   }
176   std::move(*callback).Run(
177       proceed ? content::CERTIFICATE_REQUEST_RESULT_TYPE_CONTINUE
178               : content::CERTIFICATE_REQUEST_RESULT_TYPE_CANCEL);
179   pending_cert_error_callbacks_.Remove(id);
180 }
181 
182 // This method is inspired by SelectClientCertificate() in
183 // components/browser_ui/client_certificate/android/
184 // ssl_client_certificate_request.cc
SelectClientCertificate(net::SSLCertRequestInfo * cert_request_info,std::unique_ptr<content::ClientCertificateDelegate> delegate)185 void AwContentsClientBridge::SelectClientCertificate(
186     net::SSLCertRequestInfo* cert_request_info,
187     std::unique_ptr<content::ClientCertificateDelegate> delegate) {
188   DCHECK_CURRENTLY_ON(BrowserThread::UI);
189 
190   JNIEnv* env = base::android::AttachCurrentThread();
191   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
192   if (!obj)
193     return;
194 
195   // Build the |key_types| JNI parameter, as a String[]
196   std::vector<std::string> key_types;
197   for (size_t i = 0; i < cert_request_info->cert_key_types.size(); ++i) {
198     switch (cert_request_info->cert_key_types[i]) {
199       case net::CLIENT_CERT_RSA_SIGN:
200         key_types.push_back("RSA");
201         break;
202       case net::CLIENT_CERT_ECDSA_SIGN:
203         key_types.push_back("ECDSA");
204         break;
205       default:
206         // Ignore unknown types.
207         break;
208     }
209   }
210 
211   ScopedJavaLocalRef<jobjectArray> key_types_ref =
212       base::android::ToJavaArrayOfStrings(env, key_types);
213   if (!key_types_ref) {
214     LOG(ERROR) << "Could not create key types array (String[])";
215     return;
216   }
217 
218   // Build the |encoded_principals| JNI parameter, as a byte[][]
219   ScopedJavaLocalRef<jobjectArray> principals_ref =
220       base::android::ToJavaArrayOfByteArray(
221           env, cert_request_info->cert_authorities);
222   if (!principals_ref) {
223     LOG(ERROR) << "Could not create principals array (byte[][])";
224     return;
225   }
226 
227   // Build the |host_name| and |port| JNI parameters, as a String and
228   // a jint.
229   ScopedJavaLocalRef<jstring> host_name_ref =
230       base::android::ConvertUTF8ToJavaString(
231           env, cert_request_info->host_and_port.host());
232 
233   int request_id =
234       pending_client_cert_request_delegates_.Add(std::move(delegate));
235   Java_AwContentsClientBridge_selectClientCertificate(
236       env, obj, request_id, key_types_ref, principals_ref, host_name_ref,
237       cert_request_info->host_and_port.port());
238 }
239 
240 // This method is inspired by OnSystemRequestCompletion() in
241 // components/browser_ui/client_certificate/android/
242 // ssl_client_certificate_request.cc
ProvideClientCertificateResponse(JNIEnv * env,const JavaRef<jobject> & obj,int request_id,const JavaRef<jobjectArray> & encoded_chain_ref,const JavaRef<jobject> & private_key_ref)243 void AwContentsClientBridge::ProvideClientCertificateResponse(
244     JNIEnv* env,
245     const JavaRef<jobject>& obj,
246     int request_id,
247     const JavaRef<jobjectArray>& encoded_chain_ref,
248     const JavaRef<jobject>& private_key_ref) {
249   DCHECK_CURRENTLY_ON(BrowserThread::UI);
250 
251   std::unique_ptr<content::ClientCertificateDelegate> delegate =
252       pending_client_cert_request_delegates_.Replace(request_id, nullptr);
253   pending_client_cert_request_delegates_.Remove(request_id);
254   DCHECK(delegate);
255 
256   if (!encoded_chain_ref || !private_key_ref) {
257     LOG(ERROR) << "No client certificate selected";
258     delegate->ContinueWithCertificate(nullptr, nullptr);
259     return;
260   }
261 
262   // Convert the encoded chain to a vector of strings.
263   std::vector<std::string> encoded_chain_strings;
264   if (encoded_chain_ref) {
265     base::android::JavaArrayOfByteArrayToStringVector(env, encoded_chain_ref,
266                                                       &encoded_chain_strings);
267   }
268 
269   std::vector<base::StringPiece> encoded_chain;
270   for (size_t i = 0; i < encoded_chain_strings.size(); ++i)
271     encoded_chain.push_back(encoded_chain_strings[i]);
272 
273   // Create the X509Certificate object from the encoded chain.
274   scoped_refptr<net::X509Certificate> client_cert(
275       net::X509Certificate::CreateFromDERCertChain(encoded_chain));
276   if (!client_cert.get()) {
277     LOG(ERROR) << "Could not decode client certificate chain";
278     return;
279   }
280 
281   // Create an SSLPrivateKey wrapper for the private key JNI reference.
282   scoped_refptr<net::SSLPrivateKey> private_key =
283       net::WrapJavaPrivateKey(client_cert.get(), private_key_ref);
284   if (!private_key) {
285     LOG(ERROR) << "Could not create OpenSSL wrapper for private key";
286     return;
287   }
288 
289   delegate->ContinueWithCertificate(std::move(client_cert),
290                                     std::move(private_key));
291 }
292 
RunJavaScriptDialog(content::JavaScriptDialogType dialog_type,const GURL & origin_url,const base::string16 & message_text,const base::string16 & default_prompt_text,content::JavaScriptDialogManager::DialogClosedCallback callback)293 void AwContentsClientBridge::RunJavaScriptDialog(
294     content::JavaScriptDialogType dialog_type,
295     const GURL& origin_url,
296     const base::string16& message_text,
297     const base::string16& default_prompt_text,
298     content::JavaScriptDialogManager::DialogClosedCallback callback) {
299   DCHECK_CURRENTLY_ON(BrowserThread::UI);
300   JNIEnv* env = AttachCurrentThread();
301 
302   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
303   if (!obj) {
304     std::move(callback).Run(false, base::string16());
305     return;
306   }
307 
308   int callback_id = pending_js_dialog_callbacks_.Add(
309       std::make_unique<content::JavaScriptDialogManager::DialogClosedCallback>(
310           std::move(callback)));
311   ScopedJavaLocalRef<jstring> jurl(
312       ConvertUTF8ToJavaString(env, origin_url.spec()));
313   ScopedJavaLocalRef<jstring> jmessage(
314       ConvertUTF16ToJavaString(env, message_text));
315 
316   switch (dialog_type) {
317     case content::JAVASCRIPT_DIALOG_TYPE_ALERT: {
318       devtools_instrumentation::ScopedEmbedderCallbackTask("onJsAlert");
319       Java_AwContentsClientBridge_handleJsAlert(env, obj, jurl, jmessage,
320                                                 callback_id);
321       break;
322     }
323     case content::JAVASCRIPT_DIALOG_TYPE_CONFIRM: {
324       devtools_instrumentation::ScopedEmbedderCallbackTask("onJsConfirm");
325       Java_AwContentsClientBridge_handleJsConfirm(env, obj, jurl, jmessage,
326                                                   callback_id);
327       break;
328     }
329     case content::JAVASCRIPT_DIALOG_TYPE_PROMPT: {
330       ScopedJavaLocalRef<jstring> jdefault_value(
331           ConvertUTF16ToJavaString(env, default_prompt_text));
332       devtools_instrumentation::ScopedEmbedderCallbackTask("onJsPrompt");
333       Java_AwContentsClientBridge_handleJsPrompt(env, obj, jurl, jmessage,
334                                                  jdefault_value, callback_id);
335       break;
336     }
337     default:
338       NOTREACHED();
339   }
340 }
341 
RunBeforeUnloadDialog(const GURL & origin_url,content::JavaScriptDialogManager::DialogClosedCallback callback)342 void AwContentsClientBridge::RunBeforeUnloadDialog(
343     const GURL& origin_url,
344     content::JavaScriptDialogManager::DialogClosedCallback callback) {
345   DCHECK_CURRENTLY_ON(BrowserThread::UI);
346   JNIEnv* env = AttachCurrentThread();
347 
348   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
349   if (!obj) {
350     std::move(callback).Run(false, base::string16());
351     return;
352   }
353 
354   const base::string16 message_text =
355       l10n_util::GetStringUTF16(IDS_BEFOREUNLOAD_MESSAGEBOX_MESSAGE);
356 
357   int callback_id = pending_js_dialog_callbacks_.Add(
358       std::make_unique<content::JavaScriptDialogManager::DialogClosedCallback>(
359           std::move(callback)));
360   ScopedJavaLocalRef<jstring> jurl(
361       ConvertUTF8ToJavaString(env, origin_url.spec()));
362   ScopedJavaLocalRef<jstring> jmessage(
363       ConvertUTF16ToJavaString(env, message_text));
364 
365   devtools_instrumentation::ScopedEmbedderCallbackTask("onJsBeforeUnload");
366   Java_AwContentsClientBridge_handleJsBeforeUnload(env, obj, jurl, jmessage,
367                                                    callback_id);
368 }
369 
ShouldOverrideUrlLoading(const base::string16 & url,bool has_user_gesture,bool is_redirect,bool is_main_frame,bool * ignore_navigation)370 bool AwContentsClientBridge::ShouldOverrideUrlLoading(const base::string16& url,
371                                                       bool has_user_gesture,
372                                                       bool is_redirect,
373                                                       bool is_main_frame,
374                                                       bool* ignore_navigation) {
375   *ignore_navigation = false;
376   JNIEnv* env = AttachCurrentThread();
377   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
378   if (!obj)
379     return true;
380   ScopedJavaLocalRef<jstring> jurl = ConvertUTF16ToJavaString(env, url);
381   devtools_instrumentation::ScopedEmbedderCallbackTask(
382       "shouldOverrideUrlLoading");
383   *ignore_navigation = Java_AwContentsClientBridge_shouldOverrideUrlLoading(
384       env, obj, jurl, has_user_gesture, is_redirect, is_main_frame);
385   if (HasException(env)) {
386     // Tell the chromium message loop to not perform any tasks after the current
387     // one - we want to make sure we return to Java cleanly without first making
388     // any new JNI calls.
389     base::CurrentUIThread::Get()->Abort();
390     // If we crashed we don't want to continue the navigation.
391     *ignore_navigation = true;
392     return false;
393   }
394   return true;
395 }
396 
NewDownload(const GURL & url,const std::string & user_agent,const std::string & content_disposition,const std::string & mime_type,int64_t content_length)397 void AwContentsClientBridge::NewDownload(const GURL& url,
398                                          const std::string& user_agent,
399                                          const std::string& content_disposition,
400                                          const std::string& mime_type,
401                                          int64_t content_length) {
402   DCHECK_CURRENTLY_ON(BrowserThread::UI);
403   JNIEnv* env = AttachCurrentThread();
404   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
405   if (!obj)
406     return;
407 
408   ScopedJavaLocalRef<jstring> jstring_url =
409       ConvertUTF8ToJavaString(env, url.spec());
410   ScopedJavaLocalRef<jstring> jstring_user_agent =
411       ConvertUTF8ToJavaString(env, user_agent);
412   ScopedJavaLocalRef<jstring> jstring_content_disposition =
413       ConvertUTF8ToJavaString(env, content_disposition);
414   ScopedJavaLocalRef<jstring> jstring_mime_type =
415       ConvertUTF8ToJavaString(env, mime_type);
416 
417   Java_AwContentsClientBridge_newDownload(
418       env, obj, jstring_url, jstring_user_agent, jstring_content_disposition,
419       jstring_mime_type, content_length);
420 }
421 
NewLoginRequest(const std::string & realm,const std::string & account,const std::string & args)422 void AwContentsClientBridge::NewLoginRequest(const std::string& realm,
423                                              const std::string& account,
424                                              const std::string& args) {
425   DCHECK_CURRENTLY_ON(BrowserThread::UI);
426   JNIEnv* env = AttachCurrentThread();
427   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
428   if (!obj)
429     return;
430 
431   ScopedJavaLocalRef<jstring> jrealm = ConvertUTF8ToJavaString(env, realm);
432   ScopedJavaLocalRef<jstring> jargs = ConvertUTF8ToJavaString(env, args);
433 
434   ScopedJavaLocalRef<jstring> jaccount;
435   if (!account.empty())
436     jaccount = ConvertUTF8ToJavaString(env, account);
437 
438   Java_AwContentsClientBridge_newLoginRequest(env, obj, jrealm, jaccount,
439                                               jargs);
440 }
441 
OnReceivedError(const AwWebResourceRequest & request,int error_code,bool safebrowsing_hit,bool should_omit_notifications_for_safebrowsing_hit)442 void AwContentsClientBridge::OnReceivedError(
443     const AwWebResourceRequest& request,
444     int error_code,
445     bool safebrowsing_hit,
446     bool should_omit_notifications_for_safebrowsing_hit) {
447   DCHECK(request.is_renderer_initiated.has_value());
448   DCHECK_CURRENTLY_ON(BrowserThread::UI);
449   JNIEnv* env = AttachCurrentThread();
450   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
451   if (!obj)
452     return;
453 
454   ScopedJavaLocalRef<jstring> jstring_description =
455       ConvertUTF8ToJavaString(env, net::ErrorToString(error_code));
456 
457   AwWebResourceRequest::AwJavaWebResourceRequest java_web_resource_request;
458   AwWebResourceRequest::ConvertToJava(env, request, &java_web_resource_request);
459   Java_AwContentsClientBridge_onReceivedError(
460       env, obj, java_web_resource_request.jurl, request.is_main_frame,
461       request.has_user_gesture, *request.is_renderer_initiated,
462       java_web_resource_request.jmethod,
463       java_web_resource_request.jheader_names,
464       java_web_resource_request.jheader_values, error_code, jstring_description,
465       safebrowsing_hit, should_omit_notifications_for_safebrowsing_hit);
466 }
467 
OnSafeBrowsingHit(const AwWebResourceRequest & request,const safe_browsing::SBThreatType & threat_type,SafeBrowsingActionCallback callback)468 void AwContentsClientBridge::OnSafeBrowsingHit(
469     const AwWebResourceRequest& request,
470     const safe_browsing::SBThreatType& threat_type,
471     SafeBrowsingActionCallback callback) {
472   int request_id = safe_browsing_callbacks_.Add(
473       std::make_unique<SafeBrowsingActionCallback>(std::move(callback)));
474 
475   DCHECK_CURRENTLY_ON(BrowserThread::UI);
476   JNIEnv* env = AttachCurrentThread();
477   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
478   if (!obj)
479     return;
480 
481   AwWebResourceRequest::AwJavaWebResourceRequest java_web_resource_request;
482   AwWebResourceRequest::ConvertToJava(env, request, &java_web_resource_request);
483   Java_AwContentsClientBridge_onSafeBrowsingHit(
484       env, obj, java_web_resource_request.jurl, request.is_main_frame,
485       request.has_user_gesture, java_web_resource_request.jmethod,
486       java_web_resource_request.jheader_names,
487       java_web_resource_request.jheader_values, static_cast<int>(threat_type),
488       request_id);
489 }
490 
OnReceivedHttpError(const AwWebResourceRequest & request,std::unique_ptr<HttpErrorInfo> http_error_info)491 void AwContentsClientBridge::OnReceivedHttpError(
492     const AwWebResourceRequest& request,
493     std::unique_ptr<HttpErrorInfo> http_error_info) {
494   DCHECK_CURRENTLY_ON(BrowserThread::UI);
495   JNIEnv* env = AttachCurrentThread();
496   ScopedJavaLocalRef<jobject> obj = java_ref_.get(env);
497   if (!obj)
498     return;
499 
500   AwWebResourceRequest::AwJavaWebResourceRequest java_web_resource_request;
501   AwWebResourceRequest::ConvertToJava(env, request, &java_web_resource_request);
502 
503   ScopedJavaLocalRef<jstring> jstring_mime_type =
504       ConvertUTF8ToJavaString(env, http_error_info->mime_type);
505   ScopedJavaLocalRef<jstring> jstring_encoding =
506       ConvertUTF8ToJavaString(env, http_error_info->encoding);
507   ScopedJavaLocalRef<jstring> jstring_reason =
508       ConvertUTF8ToJavaString(env, http_error_info->status_text);
509   ScopedJavaLocalRef<jobjectArray> jstringArray_response_header_names =
510       ToJavaArrayOfStrings(env, http_error_info->response_header_names);
511   ScopedJavaLocalRef<jobjectArray> jstringArray_response_header_values =
512       ToJavaArrayOfStrings(env, http_error_info->response_header_values);
513 
514   Java_AwContentsClientBridge_onReceivedHttpError(
515       env, obj, java_web_resource_request.jurl, request.is_main_frame,
516       request.has_user_gesture, java_web_resource_request.jmethod,
517       java_web_resource_request.jheader_names,
518       java_web_resource_request.jheader_values, jstring_mime_type,
519       jstring_encoding, http_error_info->status_code, jstring_reason,
520       jstringArray_response_header_names, jstringArray_response_header_values);
521 }
522 
523 // static
524 std::unique_ptr<AwContentsClientBridge::HttpErrorInfo>
ExtractHttpErrorInfo(const net::HttpResponseHeaders * response_headers)525 AwContentsClientBridge::ExtractHttpErrorInfo(
526     const net::HttpResponseHeaders* response_headers) {
527   auto http_error_info = std::make_unique<HttpErrorInfo>();
528   {
529     size_t headers_iterator = 0;
530     std::string header_name, header_value;
531     while (response_headers->EnumerateHeaderLines(
532         &headers_iterator, &header_name, &header_value)) {
533       http_error_info->response_header_names.push_back(header_name);
534       http_error_info->response_header_values.push_back(header_value);
535     }
536   }
537 
538   response_headers->GetMimeTypeAndCharset(&http_error_info->mime_type,
539                                           &http_error_info->encoding);
540   http_error_info->status_code = response_headers->response_code();
541   http_error_info->status_text = response_headers->GetStatusText();
542   return http_error_info;
543 }
544 
ConfirmJsResult(JNIEnv * env,const JavaRef<jobject> &,int id,const JavaRef<jstring> & prompt)545 void AwContentsClientBridge::ConfirmJsResult(JNIEnv* env,
546                                              const JavaRef<jobject>&,
547                                              int id,
548                                              const JavaRef<jstring>& prompt) {
549   DCHECK_CURRENTLY_ON(BrowserThread::UI);
550   content::JavaScriptDialogManager::DialogClosedCallback* callback =
551       pending_js_dialog_callbacks_.Lookup(id);
552   if (!callback) {
553     LOG(WARNING) << "Unexpected JS dialog confirm. " << id;
554     return;
555   }
556   base::string16 prompt_text;
557   if (prompt) {
558     prompt_text = ConvertJavaStringToUTF16(env, prompt);
559   }
560   std::move(*callback).Run(true, prompt_text);
561   pending_js_dialog_callbacks_.Remove(id);
562 }
563 
TakeSafeBrowsingAction(JNIEnv *,const JavaRef<jobject> &,int action,bool reporting,int request_id)564 void AwContentsClientBridge::TakeSafeBrowsingAction(JNIEnv*,
565                                                     const JavaRef<jobject>&,
566                                                     int action,
567                                                     bool reporting,
568                                                     int request_id) {
569   DCHECK_CURRENTLY_ON(BrowserThread::UI);
570   auto* callback = safe_browsing_callbacks_.Lookup(request_id);
571   if (!callback) {
572     LOG(WARNING) << "Unexpected TakeSafeBrowsingAction. " << request_id;
573     return;
574   }
575   std::move(*callback).Run(
576       static_cast<AwUrlCheckerDelegateImpl::SafeBrowsingAction>(action),
577       reporting);
578   safe_browsing_callbacks_.Remove(request_id);
579 }
580 
CancelJsResult(JNIEnv *,const JavaRef<jobject> &,int id)581 void AwContentsClientBridge::CancelJsResult(JNIEnv*,
582                                             const JavaRef<jobject>&,
583                                             int id) {
584   DCHECK_CURRENTLY_ON(BrowserThread::UI);
585   content::JavaScriptDialogManager::DialogClosedCallback* callback =
586       pending_js_dialog_callbacks_.Lookup(id);
587   if (!callback) {
588     LOG(WARNING) << "Unexpected JS dialog cancel. " << id;
589     return;
590   }
591   std::move(*callback).Run(false, base::string16());
592   pending_js_dialog_callbacks_.Remove(id);
593 }
594 
595 }  // namespace android_webview
596