Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Escape \u2028 and \u2029 for 1.8 #44

Merged
merged 4 commits into from

3 participants

@benmanns

In 1.8, the string "\u2028" is converted to "u2028", so any JSON containing "u2028" would be replaced with "\\u2028", and any string literals "\u2028" would not get escaped. This patch uses octet literals if the Ruby version is less than 1.9, and Unicode literals if the Ruby version is 1.9 or greater.

If anyone doesn't like the Ruby version comparison within the code, I can remove the comparison and use the octet literal for all versions of Ruby, because 1.9 interprets "\342\200\250" the same as "\u2028".

benmanns added some commits
@benmanns benmanns Split "should not allow literal U+2028 or U+2029" assigns and tests f…
…or ">= 1.9" and "< 1.9".
eff0146
@benmanns benmanns Use octets in string literals when translating U+2028 and U+2029 if u…
…sing a Ruby version less than 1.9.

Previously, this would translate "u2028" to "\\u2028", because the \u escape character doesn't exist in 1.8.
4122df8
@benmanns benmanns Replace Gem::Version comparison with "\u2028" == 'u2028' comparison.
This ensures that the Unicode character is properly translated without relying on Gem::Version. Thanks to @judofyr.
2b3d626
@benmanns benmanns Move U+2028 and U+2029 into constants.
This allows the Ruby compatibility check to be run once on startup rather than for every request. Thanks to @judofyr.
75b4ef8
@jamesarosen

The tests are a little hard to understand unless you've read the comments on this PR. A comment there or more descriptive naming would help.

+1 otherwise.

@rkh rkh merged commit 42b92b7 into rack:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 25, 2011
  1. @benmanns
  2. @benmanns

    Use octets in string literals when translating U+2028 and U+2029 if u…

    benmanns authored
    …sing a Ruby version less than 1.9.
    
    Previously, this would translate "u2028" to "\\u2028", because the \u escape character doesn't exist in 1.8.
Commits on Sep 26, 2011
  1. @benmanns

    Replace Gem::Version comparison with "\u2028" == 'u2028' comparison.

    benmanns authored
    This ensures that the Unicode character is properly translated without relying on Gem::Version. Thanks to @judofyr.
  2. @benmanns

    Move U+2028 and U+2029 into constants.

    benmanns authored
    This allows the Ruby compatibility check to be run once on startup rather than for every request. Thanks to @judofyr.
This page is out of date. Refresh to see the latest.
Showing with 23 additions and 3 deletions.
  1. +13 −1 lib/rack/contrib/jsonp.rb
  2. +10 −2 test/spec_rack_jsonp.rb
View
14 lib/rack/contrib/jsonp.rb
@@ -10,6 +10,18 @@ class JSONP
VALID_JS_VAR = /[a-zA-Z_$][\w$]*/
VALID_CALLBACK = /\A#{VALID_JS_VAR}(?:\.?#{VALID_JS_VAR})*\z/
+ # These hold the Unicode characters \u2028 and \u2029.
+ #
+ # They are defined in constants for Ruby 1.8 compatibility.
+ #
+ # In 1.8
+ # "\u2028" # => "u2028"
+ # "\u2029" # => "u2029"
+ # In 1.9
+ # "\342\200\250" # => "\u2028"
+ # "\342\200\251" # => "\u2029"
+ U2028, U2029 = ("\u2028" == 'u2028') ? ["\342\200\250", "\342\200\251"] : ["\u2028", "\u2029"]
+
def initialize(app)
@app = app
end
@@ -83,7 +95,7 @@ def pad(callback, response, body = "")
# replacing them with the escaped version. This should be safe because
# according to the JSON spec, these characters are *only* valid inside
# a string and should therefore not be present any other places.
- body << s.to_s.gsub("\u2028", '\u2028').gsub("\u2029", '\u2029')
+ body << s.to_s.gsub(U2028, '\u2028').gsub(U2029, '\u2029')
end
["#{callback}(#{body})"]
View
12 test/spec_rack_jsonp.rb
@@ -53,12 +53,20 @@
end
specify "should not allow literal U+2028 or U+2029" do
- test_body = "{\"bar\":\"\u2028 and \u2029\"}"
+ test_body = unless "\u2028" == 'u2028'
+ "{\"bar\":\"\u2028 and \u2029\"}"
+ else
+ "{\"bar\":\"\342\200\250 and \342\200\251\"}"
+ end
callback = 'foo'
app = lambda { |env| [200, {'Content-Type' => 'application/json'}, [test_body]] }
request = Rack::MockRequest.env_for("/", :params => "foo=bar&callback=#{callback}")
body = Rack::JSONP.new(app).call(request).last
- body.join.should.not.match(/\u2028|\u2029/)
+ unless "\u2028" == 'u2028'
+ body.join.should.not.match(/\u2028|\u2029/)
+ else
+ body.join.should.not.match(/\342\200\250|\342\200\251/)
+ end
end
context "but is empty" do
Something went wrong with that request. Please try again.