# class Rack::QueryParser

### Constants

BYTESIZE_LIMIT
COMMON_SEP
DEFAULT_SEP
PARAMS_LIMIT
ParamsTooDeepError

  `QueryLimitError` is for errors raised when the query provided exceeds one of the query parser limits.

### Attributes

bytesize_limit[R]
key_space_limit[R]
param_depth_limit[R]

### Public Class Methods

make_default(key_space_limit, param_depth_limit, **options) click to toggle source

    # File lib/rack/query_parser.rb, line 30
    def self.make_default(key_space_limit, param_depth_limit, **options)
      new(Params, key_space_limit, param_depth_limit, **options)
    end

new(params_class, key_space_limit, param_depth_limit, bytesize_limit: BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT) click to toggle source

    # File lib/rack/query_parser.rb, line 56
    def initialize(params_class, key_space_limit, param_depth_limit, bytesize_limit: BYTESIZE_LIMIT, params_limit: PARAMS_LIMIT)
      @params_class = params_class
      @key_space_limit = key_space_limit
      @param_depth_limit = param_depth_limit
      @bytesize_limit = bytesize_limit
      @params_limit = params_limit
    end

### Public Instance Methods

make_params() click to toggle source

    # File lib/rack/query_parser.rb, line 157
    def make_params
      @params_class.new @key_space_limit
    end

new_depth_limit(param_depth_limit) click to toggle source

    # File lib/rack/query_parser.rb, line 165
    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) click to toggle source

    # File lib/rack/query_parser.rb, line 161
    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) click to toggle source

`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.

    # File lib/rack/query_parser.rb, line 116
    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) click to toggle source

`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.

    # File lib/rack/query_parser.rb, line 97
    def parse_nested_query(qs, d = nil)
      params = make_params

      unless qs.nil? || qs.empty?
        check_query_string(qs, d).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) click to toggle source

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 '&;').

    # File lib/rack/query_parser.rb, line 69
    def parse_query(qs, d = nil, &unescaper)
      unescaper ||= method(:unescape)

      params = make_params

      check_query_string(qs, d).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

### Private Instance Methods

check_query_string(qs, sep) click to toggle source

    # File lib/rack/query_parser.rb, line 187
    def check_query_string(qs, sep)
      if qs
        if qs.bytesize > @bytesize_limit
          raise QueryLimitError, "total query size exceeds limit (#{@bytesize_limit})"
        end

        if (param_count = qs.count(sep.is_a?(String) ? sep : '&;')) >= @params_limit
          raise QueryLimitError, "total number of query parameters (#{param_count+1}) exceeds limit (#{@params_limit})"
        end

        qs
      else
        ''
      end
    end

params_hash_has_key?(hash, key) click to toggle source

    # File lib/rack/query_parser.rb, line 175
    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) click to toggle source

    # File lib/rack/query_parser.rb, line 171
    def params_hash_type?(obj)
      obj.kind_of?(@params_class)
    end

unescape(string) click to toggle source

    # File lib/rack/query_parser.rb, line 203
    def unescape(string)
      Utils.unescape(string)
    end