From 6bb4dc14d401b0a392ff33431dd4e61e0a312e4d Mon Sep 17 00:00:00 2001
From: Dwayne Litzenberger <dlitz@infonium.ca>
Date: Tue, 22 Dec 2009 15:17:55 -0500
Subject: [PATCH] Fix ActiveSupport::JSON encoding of control characters [\x00-\x1f]

According to RFC 4627, only the following Unicode code points are
allowed unescaped in JSON:

  unescaped = %x20-21 / %x23-5B / %x5D-10FFFF

However, ActiveSupport::JSON did not escape the range %x00-1f.  This caused
parse errors when trying to decode the resulting output.
---
 activesupport/lib/active_support/json/encoding.rb |   13 +++++++++++--
 activesupport/test/json/encoding_test.rb          |    4 +++-
 2 files changed, 14 insertions(+), 3 deletions(-)

diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb
index 3c15056..c8415d5 100644
--- a/activesupport/lib/active_support/json/encoding.rb
+++ b/activesupport/lib/active_support/json/encoding.rb
@@ -65,6 +65,15 @@ module ActiveSupport
 
 
       ESCAPED_CHARS = {
+        "\x00" => '\u0000', "\x01" => '\u0001', "\x02" => '\u0002',
+        "\x03" => '\u0003', "\x04" => '\u0004', "\x05" => '\u0005',
+        "\x06" => '\u0006', "\x07" => '\u0007', "\x0B" => '\u000B',
+        "\x0E" => '\u000E', "\x0F" => '\u000F', "\x10" => '\u0010',
+        "\x11" => '\u0011', "\x12" => '\u0012', "\x13" => '\u0013',
+        "\x14" => '\u0014', "\x15" => '\u0015', "\x16" => '\u0016',
+        "\x17" => '\u0017', "\x18" => '\u0018', "\x19" => '\u0019',
+        "\x1A" => '\u001A', "\x1B" => '\u001B', "\x1C" => '\u001C',
+        "\x1D" => '\u001D', "\x1E" => '\u001E', "\x1F" => '\u001F',
         "\010" =>  '\b',
         "\f"   =>  '\f',
         "\n"   =>  '\n',
@@ -86,9 +95,9 @@ module ActiveSupport
         def escape_html_entities_in_json=(value)
           self.escape_regex = \
             if @escape_html_entities_in_json = value
-              /[\010\f\n\r\t"\\><&]/
+              /[\x00-\x1F"\\><&]/
             else
-              /[\010\f\n\r\t"\\]/
+              /[\x00-\x1F"\\]/
             end
         end
 
diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb
index 5d81d09..cf9a635 100644
--- a/activesupport/test/json/encoding_test.rb
+++ b/activesupport/test/json/encoding_test.rb
@@ -23,7 +23,9 @@ class TestJSONEncoding < Test::Unit::TestCase
 
   StringTests   = [[ 'this is the <string>',     %("this is the \\u003Cstring\\u003E")],
                    [ 'a "string" with quotes & an ampersand', %("a \\"string\\" with quotes \\u0026 an ampersand") ],
-                   [ 'http://test.host/posts/1', %("http://test.host/posts/1")]]
+                   [ 'http://test.host/posts/1', %("http://test.host/posts/1")],
+                   [ "Control characters: \x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f",
+                     %("Control characters: \\u0000\\u0001\\u0002\\u0003\\u0004\\u0005\\u0006\\u0007\\b\\t\\n\\u000B\\f\\r\\u000E\\u000F\\u0010\\u0011\\u0012\\u0013\\u0014\\u0015\\u0016\\u0017\\u0018\\u0019\\u001A\\u001B\\u001C\\u001D\\u001E\\u001F") ]]
 
   ArrayTests    = [[ ['a', 'b', 'c'],          %([\"a\",\"b\",\"c\"])          ],
                    [ [1, 'a', :b, nil, false], %([1,\"a\",\"b\",null,false]) ]]
-- 
1.6.5.2

