• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
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 "url/android/gurl_android.h"
6 
7 #include <jni.h>
8 
9 #include <cstdint>
10 #include <string>
11 #include <vector>
12 
13 #include "base/android/jni_android.h"
14 #include "base/android/jni_string.h"
15 #include "base/functional/bind.h"
16 #include "base/functional/callback.h"
17 #include "base/memory/ptr_util.h"
18 #include "base/strings/string_util.h"
19 #include "url/android/parsed_android.h"
20 #include "url/third_party/mozilla/url_parse.h"
21 #include "url/url_jni_headers/GURL_jni.h"
22 
23 using base::android::AttachCurrentThread;
24 using base::android::JavaParamRef;
25 using base::android::JavaRef;
26 using base::android::ScopedJavaLocalRef;
27 
28 namespace url {
29 
30 namespace {
31 
FromJString(JNIEnv * env,const JavaRef<jstring> & uri)32 static GURL FromJString(JNIEnv* env, const JavaRef<jstring>& uri) {
33   if (!uri)
34     return GURL();
35   return GURL(base::android::ConvertJavaStringToUTF16(env, uri));
36 }
37 
FromJavaGURL(JNIEnv * env,const JavaRef<jstring> & j_spec,bool is_valid,jlong parsed_ptr)38 static std::unique_ptr<GURL> FromJavaGURL(JNIEnv* env,
39                                           const JavaRef<jstring>& j_spec,
40                                           bool is_valid,
41                                           jlong parsed_ptr) {
42   Parsed* parsed = reinterpret_cast<Parsed*>(parsed_ptr);
43   const std::string& spec = ConvertJavaStringToUTF8(env, j_spec);
44   std::unique_ptr<GURL> gurl =
45       std::make_unique<GURL>(spec.data(), parsed->Length(), *parsed, is_valid);
46   delete parsed;
47   return gurl;
48 }
49 
InitFromGURL(JNIEnv * env,const GURL & gurl,const JavaRef<jobject> & target)50 static void InitFromGURL(JNIEnv* env,
51                          const GURL& gurl,
52                          const JavaRef<jobject>& target) {
53   // Ensure that the spec only contains US-ASCII (single-byte characters) or the
54   // parsed indices will be wrong as the indices are in bytes while Java Strings
55   // are always 16-bit.
56   DCHECK(base::IsStringASCII(gurl.possibly_invalid_spec()));
57   Java_GURL_init(
58       env, target,
59       base::android::ConvertUTF8ToJavaString(env, gurl.possibly_invalid_spec()),
60       gurl.is_valid(),
61       ParsedAndroid::InitFromParsed(env,
62                                     gurl.parsed_for_possibly_invalid_spec()));
63 }
64 
65 // As |GetArrayLength| makes no guarantees about the returned value (e.g., it
66 // may be -1 if |array| is not a valid Java array), provide a safe wrapper
67 // that always returns a valid, non-negative size.
68 template <typename JavaArrayType>
SafeGetArrayLength(JNIEnv * env,const JavaRef<JavaArrayType> & jarray)69 size_t SafeGetArrayLength(JNIEnv* env, const JavaRef<JavaArrayType>& jarray) {
70   DCHECK(jarray);
71   jsize length = env->GetArrayLength(jarray.obj());
72   DCHECK_GE(length, 0) << "Invalid array length: " << length;
73   return static_cast<size_t>(std::max(0, length));
74 }
75 
76 }  // namespace
77 
78 // static
ToNativeGURL(JNIEnv * env,const base::android::JavaRef<jobject> & j_gurl)79 std::unique_ptr<GURL> GURLAndroid::ToNativeGURL(
80     JNIEnv* env,
81     const base::android::JavaRef<jobject>& j_gurl) {
82   return base::WrapUnique<GURL>(
83       reinterpret_cast<GURL*>(Java_GURL_toNativeGURL(env, j_gurl)));
84 }
85 
JavaGURLArrayToGURLVector(JNIEnv * env,const base::android::JavaRef<jobjectArray> & array,std::vector<GURL> * out)86 void GURLAndroid::JavaGURLArrayToGURLVector(
87     JNIEnv* env,
88     const base::android::JavaRef<jobjectArray>& array,
89     std::vector<GURL>* out) {
90   DCHECK(out);
91   DCHECK(out->empty());
92   if (!array)
93     return;
94   size_t len = SafeGetArrayLength(env, array);
95   for (size_t i = 0; i < len; ++i) {
96     ScopedJavaLocalRef<jobject> j_gurl(
97         env, static_cast<jobject>(env->GetObjectArrayElement(array.obj(), i)));
98     out->emplace_back(
99         *reinterpret_cast<GURL*>(Java_GURL_toNativeGURL(env, j_gurl)));
100   }
101 }
102 
103 // static
FromNativeGURL(JNIEnv * env,const GURL & gurl)104 ScopedJavaLocalRef<jobject> GURLAndroid::FromNativeGURL(JNIEnv* env,
105                                                         const GURL& gurl) {
106   ScopedJavaLocalRef<jobject> j_gurl = Java_GURL_Constructor(env);
107   InitFromGURL(env, gurl, j_gurl);
108   return j_gurl;
109 }
110 
111 // static
EmptyGURL(JNIEnv * env)112 ScopedJavaLocalRef<jobject> GURLAndroid::EmptyGURL(JNIEnv* env) {
113   return Java_GURL_emptyGURL(env);
114 }
115 
116 // static
ToJavaArrayOfGURLs(JNIEnv * env,base::span<ScopedJavaLocalRef<jobject>> v)117 ScopedJavaLocalRef<jobjectArray> GURLAndroid::ToJavaArrayOfGURLs(
118     JNIEnv* env,
119     base::span<ScopedJavaLocalRef<jobject>> v) {
120   jclass clazz = org_chromium_url_GURL_clazz(env);
121   DCHECK(clazz);
122   jobjectArray joa = env->NewObjectArray(v.size(), clazz, nullptr);
123   base::android::CheckException(env);
124 
125   for (size_t i = 0; i < v.size(); ++i) {
126     env->SetObjectArrayElement(joa, i, v[i].obj());
127   }
128   return ScopedJavaLocalRef<jobjectArray>(env, joa);
129 }
130 
JNI_GURL_GetOrigin(JNIEnv * env,const JavaParamRef<jstring> & j_spec,jboolean is_valid,jlong parsed_ptr,const JavaParamRef<jobject> & target)131 static void JNI_GURL_GetOrigin(JNIEnv* env,
132                                const JavaParamRef<jstring>& j_spec,
133                                jboolean is_valid,
134                                jlong parsed_ptr,
135                                const JavaParamRef<jobject>& target) {
136   std::unique_ptr<GURL> gurl = FromJavaGURL(env, j_spec, is_valid, parsed_ptr);
137   InitFromGURL(env, gurl->DeprecatedGetOriginAsURL(), target);
138 }
139 
JNI_GURL_DomainIs(JNIEnv * env,const JavaParamRef<jstring> & j_spec,jboolean is_valid,jlong parsed_ptr,const JavaParamRef<jstring> & j_domain)140 static jboolean JNI_GURL_DomainIs(JNIEnv* env,
141                                   const JavaParamRef<jstring>& j_spec,
142                                   jboolean is_valid,
143                                   jlong parsed_ptr,
144                                   const JavaParamRef<jstring>& j_domain) {
145   std::unique_ptr<GURL> gurl = FromJavaGURL(env, j_spec, is_valid, parsed_ptr);
146   const std::string& domain = ConvertJavaStringToUTF8(env, j_domain);
147   return gurl->DomainIs(domain);
148 }
149 
JNI_GURL_Init(JNIEnv * env,const base::android::JavaParamRef<jstring> & uri,const base::android::JavaParamRef<jobject> & target)150 static void JNI_GURL_Init(JNIEnv* env,
151                           const base::android::JavaParamRef<jstring>& uri,
152                           const base::android::JavaParamRef<jobject>& target) {
153   const GURL& gurl = FromJString(env, uri);
154   InitFromGURL(env, gurl, target);
155 }
156 
JNI_GURL_CreateNative(JNIEnv * env,const JavaParamRef<jstring> & j_spec,jboolean is_valid,jlong parsed_ptr)157 static jlong JNI_GURL_CreateNative(JNIEnv* env,
158                                    const JavaParamRef<jstring>& j_spec,
159                                    jboolean is_valid,
160                                    jlong parsed_ptr) {
161   return reinterpret_cast<intptr_t>(
162       FromJavaGURL(env, j_spec, is_valid, parsed_ptr).release());
163 }
164 
JNI_GURL_ReplaceComponents(JNIEnv * env,const JavaParamRef<jstring> & j_spec,jboolean is_valid,jlong parsed_ptr,const JavaParamRef<jstring> & j_username_replacement,jboolean clear_username,const JavaParamRef<jstring> & j_password_replacement,jboolean clear_password,const JavaParamRef<jobject> & j_result)165 static void JNI_GURL_ReplaceComponents(
166     JNIEnv* env,
167     const JavaParamRef<jstring>& j_spec,
168     jboolean is_valid,
169     jlong parsed_ptr,
170     const JavaParamRef<jstring>& j_username_replacement,
171     jboolean clear_username,
172     const JavaParamRef<jstring>& j_password_replacement,
173     jboolean clear_password,
174     const JavaParamRef<jobject>& j_result) {
175   GURL::Replacements replacements;
176 
177   // Replacement strings must remain in scope for ReplaceComponents().
178   std::string username;
179   std::string password;
180 
181   if (clear_username) {
182     replacements.ClearUsername();
183   } else if (j_username_replacement) {
184     username = ConvertJavaStringToUTF8(env, j_username_replacement);
185     replacements.SetUsernameStr(username);
186   }
187 
188   if (clear_password) {
189     replacements.ClearPassword();
190   } else if (j_password_replacement) {
191     password = ConvertJavaStringToUTF8(env, j_password_replacement);
192     replacements.SetPasswordStr(password);
193   }
194 
195   std::unique_ptr<GURL> original =
196       FromJavaGURL(env, j_spec, is_valid, parsed_ptr);
197   InitFromGURL(env, original->ReplaceComponents(replacements), j_result);
198 }
199 
200 }  // namespace url
201