Class: Rack::QueryParser

Inherits:
Object
  • Object
show all
Defined in:
lib/rack/query_parser.rb

Defined Under Namespace

Classes: InvalidParameterError, ParameterTypeError, Params, ParamsTooDeepError

Constant Summary collapse

DEFAULT_SEP =
/[&;] */n
COMMON_SEP =
{ ";" => /[;] */n, ";," => /[;,] */n, "&" => /[&] */n }

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(params_class, key_space_limit, param_depth_limit) ⇒ QueryParser

Returns a new instance of QueryParser.



29
30
31
32
33
# File 'lib/rack/query_parser.rb', line 29

def initialize(params_class, key_space_limit, param_depth_limit)
  @params_class = params_class
  @key_space_limit = key_space_limit
  @param_depth_limit = param_depth_limit
end

Instance Attribute Details

#key_space_limitObject (readonly)

Returns the value of attribute key_space_limit.



27
28
29
# File 'lib/rack/query_parser.rb', line 27

def key_space_limit
  @key_space_limit
end

#param_depth_limitObject (readonly)

Returns the value of attribute param_depth_limit.



27
28
29
# File 'lib/rack/query_parser.rb', line 27

def param_depth_limit
  @param_depth_limit
end

Class Method Details

.make_default(key_space_limit, param_depth_limit) ⇒ Object



23
24
25
# File 'lib/rack/query_parser.rb', line 23

def self.make_default(key_space_limit, param_depth_limit)
  new Params, key_space_limit, param_depth_limit
end

Instance Method Details

#make_paramsObject



128
129
130
# File 'lib/rack/query_parser.rb', line 128

def make_params
  @params_class.new @key_space_limit
end

#new_depth_limit(param_depth_limit) ⇒ Object



136
137
138
# File 'lib/rack/query_parser.rb', line 136

def new_depth_limit(param_depth_limit)
  self.class.new @params_class, key_space_limit, param_depth_limit
end

#new_space_limit(key_space_limit) ⇒ Object



132
133
134
# File 'lib/rack/query_parser.rb', line 132

def new_space_limit(key_space_limit)
  self.class.new @params_class, key_space_limit, param_depth_limit
end

#normalize_params(params, name, v, depth) ⇒ Object

normalize_params recursively expands parameters into structural types. If the structural types represented by two different parameter names are in conflict, a ParameterTypeError is raised.

Raises:



87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/rack/query_parser.rb', line 87

def normalize_params(params, name, v, depth)
  raise ParamsTooDeepError if depth <= 0

  name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
  k = $1 || ''
  after = $' || ''

  if k.empty?
    if !v.nil? && name == "[]"
      return Array(v)
    else
      return
    end
  end

  if after == ''
    params[k] = v
  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 =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$)
    child_key = $1
    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

#parse_nested_query(qs, d = nil) ⇒ Object

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 ParameterTypeError is raised. Users are encouraged to return a 400 in this case.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/rack/query_parser.rb', line 68

def parse_nested_query(qs, d = nil)
  params = make_params

  unless qs.nil? || qs.empty?
    (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */n) : DEFAULT_SEP).each do |p|
      k, v = p.split('=', 2).map! { |s| unescape(s) }

      normalize_params(params, k, v, param_depth_limit)
    end
  end

  return params.to_h
rescue ArgumentError => e
  raise InvalidParameterError, e.message, e.backtrace
end

#parse_query(qs, d = nil, &unescaper) ⇒ Object

Stolen from Mongrel, with some small modifications: Parses a query string by breaking it up at the '&' and ';' characters. You can also use this to parse cookies by changing the characters used in the second parameter (which defaults to '&;').



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/rack/query_parser.rb', line 40

def parse_query(qs, d = nil, &unescaper)
  unescaper ||= method(:unescape)

  params = make_params

  (qs || '').split(d ? (COMMON_SEP[d] || /[#{d}] */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