diff --git a/heroics.gemspec b/heroics.gemspec index 469d782..66ae460 100644 --- a/heroics.gemspec +++ b/heroics.gemspec @@ -31,6 +31,5 @@ Gem::Specification.new do |spec| spec.add_dependency 'excon' spec.add_dependency 'multi_json', '>= 1.9.2' spec.add_dependency 'moneta' - spec.add_dependency 'webrick' spec.add_dependency 'base64' end diff --git a/lib/heroics.rb b/lib/heroics.rb index e9a4ac5..81845d6 100644 --- a/lib/heroics.rb +++ b/lib/heroics.rb @@ -4,7 +4,6 @@ require 'excon' require 'multi_json' require 'uri' -require 'webrick' require 'zlib' # Heroics is an HTTP client for an API described by a JSON schema. diff --git a/lib/heroics/schema.rb b/lib/heroics/schema.rb index 891f360..a23dd1c 100644 --- a/lib/heroics/schema.rb +++ b/lib/heroics/schema.rb @@ -334,7 +334,39 @@ def lookup_parameter(path, schema) # @return [String] The formatted parameter. def format_parameter(parameter) formatted_parameter = parameter.instance_of?(Time) ? iso_format(parameter) : parameter.to_s - WEBrick::HTTPUtils.escape formatted_parameter + url_escape_parameter formatted_parameter + end + + # URL escape a path parameter. Copied from WEBrick::HTTPUtils.escape: + # https://github.com/ruby/webrick/blob/master/lib/webrick/httputils.rb#L498 + # + # @param [Fixnum,String,TrueClass,FalseClass,Time] The parameter to escape. + # @return [String] The escaped parameter. + def url_escape_parameter(parameter) + # Note: this RegEx is obtained by executing WEBrick::HTTPUtils::UNESCAPED, + # splitting it over multiple lines and using the x modifier to make this possible. + regex = %r{ + ([ + \x00\x01\x02\x03\x04\x05\x06\x07\x08 + \t\n\v\f\r + \x0E\x0F\x10\x11\x12\x13\x14\x15\x16 + \x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F\x7F + \ <>\#%"\{\}\|\\\^\[\]` + \x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8A\x8B\x8C\x8D\x8E\x8F + \x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9A\x9B\x9C\x9D\x9E\x9F + \xA0\xA1\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xAA\xAB\xAC\xAD\xAE\xAF + \xB0\xB1\xB2\xB3\xB4\xB5\xB6\xB7\xB8\xB9\xBA\xBB\xBC\xBD\xBE\xBF + \xC0\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xCA\xCB\xCC\xCD\xCE\xCF + \xD0\xD1\xD2\xD3\xD4\xD5\xD6\xD7\xD8\xD9\xDA\xDB\xDC\xDD\xDE\xDF + \xE0\xE1\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xEA\xEB\xEC\xED\xEE\xEF + \xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\xFA\xFB\xFC\xFD\xFE\xFF + ]) + }nx + + parameter = parameter.b + parameter.gsub!(regex) {"%%%02X" % $1.ord} + # %-escaped string should contain US-ASCII only + parameter.force_encoding(Encoding::US_ASCII) end # Convert a time to an ISO 8601 combined data and time format.