Skip to content

Commit 3c56705

Browse files
committed
Fix for #4832 -- Making PSON handle arbitrary binary data
The PSON library needlessly assumed that the data to be transmitted was well- formed unicode. This made Latin-1 users (and anyone who needed to serialize arbitrary binary data) sad. This patch goes some of the way to resolving the issues, by passing through non-unicode data rather than just failing, adds tests, and cleans up a pernicious assumption about escape characters in ruby regular expressions not marked "n" (no-encoding).
1 parent e232770 commit 3c56705

File tree

2 files changed

+22
-12
lines changed

2 files changed

+22
-12
lines changed

lib/puppet/external/pson/pure/generator.rb

+5-12
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,15 @@ def utf8_to_pson(string) # :nodoc:
6363
end
6464
else
6565
def utf8_to_pson(string) # :nodoc:
66-
string = string.gsub(/["\\\x0-\x1f]/) { MAP[$MATCH] }
67-
string.gsub!(/(
68-
(?:
66+
string.
67+
gsub(/["\\\x0-\x1f]/n) { MAP[$MATCH] }.
68+
gsub(/((?:
6969
[\xc2-\xdf][\x80-\xbf] |
7070
[\xe0-\xef][\x80-\xbf]{2} |
7171
[\xf0-\xf4][\x80-\xbf]{3}
72-
)+ |
73-
[\x80-\xc1\xf5-\xff] # invalid
74-
)/nx) { |c|
75-
c.size == 1 and raise GeneratorError, "invalid utf8 byte: '#{c}'"
76-
s = PSON::UTF8toUTF16.iconv(c).unpack('H*')[0]
77-
s.gsub!(/.{4}/n, '\\\\u\&')
72+
)+)/nx) { |c|
73+
PSON::UTF8toUTF16.iconv(c).unpack('H*')[0].gsub(/.{4}/n, '\\\\u\&')
7874
}
79-
string
80-
rescue Iconv::Failure => e
81-
raise GeneratorError, "Caught #{e.class}: #{e}"
8275
end
8376
end
8477
module_function :utf8_to_pson

spec/unit/util/json_spec.rb spec/unit/util/pson_spec.rb

+17
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,21 @@ class PsonUtil
1818
pson.expects(:from_pson).with("mydata")
1919
pson.pson_create("type" => "foo", "data" => "mydata")
2020
end
21+
22+
23+
{
24+
'foo' => '"foo"',
25+
1 => '1',
26+
"\x80" => "\"\x80\"",
27+
[] => '[]'
28+
}.each { |str,pson|
29+
it "should be able to encode #{str.inspect}" do
30+
str.to_pson.should == pson
31+
end
32+
}
33+
34+
it "should be able to handle arbitrary binary data" do
35+
bin_string = (1..20000).collect { |i| ((17*i+13*i*i) % 255).chr }.join
36+
PSON.parse(%Q{{ "type": "foo", "data": #{bin_string.to_pson} }})["data"].should == bin_string
37+
end
2138
end

0 commit comments

Comments
 (0)