Explicitly CHECK arguments in dbus::MessageWriter::AppendString/ObjectPath

Add dbus::IsStringValidObjectPath() and dbus::ObjectPath::IsValid()

BUG=129335
TEST=dbus_unittests


Review URL: https://chromiumcodereview.appspot.com/10502011

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@140489 0039d316-1c4b-4281-b951-d872f2087c98


CrOS-Libchrome-Original-Commit: 43fa5b848147d846761fecbea0317331510dd287
diff --git a/dbus/dbus.gyp b/dbus/dbus.gyp
index e7a2636..c2244cd 100644
--- a/dbus/dbus.gyp
+++ b/dbus/dbus.gyp
@@ -34,6 +34,8 @@
         'property.cc',
         'property.h',
         'scoped_dbus_error.h',
+        'string_util.cc',
+        'string_util.h',
         'values_util.cc',
         'values_util.h',
       ],
@@ -90,6 +92,7 @@
         'message_unittest.cc',
         'mock_unittest.cc',
         'property_unittest.cc',
+        'string_util_unittest.cc',
         'test_service.cc',
         'test_service.h',
         'values_util_unittest.cc',
diff --git a/dbus/message.cc b/dbus/message.cc
index 5b45d42..2caf543 100644
--- a/dbus/message.cc
+++ b/dbus/message.cc
@@ -9,6 +9,7 @@
 #include "base/basictypes.h"
 #include "base/format_macros.h"
 #include "base/logging.h"
+#include "base/string_util.h"
 #include "base/stringprintf.h"
 #include "dbus/object_path.h"
 #include "third_party/protobuf/src/google/protobuf/message_lite.h"
@@ -482,6 +483,8 @@
 }
 
 void MessageWriter::AppendString(const std::string& value) {
+  // D-Bus Specification (0.19) says a string "must be valid UTF-8".
+  CHECK(IsStringUTF8(value));
   const char* pointer = value.c_str();
   AppendBasic(DBUS_TYPE_STRING, &pointer);
   // TODO(satorux): It may make sense to return an error here, as the
@@ -490,6 +493,7 @@
 }
 
 void MessageWriter::AppendObjectPath(const ObjectPath& value) {
+  CHECK(value.IsValid());
   const char* pointer = value.value().c_str();
   AppendBasic(DBUS_TYPE_OBJECT_PATH, &pointer);
 }
diff --git a/dbus/object_path.cc b/dbus/object_path.cc
index 2dda466..1200a9b 100644
--- a/dbus/object_path.cc
+++ b/dbus/object_path.cc
@@ -4,8 +4,14 @@
 
 #include "dbus/object_path.h"
 
+#include "dbus/string_util.h"
+
 namespace dbus {
 
+bool ObjectPath::IsValid() const {
+  return IsValidObjectPath(value_);
+}
+
 bool ObjectPath::operator<(const ObjectPath& that) const {
   return value_ < that.value_;
 }
diff --git a/dbus/object_path.h b/dbus/object_path.h
index 59071da..38e1fe2 100644
--- a/dbus/object_path.h
+++ b/dbus/object_path.h
@@ -29,6 +29,9 @@
   // Retrieves value as a std::string.
   const std::string& value() const { return value_; }
 
+  // Returns true if the value is a valid object path.
+  bool IsValid() const;
+
   // Permit sufficient comparison to allow an ObjectPath to be used as a
   // key in a std::map.
   bool operator<(const ObjectPath&) const;
diff --git a/dbus/string_util.cc b/dbus/string_util.cc
new file mode 100644
index 0000000..4d4c9da
--- /dev/null
+++ b/dbus/string_util.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 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 "dbus/string_util.h"
+
+#include "base/string_util.h"
+
+namespace dbus {
+
+bool IsValidObjectPath(const std::string& value) {
+  // This implementation is based upon D-Bus Specification Version 0.19.
+
+  const bool kCaseSensitive = true;
+
+  // A valid object path begins with '/'.
+  if (!StartsWithASCII(value, "/", kCaseSensitive))
+    return false;
+
+  // Elements are pieces delimited by '/'. For instance, "org", "chromium",
+  // "Foo" are elements of "/org/chromium/Foo".
+  int element_length = 0;
+  for (size_t i = 1; i < value.size(); ++i) {
+    const char c = value[i];
+    if (c == '/') {
+      // No element may be the empty string.
+      if (element_length == 0)
+        return false;
+      element_length = 0;
+    } else {
+      // Each element must only contain "[A-Z][a-z][0-9]_".
+      const bool is_valid_character =
+          ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z') ||
+          ('0' <= c && c <= '9') || c == '_';
+      if (!is_valid_character)
+        return false;
+      element_length++;
+    }
+  }
+
+  // A trailing '/' character is not allowed unless the path is the root path.
+  if (value.size() > 1 && EndsWith(value, "/", kCaseSensitive))
+    return false;
+
+  return true;
+}
+
+}  // namespace dbus
diff --git a/dbus/string_util.h b/dbus/string_util.h
new file mode 100644
index 0000000..b83467e
--- /dev/null
+++ b/dbus/string_util.h
@@ -0,0 +1,18 @@
+// Copyright (c) 2012 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.
+
+#ifndef DBUS_STRING_UTIL_H_
+#define DBUS_STRING_UTIL_H_
+#pragma once
+
+#include <string>
+
+namespace dbus {
+
+// Returns true if the specified string is a valid object path.
+bool IsValidObjectPath(const std::string& value);
+
+}  // namespace dbus
+
+#endif  // DBUS_STRING_UTIL_H_
diff --git a/dbus/string_util_unittest.cc b/dbus/string_util_unittest.cc
new file mode 100644
index 0000000..76bdfcb
--- /dev/null
+++ b/dbus/string_util_unittest.cc
@@ -0,0 +1,27 @@
+// Copyright (c) 2012 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 "dbus/string_util.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+TEST(StringUtilTest, IsValidObjectPath) {
+  EXPECT_TRUE(dbus::IsValidObjectPath("/"));
+  EXPECT_TRUE(dbus::IsValidObjectPath("/foo/bar"));
+  EXPECT_TRUE(dbus::IsValidObjectPath("/hoge_fuga/piyo123"));
+  // Empty string.
+  EXPECT_FALSE(dbus::IsValidObjectPath(""));
+  // Emptyr elemnt.
+  EXPECT_FALSE(dbus::IsValidObjectPath("//"));
+  EXPECT_FALSE(dbus::IsValidObjectPath("/foo//bar"));
+  EXPECT_FALSE(dbus::IsValidObjectPath("/foo///bar"));
+  // Trailing '/'.
+  EXPECT_FALSE(dbus::IsValidObjectPath("/foo/"));
+  EXPECT_FALSE(dbus::IsValidObjectPath("/foo/bar/"));
+  // Not beginning with '/'.
+  EXPECT_FALSE(dbus::IsValidObjectPath("foo/bar"));
+  // Invalid characters.
+  EXPECT_FALSE(dbus::IsValidObjectPath("/foo.bar"));
+  EXPECT_FALSE(dbus::IsValidObjectPath("/foo/*"));
+  EXPECT_FALSE(dbus::IsValidObjectPath("/foo/bar(1)"));
+}