aboutsummaryrefslogtreecommitdiffstats
path: root/actionpack/lib/action_dispatch/middleware
diff options
context:
space:
mode:
Diffstat (limited to 'actionpack/lib/action_dispatch/middleware')
-rw-r--r--actionpack/lib/action_dispatch/middleware/cookies.rb17
-rw-r--r--actionpack/lib/action_dispatch/middleware/exception_wrapper.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/reloader.rb4
-rw-r--r--actionpack/lib/action_dispatch/middleware/remote_ip.rb8
-rw-r--r--actionpack/lib/action_dispatch/middleware/request_id.rb13
-rw-r--r--actionpack/lib/action_dispatch/middleware/ssl.rb2
-rw-r--r--actionpack/lib/action_dispatch/middleware/static.rb29
7 files changed, 49 insertions, 28 deletions
diff --git a/actionpack/lib/action_dispatch/middleware/cookies.rb b/actionpack/lib/action_dispatch/middleware/cookies.rb
index b1f0f5fc28..dd1f140051 100644
--- a/actionpack/lib/action_dispatch/middleware/cookies.rb
+++ b/actionpack/lib/action_dispatch/middleware/cookies.rb
@@ -79,6 +79,9 @@ module ActionDispatch
# domain: %w(.example.com .example.org) # Allow the cookie
# # for concrete domain names.
#
+ # * <tt>:tld_length</tt> - When using <tt>:domain => :all</tt>, this option can be used to explicitly
+ # set the TLD length when using a short (<= 3 character) domain that is being interpreted as part of a TLD.
+ # For example, to share cookies between user1.lvh.me and user2.lvh.me, set <tt>:tld_length</tt> to 1.
# * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
# * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
# Default is +false+.
@@ -181,7 +184,7 @@ module ActionDispatch
# to the Message{Encryptor,Verifier} allows us to handle the
# (de)serialization step within the cookie jar, which gives us the
# opportunity to detect and migrate legacy cookies.
- module VerifyAndUpgradeLegacySignedMessage
+ module VerifyAndUpgradeLegacySignedMessage # :nodoc:
def initialize(*args)
super
@legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token], serializer: ActiveSupport::MessageEncryptor::NullSerializer)
@@ -392,7 +395,7 @@ module ActionDispatch
end
end
- class JsonSerializer
+ class JsonSerializer # :nodoc:
def self.load(value)
ActiveSupport::JSON.decode(value)
end
@@ -402,7 +405,7 @@ module ActionDispatch
end
end
- module SerializedCookieJars
+ module SerializedCookieJars # :nodoc:
MARSHAL_SIGNATURE = "\x04\x08".freeze
protected
@@ -454,12 +457,16 @@ module ActionDispatch
@verifier = ActiveSupport::MessageVerifier.new(secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
end
+ # Returns the value of the cookie by +name+ if it is untampered,
+ # returns +nil+ otherwise or if no such cookie exists.
def [](name)
if signed_message = @parent_jar[name]
deserialize name, verify(signed_message)
end
end
+ # Signs and sets the cookie named +name+. The second argument may be the cookie's
+ # value or a hash of options as documented above.
def []=(name, options)
if options.is_a?(Hash)
options.symbolize_keys!
@@ -511,12 +518,16 @@ module ActionDispatch
@encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
end
+ # Returns the value of the cookie by +name+ if it is untampered,
+ # returns +nil+ otherwise or if no such cookie exists.
def [](name)
if encrypted_message = @parent_jar[name]
deserialize name, decrypt_and_verify(encrypted_message)
end
end
+ # Encrypts and sets the cookie named +name+. The second argument may be the cookie's
+ # value or a hash of options as documented above.
def []=(name, options)
if options.is_a?(Hash)
options.symbolize_keys!
diff --git a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
index d176a73633..8c3d45584d 100644
--- a/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
+++ b/actionpack/lib/action_dispatch/middleware/exception_wrapper.rb
@@ -17,7 +17,9 @@ module ActionDispatch
'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity,
'ActionDispatch::ParamsParser::ParseError' => :bad_request,
'ActionController::BadRequest' => :bad_request,
- 'ActionController::ParameterMissing' => :bad_request
+ 'ActionController::ParameterMissing' => :bad_request,
+ 'Rack::Utils::ParameterTypeError' => :bad_request,
+ 'Rack::Utils::InvalidParameterError' => :bad_request
)
cattr_accessor :rescue_templates
diff --git a/actionpack/lib/action_dispatch/middleware/reloader.rb b/actionpack/lib/action_dispatch/middleware/reloader.rb
index 15b5a48535..6c7fba00cb 100644
--- a/actionpack/lib/action_dispatch/middleware/reloader.rb
+++ b/actionpack/lib/action_dispatch/middleware/reloader.rb
@@ -11,9 +11,9 @@ module ActionDispatch
# the response body. This is important for streaming responses such as the
# following:
#
- # self.response_body = lambda { |response, output|
+ # self.response_body = -> (response, output) do
# # code here which refers to application models
- # }
+ # end
#
# Cleanup callbacks will not be called until after the response_body lambda
# is evaluated, ensuring that it can refer to application models and other
diff --git a/actionpack/lib/action_dispatch/middleware/remote_ip.rb b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
index 7c4236518d..9f894e2ec6 100644
--- a/actionpack/lib/action_dispatch/middleware/remote_ip.rb
+++ b/actionpack/lib/action_dispatch/middleware/remote_ip.rb
@@ -74,7 +74,7 @@ module ActionDispatch
# requests. For those requests that do need to know the IP, the
# GetIp#calculate_ip method will calculate the memoized client IP address.
def call(env)
- env["action_dispatch.remote_ip"] = GetIp.new(env, self)
+ env["action_dispatch.remote_ip"] = GetIp.new(env, check_ip, proxies)
@app.call(env)
end
@@ -82,10 +82,10 @@ module ActionDispatch
# into an actual IP address. If the ActionDispatch::Request#remote_ip method
# is called, this class will calculate the value and then memoize it.
class GetIp
- def initialize(env, middleware)
+ def initialize(env, check_ip, proxies)
@env = env
- @check_ip = middleware.check_ip
- @proxies = middleware.proxies
+ @check_ip = check_ip
+ @proxies = proxies
end
# Sort through the various IP address headers, looking for the IP most
diff --git a/actionpack/lib/action_dispatch/middleware/request_id.rb b/actionpack/lib/action_dispatch/middleware/request_id.rb
index b9ca524309..1555ff72af 100644
--- a/actionpack/lib/action_dispatch/middleware/request_id.rb
+++ b/actionpack/lib/action_dispatch/middleware/request_id.rb
@@ -13,22 +13,23 @@ module ActionDispatch
# from multiple pieces of the stack.
class RequestId
X_REQUEST_ID = "X-Request-Id".freeze # :nodoc:
- ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
- HTTP_X_REQUEST_ID = "HTTP_X_REQUEST_ID".freeze # :nodoc:
def initialize(app)
@app = app
end
def call(env)
- env[ACTION_DISPATCH_REQUEST_ID] = external_request_id(env) || internal_request_id
- @app.call(env).tap { |_status, headers, _body| headers[X_REQUEST_ID] = env[ACTION_DISPATCH_REQUEST_ID] }
+ req = ActionDispatch::Request.new env
+ req.request_id = make_request_id(req.x_request_id)
+ @app.call(env).tap { |_status, headers, _body| headers[X_REQUEST_ID] = req.request_id }
end
private
- def external_request_id(env)
- if request_id = env[HTTP_X_REQUEST_ID].presence
+ def make_request_id(request_id)
+ if request_id.presence
request_id.gsub(/[^\w\-]/, "".freeze).first(255)
+ else
+ internal_request_id
end
end
diff --git a/actionpack/lib/action_dispatch/middleware/ssl.rb b/actionpack/lib/action_dispatch/middleware/ssl.rb
index 0c7caef25d..7b3d8bcc5b 100644
--- a/actionpack/lib/action_dispatch/middleware/ssl.rb
+++ b/actionpack/lib/action_dispatch/middleware/ssl.rb
@@ -22,7 +22,7 @@ module ActionDispatch
if request.ssl?
status, headers, body = @app.call(env)
- headers = hsts_headers.merge(headers)
+ headers.reverse_merge!(hsts_headers)
flag_cookies_as_secure!(headers)
[status, headers, body]
else
diff --git a/actionpack/lib/action_dispatch/middleware/static.rb b/actionpack/lib/action_dispatch/middleware/static.rb
index 9a92b690c7..b098ea389f 100644
--- a/actionpack/lib/action_dispatch/middleware/static.rb
+++ b/actionpack/lib/action_dispatch/middleware/static.rb
@@ -3,29 +3,36 @@ require 'active_support/core_ext/uri'
module ActionDispatch
# This middleware returns a file's contents from disk in the body response.
- # When initialized it can accept an optional 'Cache-Control' header which
+ # When initialized, it can accept an optional 'Cache-Control' header, which
# will be set when a response containing a file's contents is delivered.
#
# This middleware will render the file specified in `env["PATH_INFO"]`
- # where the base path is in the +root+ directory. For example if the +root+
- # is set to `public/` then a request with `env["PATH_INFO"]` of
- # `assets/application.js` will return a response with contents of a file
+ # where the base path is in the +root+ directory. For example, if the +root+
+ # is set to `public/`, then a request with `env["PATH_INFO"]` of
+ # `assets/application.js` will return a response with the contents of a file
# located at `public/assets/application.js` if the file exists. If the file
- # does not exist a 404 "File not Found" response will be returned.
+ # does not exist, a 404 "File not Found" response will be returned.
class FileHandler
- def initialize(root, cache_control)
+ def initialize(root, cache_control, index: 'index')
@root = root.chomp('/')
@compiled_root = /^#{Regexp.escape(root)}/
headers = cache_control && { 'Cache-Control' => cache_control }
@file_server = ::Rack::File.new(@root, headers)
+ @index = index
end
+ # Takes a path to a file. If the file is found, has valid encoding, and has
+ # correct read permissions, the return value is a URI-escaped string
+ # representing the filename. Otherwise, false is returned.
+ #
+ # Used by the `Static` class to check the existence of a valid file
+ # in the server's `public/` directory (see Static#call).
def match?(path)
path = URI.parser.unescape(path)
return false unless path.valid_encoding?
path = Rack::Utils.clean_path_info path
- paths = [path, "#{path}#{ext}", "#{path}/index#{ext}"]
+ paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"]
if match = paths.detect { |p|
path = File.join(@root, p.force_encoding('UTF-8'))
@@ -88,7 +95,7 @@ module ActionDispatch
end
# This middleware will attempt to return the contents of a file's body from
- # disk in the response. If a file is not found on disk, the request will be
+ # disk in the response. If a file is not found on disk, the request will be
# delegated to the application stack. This middleware is commonly initialized
# to serve assets from a server's `public/` directory.
#
@@ -97,9 +104,9 @@ module ActionDispatch
# produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
# requests will result in a file being returned.
class Static
- def initialize(app, path, cache_control=nil)
+ def initialize(app, path, cache_control = nil, index: 'index')
@app = app
- @file_handler = FileHandler.new(path, cache_control)
+ @file_handler = FileHandler.new(path, cache_control, index: index)
end
def call(env)
@@ -107,7 +114,7 @@ module ActionDispatch
when 'GET', 'HEAD'
path = env['PATH_INFO'].chomp('/')
if match = @file_handler.match?(path)
- env["PATH_INFO"] = match
+ env['PATH_INFO'] = match
return @file_handler.call(env)
end
end