Class: Rack::QueryParser
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Exceptions:
| |
Inherits: | Object |
Defined in: | lib/rack/query_parser.rb |
Constant Summary
-
COMMON_SEP =
# File 'lib/rack/query_parser.rb', line 9{ ";" => /; */n, ";," => /[;,] */n, "&" => /& */n }
-
DEFAULT_SEP =
# File 'lib/rack/query_parser.rb', line 8/& */n
Class Method Summary
Instance Attribute Summary
- #param_depth_limit readonly
Instance Method Summary
- #make_params
- #new_depth_limit(param_depth_limit)
-
#normalize_params(params, name, v, _depth = nil)
normalize_params recursively expands parameters into structural types.
-
#parse_nested_query(qs, separator = nil)
parse_nested_query expands a query string into structural types.
-
#parse_query(qs, separator = nil, &unescaper)
Stolen from Mongrel, with some small modifications: Parses a query string by breaking it up at the ‘&’.
- #_normalize_params(params, name, v, depth) private
- #params_hash_has_key?(hash, key) ⇒ Boolean private
- #params_hash_type?(obj) ⇒ Boolean private
- #unescape(string, encoding = Encoding::UTF_8) private
Constructor Details
.new(params_class, param_depth_limit) ⇒ QueryParser
# File 'lib/rack/query_parser.rb', line 36
def initialize(params_class, param_depth_limit) @params_class = params_class @param_depth_limit = param_depth_limit end
Class Method Details
.make_default(param_depth_limit)
[ GitHub ]# File 'lib/rack/query_parser.rb', line 30
def self.make_default(param_depth_limit) new Params, param_depth_limit end
Instance Attribute Details
#param_depth_limit (readonly)
[ GitHub ]# File 'lib/rack/query_parser.rb', line 34
attr_reader :param_depth_limit
Instance Method Details
#_normalize_params(params, name, v, depth) (private)
# File 'lib/rack/query_parser.rb', line 98
private def _normalize_params(params, name, v, depth) raise ParamsTooDeepError if depth >= param_depth_limit if !name # nil name, treat same as empty string (required by tests) k = after = '' elsif depth == 0 # Start of parsing, don't treat [] or [ at start of string specially if start = name.index('[', 1) # Start of parameter nesting, use part before brackets as key k = name[0, start] after = name[start, name.length] else # Plain parameter with no nesting k = name after = '' end elsif name.start_with?('[]') # Array nesting k = '[]' after = name[2, name.length] elsif name.start_with?('[') && (start = name.index(']', 1)) # Hash nesting, use the part inside brackets as the key k = name[1, start-1] after = name[start+1, name.length] else # Probably malformed input, nested but not starting with [ # treat full name as key for backwards compatibility. k = name after = '' end return if k.empty? if after == '' if k == '[]' && depth != 0 return [v] else params[k] = v end elsif after == "[" params[name] = v elsif after == "[]" params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) params[k] << v elsif after.start_with?('[]') # Recognize x[][y] (hash inside array) parameters unless after[2] == '[' && after.end_with?(']') && (child_key = after[3, after.length-4]) && !child_key.empty? && !child_key.index('[') && !child_key.index(']') # Handle other nested array parameters child_key = after[2, after.length] end params[k] ||= [] raise ParameterTypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) if params_hash_type?(params[k].last) && !params_hash_has_key?(params[k].last, child_key) _normalize_params(params[k].last, child_key, v, depth + 1) else params[k] << _normalize_params(make_params, child_key, v, depth + 1) end else params[k] ||= make_params raise ParameterTypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params_hash_type?(params[k]) params[k] = _normalize_params(params[k], after, v, depth + 1) end params end
#make_params
[ GitHub ]# File 'lib/rack/query_parser.rb', line 166
def make_params @params_class.new end
#new_depth_limit(param_depth_limit)
[ GitHub ]# File 'lib/rack/query_parser.rb', line 170
def new_depth_limit(param_depth_limit) self.class.new @params_class, param_depth_limit end
#normalize_params(params, name, v, _depth = nil)
normalize_params recursively expands parameters into structural types. If the structural types represented by two different parameter names are in conflict, a QueryParser::ParameterTypeError
is raised. The depth argument is deprecated and should no longer be used, it is kept for backwards compatibility with earlier versions of rack.
# File 'lib/rack/query_parser.rb', line 94
def normalize_params(params, name, v, _depth=nil) _normalize_params(params, name, v, 0) end
#params_hash_has_key?(hash, key) ⇒ Boolean
(private)
# File 'lib/rack/query_parser.rb', line 180
def params_hash_has_key?(hash, key) return false if /\[\]/.match?(key) key.split(/[\[\]]+/).inject(hash) do |h, part| next h if part == '' return false unless params_hash_type?(h) && h.key?(part) h[part] end true end
#params_hash_type?(obj) ⇒ Boolean
(private)
# File 'lib/rack/query_parser.rb', line 176
def params_hash_type?(obj) obj.kind_of?(@params_class) end
#parse_nested_query(qs, separator = nil)
parse_nested_query expands a query string into structural types. Supported types are Arrays, Hashes and basic value types. It is possible to supply query strings with parameters of conflicting types, in this case a QueryParser::ParameterTypeError
is raised. Users are encouraged to return a 400 in this case.
# File 'lib/rack/query_parser.rb', line 73
def parse_nested_query(qs, separator = nil) params = make_params unless qs.nil? || qs.empty? (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p| k, v = p.split('=', 2).map! { |s| unescape(s) } _normalize_params(params, k, v, 0) end end return params.to_h rescue ArgumentError => e raise InvalidParameterError, e., e.backtrace end
#parse_query(qs, separator = nil, &unescaper)
Stolen from Mongrel, with some small modifications: Parses a query string by breaking it up at the ‘&’. You can also use this to parse cookies by changing the characters used in the second parameter (which defaults to ‘&’).
# File 'lib/rack/query_parser.rb', line 45
def parse_query(qs, separator = nil, &unescaper) unescaper ||= method(:unescape) params = make_params (qs || '').split(separator ? (COMMON_SEP[separator] || /[#{separator}] */n) : DEFAULT_SEP).each do |p| next if p.empty? k, v = p.split('=', 2).map!(&unescaper) if cur = params[k] if cur.class == Array params[k] << v else params[k] = [cur, v] end else params[k] = v end end return params.to_h end
#unescape(string, encoding = Encoding::UTF_8) (private)
[ GitHub ]# File 'lib/rack/query_parser.rb', line 192
def unescape(string, encoding = Encoding::UTF_8) URI.decode_www_form_component(string, encoding) end