lib/rack/utils.rb in rack-0.3.0 vs lib/rack/utils.rb in rack-0.4.0

- old
+ new

@@ -21,34 +21,47 @@ [$1.delete('%')].pack('H*') } end module_function :unescape - # Stolen from Mongrel: + # 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 '&;'). def parse_query(qs, d = '&;') params = {} - (qs||'').split(/[#{d}] */n).inject(params) { |h,p| - k, v=unescape(p).split('=',2) + + (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 + escape(k) + "=" + escape(v) + end + }.join("&") + end + module_function :build_query # Escape ampersands, brackets and quotes to their HTML/XML entities. def escape_html(string) string.to_s.gsub("&", "&amp;"). gsub("<", "&lt;"). @@ -56,18 +69,81 @@ gsub("'", "&#39;"). gsub('"', "&quot;") end module_function :escape_html - class Context < Proc - def initialize app_f=nil, app_r=nil - @for, @app = app_f, app_r + def select_best_encoding(available_encodings, accept_encoding) + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html + + expanded_accept_encoding = + accept_encoding.map { |m, q| + if m == "*" + (available_encodings - accept_encoding.map { |m2, _| m2 }).map { |m2| [m2, q] } + else + [[m, q]] + end + }.inject([]) { |mem, list| + mem + list + } + + encoding_candidates = expanded_accept_encoding.sort_by { |_, q| -q }.map { |m, _| m } + + unless encoding_candidates.include?("identity") + encoding_candidates.push("identity") end + + expanded_accept_encoding.find_all { |m, q| + q == 0.0 + }.each { |m, _| + encoding_candidates.delete(m) + } + + return (encoding_candidates & available_encodings)[0] + end + module_function :select_best_encoding + + # The recommended manner in which to implement a contexting application + # is to define a method #context in which a new Context is instantiated. + # + # As a Context is a glorified block, it is highly recommended that you + # define the contextual block within the application's operational scope. + # This would typically the application as you're place into Rack's stack. + # + # class MyObject + # ... + # def context app + # Rack::Utils::Context.new app do |env| + # do_stuff + # response = app.call(env) + # do_more_stuff + # end + # end + # ... + # end + # + # mobj = MyObject.new + # app = mobj.context other_app + # Rack::Handler::Mongrel.new app + class Context < Proc alias_method :old_inspect, :inspect + attr_reader :for, :app + def initialize app_f, app_r + raise 'running context not provided' unless app_f + raise 'running context does not respond to #context' unless app_f.respond_to? :context + raise 'application context not provided' unless app_r + raise 'application context does not respond to #call' unless app_r.respond_to? :call + @for = app_f + @app = app_r + end def inspect "#{old_inspect} ==> #{@for.inspect} ==> #{@app.inspect}" end + def context app_r + raise 'new application context not provided' unless app_r + raise 'new application context does not respond to #call' unless app_r.respond_to? :call + @for.context app_r + end def pretty_print pp pp.text old_inspect pp.nest 1 do pp.breakable pp.text '=for> ' @@ -185,10 +261,13 @@ filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1] content_type = head[/Content-Type: (.*)\r\n/ni, 1] name = head[/Content-Disposition:.* name="?([^\";]*)"?/ni, 1] - body = Tempfile.new("RackMultipart") if filename + if filename + body = Tempfile.new("RackMultipart") + body.binmode if body.respond_to?(:binmode) + end next end # Save the read body part.