Module: RestClient::Utils
- Defined in:
- lib/restclient/utils.rb
Overview
Various utility methods
Class Method Summary collapse
-
._cgi_parseparam(s) ⇒ Object
Parse semi-colon separated, potentially quoted header string iteratively.
-
.cgi_parse_header(line) ⇒ Array(String, Hash)
Parse a Content-Type like header.
-
.encode_query_string(object) ⇒ String
Serialize a ruby object into HTTP query string parameters.
-
.escape(string) ⇒ Object
Encode string for safe transport by URI or form encoding.
-
.flatten_params(object, uri_escape = false, parent_key = nil) ⇒ Object
Transform deeply nested param containers into a flat array of [key, value] pairs.
-
.get_encoding_from_headers(headers) ⇒ String?
Return encoding from an HTTP header hash.
Class Method Details
._cgi_parseparam(s) ⇒ Object
Parse semi-colon separated, potentially quoted header string iteratively.
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/restclient/utils.rb', line 40 def self._cgi_parseparam(s) return enum_for(__method__, s) unless block_given? while s[0] == ';' s = s[1..-1] ends = s.index(';') while ends && ends > 0 \ && (s[0...ends].count('"') - s[0...ends].scan('\"').count) % 2 != 0 ends = s.index(';', ends + 1) end if ends.nil? ends = s.length end f = s[0...ends] yield f.strip s = s[ends..-1] end nil end |
.cgi_parse_header(line) ⇒ Array(String, Hash)
Parse a Content-Type like header.
Return the main content-type and a hash of options.
This method was ported directly from Python’s cgi.parse_header(). It probably doesn’t read or perform particularly well in ruby. github.com/python/cpython/blob/3.4/Lib/cgi.py#L301-L331
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/restclient/utils.rb', line 73 def self.cgi_parse_header(line) parts = _cgi_parseparam(';' + line) key = parts.next pdict = {} begin while (p = parts.next) i = p.index('=') if i name = p[0...i].strip.downcase value = p[i+1..-1].strip if value.length >= 2 && value[0] == '"' && value[-1] == '"' value = value[1...-1] value = value.gsub('\\\\', '\\').gsub('\\"', '"') end pdict[name] = value end end rescue StopIteration end [key, pdict] end |
.encode_query_string(object) ⇒ String
Serialize a ruby object into HTTP query string parameters.
There is no standard for doing this, so we choose our own slightly idiosyncratic format. The output closely matches the format understood by Rails, Rack, and PHP.
If you don’t want handling of complex objects and only want to handle simple flat hashes, you may want to use ‘URI.encode_www_form` instead, which implements HTML5-compliant URL encoded form data.
Notable differences from the ActiveSupport implementation:
-
Empty hash and empty array are treated the same as nil instead of being omitted entirely from the output. Rather than disappearing, they will appear to be nil instead.
It’s most common to pass a Hash as the object to serialize, but you can also use a ParamsArray if you want to be able to pass the same key with multiple values and not use the rack/rails array convention.
167 168 169 |
# File 'lib/restclient/utils.rb', line 167 def self.encode_query_string(object) flatten_params(object, true).map {|k, v| v.nil? ? k : "#{k}=#{v}" }.join('&') end |
.escape(string) ⇒ Object
Encode string for safe transport by URI or form encoding. This uses a CGI style escape, which transforms ‘ ` into `+` and various special characters into percent encoded forms.
This calls URI.encode_www_form_component for the implementation. The only difference between this and CGI.escape is that it does not escape ‘*`. stackoverflow.com/questions/25085992/
231 232 233 |
# File 'lib/restclient/utils.rb', line 231 def self.escape(string) URI.encode_www_form_component(string) end |
.flatten_params(object, uri_escape = false, parent_key = nil) ⇒ Object
Transform deeply nested param containers into a flat array of [key, value] pairs.
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
# File 'lib/restclient/utils.rb', line 186 def self.flatten_params(object, uri_escape=false, parent_key=nil) unless object.is_a?(Hash) || object.is_a?(ParamsArray) || (parent_key && object.is_a?(Array)) raise ArgumentError.new('expected Hash or ParamsArray, got: ' + object.inspect) end # transform empty collections into nil, where possible if object.empty? && parent_key return [[parent_key, nil]] end # This is essentially .map(), but we need to do += for nested containers object.reduce([]) { |result, item| if object.is_a?(Array) # item is already the value k = nil v = item else # item is a key, value pair k, v = item k = escape(k.to_s) if uri_escape end processed_key = parent_key ? "#{parent_key}[#{k}]" : k case v when Array, Hash, ParamsArray result.concat flatten_params(v, uri_escape, processed_key) else v = escape(v.to_s) if uri_escape && v result << [processed_key, v] end } end |
.get_encoding_from_headers(headers) ⇒ String?
Return encoding from an HTTP header hash.
We use the RFC 7231 specification and do not impose a default encoding on text. This differs from the older RFC 2616 behavior, which specifies using ISO-8859-1 for text/* content types without a charset.
Strings will use the default encoding when this method returns nil. This default is likely to be UTF-8 for Ruby >= 2.0
23 24 25 26 27 28 29 30 31 32 33 34 |
# File 'lib/restclient/utils.rb', line 23 def self.get_encoding_from_headers(headers) type_header = headers[:content_type] return nil unless type_header _content_type, params = cgi_parse_header(type_header) if params.include?('charset') return params.fetch('charset').gsub(/(\A["']*)|(["']*\z)/, '') end nil end |