actionpack 5.0.7.2 → 5.1.0.beta1
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 +5 -5
- data/CHANGELOG.md +189 -1002
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller.rb +3 -3
- data/lib/abstract_controller/base.rb +10 -12
- data/lib/abstract_controller/caching.rb +6 -3
- data/lib/abstract_controller/caching/fragments.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +2 -43
- data/lib/abstract_controller/collector.rb +2 -2
- data/lib/abstract_controller/helpers.rb +19 -19
- data/lib/abstract_controller/rendering.rb +9 -11
- data/lib/abstract_controller/translation.rb +3 -3
- data/lib/action_controller.rb +15 -13
- data/lib/action_controller/api.rb +3 -3
- data/lib/action_controller/base.rb +7 -12
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +2 -2
- data/lib/action_controller/metal.rb +34 -43
- data/lib/action_controller/metal/conditional_get.rb +10 -9
- data/lib/action_controller/metal/data_streaming.rb +8 -9
- data/lib/action_controller/metal/etag_with_flash.rb +16 -0
- data/lib/action_controller/metal/etag_with_template_digest.rb +15 -15
- data/lib/action_controller/metal/exceptions.rb +4 -14
- data/lib/action_controller/metal/flash.rb +1 -1
- data/lib/action_controller/metal/force_ssl.rb +6 -6
- data/lib/action_controller/metal/head.rb +13 -19
- data/lib/action_controller/metal/helpers.rb +6 -6
- data/lib/action_controller/metal/http_authentication.rb +22 -23
- data/lib/action_controller/metal/implicit_render.rb +2 -5
- data/lib/action_controller/metal/instrumentation.rb +14 -14
- data/lib/action_controller/metal/live.rb +15 -16
- data/lib/action_controller/metal/mime_responds.rb +3 -3
- data/lib/action_controller/metal/parameter_encoding.rb +49 -0
- data/lib/action_controller/metal/params_wrapper.rb +32 -32
- data/lib/action_controller/metal/redirecting.rb +8 -24
- data/lib/action_controller/metal/renderers.rb +2 -3
- data/lib/action_controller/metal/rendering.rb +50 -60
- data/lib/action_controller/metal/request_forgery_protection.rb +51 -49
- data/lib/action_controller/metal/rescue.rb +1 -1
- data/lib/action_controller/metal/streaming.rb +4 -4
- data/lib/action_controller/metal/strong_parameters.rb +117 -250
- data/lib/action_controller/metal/testing.rb +1 -1
- data/lib/action_controller/metal/url_for.rb +4 -4
- data/lib/action_controller/railtie.rb +9 -13
- data/lib/action_controller/renderer.rb +17 -16
- data/lib/action_controller/test_case.rb +75 -148
- data/lib/action_dispatch.rb +20 -19
- data/lib/action_dispatch/http/cache.rb +9 -10
- data/lib/action_dispatch/http/filter_parameters.rb +8 -8
- data/lib/action_dispatch/http/filter_redirect.rb +2 -4
- data/lib/action_dispatch/http/headers.rb +10 -10
- data/lib/action_dispatch/http/mime_negotiation.rb +17 -22
- data/lib/action_dispatch/http/mime_type.rb +27 -52
- data/lib/action_dispatch/http/parameter_filter.rb +8 -6
- data/lib/action_dispatch/http/parameters.rb +40 -17
- data/lib/action_dispatch/http/request.rb +38 -34
- data/lib/action_dispatch/http/response.rb +16 -16
- data/lib/action_dispatch/http/upload.rb +6 -10
- data/lib/action_dispatch/http/url.rb +48 -74
- data/lib/action_dispatch/journey.rb +5 -5
- data/lib/action_dispatch/journey/formatter.rb +8 -4
- data/lib/action_dispatch/journey/gtg/builder.rb +5 -5
- data/lib/action_dispatch/journey/gtg/simulator.rb +1 -1
- data/lib/action_dispatch/journey/gtg/transition_table.rb +15 -15
- data/lib/action_dispatch/journey/nfa/builder.rb +3 -3
- data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
- data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
- data/lib/action_dispatch/journey/nfa/transition_table.rb +2 -2
- data/lib/action_dispatch/journey/nodes/node.rb +5 -5
- data/lib/action_dispatch/journey/parser.rb +23 -24
- data/lib/action_dispatch/journey/parser.y +3 -2
- data/lib/action_dispatch/journey/parser_extras.rb +2 -2
- data/lib/action_dispatch/journey/path/pattern.rb +10 -3
- data/lib/action_dispatch/journey/route.rb +19 -12
- data/lib/action_dispatch/journey/router.rb +19 -12
- data/lib/action_dispatch/journey/router/utils.rb +9 -9
- data/lib/action_dispatch/journey/scanner.rb +17 -15
- data/lib/action_dispatch/journey/visitors.rb +23 -23
- data/lib/action_dispatch/middleware/callbacks.rb +0 -12
- data/lib/action_dispatch/middleware/cookies.rb +39 -39
- data/lib/action_dispatch/middleware/debug_exceptions.rb +126 -112
- data/lib/action_dispatch/middleware/debug_locks.rb +8 -8
- data/lib/action_dispatch/middleware/exception_wrapper.rb +55 -55
- data/lib/action_dispatch/middleware/executor.rb +1 -1
- data/lib/action_dispatch/middleware/flash.rb +17 -16
- data/lib/action_dispatch/middleware/public_exceptions.rb +20 -20
- data/lib/action_dispatch/middleware/reloader.rb +3 -47
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +6 -5
- data/lib/action_dispatch/middleware/session/abstract_store.rb +14 -26
- data/lib/action_dispatch/middleware/session/cache_store.rb +3 -3
- data/lib/action_dispatch/middleware/session/cookie_store.rb +35 -35
- data/lib/action_dispatch/middleware/session/mem_cache_store.rb +2 -2
- data/lib/action_dispatch/middleware/show_exceptions.rb +19 -19
- data/lib/action_dispatch/middleware/ssl.rb +9 -27
- data/lib/action_dispatch/middleware/stack.rb +7 -26
- data/lib/action_dispatch/middleware/static.rb +13 -24
- data/lib/action_dispatch/railtie.rb +9 -11
- data/lib/action_dispatch/request/session.rb +22 -22
- data/lib/action_dispatch/request/utils.rb +11 -2
- data/lib/action_dispatch/routing.rb +8 -6
- data/lib/action_dispatch/routing/inspector.rb +37 -37
- data/lib/action_dispatch/routing/mapper.rb +296 -203
- data/lib/action_dispatch/routing/polymorphic_routes.rb +160 -134
- data/lib/action_dispatch/routing/redirection.rb +27 -22
- data/lib/action_dispatch/routing/route_set.rb +206 -92
- data/lib/action_dispatch/routing/routes_proxy.rb +2 -2
- data/lib/action_dispatch/routing/url_for.rb +14 -12
- data/lib/action_dispatch/system_test_case.rb +119 -0
- data/lib/action_dispatch/system_testing/browser.rb +28 -0
- data/lib/action_dispatch/system_testing/driver.rb +18 -0
- data/lib/action_dispatch/system_testing/server.rb +32 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +61 -0
- data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +20 -0
- data/lib/action_dispatch/testing/assertion_response.rb +6 -6
- data/lib/action_dispatch/testing/assertions.rb +4 -4
- data/lib/action_dispatch/testing/assertions/response.rb +8 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +11 -11
- data/lib/action_dispatch/testing/integration.rb +47 -138
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_request.rb +16 -16
- data/lib/action_dispatch/testing/test_response.rb +1 -1
- data/lib/action_pack.rb +2 -2
- data/lib/action_pack/gem_version.rb +3 -3
- data/lib/action_pack/version.rb +1 -1
- metadata +20 -12
- data/lib/action_dispatch/middleware/params_parser.rb +0 -46
@@ -1,34 +1,23 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
1
|
+
require "rack/utils"
|
2
|
+
require "rack/request"
|
3
|
+
require "rack/session/abstract/id"
|
4
|
+
require "action_dispatch/middleware/cookies"
|
5
|
+
require "action_dispatch/request/session"
|
6
6
|
|
7
7
|
module ActionDispatch
|
8
8
|
module Session
|
9
9
|
class SessionRestoreError < StandardError #:nodoc:
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
ActiveSupport::Deprecation.warn("Passing #original_exception is deprecated and has no effect. " \
|
14
|
-
"Exceptions will automatically capture the original exception.", caller)
|
15
|
-
end
|
16
|
-
|
17
|
-
super("Session contains objects whose class definition isn't available.\n" +
|
18
|
-
"Remember to require the classes for all objects kept in the session.\n" +
|
10
|
+
def initialize
|
11
|
+
super("Session contains objects whose class definition isn't available.\n" \
|
12
|
+
"Remember to require the classes for all objects kept in the session.\n" \
|
19
13
|
"(Original exception: #{$!.message} [#{$!.class}])\n")
|
20
14
|
set_backtrace $!.backtrace
|
21
15
|
end
|
22
|
-
|
23
|
-
def original_exception
|
24
|
-
ActiveSupport::Deprecation.warn("#original_exception is deprecated. Use #cause instead.", caller)
|
25
|
-
cause
|
26
|
-
end
|
27
16
|
end
|
28
17
|
|
29
18
|
module Compatibility
|
30
19
|
def initialize(app, options = {})
|
31
|
-
options[:key] ||=
|
20
|
+
options[:key] ||= "_session_id"
|
32
21
|
super
|
33
22
|
end
|
34
23
|
|
@@ -38,14 +27,13 @@ module ActionDispatch
|
|
38
27
|
sid
|
39
28
|
end
|
40
29
|
|
41
|
-
|
30
|
+
private
|
42
31
|
|
43
|
-
def initialize_sid
|
32
|
+
def initialize_sid # :doc:
|
44
33
|
@default_options.delete(:sidbits)
|
45
34
|
@default_options.delete(:secure_random)
|
46
35
|
end
|
47
36
|
|
48
|
-
private
|
49
37
|
def make_request(env)
|
50
38
|
ActionDispatch::Request.new env
|
51
39
|
end
|
@@ -94,9 +82,9 @@ module ActionDispatch
|
|
94
82
|
|
95
83
|
private
|
96
84
|
|
97
|
-
|
98
|
-
|
99
|
-
|
85
|
+
def set_cookie(request, session_id, cookie)
|
86
|
+
request.cookie_jar[key] = cookie
|
87
|
+
end
|
100
88
|
end
|
101
89
|
end
|
102
90
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require
|
1
|
+
require "action_dispatch/middleware/session/abstract_store"
|
2
2
|
|
3
3
|
module ActionDispatch
|
4
4
|
module Session
|
@@ -19,7 +19,7 @@ module ActionDispatch
|
|
19
19
|
|
20
20
|
# Get a session from the cache.
|
21
21
|
def find_session(env, sid)
|
22
|
-
unless sid
|
22
|
+
unless sid && (session = @cache.read(cache_key(sid)))
|
23
23
|
sid, session = generate_sid, {}
|
24
24
|
end
|
25
25
|
[sid, session]
|
@@ -29,7 +29,7 @@ module ActionDispatch
|
|
29
29
|
def write_session(env, sid, session, options)
|
30
30
|
key = cache_key(sid)
|
31
31
|
if session
|
32
|
-
@cache.write(key, session, :
|
32
|
+
@cache.write(key, session, expires_in: options[:expire_after])
|
33
33
|
else
|
34
34
|
@cache.delete(key)
|
35
35
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
1
|
+
require "active_support/core_ext/hash/keys"
|
2
|
+
require "action_dispatch/middleware/session/abstract_store"
|
3
|
+
require "rack/session/cookie"
|
4
4
|
|
5
5
|
module ActionDispatch
|
6
6
|
module Session
|
@@ -63,8 +63,8 @@ module ActionDispatch
|
|
63
63
|
# Other useful options include <tt>:key</tt>, <tt>:secure</tt> and
|
64
64
|
# <tt>:httponly</tt>.
|
65
65
|
class CookieStore < AbstractStore
|
66
|
-
def initialize(app, options={})
|
67
|
-
super(app, options.merge!(:
|
66
|
+
def initialize(app, options = {})
|
67
|
+
super(app, options.merge!(cookie_only: true))
|
68
68
|
end
|
69
69
|
|
70
70
|
def delete_session(req, session_id, options)
|
@@ -84,46 +84,46 @@ module ActionDispatch
|
|
84
84
|
|
85
85
|
private
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
def extract_session_id(req)
|
88
|
+
stale_session_check! do
|
89
|
+
unpacked_cookie_data(req)["session_id"]
|
90
|
+
end
|
90
91
|
end
|
91
|
-
end
|
92
92
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
93
|
+
def unpacked_cookie_data(req)
|
94
|
+
req.fetch_header("action_dispatch.request.unsigned_session_cookie") do |k|
|
95
|
+
v = stale_session_check! do
|
96
|
+
if data = get_cookie(req)
|
97
|
+
data.stringify_keys!
|
98
|
+
end
|
99
|
+
data || {}
|
98
100
|
end
|
99
|
-
|
101
|
+
req.set_header k, v
|
100
102
|
end
|
101
|
-
req.set_header k, v
|
102
103
|
end
|
103
|
-
end
|
104
104
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
105
|
+
def persistent_session_id!(data, sid = nil)
|
106
|
+
data ||= {}
|
107
|
+
data["session_id"] ||= sid || generate_sid
|
108
|
+
data
|
109
|
+
end
|
110
110
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
111
|
+
def write_session(req, sid, session_data, options)
|
112
|
+
session_data["session_id"] = sid
|
113
|
+
session_data
|
114
|
+
end
|
115
115
|
|
116
|
-
|
117
|
-
|
118
|
-
|
116
|
+
def set_cookie(request, session_id, cookie)
|
117
|
+
cookie_jar(request)[@key] = cookie
|
118
|
+
end
|
119
119
|
|
120
|
-
|
121
|
-
|
122
|
-
|
120
|
+
def get_cookie(req)
|
121
|
+
cookie_jar(req)[@key]
|
122
|
+
end
|
123
123
|
|
124
|
-
|
125
|
-
|
126
|
-
|
124
|
+
def cookie_jar(request)
|
125
|
+
request.cookie_jar.signed_or_encrypted
|
126
|
+
end
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require
|
1
|
+
require "action_dispatch/middleware/session/abstract_store"
|
2
2
|
begin
|
3
|
-
require
|
3
|
+
require "rack/session/dalli"
|
4
4
|
rescue LoadError => e
|
5
5
|
$stderr.puts "You don't have dalli installed in your application. Please add it to your Gemfile and run bundle install"
|
6
6
|
raise e
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "action_dispatch/http/request"
|
2
|
+
require "action_dispatch/middleware/exception_wrapper"
|
3
3
|
|
4
4
|
module ActionDispatch
|
5
5
|
# This middleware rescues any exception returned by the application
|
@@ -15,7 +15,7 @@ module ActionDispatch
|
|
15
15
|
# If any exception happens inside the exceptions app, this middleware
|
16
16
|
# catches the exceptions and returns a FAILSAFE_RESPONSE.
|
17
17
|
class ShowExceptions
|
18
|
-
FAILSAFE_RESPONSE = [500, {
|
18
|
+
FAILSAFE_RESPONSE = [500, { "Content-Type" => "text/plain" },
|
19
19
|
["500 Internal Server Error\n" \
|
20
20
|
"If you are the administrator of this website, then please read this web " \
|
21
21
|
"application's log file and/or the web server's log file to find out what " \
|
@@ -39,22 +39,22 @@ module ActionDispatch
|
|
39
39
|
|
40
40
|
private
|
41
41
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
42
|
+
def render_exception(request, exception)
|
43
|
+
backtrace_cleaner = request.get_header "action_dispatch.backtrace_cleaner"
|
44
|
+
wrapper = ExceptionWrapper.new(backtrace_cleaner, exception)
|
45
|
+
status = wrapper.status_code
|
46
|
+
request.set_header "action_dispatch.exception", wrapper.exception
|
47
|
+
request.set_header "action_dispatch.original_path", request.path_info
|
48
|
+
request.path_info = "/#{status}"
|
49
|
+
response = @exceptions_app.call(request.env)
|
50
|
+
response[1]["X-Cascade"] == "pass" ? pass_response(status) : response
|
51
|
+
rescue Exception => failsafe_error
|
52
|
+
$stderr.puts "Error during failsafe response: #{failsafe_error}\n #{failsafe_error.backtrace * "\n "}"
|
53
|
+
FAILSAFE_RESPONSE
|
54
|
+
end
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
def pass_response(status)
|
57
|
+
[status, { "Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0" }, []]
|
58
|
+
end
|
59
59
|
end
|
60
60
|
end
|
@@ -23,7 +23,7 @@ module ActionDispatch
|
|
23
23
|
# `180.days` (recommended).
|
24
24
|
# * `subdomains`: Set to `true` to tell the browser to apply these settings
|
25
25
|
# to all subdomains. This protects your cookies from interception by a
|
26
|
-
# vulnerable site on a subdomain. Defaults to `
|
26
|
+
# vulnerable site on a subdomain. Defaults to `true`.
|
27
27
|
# * `preload`: Advertise that this site may be included in browsers'
|
28
28
|
# preloaded HSTS lists. HSTS protects your site on every visit *except the
|
29
29
|
# first visit* since it hasn't seen your HSTS header yet. To close this
|
@@ -45,35 +45,17 @@ module ActionDispatch
|
|
45
45
|
HSTS_EXPIRES_IN = 15552000
|
46
46
|
|
47
47
|
def self.default_hsts_options
|
48
|
-
{ expires: HSTS_EXPIRES_IN, subdomains:
|
48
|
+
{ expires: HSTS_EXPIRES_IN, subdomains: true, preload: false }
|
49
49
|
end
|
50
50
|
|
51
|
-
def initialize(app, redirect: {}, hsts: {}, secure_cookies: true
|
51
|
+
def initialize(app, redirect: {}, hsts: {}, secure_cookies: true)
|
52
52
|
@app = app
|
53
53
|
|
54
|
-
|
55
|
-
ActiveSupport::Deprecation.warn <<-end_warning.strip_heredoc
|
56
|
-
The `:host` and `:port` options are moving within `:redirect`:
|
57
|
-
`config.ssl_options = { redirect: { host: …, port: … } }`.
|
58
|
-
end_warning
|
59
|
-
@redirect = options.slice(:host, :port)
|
60
|
-
else
|
61
|
-
@redirect = redirect
|
62
|
-
end
|
54
|
+
@redirect = redirect
|
63
55
|
|
64
56
|
@exclude = @redirect && @redirect[:exclude] || proc { !@redirect }
|
65
57
|
@secure_cookies = secure_cookies
|
66
58
|
|
67
|
-
if hsts != true && hsts != false && hsts[:subdomains].nil?
|
68
|
-
hsts[:subdomains] = false
|
69
|
-
|
70
|
-
ActiveSupport::Deprecation.warn <<-end_warning.strip_heredoc
|
71
|
-
In Rails 5.1, The `:subdomains` option of HSTS config will be treated as true if
|
72
|
-
unspecified. Set `config.ssl_options = { hsts: { subdomains: false } }` to opt out
|
73
|
-
of this behavior.
|
74
|
-
end_warning
|
75
|
-
end
|
76
|
-
|
77
59
|
@hsts_header = build_hsts_header(normalize_hsts_options(hsts))
|
78
60
|
end
|
79
61
|
|
@@ -93,7 +75,7 @@ module ActionDispatch
|
|
93
75
|
|
94
76
|
private
|
95
77
|
def set_hsts_header!(headers)
|
96
|
-
headers[
|
78
|
+
headers["Strict-Transport-Security".freeze] ||= @hsts_header
|
97
79
|
end
|
98
80
|
|
99
81
|
def normalize_hsts_options(options)
|
@@ -119,10 +101,10 @@ module ActionDispatch
|
|
119
101
|
end
|
120
102
|
|
121
103
|
def flag_cookies_as_secure!(headers)
|
122
|
-
if cookies = headers[
|
104
|
+
if cookies = headers["Set-Cookie".freeze]
|
123
105
|
cookies = cookies.split("\n".freeze)
|
124
106
|
|
125
|
-
headers[
|
107
|
+
headers["Set-Cookie".freeze] = cookies.map { |cookie|
|
126
108
|
if cookie !~ /;\s*secure\s*(;|$)/i
|
127
109
|
"#{cookie}; secure"
|
128
110
|
else
|
@@ -134,8 +116,8 @@ module ActionDispatch
|
|
134
116
|
|
135
117
|
def redirect_to_https(request)
|
136
118
|
[ @redirect.fetch(:status, redirection_status(request)),
|
137
|
-
{
|
138
|
-
|
119
|
+
{ "Content-Type" => "text/html",
|
120
|
+
"Location" => https_location_for(request) },
|
139
121
|
@redirect.fetch(:body, []) ]
|
140
122
|
end
|
141
123
|
|
@@ -88,7 +88,6 @@ module ActionDispatch
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def delete(target)
|
91
|
-
target = get_class target
|
92
91
|
middlewares.delete_if { |m| m.klass == target }
|
93
92
|
end
|
94
93
|
|
@@ -102,32 +101,14 @@ module ActionDispatch
|
|
102
101
|
|
103
102
|
private
|
104
103
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
i
|
110
|
-
end
|
111
|
-
|
112
|
-
def get_class(klass)
|
113
|
-
if klass.is_a?(String) || klass.is_a?(Symbol)
|
114
|
-
classcache = ActiveSupport::Dependencies::Reference
|
115
|
-
converted_klass = classcache[klass.to_s]
|
116
|
-
ActiveSupport::Deprecation.warn <<-eowarn
|
117
|
-
Passing strings or symbols to the middleware builder is deprecated, please change
|
118
|
-
them to actual class references. For example:
|
119
|
-
|
120
|
-
"#{klass}" => #{converted_klass}
|
121
|
-
|
122
|
-
eowarn
|
123
|
-
converted_klass
|
124
|
-
else
|
125
|
-
klass
|
104
|
+
def assert_index(index, where)
|
105
|
+
i = index.is_a?(Integer) ? index : middlewares.index { |m| m.klass == index }
|
106
|
+
raise "No such middleware to insert #{where}: #{index.inspect}" unless i
|
107
|
+
i
|
126
108
|
end
|
127
|
-
end
|
128
109
|
|
129
|
-
|
130
|
-
|
131
|
-
|
110
|
+
def build_middleware(klass, args, block)
|
111
|
+
Middleware.new(klass, args, block)
|
112
|
+
end
|
132
113
|
end
|
133
114
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "rack/utils"
|
2
|
+
require "active_support/core_ext/uri"
|
3
3
|
|
4
4
|
module ActionDispatch
|
5
5
|
# This middleware returns a file's contents from disk in the body response.
|
@@ -13,8 +13,8 @@ module ActionDispatch
|
|
13
13
|
# located at `public/assets/application.js` if the file exists. If the file
|
14
14
|
# does not exist, a 404 "File not Found" response will be returned.
|
15
15
|
class FileHandler
|
16
|
-
def initialize(root, index:
|
17
|
-
@root = root.chomp(
|
16
|
+
def initialize(root, index: "index", headers: {})
|
17
|
+
@root = root.chomp("/")
|
18
18
|
@file_server = ::Rack::File.new(@root, headers)
|
19
19
|
@index = index
|
20
20
|
end
|
@@ -27,13 +27,13 @@ module ActionDispatch
|
|
27
27
|
# in the server's `public/` directory (see Static#call).
|
28
28
|
def match?(path)
|
29
29
|
path = ::Rack::Utils.unescape_path path
|
30
|
-
return false unless valid_path?
|
31
|
-
path = Rack::Utils.clean_path_info path
|
30
|
+
return false unless ::Rack::Utils.valid_path? path
|
31
|
+
path = ::Rack::Utils.clean_path_info path
|
32
32
|
|
33
33
|
paths = [path, "#{path}#{ext}", "#{path}/#{@index}#{ext}"]
|
34
34
|
|
35
35
|
if match = paths.detect { |p|
|
36
|
-
path = File.join(@root, p.force_encoding(
|
36
|
+
path = File.join(@root, p.force_encoding(Encoding::UTF_8))
|
37
37
|
begin
|
38
38
|
File.file?(path) && File.readable?(path)
|
39
39
|
rescue SystemCallError
|
@@ -59,13 +59,13 @@ module ActionDispatch
|
|
59
59
|
if status == 304
|
60
60
|
return [status, headers, body]
|
61
61
|
end
|
62
|
-
headers[
|
63
|
-
headers[
|
62
|
+
headers["Content-Encoding"] = "gzip"
|
63
|
+
headers["Content-Type"] = content_type(path)
|
64
64
|
else
|
65
65
|
status, headers, body = @file_server.call(request.env)
|
66
66
|
end
|
67
67
|
|
68
|
-
headers[
|
68
|
+
headers["Vary"] = "Accept-Encoding" if gzip_path
|
69
69
|
|
70
70
|
return [status, headers, body]
|
71
71
|
ensure
|
@@ -78,7 +78,7 @@ module ActionDispatch
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def content_type(path)
|
81
|
-
::Rack::Mime.mime_type(::File.extname(path),
|
81
|
+
::Rack::Mime.mime_type(::File.extname(path), "text/plain".freeze)
|
82
82
|
end
|
83
83
|
|
84
84
|
def gzip_encoding_accepted?(request)
|
@@ -94,10 +94,6 @@ module ActionDispatch
|
|
94
94
|
false
|
95
95
|
end
|
96
96
|
end
|
97
|
-
|
98
|
-
def valid_path?(path)
|
99
|
-
path.valid_encoding? && !path.include?("\0")
|
100
|
-
end
|
101
97
|
end
|
102
98
|
|
103
99
|
# This middleware will attempt to return the contents of a file's body from
|
@@ -110,14 +106,7 @@ module ActionDispatch
|
|
110
106
|
# produce a directory traversal using this middleware. Only 'GET' and 'HEAD'
|
111
107
|
# requests will result in a file being returned.
|
112
108
|
class Static
|
113
|
-
def initialize(app, path,
|
114
|
-
if deprecated_cache_control != :not_set
|
115
|
-
ActiveSupport::Deprecation.warn("The `cache_control` argument is deprecated," \
|
116
|
-
"replaced by `headers: { 'Cache-Control' => #{deprecated_cache_control} }`, " \
|
117
|
-
" and will be removed in Rails 5.1.")
|
118
|
-
headers['Cache-Control'.freeze] = deprecated_cache_control
|
119
|
-
end
|
120
|
-
|
109
|
+
def initialize(app, path, index: "index", headers: {})
|
121
110
|
@app = app
|
122
111
|
@file_handler = FileHandler.new(path, index: index, headers: headers)
|
123
112
|
end
|
@@ -126,7 +115,7 @@ module ActionDispatch
|
|
126
115
|
req = Rack::Request.new env
|
127
116
|
|
128
117
|
if req.get? || req.head?
|
129
|
-
path = req.path_info.chomp(
|
118
|
+
path = req.path_info.chomp("/".freeze)
|
130
119
|
if match = @file_handler.match?(path)
|
131
120
|
req.path_info = match
|
132
121
|
return @file_handler.serve(req)
|