diff options
Diffstat (limited to 'actionpack/lib/action_dispatch/http')
-rw-r--r-- | actionpack/lib/action_dispatch/http/cache.rb | 8 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/filter_parameters.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/filter_redirect.rb | 11 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/mime_type.rb | 4 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/mime_types.rb | 2 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/parameter_filter.rb | 26 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/parameters.rb | 17 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/request.rb | 109 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/response.rb | 53 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/upload.rb | 8 | ||||
-rw-r--r-- | actionpack/lib/action_dispatch/http/url.rb | 2 |
11 files changed, 135 insertions, 107 deletions
diff --git a/actionpack/lib/action_dispatch/http/cache.rb b/actionpack/lib/action_dispatch/http/cache.rb index 747d295261..cc1cb3f0f0 100644 --- a/actionpack/lib/action_dispatch/http/cache.rb +++ b/actionpack/lib/action_dispatch/http/cache.rb @@ -151,11 +151,11 @@ module ActionDispatch control.merge! @cache_control if control.empty? - headers[CACHE_CONTROL] = DEFAULT_CACHE_CONTROL + self[CACHE_CONTROL] = DEFAULT_CACHE_CONTROL elsif control[:no_cache] - headers[CACHE_CONTROL] = NO_CACHE + self[CACHE_CONTROL] = NO_CACHE if control[:extras] - headers[CACHE_CONTROL] += ", #{control[:extras].join(', ')}" + self[CACHE_CONTROL] += ", #{control[:extras].join(', ')}" end else extras = control[:extras] @@ -167,7 +167,7 @@ module ActionDispatch options << MUST_REVALIDATE if control[:must_revalidate] options.concat(extras) if extras - headers[CACHE_CONTROL] = options.join(", ") + self[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 2b851cc28d..3170389b36 100644 --- a/actionpack/lib/action_dispatch/http/filter_parameters.rb +++ b/actionpack/lib/action_dispatch/http/filter_parameters.rb @@ -16,7 +16,7 @@ module ActionDispatch # env["action_dispatch.parameter_filter"] = [:foo, "bar"] # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]" # - # env["action_dispatch.parameter_filter"] = lambda do |k,v| + # env["action_dispatch.parameter_filter"] = -> (k, v) do # v.reverse! if k =~ /secret/i # end # => reverses the value to all keys matching /secret/i diff --git a/actionpack/lib/action_dispatch/http/filter_redirect.rb b/actionpack/lib/action_dispatch/http/filter_redirect.rb index bf79963351..94c1f2b41f 100644 --- a/actionpack/lib/action_dispatch/http/filter_redirect.rb +++ b/actionpack/lib/action_dispatch/http/filter_redirect.rb @@ -5,8 +5,7 @@ module ActionDispatch FILTERED = '[FILTERED]'.freeze # :nodoc: def filtered_location # :nodoc: - filters = location_filter - if !filters.empty? && location_filter_match?(filters) + if location_filter_match? FILTERED else location @@ -15,7 +14,7 @@ module ActionDispatch private - def location_filter + def location_filters if request request.env['action_dispatch.redirect_filter'] || [] else @@ -23,12 +22,12 @@ module ActionDispatch end end - def location_filter_match?(filters) - filters.any? do |filter| + def location_filter_match? + location_filters.any? do |filter| if String === filter location.include?(filter) elsif Regexp === filter - location.match(filter) + location =~ filter end end end diff --git a/actionpack/lib/action_dispatch/http/mime_type.rb b/actionpack/lib/action_dispatch/http/mime_type.rb index 7e585aa244..a639f8a8f8 100644 --- a/actionpack/lib/action_dispatch/http/mime_type.rb +++ b/actionpack/lib/action_dispatch/http/mime_type.rb @@ -45,7 +45,7 @@ module Mime # # respond_to do |format| # format.html - # format.ics { render text: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") } + # format.ics { render body: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") } # format.xml { render xml: @post } # end # end @@ -211,7 +211,7 @@ module Mime # This method is opposite of register method. # - # Usage: + # To unregister a MIME type: # # Mime::Type.unregister(:mobile) def unregister(symbol) diff --git a/actionpack/lib/action_dispatch/http/mime_types.rb b/actionpack/lib/action_dispatch/http/mime_types.rb index 0e4da36038..01a10c693b 100644 --- a/actionpack/lib/action_dispatch/http/mime_types.rb +++ b/actionpack/lib/action_dispatch/http/mime_types.rb @@ -27,7 +27,7 @@ Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form # http://www.ietf.org/rfc/rfc4627.txt # http://www.json.org/JSONRequest.html -Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest ) +Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest application/vnd.api+json ) Mime::Type.register "application/pdf", :pdf, [], %w(pdf) Mime::Type.register "application/zip", :zip, [], %w(zip) diff --git a/actionpack/lib/action_dispatch/http/parameter_filter.rb b/actionpack/lib/action_dispatch/http/parameter_filter.rb index df4b073a17..e826551f4b 100644 --- a/actionpack/lib/action_dispatch/http/parameter_filter.rb +++ b/actionpack/lib/action_dispatch/http/parameter_filter.rb @@ -30,36 +30,46 @@ module ActionDispatch when Regexp regexps << item else - strings << item.to_s + strings << Regexp.escape(item.to_s) end end - regexps << Regexp.new(strings.join('|'), true) unless strings.empty? - new regexps, blocks + deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) } + deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) } + + regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty? + deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty? + + new regexps, deep_regexps, blocks end - attr_reader :regexps, :blocks + attr_reader :regexps, :deep_regexps, :blocks - def initialize(regexps, blocks) + def initialize(regexps, deep_regexps, blocks) @regexps = regexps + @deep_regexps = deep_regexps.any? ? deep_regexps : nil @blocks = blocks end - def call(original_params) + def call(original_params, parents = []) filtered_params = {} original_params.each do |key, value| + parents.push(key) if deep_regexps if regexps.any? { |r| key =~ r } value = FILTERED + elsif deep_regexps && (joined = parents.join('.')) && deep_regexps.any? { |r| joined =~ r } + value = FILTERED elsif value.is_a?(Hash) - value = call(value) + value = call(value, parents) elsif value.is_a?(Array) - value = value.map { |v| v.is_a?(Hash) ? call(v) : v } + value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v } elsif blocks.any? key = key.dup if key.duplicable? value = value.dup if value.duplicable? blocks.each { |b| b.call(key, value) } end + parents.pop if deep_regexps filtered_params[key] = value end diff --git a/actionpack/lib/action_dispatch/http/parameters.rb b/actionpack/lib/action_dispatch/http/parameters.rb index c2f05ecc86..4defb7f858 100644 --- a/actionpack/lib/action_dispatch/http/parameters.rb +++ b/actionpack/lib/action_dispatch/http/parameters.rb @@ -37,22 +37,7 @@ module ActionDispatch # Convert nested Hash to HashWithIndifferentAccess. # def normalize_encode_params(params) - case params - when Hash - if params.has_key?(:tempfile) - UploadedFile.new(params) - else - params.each_with_object({}) do |(key, val), new_hash| - new_hash[key] = if val.is_a?(Array) - val.map! { |el| normalize_encode_params(el) } - else - normalize_encode_params(val) - end - end.with_indifferent_access - end - else - params - end + ActionDispatch::Request::Utils.normalize_encode_params params end end end diff --git a/actionpack/lib/action_dispatch/http/request.rb b/actionpack/lib/action_dispatch/http/request.rb index a1f84e5ace..de28cd0998 100644 --- a/actionpack/lib/action_dispatch/http/request.rb +++ b/actionpack/lib/action_dispatch/http/request.rb @@ -20,6 +20,8 @@ module ActionDispatch include ActionDispatch::Http::FilterParameters include ActionDispatch::Http::URL + HTTP_X_REQUEST_ID = "HTTP_X_REQUEST_ID".freeze # :nodoc: + autoload :Session, 'action_dispatch/request/session' autoload :Utils, 'action_dispatch/request/utils' @@ -32,12 +34,14 @@ module ActionDispatch HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM - HTTP_NEGOTIATE HTTP_PRAGMA ].freeze + HTTP_NEGOTIATE HTTP_PRAGMA HTTP_CLIENT_IP + HTTP_X_FORWARDED_FOR HTTP_VERSION + ].freeze ENV_METHODS.each do |env| class_eval <<-METHOD, __FILE__, __LINE__ + 1 def #{env.sub(/^HTTP_/n, '').downcase} # def accept_charset - @env["#{env}"] # @env["HTTP_ACCEPT_CHARSET"] + @env["#{env}".freeze] # @env["HTTP_ACCEPT_CHARSET".freeze] end # end METHOD end @@ -50,7 +54,6 @@ module ActionDispatch @original_fullpath = nil @fullpath = nil @ip = nil - @request_id = nil end def check_path_parameters! @@ -102,13 +105,17 @@ module ActionDispatch # the application should use), this \method returns the overridden # value, not the original. def request_method - @request_method ||= check_method(env["REQUEST_METHOD"]) + @request_method ||= check_method(super) end def routes # :nodoc: env["action_dispatch.routes".freeze] end + def routes=(routes) # :nodoc: + env["action_dispatch.routes".freeze] = routes + end + def original_script_name # :nodoc: env['ORIGINAL_SCRIPT_NAME'.freeze] end @@ -117,12 +124,31 @@ module ActionDispatch env[_routes.env_key] end + def engine_script_name=(name) # :nodoc: + env[routes.env_key] = name.dup + end + def request_method=(request_method) #:nodoc: if check_method(request_method) @request_method = env["REQUEST_METHOD"] = request_method end end + def controller_instance # :nodoc: + env['action_controller.instance'.freeze] + end + + def controller_instance=(controller) # :nodoc: + env['action_controller.instance'.freeze] = controller + end + + def show_exceptions? # :nodoc: + # We're treating `nil` as "unset", and we want the default setting to be + # `true`. This logic should be extracted to `env_config` and calculated + # once. + !(env['action_dispatch.show_exceptions'.freeze] == false) + end + # Returns a symbol form of the #request_method def request_method_symbol HTTP_METHOD_LOOKUP[request_method] @@ -140,47 +166,11 @@ module ActionDispatch HTTP_METHOD_LOOKUP[method] end - # Is this a GET (or HEAD) request? - # Equivalent to <tt>request.request_method_symbol == :get</tt>. - def get? - HTTP_METHOD_LOOKUP[request_method] == :get - end - - # Is this a POST request? - # Equivalent to <tt>request.request_method_symbol == :post</tt>. - def post? - 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? - HTTP_METHOD_LOOKUP[request_method] == :put - end - - # Is this a DELETE request? - # Equivalent to <tt>request.request_method_symbol == :delete</tt>. - def delete? - HTTP_METHOD_LOOKUP[request_method] == :delete - end - - # Is this a HEAD request? - # Equivalent to <tt>request.request_method_symbol == :head</tt>. - def head? - HTTP_METHOD_LOOKUP[request_method] == :head - end - # Provides access to the request's HTTP headers, for example: # # request.headers["Content-Type"] # => "text/plain" def headers - Http::Headers.new(@env) + @headers ||= Http::Headers.new(@env) end # Returns a +String+ with the last requested path including their params. @@ -234,15 +224,23 @@ module ActionDispatch end alias :xhr? :xml_http_request? + # Returns the IP address of client as a +String+. def ip @ip ||= super end - # Originating IP address, usually set by the RemoteIp middleware. + # Returns the IP address of client as a +String+, + # usually set by the RemoteIp middleware. def remote_ip @remote_ip ||= (@env["action_dispatch.remote_ip"] || ip).to_s end + def remote_ip=(remote_ip) + @env["action_dispatch.remote_ip".freeze] = remote_ip + end + + ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc: + # Returns the unique request id, which is based on either the X-Request-Id header that can # be generated by a firewall, load balancer, or web server or by the RequestId middleware # (which sets the action_dispatch.request_id environment variable). @@ -250,11 +248,19 @@ module ActionDispatch # This unique ID is useful for tracing a request from end-to-end as part of logging or debugging. # This relies on the rack variable set by the ActionDispatch::RequestId middleware. def request_id - @request_id ||= env["action_dispatch.request_id"] + env[ACTION_DISPATCH_REQUEST_ID] + end + + def request_id=(id) # :nodoc: + env[ACTION_DISPATCH_REQUEST_ID] = id end alias_method :uuid, :request_id + def x_request_id # :nodoc: + @env[HTTP_X_REQUEST_ID] + end + # Returns the lowercase name of the HTTP server software. def server_software (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil @@ -282,6 +288,8 @@ module ActionDispatch end end + # Returns true if the request's content MIME type is + # +application/x-www-form-urlencoded+ or +multipart/form-data+. def form_data? FORM_DATA_MEDIA_TYPES.include?(content_mime_type.to_s) end @@ -311,7 +319,7 @@ module ActionDispatch # Override Rack's GET method to support indifferent access def GET - @env["action_dispatch.request.query_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {})) + @env["action_dispatch.request.query_parameters"] ||= normalize_encode_params(super || {}) rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e raise ActionController::BadRequest.new(:query, e) end @@ -319,7 +327,7 @@ module ActionDispatch # Override Rack's POST method to support indifferent access def POST - @env["action_dispatch.request.request_parameters"] ||= Utils.deep_munge(normalize_encode_params(super || {})) + @env["action_dispatch.request.request_parameters"] ||= normalize_encode_params(super || {}) rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e raise ActionController::BadRequest.new(:request, e) end @@ -339,10 +347,13 @@ module ActionDispatch LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip end - protected - def parse_query(*) - Utils.deep_munge(super) - end + def request_parameters=(params) + env["action_dispatch.request.request_parameters".freeze] = params + end + + def logger + env["action_dispatch.logger".freeze] + end private def check_method(name) diff --git a/actionpack/lib/action_dispatch/http/response.rb b/actionpack/lib/action_dispatch/http/response.rb index a895d1ab18..fd92e89231 100644 --- a/actionpack/lib/action_dispatch/http/response.rb +++ b/actionpack/lib/action_dispatch/http/response.rb @@ -40,10 +40,9 @@ module ActionDispatch # :nodoc: attr_writer :sending_file - # Get and set headers for this response. - attr_accessor :header + # Get headers for this response. + attr_reader :header - alias_method :headers=, :header= alias_method :headers, :header delegate :[], :[]=, :to => :@header @@ -61,7 +60,7 @@ module ActionDispatch # :nodoc: # The charset of the response. HTML wants to know the encoding of the # content you're giving them, so we need to send that along. - attr_accessor :charset + attr_reader :charset CONTENT_TYPE = "Content-Type".freeze SET_COOKIE = "Set-Cookie".freeze @@ -81,11 +80,21 @@ module ActionDispatch # :nodoc: @response = response @buf = buf @closed = false + @str_body = nil + end + + def body + @str_body ||= begin + buf = '' + each { |chunk| buf << chunk } + buf + end end def write(string) raise IOError, "closed stream" if closed? + @str_body = nil @response.commit! @buf.push string end @@ -117,8 +126,9 @@ module ActionDispatch # :nodoc: super() header = merge_default_headers(header, default_headers) + @header = header - self.body, self.header, self.status = body, header, status + self.body, self.status = body, status @sending_file = false @blank = false @@ -127,7 +137,7 @@ module ActionDispatch # :nodoc: @sending = false @sent = false @content_type = nil - @charset = nil + @charset = self.class.default_charset if content_type = self[CONTENT_TYPE] type, charset = content_type.split(/;\s*charset=/) @@ -187,6 +197,15 @@ module ActionDispatch # :nodoc: @content_type = content_type.to_s end + # Sets the HTTP character set. In case of nil parameter + # it sets the charset to utf-8. + # + # response.charset = 'utf-16' # => 'utf-16' + # response.charset = nil # => 'utf-8' + def charset=(charset) + @charset = charset.nil? ? self.class.default_charset : charset + end + # The response code of the request. def response_code @status @@ -213,9 +232,7 @@ module ActionDispatch # :nodoc: # Returns the content of the response as a string. This contains the contents # of any calls to <tt>render</tt>. def body - strings = [] - each { |part| strings << part.to_s } - strings.join + @stream.body end EMPTY = " " @@ -274,10 +291,11 @@ module ActionDispatch # :nodoc: end # Turns the Response into a Rack-compatible array of the status, headers, - # and body. Allows explict splatting: + # and body. Allows explicit splatting: # # status, headers, body = *response def to_a + commit! rack_response @status, @header.to_hash end alias prepare! to_a @@ -302,6 +320,9 @@ module ActionDispatch # :nodoc: private def before_committed + return if committed? + assign_default_content_type_and_charset! + handle_conditional_get! end def before_sending @@ -319,16 +340,15 @@ module ActionDispatch # :nodoc: body.respond_to?(:each) ? body : [body] end - def assign_default_content_type_and_charset!(headers) - return if headers[CONTENT_TYPE].present? + def assign_default_content_type_and_charset! + return if self[CONTENT_TYPE].present? @content_type ||= Mime::HTML - @charset ||= self.class.default_charset unless @charset == false type = @content_type.to_s.dup - type << "; charset=#{@charset}" if append_charset? + type << "; charset=#{charset}" if append_charset? - headers[CONTENT_TYPE] = type + self[CONTENT_TYPE] = type end def append_charset? @@ -372,9 +392,6 @@ module ActionDispatch # :nodoc: end def rack_response(status, header) - assign_default_content_type_and_charset!(header) - handle_conditional_get! - header[SET_COOKIE] = header[SET_COOKIE].join("\n") if header[SET_COOKIE].respond_to?(:join) if NO_CONTENT_CODES.include?(@status) diff --git a/actionpack/lib/action_dispatch/http/upload.rb b/actionpack/lib/action_dispatch/http/upload.rb index 540e11a4a0..a221f4c5af 100644 --- a/actionpack/lib/action_dispatch/http/upload.rb +++ b/actionpack/lib/action_dispatch/http/upload.rb @@ -28,7 +28,13 @@ module ActionDispatch raise(ArgumentError, ':tempfile is required') unless @tempfile @original_filename = hash[:filename] - @original_filename &&= @original_filename.encode "UTF-8" + if @original_filename + begin + @original_filename.encode!(Encoding::UTF_8) + rescue EncodingError + @original_filename.force_encoding(Encoding::UTF_8) + end + end @content_type = hash[:type] @headers = hash[:head] end diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index f5b709ccd6..6fcf49030b 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -245,7 +245,7 @@ module ActionDispatch # req = Request.new 'HTTP_HOST' => 'example.com:8080' # req.host # => "example.com" def host - raw_host_with_port.sub(/:\d+$/, '') + raw_host_with_port.sub(/:\d+$/, ''.freeze) end # Returns a \host:\port string for this request, such as "example.com" or |