build_nested_query(value, prefix = nil)click to toggle source
# File lib/rack/utils.rb, line 185defbuild_nested_query(value, prefix = nil)
casevaluewhenArrayvalue.map { |v|build_nested_query(v, "#{prefix}[]")
}.join("&")
whenHashvalue.map { |k, v|build_nested_query(v, prefix?"#{prefix}[#{escape(k)}]":escape(k))
}.reject(&:empty?).join('&')
whennilprefixelseraiseArgumentError, "value must be a Hash"ifprefix.nil?"#{prefix}=#{escape(value)}"endend
build_query(params)click to toggle source
# File lib/rack/utils.rb, line 174defbuild_query(params)
params.map { |k, v|ifv.class==Arraybuild_query(v.map { |x| [k, x] })
elsev.nil??escape(k) :"#{escape(k)}=#{escape(v)}"end
}.join("&")
end
byte_ranges(env, size)click to toggle source
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.
# File lib/rack/utils.rb, line 401defbyte_ranges(env, size)
# See <http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35>http_range = env['HTTP_RANGE']
returnnilunlesshttp_range&&http_range=~/bytes=([^;]+)/ranges = []
$1.split(/,\s*/).eachdo|range_spec|returnnilunlessrange_spec=~/(\d*)-(\d*)/r0,r1 = $1, $2ifr0.empty?returnnilifr1.empty?# suffix-byte-range-spec, represents trailing suffix of filer0 = size-r1.to_ir0 = 0ifr0<0r1 = size-1elser0 = r0.to_iifr1.empty?r1 = size-1elser1 = r1.to_ireturnnilifr1<r0# backwards range is syntactically invalidr1 = size-1ifr1>=sizeendendranges<< (r0..r1) ifr0<=r1endrangesend
bytesize(string)click to toggle source
# File lib/rack/utils.rb, line 367defbytesize(string)
string.bytesizeend
clean_path_info(path_info)click to toggle source
# File lib/rack/utils.rb, line 666defclean_path_info(path_info)
parts = path_info.splitPATH_SEPSclean = []
parts.eachdo|part|nextifpart.empty?||part=='.'part=='..'?clean.pop:clean<<partendclean.unshift'/'ifparts.empty?||parts.first.empty?::File.join(*clean)
end
delete_cookie_header!(header, key, value = {})click to toggle source
# File lib/rack/utils.rb, line 34defescape(s)
URI.encode_www_form_component(s)
end
escape_html(string)click to toggle source
Escape ampersands, brackets and quotes to their HTML/XML entities.
# File lib/rack/utils.rb, line 247defescape_html(string)
string.to_s.gsub(ESCAPE_HTML_PATTERN){|c|ESCAPE_HTML[c] }
end
escape_path(s)click to toggle source
Like URI escaping, but with %20 instead of +. Strictly speaking this is
true URI escaping.
# File lib/rack/utils.rb, line 41defescape_path(s)
escape(s).gsub('+', '%20')
end
normalize_params(params, name, v = nil, depth = Utils.param_depth_limit)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/utils.rb, line 169defparams_hash_type?(obj)
obj.kind_of?(KeySpaceConstrainedParams) ||obj.kind_of?(Hash)
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/utils.rb, line 115defparse_nested_query(qs, d = nil)
params = KeySpaceConstrainedParams.new
(qs||'').split(d?/[#{d}] */:DEFAULT_SEP).eachdo|p|k, v = p.split('=', 2).map { |s|unescape(s) }
normalize_params(params, k, v)
endreturnparams.to_params_hashrescueArgumentError =>eraiseInvalidParameterError, e.messageend
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/utils.rb, line 86defparse_query(qs, d = nil, &unescaper)
unescaper||=method(:unescape)
params = KeySpaceConstrainedParams.new
(qs||'').split(d?/[#{d}] */:DEFAULT_SEP).eachdo|p|nextifp.empty?k, v = p.split('=', 2).map(&unescaper)
ifcur = params[k]
ifcur.class==Arrayparams[k] <<velseparams[k] = [cur, v]
endelseparams[k] = vendendreturnparams.to_params_hashend
Modified version of stdlib time.rb Time#rfc2822 to use '%d-%b-%Y' instead
of '% %b %Y'. It assumes that the time is in GMT to comply to the RFC 2109.
NOTE: I'm not sure the RFC says it requires GMT, but is ambiguous enough
that I'm certain someone implemented only that option. Do not use %a and %b
from Time.strptime, it would use localized names for weekday and month.
# File lib/rack/utils.rb, line 391defrfc2109(time)
wday = Time::RFC2822_DAY_NAME[time.wday]
mon = Time::RFC2822_MONTH_NAME[time.mon-1]
time.strftime("#{wday}, %d-#{mon}-%Y %H:%M:%S GMT")
end
rfc2822(time)click to toggle source
# File lib/rack/utils.rb, line 377defrfc2822(time)
time.rfc2822end
secure_compare(a, b)click to toggle source
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.
# File lib/rack/utils.rb, line 437defsecure_compare(a, b)
returnfalseunlessbytesize(a) ==bytesize(b)
l = a.unpack("C*")
r, i = 0, -1b.each_byte { |v|r|=v^l[i+=1] }
r==0end
select_best_encoding(available_encodings, accept_encoding)click to toggle source
set_cookie_header!(header, key, value)click to toggle source
# File lib/rack/utils.rb, line 280defset_cookie_header!(header, key, value)
casevaluewhenHashdomain = "; domain="+value[:domain] ifvalue[:domain]
path = "; path="+value[:path] ifvalue[:path]
max_age = "; max-age="+value[:max_age].to_sifvalue[:max_age]
# There is an RFC mess in the area of date formatting for Cookies. Not# only are there contradicting RFCs and examples within RFC text, but# there are also numerous conflicting names of fields and partially# cross-applicable specifications.## These are best described in RFC 2616 3.3.1. This RFC text also# specifies that RFC 822 as updated by RFC 1123 is preferred. That is a# fixed length format with space-date delimeted fields.## See also RFC 1123 section 5.2.14.## RFC 6265 also specifies "sane-cookie-date" as RFC 1123 date, defined# in RFC 2616 3.3.1. RFC 6265 also gives examples that clearly denote# the space delimited format. These formats are compliant with RFC 2822.## For reference, all involved RFCs are:# RFC 822# RFC 1123# RFC 2109# RFC 2616# RFC 2822# RFC 2965# RFC 6265expires = "; expires="+rfc2822(value[:expires].clone.gmtime) ifvalue[:expires]
secure = "; secure"ifvalue[:secure]
httponly = "; HttpOnly"if (value.key?(:httponly) ?value[:httponly] :value[:http_only])
value = value[:value]
endvalue = [value] unlessArray===valuecookie = escape(key) +"="+value.map { |v|escapev }.join("&") +"#{domain}#{path}#{max_age}#{expires}#{secure}#{httponly}"caseheader["Set-Cookie"]
whennil, ''header["Set-Cookie"] = cookiewhenStringheader["Set-Cookie"] = [header["Set-Cookie"], cookie].join("\n")
whenArrayheader["Set-Cookie"] = (header["Set-Cookie"] + [cookie]).join("\n")
endnilend
status_code(status)click to toggle source
# File lib/rack/utils.rb, line 653defstatus_code(status)
ifstatus.is_a?(Symbol)
SYMBOL_TO_STATUS_CODE[status] ||500elsestatus.to_iendend
unescape(s, encoding = Encoding::UTF_8)click to toggle source
# File lib/rack/utils.rb, line 49defunescape(s, encoding = Encoding::UTF_8)
URI.decode_www_form_component(s, encoding)
end