diff options
-rw-r--r-- | Gemfile | 2 | ||||
-rw-r--r-- | Gemfile.lock | 10 | ||||
-rw-r--r-- | lib/zero.rb | 4 | ||||
-rw-r--r-- | lib/zero/patches/uri.rb | 90 | ||||
-rw-r--r-- | spec/unit/uri/decode_www_form_18_spec.rb | 147 |
5 files changed, 242 insertions, 11 deletions
@@ -2,8 +2,6 @@ source 'https://rubygems.org' gemspec -gem 'backports', :platform => :ruby_18 - group :development do gem 'guard' gem 'guard-bundler' diff --git a/Gemfile.lock b/Gemfile.lock index a1be407..8ae450d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -7,18 +7,17 @@ PATH GEM remote: https://rubygems.org/ specs: - backports (2.6.5) coderay (1.0.8) diff-lcs (1.1.3) - guard (1.5.4) - listen (>= 0.4.2) + guard (1.6.0) + listen (>= 0.6.0) lumberjack (>= 1.0.2) pry (>= 0.9.10) thor (>= 0.14.6) guard-bundler (1.0.0) bundler (~> 1.0) guard (~> 1.1) - guard-rspec (2.3.1) + guard-rspec (2.3.3) guard (>= 1.1) rspec (~> 2.11) kramdown (0.14.1) @@ -44,7 +43,7 @@ GEM rspec-core (2.12.2) rspec-expectations (2.12.1) diff-lcs (~> 1.1.3) - rspec-mocks (2.12.0) + rspec-mocks (2.12.1) simplecov (0.7.1) multi_json (~> 1.0) simplecov-html (~> 0.7.1) @@ -60,7 +59,6 @@ PLATFORMS ruby DEPENDENCIES - backports guard guard-bundler guard-rspec diff --git a/lib/zero.rb b/lib/zero.rb index 03c77b8..c9909a7 100644 --- a/lib/zero.rb +++ b/lib/zero.rb @@ -1,6 +1,4 @@ -if RUBY_VERSION <= '1.9' - require 'backports' -end +require 'zero/patches/uri' module Zero require 'zero/controller' diff --git a/lib/zero/patches/uri.rb b/lib/zero/patches/uri.rb new file mode 100644 index 0000000..0b64abb --- /dev/null +++ b/lib/zero/patches/uri.rb @@ -0,0 +1,90 @@ +module URI + + # Gets a query string and splits it into its key value pairs. + # If URI already supports this functionality (decode_www_form on Ruby 1.9+), + # it will use this. Else it will run an onw implementation, without any + # encoding functionality. + # + # @param [String] query The query string + # @return [Array] Parsed query + # + def self.parse_query_string(query) + # Call the original decode_www_form method on ruby 1.9+ + if URI::respond_to? 'decode_www_form' + return self.decode_www_form query + end + + # else split the query self + return self.decode_www_form_18 query + end + + # Own implementation of decode_www_form. + # Shall behave almost like the original method, but without any encoding + # stuff. + # + # @param [String] query The query string + # @return [Array] Parsed query + # + def self.decode_www_form_18(query) + return [] if query.empty? + + unless query.match /^[^#=;&]*=[^#=;&]*([;&][^#=;&]*=[^#=;&]*)*$/ + raise ArgumentError, + "invalid data of application/x-www-form-urlencoded (#{query})" + end + parsed = [] + # breakes the string at & and ; + query.split(/[&;]/).each do |query_part| + # breakes the string parts at = + key, value = query_part.split('=') + + # make an empty string out of value, if it's nil + value = '' if value.nil? + # append the key value pair on the result array + parsed << [ + decode_www_form_component_18(key), + decode_www_form_component_18(value) + ] + end + # return result array + return parsed + end + + TBLDECWWWCOMP18_ = {} + + # Own implementation of decode_www_form_component. + # Shall behave almost like the original method, but without any encoding + # stuff. + # + # @param [String] string + # @return [String] + # + def self.decode_www_form_component_18(string) + # Fill table for URI special chars + if TBLDECWWWCOMP18_.empty? + tbl = {} + 256.times do |i| + h, l = i>>4, i&15 + tbl['%%%X%X' % [h, l]] = i.chr + tbl['%%%x%X' % [h, l]] = i.chr + tbl['%%%X%x' % [h, l]] = i.chr + tbl['%%%x%x' % [h, l]] = i.chr + end + tbl['+'] = ' ' + begin + TBLDECWWWCOMP18_.replace(tbl) + TBLDECWWWCOMP18_.freeze + rescue + end + end + # unless /\A[^%]*(?:%\h\h[^%]*)*\z/ =~ str + # raise ArgumentError, "invalid %-encoding (#{str})" + # end + + # Replace URI special chars + string.gsub(/\+|%[a-zA-Z0-9]{2}/) do |sub_string| + TBLDECWWWCOMP18_[sub_string] + end + end + +end diff --git a/spec/unit/uri/decode_www_form_18_spec.rb b/spec/unit/uri/decode_www_form_18_spec.rb new file mode 100644 index 0000000..21e1b7c --- /dev/null +++ b/spec/unit/uri/decode_www_form_18_spec.rb @@ -0,0 +1,147 @@ +# encoding: UTF-8 + +require 'spec_helper' + +describe URI, '#decode_www_form_18' do + + it 'seperates parameter into an array' do + result = URI::decode_www_form_18("foo=bar&bar=foo") + + result.should eq([['foo', 'bar'], ['bar', 'foo']]) + end + + it 'can handle more than two equal parameter names' do + result = URI::decode_www_form_18("foo=bar1&foo=bar2") + + result.should eq([['foo', 'bar1'], ['foo', 'bar2']]) + end + + it 'can handle whitespaces in query string' do + result = URI::decode_www_form_18("foo=bar&bar=bar%20foo") + + result.should eq([['foo', 'bar'], ['bar', 'bar foo']]) + end + + it 'accepts semi-colons as seperators' do + result = URI::decode_www_form_18("foo=bar;bar=foo") + + result.should eq([['foo', 'bar'], ['bar', 'foo']]) + end + + it 'seperates & and ; mixed queries properly' do + result = URI::decode_www_form_18("foo=bar&bar=foo;baz=foo") + + result.should eq([['foo', 'bar'], ['bar', 'foo'], ['baz', 'foo']]) + end + + it 'does not accept only a normal string as query string' do + expect{ + result = URI::decode_www_form_18("foo") + + # does not work, probably should? + #result.should eq([['foo', '']]) + }.to raise_error( + ArgumentError, + "invalid data of application/x-www-form-urlencoded (foo)" + ) + end + + it 'accepts empty values' do + result = URI::decode_www_form_18("foo=bar&bar=&baz=foo") + + result.should eq([['foo', 'bar'], ['bar', ''], ['baz', 'foo']]) + end + + it 'understands plus as whitespace' do + result = URI::decode_www_form_18("foo=bar&bar=bar+foo") + + result.should eq([['foo', 'bar'], ['bar', 'bar foo']]) + end + + it 'does not accept whitespaces in query string' do + result = URI::decode_www_form_18("foo=bar&bar=bar foo&baz=foo") + + # Works, it probably shouldn't? + result.should eq([['foo', 'bar'], ['bar', 'bar foo'], ['baz', 'foo']]) + end + + it 'can handle non ascii letters in query string' do + result = URI::decode_www_form_18("foo=bär&bar=föö") + + # Works, but it maybe shouldn't? + result.should eq([['foo', 'bär'], ['bar', 'föö']]) + end + + it 'can handle escaped non ascii letters in query string' do + result = URI::decode_www_form_18("foo=b%C3%A4r&bar=f%C3%B6%C3%B6") + + result.should eq([['foo', 'bär'], ['bar', 'föö']]) + end + + it 'accepts - in query string' do + result = URI::decode_www_form_18("foo-bar=bar&bar=foo-bar") + + puts (URI::decode_www_form_18("foo-bar=bar&bar=foo-bar") == [['foo-bar', 'bar'], ['bar', 'foo-bar']]).inspect + + result.should eq([['foo-bar', 'bar'], ['bar', 'foo-bar']]) + end + + it 'accepts . in query string' do + result = URI::decode_www_form_18("foo.bar=bar&bar=foo.bar") + + result.should eq([['foo.bar', 'bar'], ['bar', 'foo.bar']]) + end + + it 'accepts ~ in query string' do + result = URI::decode_www_form_18("foo~bar=bar&bar=foo~bar") + + result.should eq([['foo~bar', 'bar'], ['bar', 'foo~bar']]) + end + + it 'accepts _ in query string' do + result = URI::decode_www_form_18("foo_bar=bar&bar=foo_bar") + + result.should eq([['foo_bar', 'bar'], ['bar', 'foo_bar']]) + end + + it 'handles [ ] in query string' do + result = URI::decode_www_form_18("foo[]=foo&foo[]=bar") + + result.should eq([['foo[]', 'foo'], ['foo[]', 'bar']]) + end + + it 'returns an empty array, if query string is empty' do + result = URI::decode_www_form_18("") + + result.should eq([]) + end + + it 'throws an error, if more than one = without an & or ; in between' do + expect { + result = URI::decode_www_form_18("foo=bar=foo&bar=foo=bar") + }.to raise_error( + ArgumentError, + "invalid data of application/x-www-form-urlencoded "+ + "(foo=bar=foo&bar=foo=bar)" + ) + end + + it 'throws an error, if more than one & without an = in between' do + expect { + result = URI::decode_www_form_18("foo&bar=foo&bar") + }.to raise_error( + ArgumentError, + "invalid data of application/x-www-form-urlencoded (foo&bar=foo&bar)" + ) + end + + it 'throws an error, if more than one ; without an = in between' do + expect { + result = URI::decode_www_form_18("foo;bar=foo;bar") + }.to raise_error( + ArgumentError, + "invalid data of application/x-www-form-urlencoded (foo;bar=foo;bar)" + ) + end + +end |