You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mesos.apache.org by be...@apache.org on 2012/12/20 19:34:33 UTC

svn commit: r1424622 - in /incubator/mesos/trunk: src/tests/stout_tests.cpp third_party/libprocess/include/process/http.hpp third_party/libprocess/include/stout/json.hpp third_party/libprocess/src/tests.cpp

Author: benh
Date: Thu Dec 20 18:34:33 2012
New Revision: 1424622

URL: http://svn.apache.org/viewvc?rev=1424622&view=rev
Log:
Added ASCII escaping for binary data in JSON strings.

From: Ben Mahler <be...@gmail.com>
Review: https://reviews.apache.org/r/8056

Modified:
    incubator/mesos/trunk/src/tests/stout_tests.cpp
    incubator/mesos/trunk/third_party/libprocess/include/process/http.hpp
    incubator/mesos/trunk/third_party/libprocess/include/stout/json.hpp
    incubator/mesos/trunk/third_party/libprocess/src/tests.cpp

Modified: incubator/mesos/trunk/src/tests/stout_tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/src/tests/stout_tests.cpp?rev=1424622&r1=1424621&r2=1424622&view=diff
==============================================================================
--- incubator/mesos/trunk/src/tests/stout_tests.cpp (original)
+++ incubator/mesos/trunk/src/tests/stout_tests.cpp Thu Dec 20 18:34:33 2012
@@ -627,6 +627,15 @@ TEST(StoutMultihashmapTest, Foreach)
 }
 
 
+TEST(StoutJsonTest, BinaryData)
+{
+  JSON::String s(string("\"\\/\b\f\n\r\t\x00\x19 !#[]\x7F\xFF", 17));
+
+  EXPECT_EQ("\"\\\"\\\\\\/\\b\\f\\n\\r\\t\\u0000\\u0019 !#[]\\u007F\\u00FF\"",
+            stringify(s));
+}
+
+
 #ifdef HAVE_LIBZ
 TEST(StoutCompressionTest, Gzip)
 {

Modified: incubator/mesos/trunk/third_party/libprocess/include/process/http.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/libprocess/include/process/http.hpp?rev=1424622&r1=1424621&r2=1424622&view=diff
==============================================================================
--- incubator/mesos/trunk/third_party/libprocess/include/process/http.hpp (original)
+++ incubator/mesos/trunk/third_party/libprocess/include/process/http.hpp Thu Dec 20 18:34:33 2012
@@ -264,12 +264,16 @@ inline std::string encode(const std::str
       case '[':
       case ']':
       case '`':
-        out << '%' << std::setfill('0') << std::setw(2) << std::hex << c;
+        // NOTE: The cast to unsigned int is needed.
+        out << '%' << std::setfill('0') << std::setw(2) << std::hex
+            << std::uppercase << (unsigned int) c;
         break;
       default:
         // ASCII control characters and non-ASCII characters.
+        // NOTE: The cast to unsigned int is needed.
         if (c < 0x20 || c > 0x7F) {
-          out << '%' << std::setfill('0') << std::setw(2) << std::hex << c;
+          out << '%' << std::setfill('0') << std::setw(2) << std::hex
+              << std::uppercase << (unsigned int) c;
         } else {
           out << c;
         }

Modified: incubator/mesos/trunk/third_party/libprocess/include/stout/json.hpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/libprocess/include/stout/json.hpp?rev=1424622&r1=1424621&r2=1424622&view=diff
==============================================================================
--- incubator/mesos/trunk/third_party/libprocess/include/stout/json.hpp (original)
+++ incubator/mesos/trunk/third_party/libprocess/include/stout/json.hpp Thu Dec 20 18:34:33 2012
@@ -1,6 +1,7 @@
 #ifndef __STOUT_JSON__
 #define __STOUT_JSON__
 
+#include <iomanip>
 #include <iostream>
 #include <list>
 #include <map>
@@ -8,6 +9,8 @@
 
 #include <boost/variant.hpp>
 
+#include <stout/foreach.hpp>
+
 // TODO(jsirois): Implement parsing that constructs JSON objects.
 
 
@@ -93,22 +96,36 @@ struct Renderer : boost::static_visitor<
 
   void operator () (const String& string) const
   {
-    // TODO(benh): This escaping DOES NOT handle unicode.
+    // TODO(benh): This escaping DOES NOT handle unicode, it encodes as ASCII.
+    // See RFC4627 for the JSON string specificiation.
     out << "\"";
-    std::string::const_iterator iterator = string.value.begin();
-    while (iterator != string.value.end()) {
-      switch (*iterator) {
-        case '"': out << "\\\""; break;
+    foreach (unsigned char c, string.value) {
+      switch (c) {
+        case '"':  out << "\\\""; break;
         case '\\': out << "\\\\"; break;
-        case '/': out << "\\/"; break;
-        case '\b': out << "\\b"; break;
-        case '\f': out << "\\f"; break;
-        case '\n': out << "\\n"; break;
-        case '\r': out << "\\r"; break;
-        case '\t': out << "\\t"; break;
-        default: out << *iterator; break;
+        case '/':  out << "\\/";  break;
+        case '\b': out << "\\b";  break;
+        case '\f': out << "\\f";  break;
+        case '\n': out << "\\n";  break;
+        case '\r': out << "\\r";  break;
+        case '\t': out << "\\t";  break;
+        default:
+          // See RFC4627 for these ranges.
+          if ((c >= 0x20 && c <= 0x21) ||
+              (c >= 0x23 && c <= 0x5B) ||
+              (c >= 0x5D && c < 0x7F)) {
+            out << c;
+          } else {
+            // NOTE: We also escape all bytes > 0x7F since they imply more than
+            // 1 byte in UTF-8. This is why we don't escape UTF-8 properly.
+            // See RFC4627 for the escaping format: \uXXXX (X is a hex digit).
+            // Each byte here will be of the form: \u00XX (this is why we need
+            // setw and the cast to unsigned int).
+            out << "\\u" << std::setfill('0') << std::setw(4)
+                << std::hex << std::uppercase << (unsigned int) c;
+          }
+          break;
       }
-      ++iterator;
     }
     out << "\"";
   }

Modified: incubator/mesos/trunk/third_party/libprocess/src/tests.cpp
URL: http://svn.apache.org/viewvc/incubator/mesos/trunk/third_party/libprocess/src/tests.cpp?rev=1424622&r1=1424621&r2=1424622&view=diff
==============================================================================
--- incubator/mesos/trunk/third_party/libprocess/src/tests.cpp (original)
+++ incubator/mesos/trunk/third_party/libprocess/src/tests.cpp Thu Dec 20 18:34:33 2012
@@ -1333,10 +1333,11 @@ TEST(Process, async)
 
 TEST(HTTP, encode)
 {
-  std::string unencoded = "a$&+,/:;=?@ \"<>#%{}|\\^~[]`\x19\x80\xFF\x00";
+  std::string unencoded = "a$&+,/:;=?@ \"<>#%{}|\\^~[]`\x19\x80\xFF";
+  unencoded += std::string("\x00", 1); // Add a null byte to the end.
   std::string encoded = http::encode(unencoded);
 
-  EXPECT_EQ("a%24%26%2B%2C%2F%3A$3B%3D%3F%40%20%22%3C%3E%32"
+  EXPECT_EQ("a%24%26%2B%2C%2F%3A%3B%3D%3F%40%20%22%3C%3E%23"
             "%25%7B%7D%7C%5C%5E%7E%5B%5D%60%19%80%FF%00",
             encoded);