1 // Copyright 2015 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.
5 #include "components/safe_json/json_sanitizer.h"
7 #include "base/android/jni_string.h"
9 #include "base/callback.h"
10 #include "base/memory/weak_ptr.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/strings/string_util.h"
13 #include "jni/JsonSanitizer_jni.h"
19 // An implementation of JsonSanitizer that calls into Java. It deals with
20 // malformed input (in particular malformed Unicode encodings) in the following
22 // 1. The input string is checked for whether it is well-formed UTF-8. Malformed
24 // 2. The UTF-8 string is converted in native code to a Java String, which is
26 // 2. The Java String is parsed as JSON in the memory-safe environment of the
27 // Java VM and any string literals are unescaped.
28 // 3. The string literals themselves are now untrusted, so they are checked in
29 // Java for whether they are valid UTF-16.
30 // 4. The parsed JSON with sanitized literals is encoded back into a Java
31 // String and passed back to native code.
32 // 5. The Java String is converted back to UTF-8 in native code.
33 // This ensures that both invalid UTF-8 and invalid escaped UTF-16 will be
35 class JsonSanitizerAndroid
: public JsonSanitizer
{
37 JsonSanitizerAndroid(const StringCallback
& success_callback
,
38 const StringCallback
& error_callback
);
39 ~JsonSanitizerAndroid() {}
41 void Sanitize(const std::string
& unsafe_json
);
43 void OnSuccess(const std::string
& json
);
44 void OnError(const std::string
& error
);
47 StringCallback success_callback_
;
48 StringCallback error_callback_
;
50 DISALLOW_COPY_AND_ASSIGN(JsonSanitizerAndroid
);
53 JsonSanitizerAndroid::JsonSanitizerAndroid(
54 const StringCallback
& success_callback
,
55 const StringCallback
& error_callback
)
56 : success_callback_(success_callback
),
57 error_callback_(error_callback
) {}
59 void JsonSanitizerAndroid::Sanitize(const std::string
& unsafe_json
) {
60 // The JSON parser only accepts wellformed UTF-8.
61 if (!base::IsStringUTF8(unsafe_json
)) {
62 OnError("Unsupported encoding");
66 JNIEnv
* env
= base::android::AttachCurrentThread();
67 base::android::ScopedJavaLocalRef
<jstring
> unsafe_json_java
=
68 base::android::ConvertUTF8ToJavaString(env
, unsafe_json
);
70 // This will synchronously call either OnSuccess() or OnError().
71 Java_JsonSanitizer_sanitize(env
, reinterpret_cast<jlong
>(this),
72 unsafe_json_java
.obj());
75 void JsonSanitizerAndroid::OnSuccess(const std::string
& json
) {
76 base::MessageLoop::current()->PostTask(FROM_HERE
,
77 base::Bind(success_callback_
, json
));
80 void JsonSanitizerAndroid::OnError(const std::string
& error
) {
81 base::MessageLoop::current()->PostTask(FROM_HERE
,
82 base::Bind(error_callback_
, error
));
87 void OnSuccess(JNIEnv
* env
, jclass clazz
, jlong jsanitizer
, jstring json
) {
88 JsonSanitizerAndroid
* sanitizer
=
89 reinterpret_cast<JsonSanitizerAndroid
*>(jsanitizer
);
90 sanitizer
->OnSuccess(base::android::ConvertJavaStringToUTF8(env
, json
));
93 void OnError(JNIEnv
* env
, jclass clazz
, jlong jsanitizer
, jstring error
) {
94 JsonSanitizerAndroid
* sanitizer
=
95 reinterpret_cast<JsonSanitizerAndroid
*>(jsanitizer
);
96 sanitizer
->OnError(base::android::ConvertJavaStringToUTF8(env
, error
));
100 void JsonSanitizer::Sanitize(const std::string
& unsafe_json
,
101 const StringCallback
& success_callback
,
102 const StringCallback
& error_callback
) {
103 // JsonSanitizerAndroid does all its work synchronously, but posts any
104 // callbacks to the current message loop. This means it can be destroyed at
105 // the end of this method.
106 JsonSanitizerAndroid
sanitizer(success_callback
, error_callback
);
107 sanitizer
.Sanitize(unsafe_json
);
111 bool JsonSanitizer::Register(JNIEnv
* env
) {
112 return RegisterNativesImpl(env
);
115 } // namespace safe_json