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 "url/android/parsed_android.h"
19 #include "url/gurl_jni_headers/GURL_jni.h"
20 #include "url/third_party/mozilla/url_parse.h"
21
22 using base::android::AttachCurrentThread;
23 using base::android::JavaParamRef;
24 using base::android::JavaRef;
25 using base::android::ScopedJavaLocalRef;
26
27 namespace url {
28
29 namespace {
30
FromJString(JNIEnv * env,const JavaRef<jstring> & uri)31 static GURL FromJString(JNIEnv* env, const JavaRef<jstring>& uri) {
32 if (!uri)
33 return GURL();
34 return GURL(base::android::ConvertJavaStringToUTF16(env, uri));
35 }
36
FromJavaGURL(JNIEnv * env,const JavaRef<jstring> & j_spec,bool is_valid,jlong parsed_ptr)37 static std::unique_ptr<GURL> FromJavaGURL(JNIEnv* env,
38 const JavaRef<jstring>& j_spec,
39 bool is_valid,
40 jlong parsed_ptr) {
41 Parsed* parsed = reinterpret_cast<Parsed*>(parsed_ptr);
42 const std::string& spec = ConvertJavaStringToUTF8(env, j_spec);
43 std::unique_ptr<GURL> gurl =
44 std::make_unique<GURL>(spec.data(), parsed->Length(), *parsed, is_valid);
45 delete parsed;
46 return gurl;
47 }
48
InitFromGURL(JNIEnv * env,const GURL & gurl,const JavaRef<jobject> & target)49 static void InitFromGURL(JNIEnv* env,
50 const GURL& gurl,
51 const JavaRef<jobject>& target) {
52 Java_GURL_init(
53 env, target,
54 base::android::ConvertUTF8ToJavaString(env, gurl.possibly_invalid_spec()),
55 gurl.is_valid(),
56 ParsedAndroid::InitFromParsed(env,
57 gurl.parsed_for_possibly_invalid_spec()));
58 }
59
60 // As |GetArrayLength| makes no guarantees about the returned value (e.g., it
61 // may be -1 if |array| is not a valid Java array), provide a safe wrapper
62 // that always returns a valid, non-negative size.
63 template <typename JavaArrayType>
SafeGetArrayLength(JNIEnv * env,const JavaRef<JavaArrayType> & jarray)64 size_t SafeGetArrayLength(JNIEnv* env, const JavaRef<JavaArrayType>& jarray) {
65 DCHECK(jarray);
66 jsize length = env->GetArrayLength(jarray.obj());
67 DCHECK_GE(length, 0) << "Invalid array length: " << length;
68 return static_cast<size_t>(std::max(0, length));
69 }
70
71 } // namespace
72
73 // static
ToNativeGURL(JNIEnv * env,const base::android::JavaRef<jobject> & j_gurl)74 std::unique_ptr<GURL> GURLAndroid::ToNativeGURL(
75 JNIEnv* env,
76 const base::android::JavaRef<jobject>& j_gurl) {
77 return base::WrapUnique<GURL>(
78 reinterpret_cast<GURL*>(Java_GURL_toNativeGURL(env, j_gurl)));
79 }
80
JavaGURLArrayToGURLVector(JNIEnv * env,const base::android::JavaRef<jobjectArray> & array,std::vector<GURL> * out)81 void GURLAndroid::JavaGURLArrayToGURLVector(
82 JNIEnv* env,
83 const base::android::JavaRef<jobjectArray>& array,
84 std::vector<GURL>* out) {
85 DCHECK(out);
86 DCHECK(out->empty());
87 if (!array)
88 return;
89 size_t len = SafeGetArrayLength(env, array);
90 for (size_t i = 0; i < len; ++i) {
91 ScopedJavaLocalRef<jobject> j_gurl(
92 env, static_cast<jobject>(env->GetObjectArrayElement(array.obj(), i)));
93 out->emplace_back(
94 *reinterpret_cast<GURL*>(Java_GURL_toNativeGURL(env, j_gurl)));
95 }
96 }
97
98 // static
FromNativeGURL(JNIEnv * env,const GURL & gurl)99 ScopedJavaLocalRef<jobject> GURLAndroid::FromNativeGURL(JNIEnv* env,
100 const GURL& gurl) {
101 ScopedJavaLocalRef<jobject> j_gurl = Java_GURL_Constructor(env);
102 InitFromGURL(env, gurl, j_gurl);
103 return j_gurl;
104 }
105
106 // static
EmptyGURL(JNIEnv * env)107 ScopedJavaLocalRef<jobject> GURLAndroid::EmptyGURL(JNIEnv* env) {
108 return Java_GURL_emptyGURL(env);
109 }
110
111 // static
ToJavaArrayOfGURLs(JNIEnv * env,base::span<ScopedJavaLocalRef<jobject>> v)112 ScopedJavaLocalRef<jobjectArray> GURLAndroid::ToJavaArrayOfGURLs(
113 JNIEnv* env,
114 base::span<ScopedJavaLocalRef<jobject>> v) {
115 jclass clazz = org_chromium_url_GURL_clazz(env);
116 DCHECK(clazz);
117 jobjectArray joa = env->NewObjectArray(v.size(), clazz, nullptr);
118 base::android::CheckException(env);
119
120 for (size_t i = 0; i < v.size(); ++i) {
121 env->SetObjectArrayElement(joa, i, v[i].obj());
122 }
123 return ScopedJavaLocalRef<jobjectArray>(env, joa);
124 }
125
JNI_GURL_GetOrigin(JNIEnv * env,const JavaParamRef<jstring> & j_spec,jboolean is_valid,jlong parsed_ptr,const JavaParamRef<jobject> & target)126 static void JNI_GURL_GetOrigin(JNIEnv* env,
127 const JavaParamRef<jstring>& j_spec,
128 jboolean is_valid,
129 jlong parsed_ptr,
130 const JavaParamRef<jobject>& target) {
131 std::unique_ptr<GURL> gurl = FromJavaGURL(env, j_spec, is_valid, parsed_ptr);
132 InitFromGURL(env, gurl->DeprecatedGetOriginAsURL(), target);
133 }
134
JNI_GURL_DomainIs(JNIEnv * env,const JavaParamRef<jstring> & j_spec,jboolean is_valid,jlong parsed_ptr,const JavaParamRef<jstring> & j_domain)135 static jboolean JNI_GURL_DomainIs(JNIEnv* env,
136 const JavaParamRef<jstring>& j_spec,
137 jboolean is_valid,
138 jlong parsed_ptr,
139 const JavaParamRef<jstring>& j_domain) {
140 std::unique_ptr<GURL> gurl = FromJavaGURL(env, j_spec, is_valid, parsed_ptr);
141 const std::string& domain = ConvertJavaStringToUTF8(env, j_domain);
142 return gurl->DomainIs(domain);
143 }
144
JNI_GURL_Init(JNIEnv * env,const base::android::JavaParamRef<jstring> & uri,const base::android::JavaParamRef<jobject> & target)145 static void JNI_GURL_Init(JNIEnv* env,
146 const base::android::JavaParamRef<jstring>& uri,
147 const base::android::JavaParamRef<jobject>& target) {
148 const GURL& gurl = FromJString(env, uri);
149 InitFromGURL(env, gurl, target);
150 }
151
JNI_GURL_CreateNative(JNIEnv * env,const JavaParamRef<jstring> & j_spec,jboolean is_valid,jlong parsed_ptr)152 static jlong JNI_GURL_CreateNative(JNIEnv* env,
153 const JavaParamRef<jstring>& j_spec,
154 jboolean is_valid,
155 jlong parsed_ptr) {
156 return reinterpret_cast<intptr_t>(
157 FromJavaGURL(env, j_spec, is_valid, parsed_ptr).release());
158 }
159
160 } // namespace url
161