Index: components/safe_json/json_sanitizer_android.cc |
diff --git a/components/safe_json/json_sanitizer_android.cc b/components/safe_json/json_sanitizer_android.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..9ccad08f6c9d6966cabb818d07756c1cb0b149ca |
--- /dev/null |
+++ b/components/safe_json/json_sanitizer_android.cc |
@@ -0,0 +1,115 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "components/safe_json/json_sanitizer.h" |
+ |
+#include "base/android/jni_string.h" |
+#include "base/bind.h" |
+#include "base/callback.h" |
+#include "base/memory/weak_ptr.h" |
+#include "base/message_loop/message_loop.h" |
+#include "base/strings/string_util.h" |
+#include "jni/JsonSanitizer_jni.h" |
+ |
+namespace safe_json { |
+ |
+namespace { |
+ |
+// An implementation of JsonSanitizer that calls into Java. It deals with |
+// malformed input (in particular malformed Unicode encodings) in the following |
+// steps: |
+// 1. The input string is checked for whether it is well-formed UTF-8. Malformed |
+// UTF-8 is rejected. |
+// 2. The UTF-8 string is converted in native code to a Java String, which is |
+// encoded as UTF-16. |
+// 2. The Java String is parsed as JSON in the memory-safe environment of the |
+// Java VM and any string literals are unescaped. |
+// 3. The string literals themselves are now untrusted, so they are checked in |
+// Java for whether they are valid UTF-16. |
+// 4. The parsed JSON with sanitized literals is encoded back into a Java |
+// String and passed back to native code. |
+// 5. The Java String is converted back to UTF-8 in native code. |
+// This ensures that both invalid UTF-8 and invalid escaped UTF-16 will be |
+// rejected. |
+class JsonSanitizerAndroid : public JsonSanitizer { |
+ public: |
+ JsonSanitizerAndroid(const StringCallback& success_callback, |
+ const StringCallback& error_callback); |
+ ~JsonSanitizerAndroid() {} |
+ |
+ void Sanitize(const std::string& unsafe_json); |
+ |
+ void OnSuccess(const std::string& json); |
+ void OnError(const std::string& error); |
+ |
+ private: |
+ StringCallback success_callback_; |
+ StringCallback error_callback_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(JsonSanitizerAndroid); |
+}; |
+ |
+JsonSanitizerAndroid::JsonSanitizerAndroid( |
+ const StringCallback& success_callback, |
+ const StringCallback& error_callback) |
+ : success_callback_(success_callback), |
+ error_callback_(error_callback) {} |
+ |
+void JsonSanitizerAndroid::Sanitize(const std::string& unsafe_json) { |
+ // The JSON parser only accepts wellformed UTF-8. |
+ if (!base::IsStringUTF8(unsafe_json)) { |
+ OnError("Unsupported encoding"); |
+ return; |
+ } |
+ |
+ JNIEnv* env = base::android::AttachCurrentThread(); |
+ base::android::ScopedJavaLocalRef<jstring> unsafe_json_java = |
+ base::android::ConvertUTF8ToJavaString(env, unsafe_json); |
+ |
+ // This will synchronously call either OnSuccess() or OnError(). |
+ Java_JsonSanitizer_sanitize(env, reinterpret_cast<jlong>(this), |
+ unsafe_json_java.obj()); |
+} |
+ |
+void JsonSanitizerAndroid::OnSuccess(const std::string& json) { |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(success_callback_, json)); |
+} |
+ |
+void JsonSanitizerAndroid::OnError(const std::string& error) { |
+ base::MessageLoop::current()->PostTask(FROM_HERE, |
+ base::Bind(error_callback_, error)); |
+} |
+ |
+} // namespace |
+ |
+void OnSuccess(JNIEnv* env, jclass clazz, jlong jsanitizer, jstring json) { |
+ JsonSanitizerAndroid* sanitizer = |
+ reinterpret_cast<JsonSanitizerAndroid*>(jsanitizer); |
+ sanitizer->OnSuccess(base::android::ConvertJavaStringToUTF8(env, json)); |
+} |
+ |
+void OnError(JNIEnv* env, jclass clazz, jlong jsanitizer, jstring error) { |
+ JsonSanitizerAndroid* sanitizer = |
+ reinterpret_cast<JsonSanitizerAndroid*>(jsanitizer); |
+ sanitizer->OnError(base::android::ConvertJavaStringToUTF8(env, error)); |
+} |
+ |
+// static |
+void JsonSanitizer::Sanitize(const std::string& unsafe_json, |
+ const StringCallback& success_callback, |
+ const StringCallback& error_callback) { |
+ // JsonSanitizerAndroid does all its work synchronously, but posts any |
+ // callbacks to the current message loop. This means it can be destroyed at |
+ // the end of this method. |
+ JsonSanitizerAndroid sanitizer(success_callback, error_callback); |
+ sanitizer.Sanitize(unsafe_json); |
+} |
+ |
+// static |
+bool JsonSanitizer::Register(JNIEnv* env) { |
+ return RegisterNativesImpl(env); |
+} |
+ |
+} // namespace safe_json |