actionpack 7.0.4.3 → 7.0.5.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +51 -1
- data/lib/abstract_controller/helpers.rb +8 -7
- data/lib/abstract_controller/rendering.rb +9 -11
- data/lib/action_controller/api.rb +1 -1
- data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
- data/lib/action_controller/metal/conditional_get.rb +121 -123
- data/lib/action_controller/metal/content_security_policy.rb +4 -4
- data/lib/action_controller/metal/data_streaming.rb +18 -18
- data/lib/action_controller/metal/etag_with_flash.rb +1 -1
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/live.rb +1 -1
- data/lib/action_controller/metal/permissions_policy.rb +1 -1
- data/lib/action_controller/metal/redirecting.rb +19 -2
- data/lib/action_controller/metal/rendering.rb +114 -2
- data/lib/action_controller/metal/request_forgery_protection.rb +5 -3
- data/lib/action_controller/metal/streaming.rb +1 -1
- data/lib/action_controller/metal/url_for.rb +2 -4
- data/lib/action_controller/railtie.rb +2 -1
- data/lib/action_controller/renderer.rb +1 -20
- data/lib/action_dispatch/http/cache.rb +7 -7
- data/lib/action_dispatch/http/content_security_policy.rb +5 -1
- data/lib/action_dispatch/http/filter_parameters.rb +4 -24
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/request.rb +15 -16
- data/lib/action_dispatch/http/response.rb +0 -4
- data/lib/action_dispatch/http/upload.rb +13 -2
- data/lib/action_dispatch/middleware/cookies.rb +6 -6
- data/lib/action_dispatch/middleware/remote_ip.rb +4 -4
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/static.rb +3 -3
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +17 -8
- data/lib/action_dispatch/routing/mapper.rb +23 -0
- data/lib/action_dispatch/routing/url_for.rb +21 -21
- data/lib/action_dispatch/system_testing/driver.rb +1 -1
- data/lib/action_dispatch/testing/assertions/response.rb +1 -1
- data/lib/action_pack/gem_version.rb +2 -2
- metadata +14 -14
@@ -17,7 +17,7 @@ module ActionController
|
|
17
17
|
# return head(:bad_request) unless valid_request?
|
18
18
|
# render
|
19
19
|
#
|
20
|
-
# See Rack::Utils::SYMBOL_TO_STATUS_CODE for a full list of valid +status+ symbols.
|
20
|
+
# See +Rack::Utils::SYMBOL_TO_STATUS_CODE+ for a full list of valid +status+ symbols.
|
21
21
|
def head(status, options = {})
|
22
22
|
if status.is_a?(Hash)
|
23
23
|
raise ArgumentError, "#{status.inspect} is not a valid value for `status`."
|
@@ -321,7 +321,7 @@ module ActionController
|
|
321
321
|
def send_stream(filename:, disposition: "attachment", type: nil)
|
322
322
|
response.headers["Content-Type"] =
|
323
323
|
(type.is_a?(Symbol) ? Mime[type].to_s : type) ||
|
324
|
-
Mime::Type.lookup_by_extension(File.extname(filename).downcase.delete(".")) ||
|
324
|
+
Mime::Type.lookup_by_extension(File.extname(filename).downcase.delete("."))&.to_s ||
|
325
325
|
"application/octet-stream"
|
326
326
|
|
327
327
|
response.headers["Content-Disposition"] =
|
@@ -5,7 +5,7 @@ module ActionController # :nodoc:
|
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
7
|
module ClassMethods
|
8
|
-
# Overrides parts of the globally configured Feature-Policy
|
8
|
+
# Overrides parts of the globally configured +Feature-Policy+
|
9
9
|
# header:
|
10
10
|
#
|
11
11
|
# class PagesController < ApplicationController
|
@@ -4,6 +4,8 @@ module ActionController
|
|
4
4
|
module Redirecting
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
+
ILLEGAL_HEADER_VALUE_REGEX = /[\x00-\x08\x0A-\x1F]/.freeze
|
8
|
+
|
7
9
|
include AbstractController::Logger
|
8
10
|
include ActionController::UrlFor
|
9
11
|
|
@@ -86,7 +88,11 @@ module ActionController
|
|
86
88
|
allow_other_host = response_options.delete(:allow_other_host) { _allow_other_host }
|
87
89
|
|
88
90
|
self.status = _extract_redirect_to_status(options, response_options)
|
89
|
-
|
91
|
+
|
92
|
+
redirect_to_location = _compute_redirect_to_location(request, options)
|
93
|
+
_ensure_url_is_http_header_safe(redirect_to_location)
|
94
|
+
|
95
|
+
self.location = _enforce_open_redirect_protection(redirect_to_location, allow_other_host: allow_other_host)
|
90
96
|
self.response_body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(response.location)}\">redirected</a>.</body></html>"
|
91
97
|
end
|
92
98
|
|
@@ -200,9 +206,20 @@ module ActionController
|
|
200
206
|
return true if host == request.host
|
201
207
|
return false unless host.nil?
|
202
208
|
return false unless url.to_s.start_with?("/")
|
203
|
-
|
209
|
+
!url.to_s.start_with?("//")
|
204
210
|
rescue ArgumentError, URI::Error
|
205
211
|
false
|
206
212
|
end
|
213
|
+
|
214
|
+
def _ensure_url_is_http_header_safe(url)
|
215
|
+
# Attempt to comply with the set of valid token characters
|
216
|
+
# defined for an HTTP header value in
|
217
|
+
# https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6
|
218
|
+
if url.match(ILLEGAL_HEADER_VALUE_REGEX)
|
219
|
+
msg = "The redirect URL #{url} contains one or more illegal HTTP header field character. " \
|
220
|
+
"Set of legal characters defined in https://datatracker.ietf.org/doc/html/rfc7230#section-3.2.6"
|
221
|
+
raise UnsafeRedirectError, msg
|
222
|
+
end
|
223
|
+
end
|
207
224
|
end
|
208
225
|
end
|
@@ -24,12 +24,124 @@ module ActionController
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
# Renders a template and assigns the result to +self.response_body+.
|
28
|
+
#
|
29
|
+
# If no rendering mode option is specified, the template will be derived
|
30
|
+
# from the first argument.
|
31
|
+
#
|
32
|
+
# render "posts/show"
|
33
|
+
# # => renders app/views/posts/show.html.erb
|
34
|
+
#
|
35
|
+
# # In a PostsController action...
|
36
|
+
# render :show
|
37
|
+
# # => renders app/views/posts/show.html.erb
|
38
|
+
#
|
39
|
+
# If the first argument responds to +render_in+, the template will be
|
40
|
+
# rendered by calling +render_in+ with the current view context.
|
41
|
+
#
|
42
|
+
# ==== \Rendering Mode
|
43
|
+
#
|
44
|
+
# [+:partial+]
|
45
|
+
# See ActionView::PartialRenderer for details.
|
46
|
+
#
|
47
|
+
# render partial: "posts/form", locals: { post: Post.new }
|
48
|
+
# # => renders app/views/posts/_form.html.erb
|
49
|
+
#
|
50
|
+
# [+:file+]
|
51
|
+
# Renders the contents of a file. This option should <b>not</b> be used
|
52
|
+
# with unsanitized user input.
|
53
|
+
#
|
54
|
+
# render file: "/path/to/some/file"
|
55
|
+
# # => renders /path/to/some/file
|
56
|
+
#
|
57
|
+
# [+:inline+]
|
58
|
+
# Renders an ERB template string.
|
59
|
+
#
|
60
|
+
# @name = "World"
|
61
|
+
# render inline: "<h1>Hello, <%= @name %>!</h1>"
|
62
|
+
# # => renders "<h1>Hello, World!</h1>"
|
63
|
+
#
|
64
|
+
# [+:body+]
|
65
|
+
# Renders the provided text, and sets the content type as +text/plain+.
|
66
|
+
#
|
67
|
+
# render body: "Hello, World!"
|
68
|
+
# # => renders "Hello, World!"
|
69
|
+
#
|
70
|
+
# [+:plain+]
|
71
|
+
# Renders the provided text, and sets the content type as +text/plain+.
|
72
|
+
#
|
73
|
+
# render plain: "Hello, World!"
|
74
|
+
# # => renders "Hello, World!"
|
75
|
+
#
|
76
|
+
# [+:html+]
|
77
|
+
# Renders the provided HTML string, and sets the content type as +text/html+.
|
78
|
+
# If the string is not +html_safe?+, performs HTML escaping on the string
|
79
|
+
# before rendering.
|
80
|
+
#
|
81
|
+
# render html: "<h1>Hello, World!</h1>".html_safe
|
82
|
+
# # => renders "<h1>Hello, World!</h1>"
|
83
|
+
#
|
84
|
+
# render html: "<h1>Hello, World!</h1>"
|
85
|
+
# # => renders "<h1>Hello, World!</h1>"
|
86
|
+
#
|
87
|
+
# [+:json+]
|
88
|
+
# Renders the provided object as JSON, and sets the content type as
|
89
|
+
# +application/json+. If the object is not a string, it will be converted
|
90
|
+
# to JSON by calling +to_json+.
|
91
|
+
#
|
92
|
+
# render json: { hello: "world" }
|
93
|
+
# # => renders "{\"hello\":\"world\"}"
|
94
|
+
#
|
95
|
+
# By default, when a rendering mode is specified, no layout template is
|
96
|
+
# rendered.
|
97
|
+
#
|
98
|
+
# ==== Options
|
99
|
+
#
|
100
|
+
# [+:assigns+]
|
101
|
+
# Hash of instance variable assignments for the template.
|
102
|
+
#
|
103
|
+
# render inline: "<h1>Hello, <%= @name %>!</h1>", assigns: { name: "World" }
|
104
|
+
# # => renders "<h1>Hello, World!</h1>"
|
105
|
+
#
|
106
|
+
# [+:locals+]
|
107
|
+
# Hash of local variable assignments for the template.
|
108
|
+
#
|
109
|
+
# render inline: "<h1>Hello, <%= name %>!</h1>", locals: { name: "World" }
|
110
|
+
# # => renders "<h1>Hello, World!</h1>"
|
111
|
+
#
|
112
|
+
# [+:layout+]
|
113
|
+
# The layout template to render. Can also be +false+ or +true+ to disable
|
114
|
+
# or (re)enable the default layout template.
|
115
|
+
#
|
116
|
+
# render "posts/show", layout: "holiday"
|
117
|
+
# # => renders app/views/posts/show.html.erb with the app/views/layouts/holiday.html.erb layout
|
118
|
+
#
|
119
|
+
# render "posts/show", layout: false
|
120
|
+
# # => renders app/views/posts/show.html.erb with no layout
|
121
|
+
#
|
122
|
+
# render inline: "<h1>Hello, World!</h1>", layout: true
|
123
|
+
# # => renders "<h1>Hello, World!</h1>" with the default layout
|
124
|
+
#
|
125
|
+
# [+:status+]
|
126
|
+
# The HTTP status code to send with the response. Can be specified as a
|
127
|
+
# number or as the status name in Symbol form. Defaults to 200.
|
128
|
+
#
|
129
|
+
# render "posts/new", status: 422
|
130
|
+
# # => renders app/views/posts/new.html.erb with HTTP status code 422
|
131
|
+
#
|
132
|
+
# render "posts/new", status: :unprocessable_entity
|
133
|
+
# # => renders app/views/posts/new.html.erb with HTTP status code 422
|
134
|
+
#
|
135
|
+
#--
|
27
136
|
# Check for double render errors and set the content_type after rendering.
|
28
|
-
def render(*args)
|
137
|
+
def render(*args)
|
29
138
|
raise ::AbstractController::DoubleRenderError if response_body
|
30
139
|
super
|
31
140
|
end
|
32
141
|
|
142
|
+
# Similar to #render, but only returns the rendered template as a string,
|
143
|
+
# instead of setting +self.response_body+.
|
144
|
+
#--
|
33
145
|
# Override render_to_string because body can now be set to a Rack body.
|
34
146
|
def render_to_string(*)
|
35
147
|
result = super
|
@@ -42,7 +154,7 @@ module ActionController
|
|
42
154
|
end
|
43
155
|
end
|
44
156
|
|
45
|
-
def render_to_body(options = {})
|
157
|
+
def render_to_body(options = {}) # :nodoc:
|
46
158
|
super || _render_in_priorities(options) || " "
|
47
159
|
end
|
48
160
|
|
@@ -118,9 +118,11 @@ module ActionController # :nodoc:
|
|
118
118
|
# protect_from_forgery except: :index
|
119
119
|
# end
|
120
120
|
#
|
121
|
-
# You can disable forgery protection on controller
|
121
|
+
# You can disable forgery protection on a controller using skip_forgery_protection:
|
122
122
|
#
|
123
|
-
#
|
123
|
+
# class BarController < ApplicationController
|
124
|
+
# skip_forgery_protection
|
125
|
+
# end
|
124
126
|
#
|
125
127
|
# Valid Options:
|
126
128
|
#
|
@@ -334,7 +336,7 @@ module ActionController # :nodoc:
|
|
334
336
|
#
|
335
337
|
# * Is it a GET or HEAD request? GETs should be safe and idempotent
|
336
338
|
# * Does the form_authenticity_token match the given token value from the params?
|
337
|
-
# * Does the X-CSRF-Token header match the form_authenticity_token?
|
339
|
+
# * Does the +X-CSRF-Token+ header match the form_authenticity_token?
|
338
340
|
def verified_request? # :doc:
|
339
341
|
!protect_against_forgery? || request.get? || request.head? ||
|
340
342
|
(valid_request_origin? && any_authenticity_token_valid?)
|
@@ -147,7 +147,7 @@ module ActionController # :nodoc:
|
|
147
147
|
# needs to inject contents in the HTML body.
|
148
148
|
#
|
149
149
|
# Also <tt>Rack::Cache</tt> won't work with streaming as it does not support
|
150
|
-
# streaming bodies yet. Whenever streaming Cache-Control is automatically
|
150
|
+
# streaming bodies yet. Whenever streaming +Cache-Control+ is automatically
|
151
151
|
# set to "no-cache".
|
152
152
|
#
|
153
153
|
# == Errors
|
@@ -6,10 +6,8 @@ module ActionController
|
|
6
6
|
#
|
7
7
|
# In addition to AbstractController::UrlFor, this module accesses the HTTP layer to define
|
8
8
|
# URL options like the +host+. In order to do so, this module requires the host class
|
9
|
-
# to implement +env+ which needs to be Rack-compatible and +request+
|
10
|
-
#
|
11
|
-
# that responds to the +host+, +optional_port+, +protocol+, and
|
12
|
-
# +symbolized_path_parameter+ methods.
|
9
|
+
# to implement +env+ which needs to be Rack-compatible, and +request+ which
|
10
|
+
# returns an ActionDispatch::Request instance.
|
13
11
|
#
|
14
12
|
# class RootUrl
|
15
13
|
# include ActionController::UrlFor
|
@@ -111,7 +111,8 @@ module ActionController
|
|
111
111
|
app.config.action_controller.log_query_tags_around_actions
|
112
112
|
|
113
113
|
if query_logs_tags_enabled
|
114
|
-
app.config.active_record.query_log_tags
|
114
|
+
app.config.active_record.query_log_tags |= [:controller] unless app.config.active_record.query_log_tags.include?(:namespaced_controller)
|
115
|
+
app.config.active_record.query_log_tags |= [:action]
|
115
116
|
|
116
117
|
ActiveSupport.on_load(:active_record) do
|
117
118
|
ActiveRecord::QueryLogs.taggings.merge!(
|
@@ -68,26 +68,7 @@ module ActionController
|
|
68
68
|
@env = normalize_keys defaults, env
|
69
69
|
end
|
70
70
|
|
71
|
-
#
|
72
|
-
#
|
73
|
-
# The primary options are:
|
74
|
-
# * <tt>:partial</tt> - See ActionView::PartialRenderer for details.
|
75
|
-
# * <tt>:file</tt> - Renders an explicit template file. Add <tt>:locals</tt> to pass in, if so desired.
|
76
|
-
# It shouldn’t be used directly with unsanitized user input due to lack of validation.
|
77
|
-
# * <tt>:inline</tt> - Renders an ERB template string.
|
78
|
-
# * <tt>:plain</tt> - Renders provided text and sets the content type as <tt>text/plain</tt>.
|
79
|
-
# * <tt>:html</tt> - Renders the provided HTML safe string, otherwise
|
80
|
-
# performs HTML escape on the string first. Sets the content type as <tt>text/html</tt>.
|
81
|
-
# * <tt>:json</tt> - Renders the provided hash or object in JSON. You don't
|
82
|
-
# need to call <tt>.to_json</tt> on the object you want to render.
|
83
|
-
# * <tt>:body</tt> - Renders provided text and sets content type of <tt>text/plain</tt>.
|
84
|
-
#
|
85
|
-
# If no <tt>options</tt> hash is passed or if <tt>:update</tt> is specified, then:
|
86
|
-
#
|
87
|
-
# If an object responding to +render_in+ is passed, +render_in+ is called on the object,
|
88
|
-
# passing in the current view context.
|
89
|
-
#
|
90
|
-
# Otherwise, a partial is rendered using the second parameter as the locals hash.
|
71
|
+
# Renders a template to a string, just like ActionController::Rendering#render_to_string.
|
91
72
|
def render(*args)
|
92
73
|
raise "missing controller" unless controller
|
93
74
|
|
@@ -32,8 +32,8 @@ module ActionDispatch
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
# Check response freshness (Last-Modified and ETag) against request
|
36
|
-
# If-Modified-Since and If-None-Match conditions. If both headers are
|
35
|
+
# Check response freshness (+Last-Modified+ and ETag) against request
|
36
|
+
# +If-Modified-Since+ and +If-None-Match+ conditions. If both headers are
|
37
37
|
# supplied, both must match, or the request is not considered fresh.
|
38
38
|
def fresh?(response)
|
39
39
|
last_modified = if_modified_since
|
@@ -81,8 +81,8 @@ module ActionDispatch
|
|
81
81
|
|
82
82
|
# This method sets a weak ETag validator on the response so browsers
|
83
83
|
# and proxies may cache the response, keyed on the ETag. On subsequent
|
84
|
-
# requests, the If-None-Match header is set to the cached ETag. If it
|
85
|
-
# matches the current ETag, we can return a 304 Not Modified response
|
84
|
+
# requests, the +If-None-Match+ header is set to the cached ETag. If it
|
85
|
+
# matches the current ETag, we can return a <tt>304 Not Modified</tt> response
|
86
86
|
# with no body, letting the browser or proxy know that their cache is
|
87
87
|
# current. Big savings in request time and network bandwidth.
|
88
88
|
#
|
@@ -92,7 +92,7 @@ module ActionDispatch
|
|
92
92
|
# is viewing.
|
93
93
|
#
|
94
94
|
# Strong ETags are considered byte-for-byte identical. They allow a
|
95
|
-
# browser or proxy cache to support Range requests, useful for paging
|
95
|
+
# browser or proxy cache to support +Range+ requests, useful for paging
|
96
96
|
# through a PDF file or scrubbing through a video. Some CDNs only
|
97
97
|
# support strong ETags and will ignore weak ETags entirely.
|
98
98
|
#
|
@@ -112,12 +112,12 @@ module ActionDispatch
|
|
112
112
|
|
113
113
|
def etag?; etag; end
|
114
114
|
|
115
|
-
# True if an ETag is set and it's a weak validator (preceded with W
|
115
|
+
# True if an ETag is set, and it's a weak validator (preceded with <tt>W/</tt>).
|
116
116
|
def weak_etag?
|
117
117
|
etag? && etag.start_with?('W/"')
|
118
118
|
end
|
119
119
|
|
120
|
-
# True if an ETag is set and it isn't a weak validator (not preceded with W
|
120
|
+
# True if an ETag is set, and it isn't a weak validator (not preceded with <tt>W/</tt>).
|
121
121
|
def strong_etag?
|
122
122
|
etag? && !weak_etag?
|
123
123
|
end
|
@@ -33,7 +33,11 @@ module ActionDispatch # :nodoc:
|
|
33
33
|
|
34
34
|
def call(env)
|
35
35
|
request = ActionDispatch::Request.new env
|
36
|
-
|
36
|
+
status, headers, _ = response = @app.call(env)
|
37
|
+
|
38
|
+
# Returning CSP headers with a 304 Not Modified is harmful, since nonces in the new
|
39
|
+
# CSP headers might not match nonces in the cached HTML.
|
40
|
+
return response if status == 304
|
37
41
|
|
38
42
|
return response if policy_present?(headers)
|
39
43
|
|
@@ -4,33 +4,13 @@ require "active_support/parameter_filter"
|
|
4
4
|
|
5
5
|
module ActionDispatch
|
6
6
|
module Http
|
7
|
-
# Allows you to specify sensitive
|
8
|
-
# the request log
|
9
|
-
# sub-hashes of the params hash to filter. Filtering only certain sub-keys
|
10
|
-
# from a hash is possible by using the dot notation: 'credit_card.number'.
|
11
|
-
# If a block is given, each key and value of the params hash and all
|
12
|
-
# sub-hashes are passed to it, where the value or the key can be replaced using
|
13
|
-
# String#replace or similar methods.
|
14
|
-
#
|
15
|
-
# env["action_dispatch.parameter_filter"] = [:password]
|
16
|
-
# => replaces the value to all keys matching /password/i with "[FILTERED]"
|
7
|
+
# Allows you to specify sensitive query string and POST parameters to filter
|
8
|
+
# from the request log.
|
17
9
|
#
|
10
|
+
# # Replaces values with "[FILTERED]" for keys that match /foo|bar/i.
|
18
11
|
# env["action_dispatch.parameter_filter"] = [:foo, "bar"]
|
19
|
-
# => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
|
20
|
-
#
|
21
|
-
# env["action_dispatch.parameter_filter"] = [ /\Apin\z/i, /\Apin_/i ]
|
22
|
-
# => replaces the value for the exact (case-insensitive) key 'pin' and all
|
23
|
-
# (case-insensitive) keys beginning with 'pin_', with "[FILTERED]"
|
24
|
-
# Does not match keys with 'pin' as a substring, such as 'shipping_id'.
|
25
|
-
#
|
26
|
-
# env["action_dispatch.parameter_filter"] = [ "credit_card.code" ]
|
27
|
-
# => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
|
28
|
-
# change { file: { code: "xxxx"} }
|
29
12
|
#
|
30
|
-
#
|
31
|
-
# v.reverse! if k.match?(/secret/i)
|
32
|
-
# end
|
33
|
-
# => reverses the value to all keys matching /secret/i
|
13
|
+
# For more information about filter behavior, see ActiveSupport::ParameterFilter.
|
34
14
|
module FilterParameters
|
35
15
|
ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
|
36
16
|
NULL_PARAM_FILTER = ActiveSupport::ParameterFilter.new # :nodoc:
|
@@ -65,7 +65,7 @@ module ActionDispatch
|
|
65
65
|
@req.set_header env_name(key), value
|
66
66
|
end
|
67
67
|
|
68
|
-
# Add a value to a multivalued header like Vary or Accept-Encoding
|
68
|
+
# Add a value to a multivalued header like +Vary+ or +Accept-Encoding+.
|
69
69
|
def add(key, value)
|
70
70
|
@req.add_header env_name(key), value
|
71
71
|
end
|
@@ -107,22 +107,21 @@ module ActionDispatch
|
|
107
107
|
has_header? key
|
108
108
|
end
|
109
109
|
|
110
|
-
#
|
111
|
-
# Hypertext Transfer Protocol -- HTTP/1.1 (https://www.ietf.org/rfc/rfc2616.txt)
|
112
|
-
# HTTP Extensions for Distributed Authoring -- WEBDAV (https://www.ietf.org/rfc/rfc2518.txt)
|
113
|
-
# Versioning Extensions to WebDAV (https://www.ietf.org/rfc/rfc3253.txt)
|
114
|
-
# Ordered Collections Protocol (WebDAV) (https://www.ietf.org/rfc/rfc3648.txt)
|
115
|
-
# Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (https://www.ietf.org/rfc/rfc3744.txt)
|
116
|
-
# Web Distributed Authoring and Versioning (WebDAV) SEARCH (https://www.ietf.org/rfc/rfc5323.txt)
|
117
|
-
# Calendar Extensions to WebDAV (https://www.ietf.org/rfc/rfc4791.txt)
|
118
|
-
# PATCH Method for HTTP (https://www.ietf.org/rfc/rfc5789.txt)
|
110
|
+
# HTTP methods from {RFC 2616: Hypertext Transfer Protocol -- HTTP/1.1}[https://www.ietf.org/rfc/rfc2616.txt]
|
119
111
|
RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
|
112
|
+
# HTTP methods from {RFC 2518: HTTP Extensions for Distributed Authoring -- WEBDAV}[https://www.ietf.org/rfc/rfc2518.txt]
|
120
113
|
RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
|
114
|
+
# HTTP methods from {RFC 3253: Versioning Extensions to WebDAV}[https://www.ietf.org/rfc/rfc3253.txt]
|
121
115
|
RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
|
116
|
+
# HTTP methods from {RFC 3648: WebDAV Ordered Collections Protocol}[https://www.ietf.org/rfc/rfc3648.txt]
|
122
117
|
RFC3648 = %w(ORDERPATCH)
|
118
|
+
# HTTP methods from {RFC 3744: WebDAV Access Control Protocol}[https://www.ietf.org/rfc/rfc3744.txt]
|
123
119
|
RFC3744 = %w(ACL)
|
120
|
+
# HTTP methods from {RFC 5323: WebDAV SEARCH}[https://www.ietf.org/rfc/rfc5323.txt]
|
124
121
|
RFC5323 = %w(SEARCH)
|
122
|
+
# HTTP methods from {RFC 4791: Calendaring Extensions to WebDAV}[https://www.ietf.org/rfc/rfc4791.txt]
|
125
123
|
RFC4791 = %w(MKCALENDAR)
|
124
|
+
# HTTP methods from {RFC 5789: PATCH Method for HTTP}[https://www.ietf.org/rfc/rfc5789.txt]
|
126
125
|
RFC5789 = %w(PATCH)
|
127
126
|
|
128
127
|
HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
|
@@ -271,7 +270,7 @@ module ActionDispatch
|
|
271
270
|
super.to_i
|
272
271
|
end
|
273
272
|
|
274
|
-
# Returns true if the
|
273
|
+
# Returns true if the +X-Requested-With+ header contains "XMLHttpRequest"
|
275
274
|
# (case-insensitive), which may need to be manually added depending on the
|
276
275
|
# choice of JavaScript libraries and frameworks.
|
277
276
|
def xml_http_request?
|
@@ -297,7 +296,7 @@ module ActionDispatch
|
|
297
296
|
|
298
297
|
ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id" # :nodoc:
|
299
298
|
|
300
|
-
# Returns the unique request id, which is based on either the X-Request-Id header that can
|
299
|
+
# Returns the unique request id, which is based on either the +X-Request-Id+ header that can
|
301
300
|
# be generated by a firewall, load balancer, or web server, or by the RequestId middleware
|
302
301
|
# (which sets the +action_dispatch.request_id+ environment variable).
|
303
302
|
#
|
@@ -341,13 +340,13 @@ module ActionDispatch
|
|
341
340
|
end
|
342
341
|
|
343
342
|
# Determine whether the request body contains form-data by checking
|
344
|
-
# the request Content-Type for one of the media-types:
|
345
|
-
#
|
343
|
+
# the request +Content-Type+ for one of the media-types:
|
344
|
+
# +application/x-www-form-urlencoded+ or +multipart/form-data+. The
|
346
345
|
# list of form-data media types can be modified through the
|
347
346
|
# +FORM_DATA_MEDIA_TYPES+ array.
|
348
347
|
#
|
349
348
|
# A request body is not assumed to contain form-data when no
|
350
|
-
# Content-Type header is provided and the request_method is POST.
|
349
|
+
# +Content-Type+ header is provided and the request_method is POST.
|
351
350
|
def form_data?
|
352
351
|
FORM_DATA_MEDIA_TYPES.include?(media_type)
|
353
352
|
end
|
@@ -379,7 +378,7 @@ module ActionDispatch
|
|
379
378
|
Request::Utils.check_param_encoding(rack_query_params)
|
380
379
|
set_header k, Request::Utils.normalize_encode_params(rack_query_params)
|
381
380
|
end
|
382
|
-
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
381
|
+
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError, Rack::QueryParser::ParamsTooDeepError => e
|
383
382
|
raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}")
|
384
383
|
end
|
385
384
|
alias :query_parameters :GET
|
@@ -394,7 +393,7 @@ module ActionDispatch
|
|
394
393
|
Request::Utils.check_param_encoding(pr)
|
395
394
|
self.request_parameters = Request::Utils.normalize_encode_params(pr)
|
396
395
|
end
|
397
|
-
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
|
396
|
+
rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError, Rack::QueryParser::ParamsTooDeepError, EOFError => e
|
398
397
|
raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
|
399
398
|
end
|
400
399
|
alias :request_parameters :POST
|
@@ -28,6 +28,8 @@ module ActionDispatch
|
|
28
28
|
@tempfile = hash[:tempfile]
|
29
29
|
raise(ArgumentError, ":tempfile is required") unless @tempfile
|
30
30
|
|
31
|
+
@content_type = hash[:type]
|
32
|
+
|
31
33
|
if hash[:filename]
|
32
34
|
@original_filename = hash[:filename].dup
|
33
35
|
|
@@ -40,8 +42,17 @@ module ActionDispatch
|
|
40
42
|
@original_filename = nil
|
41
43
|
end
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
+
if hash[:head]
|
46
|
+
@headers = hash[:head].dup
|
47
|
+
|
48
|
+
begin
|
49
|
+
@headers.encode!(Encoding::UTF_8)
|
50
|
+
rescue EncodingError
|
51
|
+
@headers.force_encoding(Encoding::UTF_8)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
@headers = nil
|
55
|
+
end
|
45
56
|
end
|
46
57
|
|
47
58
|
# Shortcut for +tempfile.read+.
|
@@ -95,7 +95,7 @@ module ActionDispatch
|
|
95
95
|
# Read and write data to cookies through ActionController::Base#cookies.
|
96
96
|
#
|
97
97
|
# When reading cookie data, the data is read from the HTTP request header, Cookie.
|
98
|
-
# When writing cookie data, the data is sent out in the HTTP response header, Set-Cookie
|
98
|
+
# When writing cookie data, the data is sent out in the HTTP response header, +Set-Cookie+.
|
99
99
|
#
|
100
100
|
# Examples of writing:
|
101
101
|
#
|
@@ -443,7 +443,7 @@ module ActionDispatch
|
|
443
443
|
|
444
444
|
if options[:domain] == :all || options[:domain] == "all"
|
445
445
|
cookie_domain = ""
|
446
|
-
dot_splitted_host = request.host.split(
|
446
|
+
dot_splitted_host = request.host.split(".", -1)
|
447
447
|
|
448
448
|
# Case where request.host is not an IP address or it's an invalid domain
|
449
449
|
# (ip confirms to the domain structure we expect so we explicitly check for ip)
|
@@ -453,10 +453,10 @@ module ActionDispatch
|
|
453
453
|
end
|
454
454
|
|
455
455
|
# If there is a provided tld length then we use it otherwise default domain.
|
456
|
-
if options[:tld_length].present?
|
456
|
+
if options[:tld_length].present?
|
457
457
|
# Case where the tld_length provided is valid
|
458
458
|
if dot_splitted_host.length >= options[:tld_length]
|
459
|
-
cookie_domain = dot_splitted_host.last(options[:tld_length]).join(
|
459
|
+
cookie_domain = dot_splitted_host.last(options[:tld_length]).join(".")
|
460
460
|
end
|
461
461
|
# Case where tld_length is not provided
|
462
462
|
else
|
@@ -465,7 +465,7 @@ module ActionDispatch
|
|
465
465
|
cookie_domain = dot_splitted_host.last(2).join(".")
|
466
466
|
# **.**, ***.** style TLDs like co.uk and com.au
|
467
467
|
else
|
468
|
-
cookie_domain = dot_splitted_host.last(3).join(
|
468
|
+
cookie_domain = dot_splitted_host.last(3).join(".")
|
469
469
|
end
|
470
470
|
end
|
471
471
|
|
@@ -683,7 +683,7 @@ module ActionDispatch
|
|
683
683
|
deserialize(name) do |rotate|
|
684
684
|
@encryptor.decrypt_and_verify(encrypted_message, on_rotation: rotate, purpose: purpose)
|
685
685
|
end
|
686
|
-
rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature
|
686
|
+
rescue ActiveSupport::MessageEncryptor::InvalidMessage, ActiveSupport::MessageVerifier::InvalidSignature, JSON::ParserError
|
687
687
|
nil
|
688
688
|
end
|
689
689
|
|
@@ -22,7 +22,7 @@ module ActionDispatch
|
|
22
22
|
# This middleware assumes that there is at least one proxy sitting around
|
23
23
|
# and setting headers with the client's remote IP address. If you don't use
|
24
24
|
# a proxy, because you are hosted on e.g. Heroku without SSL, any client can
|
25
|
-
# claim to have any IP address by setting the X-Forwarded-For header. If you
|
25
|
+
# claim to have any IP address by setting the +X-Forwarded-For+ header. If you
|
26
26
|
# care about that, then you need to explicitly drop or ignore those headers
|
27
27
|
# sometime before this middleware runs.
|
28
28
|
class RemoteIp
|
@@ -53,7 +53,7 @@ module ActionDispatch
|
|
53
53
|
#
|
54
54
|
# The +custom_proxies+ argument can take an enumerable which will be used
|
55
55
|
# instead of +TRUSTED_PROXIES+. Any proxy setup will put the value you
|
56
|
-
# want in the middle (or at the beginning) of the X-Forwarded-For list,
|
56
|
+
# want in the middle (or at the beginning) of the +X-Forwarded-For+ list,
|
57
57
|
# with your proxy servers after it. If your proxies aren't removed, pass
|
58
58
|
# them in via the +custom_proxies+ parameter. That way, the middleware will
|
59
59
|
# ignore those IP addresses, and return the one that you want.
|
@@ -110,9 +110,9 @@ module ActionDispatch
|
|
110
110
|
# REMOTE_ADDR will be correct if the request is made directly against the
|
111
111
|
# Ruby process, on e.g. Heroku. When the request is proxied by another
|
112
112
|
# server like HAProxy or NGINX, the IP address that made the original
|
113
|
-
# request will be put in an X-Forwarded-For header. If there are multiple
|
113
|
+
# request will be put in an +X-Forwarded-For+ header. If there are multiple
|
114
114
|
# proxies, that header may contain a list of IPs. Other proxy services
|
115
|
-
# set the Client-Ip header instead, so we check that too.
|
115
|
+
# set the +Client-Ip+ header instead, so we check that too.
|
116
116
|
#
|
117
117
|
# As discussed in {this post about Rails IP Spoofing}[https://blog.gingerlime.com/2012/rails-ip-spoofing-vulnerabilities-and-protection/],
|
118
118
|
# while the first IP in the list is likely to be the "originating" IP,
|
@@ -6,9 +6,9 @@ require "active_support/core_ext/string/access"
|
|
6
6
|
module ActionDispatch
|
7
7
|
# Makes a unique request id available to the +action_dispatch.request_id+ env variable (which is then accessible
|
8
8
|
# through ActionDispatch::Request#request_id or the alias ActionDispatch::Request#uuid) and sends
|
9
|
-
# the same id to the client via the X-Request-Id header.
|
9
|
+
# the same id to the client via the +X-Request-Id+ header.
|
10
10
|
#
|
11
|
-
# The unique request id is either based on the X-Request-Id header in the request, which would typically be generated
|
11
|
+
# The unique request id is either based on the +X-Request-Id+ header in the request, which would typically be generated
|
12
12
|
# by a firewall, load balancer, or the web server, or, if this header is not available, a random uuid. If the
|
13
13
|
# header is accepted from the outside world, we sanitize it to a max of 255 chars and alphanumeric and dashes only.
|
14
14
|
#
|