lib/rack/utils.rb in rack-0.4.0 vs lib/rack/utils.rb in rack-0.9.0
- old
+ new
@@ -1,5 +1,6 @@
+require 'set'
require 'tempfile'
module Rack
# Rack::Utils contains a grab-bag of useful methods for writing web
# applications adopted from all kinds of Ruby libraries.
@@ -29,29 +30,29 @@
# cookies by changing the characters used in the second
# parameter (which defaults to '&;').
def parse_query(qs, d = '&;')
params = {}
-
+
(qs || '').split(/[#{d}] */n).each do |p|
k, v = unescape(p).split('=', 2)
-
+
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
end
module_function :parse_query
-
+
def build_query(params)
params.map { |k, v|
if v.class == Array
build_query(v.map { |x| [k, x] })
else
@@ -153,31 +154,53 @@
pp.pp @app
end
end
end
- # A case-normalizing Hash, adjusting on [] and []=.
+ # A case-insensitive Hash that preserves the original case of a
+ # header when set.
class HeaderHash < Hash
def initialize(hash={})
+ @names = {}
hash.each { |k, v| self[k] = v }
end
def to_hash
{}.replace(self)
end
def [](k)
- super capitalize(k)
+ super @names[k.downcase]
end
def []=(k, v)
- super capitalize(k), v
+ delete k
+ @names[k.downcase] = k
+ super k, v
end
- def capitalize(k)
- k.to_s.downcase.gsub(/^.|[-_\s]./) { |x| x.upcase }
+ def delete(k)
+ super @names.delete(k.downcase)
end
+
+ def include?(k)
+ @names.has_key? k.downcase
+ end
+
+ alias_method :has_key?, :include?
+ alias_method :member?, :include?
+ alias_method :key?, :include?
+
+ def merge!(other)
+ other.each { |k, v| self[k] = v }
+ self
+ end
+
+ def merge(other)
+ hash = dup
+ hash.merge! other
+ end
end
# Every standard HTTP code mapped to the appropriate message.
# Stolen from Mongrel.
HTTP_STATUS_CODES = {
@@ -190,36 +213,42 @@
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
- 302 => 'Moved Temporarily',
+ 302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
+ 307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
- 408 => 'Request Time-out',
+ 408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Large',
415 => 'Unsupported Media Type',
+ 416 => 'Requested Range Not Satisfiable',
+ 417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
- 504 => 'Gateway Time-out',
- 505 => 'HTTP Version not supported'
+ 504 => 'Gateway Timeout',
+ 505 => 'HTTP Version Not Supported'
}
+
+ # Responses with HTTP status codes that should not have an entity body
+ STATUS_WITH_NO_ENTITY_BODY = Set.new((100..199).to_a << 204 << 304)
# A multipart form data parser, adapted from IOWA.
#
# Usually, Rack::Request#POST takes care of calling this.