aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.lock10
-rw-r--r--lib/zero.rb4
-rw-r--r--lib/zero/patches/uri.rb90
-rw-r--r--spec/unit/uri/decode_www_form_18_spec.rb147
5 files changed, 242 insertions, 11 deletions
diff --git a/Gemfile b/Gemfile
index 9bd3f2c..095cb54 100644
--- a/Gemfile
+++ b/Gemfile
@@ -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