diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/http')
-rw-r--r-- | actionpack/lib/action_dispatch/http/cache.rb | 56 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/filter_parameters.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/mime_negotiation.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/mime_type.rb | 8 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/mime_types.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/parameter_filter.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/parameters.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/rack_cache.rb | 5 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/request.rb | 29 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/response.rb | 42 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/upload.rb | 18 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/url.rb | 55 |
12 files changed, 134 insertions, 91 deletions
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb index aaed0d750f..5ee4c044ea 100644 --- a/actionpack/lib/action_dispatch/http/cache.rb +++ b/actionpack/lib/action_dispatch/http/cache.rb @@ -4,14 +4,18 @@ module ActionDispatch module Http module Cache module Request + + HTTP_IF_MODIFIED_SINCE = 'HTTP_IF_MODIFIED_SINCE'.freeze + HTTP_IF_NONE_MATCH = 'HTTP_IF_NONE_MATCH'.freeze + def if_modified_since - if since = env['HTTP_IF_MODIFIED_SINCE'] + if since = env[HTTP_IF_MODIFIED_SINCE] Time.rfc2822(since) rescue nil end end def if_none_match - env['HTTP_IF_NONE_MATCH'] + env[HTTP_IF_NONE_MATCH] end def not_modified?(modified_at) @@ -43,31 +47,49 @@ module ActionDispatch alias :etag? :etag def last_modified - if last = headers['Last-Modified'] + if last = headers[LAST_MODIFIED] Time.httpdate(last) end end def last_modified? - headers.include?('Last-Modified') + headers.include?(LAST_MODIFIED) end def last_modified=(utc_time) - headers['Last-Modified'] = utc_time.httpdate + headers[LAST_MODIFIED] = utc_time.httpdate + end + + def date + if date_header = headers['Date'] + Time.httpdate(date_header) + end + end + + def date? + headers.include?('Date') + end + + def date=(utc_time) + headers['Date'] = utc_time.httpdate end def etag=(etag) key = ActiveSupport::Cache.expand_cache_key(etag) - @etag = self["ETag"] = %("#{Digest::MD5.hexdigest(key)}") + @etag = self[ETAG] = %("#{Digest::MD5.hexdigest(key)}") end private + LAST_MODIFIED = "Last-Modified".freeze + ETAG = "ETag".freeze + CACHE_CONTROL = "Cache-Control".freeze + def prepare_cache_control! @cache_control = {} - @etag = self["ETag"] + @etag = self[ETAG] - if cache_control = self["Cache-Control"] + if cache_control = self[CACHE_CONTROL] cache_control.split(/,\s*/).each do |segment| first, last = segment.split("=") @cache_control[first.to_sym] = last || true @@ -81,28 +103,32 @@ module ActionDispatch end end - DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate" + DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze + NO_CACHE = "no-cache".freeze + PUBLIC = "public".freeze + PRIVATE = "private".freeze + MUST_REVALIDATE = "must-revalidate".freeze def set_conditional_cache_control! - return if self["Cache-Control"].present? + return if self[CACHE_CONTROL].present? control = @cache_control if control.empty? - headers["Cache-Control"] = DEFAULT_CACHE_CONTROL + headers[CACHE_CONTROL] = DEFAULT_CACHE_CONTROL elsif control[:no_cache] - headers["Cache-Control"] = "no-cache" + headers[CACHE_CONTROL] = NO_CACHE else extras = control[:extras] max_age = control[:max_age] options = [] options << "max-age=#{max_age.to_i}" if max_age - options << (control[:public] ? "public" : "private") - options << "must-revalidate" if control[:must_revalidate] + options << (control[:public] ? PUBLIC : PRIVATE) + options << MUST_REVALIDATE if control[:must_revalidate] options.concat(extras) if extras - headers["Cache-Control"] = options.join(", ") + headers[CACHE_CONTROL] = options.join(", ") end end end diff --git a/actionpack/lib/action_dispatch/http/filter_parameters.rb b/actionpack/lib/action_dispatch/http/filter_parameters.rb index 8dd1af7f3d..132b0c82bc 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -50,7 +50,7 @@ module ActionDispatch end def env_filter - parameter_filter_for(Array.wrap(@env["action_dispatch.parameter_filter"]) << /RAW_POST_DATA/) + parameter_filter_for(Array(@env["action_dispatch.parameter_filter"]) + [/RAW_POST_DATA/, "rack.request.form_vars"]) end def parameter_filter_for(filters) diff --git a/actionpack/lib/action_dispatch/http/mime_negotiation.rb b/actionpack/lib/action_dispatch/http/mime_negotiation.rb index 5c48a60469..e31f3b823d 100644 --- a/actionpack/lib/action_dispatch/http/mime_negotiation.rb +++ b/actionpack/lib/action_dispatch/http/mime_negotiation.rb @@ -1,3 +1,5 @@ +require 'active_support/core_ext/module/attribute_accessors' + module ActionDispatch module Http module MimeNegotiation diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 8a9f9c4315..26f4c16218 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -38,7 +38,7 @@ module Mime # respond_to do |format| # format.html # format.ics { render :text => post.to_ics, :mime_type => Mime::Type["text/calendar"] } - # format.xml { render :xml => @people.to_xml } + # format.xml { render :xml => @people } # end # end # end @@ -82,6 +82,7 @@ module Mime class << self TRAILING_STAR_REGEXP = /(text|application)\/\*/ + PARAMETER_SEPARATOR_REGEXP = /;\s*\w+="?\w+"?/ def lookup(string) LOOKUP[string] @@ -103,11 +104,12 @@ module Mime SET << Mime.const_get(symbol.to_s.upcase) ([string] + mime_type_synonyms).each { |str| LOOKUP[str] = SET.last } unless skip_lookup - ([symbol.to_s] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext] = SET.last } + ([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = SET.last } end def parse(accept_header) if accept_header !~ /,/ + accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first if accept_header =~ TRAILING_STAR_REGEXP parse_data_with_trailing_star($1) else @@ -117,7 +119,7 @@ module Mime # keep track of creation order to keep the subsequent sort stable list, index = [], 0 accept_header.split(/,/).each do |header| - params, q = header.split(/;\s*q=/) + params, q = header.split(PARAMETER_SEPARATOR_REGEXP) if params.present? params.strip! diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb index 3da4f91051..a6b3aee5e7 100644 --- a/actionpack/lib/action_dispatch/http/mime_types.rb +++ b/actionpack/lib/action_dispatch/http/mime_types.rb @@ -9,7 +9,7 @@ Mime::Type.register "text/calendar", :ics Mime::Type.register "text/csv", :csv Mime::Type.register "image/png", :png, [], %w(png) -Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe) +Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg) Mime::Type.register "image/gif", :gif, [], %w(gif) Mime::Type.register "image/bmp", :bmp, [], %w(bmp) Mime::Type.register "image/tiff", :tiff, [], %w(tif tiff) diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb index 1480e8f77c..490b46c990 100644 --- a/actionpack/lib/action_dispatch/http/parameter_filter.rb +++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb @@ -20,6 +20,8 @@ module ActionDispatch @filters.present? end + FILTERED = '[FILTERED]'.freeze + def compiled_filter @compiled_filter ||= begin regexps, blocks = compile_filter @@ -29,7 +31,7 @@ module ActionDispatch original_params.each do |key, value| if regexps.find { |r| key =~ r } - value = '[FILTERED]' + value = FILTERED elsif value.is_a?(Hash) value = filter(value) elsif value.is_a?(Array) diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index ef5d207b26..d9b63faf5e 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -41,8 +41,6 @@ module ActionDispatch # you'll get a weird error down the road, but our form handling # should really prevent that from happening def encode_params(params) - return params unless "ruby".encoding_aware? - if params.is_a?(String) return params.force_encoding("UTF-8").encode! elsif !params.is_a?(Hash) diff --git a/actionpack/lib/action_dispatch/http/rack_cache.rb b/actionpack/lib/action_dispatch/http/rack_cache.rb index cc8edee300..003ae4029d 100644 --- a/actionpack/lib/action_dispatch/http/rack_cache.rb +++ b/actionpack/lib/action_dispatch/http/rack_cache.rb @@ -8,8 +8,7 @@ module ActionDispatch new end - # TODO: Finally deal with the RAILS_CACHE global - def initialize(store = RAILS_CACHE) + def initialize(store = Rails.cache) @store = store end @@ -33,7 +32,7 @@ module ActionDispatch new end - def initialize(store = RAILS_CACHE) + def initialize(store = Rails.cache) @store = store end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index e86dfd64d2..796e0dbc45 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -17,7 +17,8 @@ module ActionDispatch include ActionDispatch::Http::Upload include ActionDispatch::Http::URL - LOCALHOST = [/^127\.0\.0\.\d{1,3}$/, "::1", /^0:0:0:0:0:0:0:1(%.*)?$/].freeze + LOCALHOST = Regexp.union [/^127\.0\.0\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/] + ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE PATH_TRANSLATED REMOTE_HOST REMOTE_IDENT REMOTE_USER REMOTE_ADDR @@ -35,14 +36,6 @@ module ActionDispatch METHOD end - def self.new(env) - if request = env["action_dispatch.request"] && request.instance_of?(self) - return request - end - - super - end - def key?(key) @env.key?(key) end @@ -105,6 +98,12 @@ module ActionDispatch HTTP_METHOD_LOOKUP[request_method] == :post end + # Is this a PATCH request? + # Equivalent to <tt>request.request_method == :patch</tt>. + def patch? + HTTP_METHOD_LOOKUP[request_method] == :patch + end + # Is this a PUT request? # Equivalent to <tt>request.request_method_symbol == :put</tt>. def put? @@ -130,10 +129,18 @@ module ActionDispatch Http::Headers.new(@env) end + def original_fullpath + @original_fullpath ||= (env["ORIGINAL_FULLPATH"] || fullpath) + end + def fullpath @fullpath ||= super end + def original_url + base_url + original_fullpath + end + def media_type content_mime_type.to_s end @@ -189,7 +196,7 @@ module ActionDispatch # variable is already set, wrap it in a StringIO. def body if raw_post = @env['RAW_POST_DATA'] - raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding) + raw_post.force_encoding(Encoding::BINARY) StringIO.new(raw_post) else @env['rack.input'] @@ -244,7 +251,7 @@ module ActionDispatch # True if the request came from localhost, 127.0.0.1. def local? - LOCALHOST.any? { |local_ip| local_ip === remote_addr && local_ip === remote_ip } + LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip end private diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index f1e85559a3..cc46f9983c 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -29,7 +29,7 @@ module ActionDispatch # :nodoc: # class DemoControllerTest < ActionDispatch::IntegrationTest # def test_print_root_path_to_console # get('/') - # puts @response.body + # puts response.body # end # end class Response @@ -51,9 +51,12 @@ module ActionDispatch # :nodoc: # If a character set has been defined for this response (see charset=) then # the character set information will also be included in the content type # information. - attr_accessor :charset, :content_type + attr_accessor :charset + attr_reader :content_type - CONTENT_TYPE = "Content-Type" + CONTENT_TYPE = "Content-Type".freeze + SET_COOKIE = "Set-Cookie".freeze + LOCATION = "Location".freeze cattr_accessor(:default_charset) { "utf-8" } @@ -66,10 +69,10 @@ module ActionDispatch # :nodoc: @sending_file = false @blank = false - if content_type = self["Content-Type"] + if content_type = self[CONTENT_TYPE] type, charset = content_type.split(/;\s*charset=/) @content_type = Mime::Type.lookup(type) - @charset = charset || "UTF-8" + @charset = charset || self.class.default_charset end prepare_cache_control! @@ -81,6 +84,10 @@ module ActionDispatch # :nodoc: @status = Rack::Utils.status_code(status) end + def content_type=(content_type) + @content_type = content_type.to_s + end + # The response code of the request def response_code @status @@ -109,9 +116,9 @@ module ActionDispatch # :nodoc: end def body - str = '' - each { |part| str << part.to_s } - str + strings = [] + each { |part| strings << part.to_s } + strings.join end EMPTY = " " @@ -119,14 +126,7 @@ module ActionDispatch # :nodoc: def body=(body) @blank = true if body == EMPTY - # Explicitly check for strings. This is *wrong* theoretically - # but if we don't check this, the performance on string bodies - # is bad on Ruby 1.8 (because strings responds to each then). - @body = if body.respond_to?(:to_str) || !body.respond_to?(:each) - [body] - else - body - end + @body = body.respond_to?(:each) ? body : [body] end def body_parts @@ -142,12 +142,12 @@ module ActionDispatch # :nodoc: end def location - headers['Location'] + headers[LOCATION] end alias_method :redirect_url, :location def location=(url) - headers['Location'] = url + headers[LOCATION] = url end def close @@ -158,10 +158,10 @@ module ActionDispatch # :nodoc: assign_default_content_type_and_charset! handle_conditional_get! - @header["Set-Cookie"] = @header["Set-Cookie"].join("\n") if @header["Set-Cookie"].respond_to?(:join) + @header[SET_COOKIE] = @header[SET_COOKIE].join("\n") if @header[SET_COOKIE].respond_to?(:join) if [204, 304].include?(@status) - @header.delete "Content-Type" + @header.delete CONTENT_TYPE [@status, @header, []] else [@status, @header, self] @@ -175,7 +175,7 @@ module ActionDispatch # :nodoc: # assert_equal 'AuthorOfNewPage', r.cookies['author'] def cookies cookies = {} - if header = self["Set-Cookie"] + if header = self[SET_COOKIE] header = header.split("\n") if header.respond_to?(:to_str) header.each do |cookie| if pair = cookie.split(';').first diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index 94fa747a79..ce8c2729e9 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -4,11 +4,12 @@ module ActionDispatch attr_accessor :original_filename, :content_type, :tempfile, :headers def initialize(hash) + @tempfile = hash[:tempfile] + raise(ArgumentError, ':tempfile is required') unless @tempfile + @original_filename = encode_filename(hash[:filename]) @content_type = hash[:type] @headers = hash[:head] - @tempfile = hash[:tempfile] - raise(ArgumentError, ':tempfile is required') unless @tempfile end def read(*args) @@ -16,18 +17,15 @@ module ActionDispatch end # Delegate these methods to the tempfile. - [:open, :path, :rewind, :size].each do |method| + [:open, :path, :rewind, :size, :eof?].each do |method| class_eval "def #{method}; @tempfile.#{method}; end" end - + private + def encode_filename(filename) - # Encode the filename in the utf8 encoding, unless it is nil or we're in 1.8 - if "ruby".encoding_aware? && filename - filename.force_encoding("UTF-8").encode! - else - filename - end + # Encode the filename in the utf8 encoding, unless it is nil + filename.force_encoding("UTF-8").encode! if filename end end diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 129a8b1031..4266ec042e 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -1,6 +1,8 @@ module ActionDispatch module Http module URL + IP_HOST_REGEXP = /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/ + mattr_accessor :tld_length self.tld_length = 1 @@ -21,38 +23,45 @@ module ActionDispatch end def url_for(options = {}) - unless options[:host].present? || options[:only_path].present? + path = "" + path << options.delete(:script_name).to_s.chomp("/") + path << options.delete(:path).to_s + + params = options[:params] || {} + params.reject! {|k,v| v.to_param.nil? } + + result = build_host_url(options) + + result << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) + result << "?#{params.to_query}" unless params.empty? + result << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor] + result + end + + private + + def build_host_url(options) + if options[:host].blank? && options[:only_path].blank? raise ArgumentError, 'Missing host to link to! Please provide the :host parameter, set default_url_options[:host], or set :only_path to true' end - rewritten_url = "" + result = "" unless options[:only_path] unless options[:protocol] == false - rewritten_url << (options[:protocol] || "http") - rewritten_url << ":" unless rewritten_url.match(%r{:|//}) + result << (options[:protocol] || "http") + result << ":" unless result.match(%r{:|//}) end - rewritten_url << "//" unless rewritten_url.match("//") - rewritten_url << rewrite_authentication(options) - rewritten_url << host_or_subdomain_and_domain(options) - rewritten_url << ":#{options.delete(:port)}" if options[:port] + result << "//" unless result.match("//") + result << rewrite_authentication(options) + result << host_or_subdomain_and_domain(options) + result << ":#{options.delete(:port)}" if options[:port] end - - path = options.delete(:path) || '' - - params = options[:params] || {} - params.reject! {|k,v| v.to_param.nil? } - - rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path) - rewritten_url << "?#{params.to_query}" unless params.empty? - rewritten_url << "##{Journey::Router::Utils.escape_fragment(options[:anchor].to_param.to_s)}" if options[:anchor] - rewritten_url + result end - private - def named_host?(host) - !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host)) + host && IP_HOST_REGEXP !~ host end def rewrite_authentication(options) @@ -70,7 +79,7 @@ module ActionDispatch host = "" unless options[:subdomain] == false - host << (options[:subdomain] || extract_subdomain(options[:host], tld_length)) + host << (options[:subdomain] || extract_subdomain(options[:host], tld_length)).to_param host << "." end host << (options[:domain] || extract_domain(options[:host], tld_length)) @@ -167,7 +176,7 @@ module ActionDispatch # such as 2 to catch <tt>"www"</tt> instead of <tt>"www.rubyonrails"</tt> # in "www.rubyonrails.co.uk". def subdomain(tld_length = @@tld_length) - subdomains(tld_length).join(".") + ActionDispatch::Http::URL.extract_subdomain(host, tld_length) end end end |