module Rack::Utils
Rack::Utils
contains a grab-bag of useful methods for writing web applications adopted from all kinds of Ruby libraries.
Constants
- COMMON_SEP
- DEFAULT_SEP
- ESCAPE_HTML
- ESCAPE_HTML_PATTERN
- HTTP_STATUS_CODES
-
Every standard HTTP code mapped to the appropriate message. Generated with:
curl -s https://www.iana.org/assignments/http-status-codes/http-status-codes-1.csv | \ ruby -ne 'm = /^(\d{3}),(?!Unassigned|\(Unused\))([^,]+)/.match($_) and \ puts "#{m[1]} => \x27#{m[2].strip}\x27,"'
- InvalidParameterError
- KeySpaceConstrainedParams
- NULL_BYTE
- PATH_SEPS
- ParameterTypeError
- ParamsTooDeepError
- STATUS_WITH_NO_ENTITY_BODY
-
Responses with HTTP status codes that should not have an entity body
- SYMBOL_TO_STATUS_CODE
Attributes
Public Class Methods
Source
# File lib/rack/utils.rb, line 155 def forwarded_values(forwarded_header) return nil unless forwarded_header forwarded_header = forwarded_header.to_s.gsub("\n", ";") forwarded_header.split(';').each_with_object({}) do |field, values| field.split(',').each do |pair| pair = pair.split('=').map(&:strip).join('=') return nil unless pair =~ /\A(by|for|host|proto)="?([^"]+)"?\Z/i (values[$1.downcase.to_sym] ||= []) << $2 end end end
Source
# File lib/rack/utils.rb, line 87 def self.key_space_limit warn("`Rack::Utils.key_space_limit` is deprecated as this value no longer has an effect. It will be removed in Rack 3.1", uplevel: 1) 65536 end
Source
# File lib/rack/utils.rb, line 92 def self.key_space_limit=(v) warn("`Rack::Utils.key_space_limit=` is deprecated and no longer has an effect. It will be removed in Rack 3.1", uplevel: 1) end
Source
# File lib/rack/utils.rb, line 79 def self.param_depth_limit default_query_parser.param_depth_limit end
Source
# File lib/rack/utils.rb, line 83 def self.param_depth_limit=(v) self.default_query_parser = self.default_query_parser.new_depth_limit(v) end
Public Instance Methods
Source
# File lib/rack/utils.rb, line 173 def best_q_match(q_value_header, available_mimes) values = q_values(q_value_header) matches = values.map do |req_mime, quality| match = available_mimes.find { |am| Rack::Mime.match?(am, req_mime) } next unless match [match, quality] end.compact.sort_by do |match, quality| (match.split('/', 2).count('*') * -10) + quality end.last matches&.first end
Return best accept value to use, based on the algorithm in RFC 2616 Section 14. If there are multiple best matches (same specificity and quality), the value returned is arbitrary.
Source
# File lib/rack/utils.rb, line 126 def build_nested_query(value, prefix = nil) case value when Array value.map { |v| build_nested_query(v, "#{prefix}[]") }.join("&") when Hash value.map { |k, v| build_nested_query(v, prefix ? "#{prefix}[#{k}]" : k) }.delete_if(&:empty?).join('&') when nil escape(prefix) else raise ArgumentError, "value must be a Hash" if prefix.nil? "#{escape(prefix)}=#{escape(value)}" end end
Source
# File lib/rack/utils.rb, line 116 def build_query(params) params.map { |k, v| if v.class == Array build_query(v.map { |x| [k, x] }) else v.nil? ? escape(k) : "#{escape(k)}=#{escape(v)}" end }.join("&") end
Source
# File lib/rack/utils.rb, line 431 def byte_ranges(env, size) get_byte_ranges env['HTTP_RANGE'], size end
Parses the “Range:” header, if present, into an array of Range objects. Returns nil if the header is missing or syntactically invalid. Returns an empty array if none of the ranges are satisfiable.
Source
# File lib/rack/utils.rb, line 635 def clean_path_info(path_info) parts = path_info.split PATH_SEPS clean = [] parts.each do |part| next if part.empty? || part == '.' part == '..' ? clean.pop : clean << part end clean_path = clean.join(::File::SEPARATOR) clean_path.prepend("/") if parts.empty? || parts.first.empty? clean_path end
Source
# File lib/rack/utils.rb, line 97 def clock_time Process.clock_gettime(Process::CLOCK_MONOTONIC) end
Source
# File lib/rack/utils.rb, line 37 def escape(s) URI.encode_www_form_component(s) end
URI escapes. (CGI style space to +)
Source
# File lib/rack/utils.rb, line 198 def escape_html(string) string.to_s.gsub(ESCAPE_HTML_PATTERN){|c| ESCAPE_HTML[c] } end
Escape ampersands, brackets and quotes to their HTML/XML entities.
Source
# File lib/rack/utils.rb, line 43 def escape_path(s) ::URI::DEFAULT_PARSER.escape s end
Like URI escaping, but with %20 instead of +. Strictly speaking this is true URI escaping.
Source
# File lib/rack/utils.rb, line 435 def get_byte_ranges(http_range, size) # See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35> return nil unless http_range && http_range =~ /bytes=([^;]+)/ ranges = [] $1.split(/,\s*/).each do |range_spec| return nil unless range_spec.include?('-') range = range_spec.split('-') r0, r1 = range[0], range[1] if r0.nil? || r0.empty? return nil if r1.nil? # suffix-byte-range-spec, represents trailing suffix of file r0 = size - r1.to_i r0 = 0 if r0 < 0 r1 = size - 1 else r0 = r0.to_i if r1.nil? r1 = size - 1 else r1 = r1.to_i return nil if r1 < r0 # backwards range is syntactically invalid r1 = size - 1 if r1 >= size end end ranges << (r0..r1) if r0 <= r1 end return [] if ranges.map(&:size).sum > size ranges end
Source
# File lib/rack/utils.rb, line 112 def parse_nested_query(qs, d = nil) Rack::Utils.default_query_parser.parse_nested_query(qs, d) end
Source
# File lib/rack/utils.rb, line 108 def parse_query(qs, d = nil, &unescaper) Rack::Utils.default_query_parser.parse_query(qs, d, &unescaper) end
Source
# File lib/rack/utils.rb, line 144 def q_values(q_value_header) q_value_header.to_s.split(',').map do |part| value, parameters = part.split(';', 2).map(&:strip) quality = 1.0 if parameters && (md = /\Aq=([\d.]+)/.match(parameters)) quality = md[1].to_f end [value, quality] end end
Source
# File lib/rack/utils.rb, line 475 def secure_compare(a, b) return false unless a.bytesize == b.bytesize OpenSSL.fixed_length_secure_compare(a, b) end
Constant time string comparison.
NOTE: the values compared should be of fixed length, such as strings that have already been processed by HMAC. This should not be used on variable length plaintext strings because it could leak length info via timing attacks.
Source
# File lib/rack/utils.rb, line 202 def select_best_encoding(available_encodings, accept_encoding) # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html expanded_accept_encoding = [] accept_encoding.each do |m, q| preference = available_encodings.index(m) || available_encodings.size if m == "*" (available_encodings - accept_encoding.map(&:first)).each do |m2| expanded_accept_encoding << [m2, q, preference] end else expanded_accept_encoding << [m, q, preference] end end encoding_candidates = expanded_accept_encoding .sort_by { |_, q, p| [-q, p] } .map!(&:first) unless encoding_candidates.include?("identity") encoding_candidates.push("identity") end expanded_accept_encoding.each do |m, q| encoding_candidates.delete(m) if q == 0.0 end (encoding_candidates & available_encodings)[0] end
Source
# File lib/rack/utils.rb, line 625 def status_code(status) if status.is_a?(Symbol) SYMBOL_TO_STATUS_CODE.fetch(status) { raise ArgumentError, "Unrecognized status code #{status.inspect}" } else status.to_i end end
Source
# File lib/rack/utils.rb, line 55 def unescape(s, encoding = Encoding::UTF_8) URI.decode_www_form_component(s, encoding) end
Unescapes a URI escaped string with encoding
. encoding
will be the target encoding of the string returned, and it defaults to UTF-8
Source
# File lib/rack/utils.rb, line 49 def unescape_path(s) ::URI::DEFAULT_PARSER.unescape s end
Unescapes the path component of a URI. See Rack::Utils.unescape
for unescaping query parameters or form components.
Source
# File lib/rack/utils.rb, line 652 def valid_path?(path) path.valid_encoding? && !path.include?(NULL_BYTE) end