actionpack 5.2.4.rc1 → 6.0.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 +4 -4
- data/CHANGELOG.md +120 -366
- data/MIT-LICENSE +1 -1
- data/README.rdoc +1 -1
- data/lib/abstract_controller/base.rb +4 -2
- data/lib/abstract_controller/caching/fragments.rb +6 -21
- data/lib/abstract_controller/callbacks.rb +12 -0
- data/lib/abstract_controller/collector.rb +1 -1
- data/lib/abstract_controller/helpers.rb +2 -2
- data/lib/abstract_controller/railties/routes_helpers.rb +1 -1
- data/lib/action_controller.rb +1 -0
- data/lib/action_controller/api.rb +2 -1
- data/lib/action_controller/base.rb +2 -7
- data/lib/action_controller/caching.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -5
- data/lib/action_controller/metal.rb +2 -2
- data/lib/action_controller/metal/conditional_get.rb +9 -3
- data/lib/action_controller/metal/data_streaming.rb +5 -6
- data/lib/action_controller/metal/default_headers.rb +17 -0
- data/lib/action_controller/metal/exceptions.rb +22 -1
- data/lib/action_controller/metal/flash.rb +5 -5
- data/lib/action_controller/metal/force_ssl.rb +17 -57
- data/lib/action_controller/metal/head.rb +1 -1
- data/lib/action_controller/metal/helpers.rb +1 -2
- data/lib/action_controller/metal/http_authentication.rb +20 -21
- data/lib/action_controller/metal/implicit_render.rb +2 -12
- data/lib/action_controller/metal/instrumentation.rb +3 -5
- data/lib/action_controller/metal/live.rb +28 -26
- data/lib/action_controller/metal/mime_responds.rb +13 -2
- data/lib/action_controller/metal/params_wrapper.rb +18 -14
- data/lib/action_controller/metal/redirecting.rb +32 -11
- data/lib/action_controller/metal/rendering.rb +1 -1
- data/lib/action_controller/metal/request_forgery_protection.rb +22 -11
- data/lib/action_controller/metal/strong_parameters.rb +57 -32
- data/lib/action_controller/metal/url_for.rb +1 -1
- data/lib/action_controller/railties/helpers.rb +1 -1
- data/lib/action_controller/renderer.rb +15 -2
- data/lib/action_controller/test_case.rb +3 -7
- data/lib/action_dispatch.rb +3 -1
- data/lib/action_dispatch/http/cache.rb +14 -10
- data/lib/action_dispatch/http/content_disposition.rb +45 -0
- data/lib/action_dispatch/http/content_security_policy.rb +9 -8
- data/lib/action_dispatch/http/filter_parameters.rb +8 -6
- data/lib/action_dispatch/http/filter_redirect.rb +1 -1
- data/lib/action_dispatch/http/headers.rb +1 -1
- data/lib/action_dispatch/http/mime_negotiation.rb +7 -10
- data/lib/action_dispatch/http/mime_type.rb +1 -5
- data/lib/action_dispatch/http/parameter_filter.rb +5 -79
- data/lib/action_dispatch/http/parameters.rb +13 -3
- data/lib/action_dispatch/http/request.rb +10 -13
- data/lib/action_dispatch/http/response.rb +14 -14
- data/lib/action_dispatch/http/upload.rb +5 -0
- data/lib/action_dispatch/http/url.rb +81 -81
- data/lib/action_dispatch/journey/formatter.rb +1 -1
- data/lib/action_dispatch/journey/nfa/simulator.rb +0 -2
- data/lib/action_dispatch/journey/nodes/node.rb +9 -8
- data/lib/action_dispatch/journey/path/pattern.rb +3 -4
- data/lib/action_dispatch/journey/router.rb +0 -3
- data/lib/action_dispatch/journey/router/utils.rb +10 -10
- data/lib/action_dispatch/journey/scanner.rb +11 -4
- data/lib/action_dispatch/journey/visitors.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +2 -4
- data/lib/action_dispatch/middleware/cookies.rb +49 -70
- data/lib/action_dispatch/middleware/debug_exceptions.rb +32 -58
- data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
- data/lib/action_dispatch/middleware/debug_view.rb +50 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +36 -7
- data/lib/action_dispatch/middleware/flash.rb +1 -1
- data/lib/action_dispatch/middleware/host_authorization.rb +103 -0
- data/lib/action_dispatch/middleware/remote_ip.rb +6 -8
- data/lib/action_dispatch/middleware/request_id.rb +2 -2
- data/lib/action_dispatch/middleware/session/cookie_store.rb +4 -10
- data/lib/action_dispatch/middleware/ssl.rb +8 -8
- data/lib/action_dispatch/middleware/stack.rb +2 -2
- data/lib/action_dispatch/middleware/static.rb +5 -6
- data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
- data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
- data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +20 -2
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +4 -4
- data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
- data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
- data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +3 -0
- data/lib/action_dispatch/railtie.rb +1 -0
- data/lib/action_dispatch/request/session.rb +8 -0
- data/lib/action_dispatch/routing.rb +3 -2
- data/lib/action_dispatch/routing/inspector.rb +99 -50
- data/lib/action_dispatch/routing/mapper.rb +36 -29
- data/lib/action_dispatch/routing/polymorphic_routes.rb +3 -4
- data/lib/action_dispatch/routing/route_set.rb +11 -12
- data/lib/action_dispatch/routing/url_for.rb +1 -0
- data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +2 -3
- data/lib/action_dispatch/testing/assertions/routing.rb +7 -2
- data/lib/action_dispatch/testing/integration.rb +11 -4
- data/lib/action_dispatch/testing/test_process.rb +2 -2
- data/lib/action_dispatch/testing/test_response.rb +4 -32
- data/lib/action_pack.rb +1 -1
- data/lib/action_pack/gem_version.rb +4 -4
- metadata +20 -12
@@ -32,7 +32,7 @@ module ActionDispatch
|
|
32
32
|
req = ActionDispatch::Request.new env
|
33
33
|
|
34
34
|
if req.get?
|
35
|
-
path = req.path_info.chomp("/"
|
35
|
+
path = req.path_info.chomp("/")
|
36
36
|
if path == @path
|
37
37
|
return render_details(req)
|
38
38
|
end
|
@@ -63,19 +63,19 @@ module ActionDispatch
|
|
63
63
|
|
64
64
|
str = threads.map do |thread, info|
|
65
65
|
if info[:exclusive]
|
66
|
-
lock_state = "Exclusive"
|
66
|
+
lock_state = +"Exclusive"
|
67
67
|
elsif info[:sharing] > 0
|
68
|
-
lock_state = "Sharing"
|
68
|
+
lock_state = +"Sharing"
|
69
69
|
lock_state << " x#{info[:sharing]}" if info[:sharing] > 1
|
70
70
|
else
|
71
|
-
lock_state = "No lock"
|
71
|
+
lock_state = +"No lock"
|
72
72
|
end
|
73
73
|
|
74
74
|
if info[:waiting]
|
75
75
|
lock_state << " (yielded share)"
|
76
76
|
end
|
77
77
|
|
78
|
-
msg = "Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n"
|
78
|
+
msg = +"Thread #{info[:index]} [0x#{thread.__id__.to_s(16)} #{thread.status || 'dead'}] #{lock_state}\n"
|
79
79
|
|
80
80
|
if info[:sleeper]
|
81
81
|
msg << " Waiting in #{info[:sleeper]}"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "pp"
|
4
|
+
|
5
|
+
require "action_view"
|
6
|
+
require "action_view/base"
|
7
|
+
|
8
|
+
module ActionDispatch
|
9
|
+
class DebugView < ActionView::Base # :nodoc:
|
10
|
+
RESCUES_TEMPLATE_PATH = File.expand_path("templates", __dir__)
|
11
|
+
|
12
|
+
def initialize(assigns)
|
13
|
+
super([RESCUES_TEMPLATE_PATH], assigns)
|
14
|
+
end
|
15
|
+
|
16
|
+
def debug_params(params)
|
17
|
+
clean_params = params.clone
|
18
|
+
clean_params.delete("action")
|
19
|
+
clean_params.delete("controller")
|
20
|
+
|
21
|
+
if clean_params.empty?
|
22
|
+
"None"
|
23
|
+
else
|
24
|
+
PP.pp(clean_params, +"", 200)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def debug_headers(headers)
|
29
|
+
if headers.present?
|
30
|
+
headers.inspect.gsub(",", ",\n")
|
31
|
+
else
|
32
|
+
"None"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def debug_hash(object)
|
37
|
+
object.to_hash.sort_by { |k, _| k.to_s }.map { |k, v| "#{k}: #{v.inspect rescue $!.message}" }.join("\n")
|
38
|
+
end
|
39
|
+
|
40
|
+
def render(*)
|
41
|
+
logger = ActionView::Base.logger
|
42
|
+
|
43
|
+
if logger && logger.respond_to?(:silence)
|
44
|
+
logger.silence { super }
|
45
|
+
else
|
46
|
+
super
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -12,6 +12,7 @@ module ActionDispatch
|
|
12
12
|
"ActionController::UnknownHttpMethod" => :method_not_allowed,
|
13
13
|
"ActionController::NotImplemented" => :not_implemented,
|
14
14
|
"ActionController::UnknownFormat" => :not_acceptable,
|
15
|
+
"ActionController::MissingExactTemplate" => :not_acceptable,
|
15
16
|
"ActionController::InvalidAuthenticityToken" => :unprocessable_entity,
|
16
17
|
"ActionController::InvalidCrossOriginRequest" => :unprocessable_entity,
|
17
18
|
"ActionDispatch::Http::Parameters::ParseError" => :bad_request,
|
@@ -22,18 +23,20 @@ module ActionDispatch
|
|
22
23
|
)
|
23
24
|
|
24
25
|
cattr_accessor :rescue_templates, default: Hash.new("diagnostics").merge!(
|
25
|
-
"ActionView::MissingTemplate"
|
26
|
-
"ActionController::RoutingError"
|
27
|
-
"AbstractController::ActionNotFound"
|
28
|
-
"ActiveRecord::StatementInvalid"
|
29
|
-
"ActionView::Template::Error"
|
26
|
+
"ActionView::MissingTemplate" => "missing_template",
|
27
|
+
"ActionController::RoutingError" => "routing_error",
|
28
|
+
"AbstractController::ActionNotFound" => "unknown_action",
|
29
|
+
"ActiveRecord::StatementInvalid" => "invalid_statement",
|
30
|
+
"ActionView::Template::Error" => "template_error",
|
31
|
+
"ActionController::MissingExactTemplate" => "missing_exact_template",
|
30
32
|
)
|
31
33
|
|
32
|
-
attr_reader :backtrace_cleaner, :exception, :line_number, :file
|
34
|
+
attr_reader :backtrace_cleaner, :exception, :wrapped_causes, :line_number, :file
|
33
35
|
|
34
36
|
def initialize(backtrace_cleaner, exception)
|
35
37
|
@backtrace_cleaner = backtrace_cleaner
|
36
38
|
@exception = original_exception(exception)
|
39
|
+
@wrapped_causes = wrapped_causes_for(exception, backtrace_cleaner)
|
37
40
|
|
38
41
|
expand_backtrace if exception.is_a?(SyntaxError) || exception.cause.is_a?(SyntaxError)
|
39
42
|
end
|
@@ -64,7 +67,11 @@ module ActionDispatch
|
|
64
67
|
full_trace_with_ids = []
|
65
68
|
|
66
69
|
full_trace.each_with_index do |trace, idx|
|
67
|
-
trace_with_id = {
|
70
|
+
trace_with_id = {
|
71
|
+
exception_object_id: @exception.object_id,
|
72
|
+
id: idx,
|
73
|
+
trace: trace
|
74
|
+
}
|
68
75
|
|
69
76
|
if application_trace.include?(trace)
|
70
77
|
application_trace_with_ids << trace_with_id
|
@@ -97,6 +104,18 @@ module ActionDispatch
|
|
97
104
|
end
|
98
105
|
end
|
99
106
|
|
107
|
+
def trace_to_show
|
108
|
+
if traces["Application Trace"].empty? && rescue_template != "routing_error"
|
109
|
+
"Full Trace"
|
110
|
+
else
|
111
|
+
"Application Trace"
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
def source_to_show_id
|
116
|
+
(traces[trace_to_show].first || {})[:id]
|
117
|
+
end
|
118
|
+
|
100
119
|
private
|
101
120
|
|
102
121
|
def backtrace
|
@@ -111,6 +130,16 @@ module ActionDispatch
|
|
111
130
|
end
|
112
131
|
end
|
113
132
|
|
133
|
+
def causes_for(exception)
|
134
|
+
return enum_for(__method__, exception) unless block_given?
|
135
|
+
|
136
|
+
yield exception while exception = exception.cause
|
137
|
+
end
|
138
|
+
|
139
|
+
def wrapped_causes_for(exception, backtrace_cleaner)
|
140
|
+
causes_for(exception).map { |cause| self.class.new(backtrace_cleaner, cause) }
|
141
|
+
end
|
142
|
+
|
114
143
|
def clean_backtrace(*args)
|
115
144
|
if backtrace_cleaner
|
116
145
|
backtrace_cleaner.clean(backtrace, *args)
|
@@ -38,7 +38,7 @@ module ActionDispatch
|
|
38
38
|
#
|
39
39
|
# See docs on the FlashHash class for more details about the flash.
|
40
40
|
class Flash
|
41
|
-
KEY = "action_dispatch.request.flash_hash"
|
41
|
+
KEY = "action_dispatch.request.flash_hash"
|
42
42
|
|
43
43
|
module RequestMethods
|
44
44
|
# Access the contents of the flash. Use <tt>flash["notice"]</tt> to
|
@@ -0,0 +1,103 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_dispatch/http/request"
|
4
|
+
|
5
|
+
module ActionDispatch
|
6
|
+
# This middleware guards from DNS rebinding attacks by white-listing the
|
7
|
+
# hosts a request can be sent to.
|
8
|
+
#
|
9
|
+
# When a request comes to an unauthorized host, the +response_app+
|
10
|
+
# application will be executed and rendered. If no +response_app+ is given, a
|
11
|
+
# default one will run, which responds with +403 Forbidden+.
|
12
|
+
class HostAuthorization
|
13
|
+
class Permissions # :nodoc:
|
14
|
+
def initialize(hosts)
|
15
|
+
@hosts = sanitize_hosts(hosts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def empty?
|
19
|
+
@hosts.empty?
|
20
|
+
end
|
21
|
+
|
22
|
+
def allows?(host)
|
23
|
+
@hosts.any? do |allowed|
|
24
|
+
allowed === host
|
25
|
+
rescue
|
26
|
+
# IPAddr#=== raises an error if you give it a hostname instead of
|
27
|
+
# IP. Treat similar errors as blocked access.
|
28
|
+
false
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
def sanitize_hosts(hosts)
|
35
|
+
Array(hosts).map do |host|
|
36
|
+
case host
|
37
|
+
when Regexp then sanitize_regexp(host)
|
38
|
+
when String then sanitize_string(host)
|
39
|
+
else host
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def sanitize_regexp(host)
|
45
|
+
/\A#{host}\z/
|
46
|
+
end
|
47
|
+
|
48
|
+
def sanitize_string(host)
|
49
|
+
if host.start_with?(".")
|
50
|
+
/\A(.+\.)?#{Regexp.escape(host[1..-1])}\z/
|
51
|
+
else
|
52
|
+
host
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
DEFAULT_RESPONSE_APP = -> env do
|
58
|
+
request = Request.new(env)
|
59
|
+
|
60
|
+
format = request.xhr? ? "text/plain" : "text/html"
|
61
|
+
template = DebugView.new(host: request.host)
|
62
|
+
body = template.render(template: "rescues/blocked_host", layout: "rescues/layout")
|
63
|
+
|
64
|
+
[403, {
|
65
|
+
"Content-Type" => "#{format}; charset=#{Response.default_charset}",
|
66
|
+
"Content-Length" => body.bytesize.to_s,
|
67
|
+
}, [body]]
|
68
|
+
end
|
69
|
+
|
70
|
+
def initialize(app, hosts, response_app = nil)
|
71
|
+
@app = app
|
72
|
+
@permissions = Permissions.new(hosts)
|
73
|
+
@response_app = response_app || DEFAULT_RESPONSE_APP
|
74
|
+
end
|
75
|
+
|
76
|
+
def call(env)
|
77
|
+
return @app.call(env) if @permissions.empty?
|
78
|
+
|
79
|
+
request = Request.new(env)
|
80
|
+
|
81
|
+
if authorized?(request)
|
82
|
+
mark_as_authorized(request)
|
83
|
+
@app.call(env)
|
84
|
+
else
|
85
|
+
@response_app.call(env)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def authorized?(request)
|
92
|
+
origin_host = request.get_header("HTTP_HOST").to_s.sub(/:\d+\z/, "")
|
93
|
+
forwarded_host = request.x_forwarded_host.to_s.split(/,\s?/).last.to_s.sub(/:\d+\z/, "")
|
94
|
+
|
95
|
+
@permissions.allows?(origin_host) &&
|
96
|
+
(forwarded_host.blank? || @permissions.allows?(forwarded_host))
|
97
|
+
end
|
98
|
+
|
99
|
+
def mark_as_authorized(request)
|
100
|
+
request.set_header("action_dispatch.authorized_host", request.host)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -162,14 +162,12 @@ module ActionDispatch
|
|
162
162
|
# Split the comma-separated list into an array of strings.
|
163
163
|
ips = header.strip.split(/[,\s]+/)
|
164
164
|
ips.select do |ip|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
nil
|
172
|
-
end
|
165
|
+
# Only return IPs that are valid according to the IPAddr#new method.
|
166
|
+
range = IPAddr.new(ip).to_range
|
167
|
+
# We want to make sure nobody is sneaking a netmask in.
|
168
|
+
range.begin == range.end
|
169
|
+
rescue ArgumentError
|
170
|
+
nil
|
173
171
|
end
|
174
172
|
end
|
175
173
|
|
@@ -15,7 +15,7 @@ module ActionDispatch
|
|
15
15
|
# The unique request id can be used to trace a request end-to-end and would typically end up being part of log files
|
16
16
|
# from multiple pieces of the stack.
|
17
17
|
class RequestId
|
18
|
-
X_REQUEST_ID = "X-Request-Id"
|
18
|
+
X_REQUEST_ID = "X-Request-Id" #:nodoc:
|
19
19
|
|
20
20
|
def initialize(app)
|
21
21
|
@app = app
|
@@ -30,7 +30,7 @@ module ActionDispatch
|
|
30
30
|
private
|
31
31
|
def make_request_id(request_id)
|
32
32
|
if request_id.presence
|
33
|
-
request_id.gsub(/[^\w\-@]/, ""
|
33
|
+
request_id.gsub(/[^\w\-@]/, "").first(255)
|
34
34
|
else
|
35
35
|
internal_request_id
|
36
36
|
end
|
@@ -16,23 +16,17 @@ module ActionDispatch
|
|
16
16
|
# The cookie jar used for storage is automatically configured to be the
|
17
17
|
# best possible option given your application's configuration.
|
18
18
|
#
|
19
|
-
# If you only have secret_token set, your cookies will be signed, but
|
20
|
-
# not encrypted. This means a user cannot alter their +user_id+ without
|
21
|
-
# knowing your app's secret key, but can easily read their +user_id+. This
|
22
|
-
# was the default for Rails 3 apps.
|
23
|
-
#
|
24
19
|
# Your cookies will be encrypted using your apps secret_key_base. This
|
25
20
|
# goes a step further than signed cookies in that encrypted cookies cannot
|
26
21
|
# be altered or read by users. This is the default starting in Rails 4.
|
27
22
|
#
|
28
|
-
# Configure your session store in
|
23
|
+
# Configure your session store in an initializer:
|
29
24
|
#
|
30
25
|
# Rails.application.config.session_store :cookie_store, key: '_your_app_session'
|
31
26
|
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
# <tt>config/credentials.yml.enc</tt> file.
|
27
|
+
# By default, your secret key base is derived from your application name in
|
28
|
+
# the test and development environments. In all other environments, it is stored
|
29
|
+
# encrypted in the <tt>config/credentials.yml.enc</tt> file.
|
36
30
|
#
|
37
31
|
# If your application was not updated to Rails 5.2 defaults, the secret_key_base
|
38
32
|
# will be found in the old <tt>config/secrets.yml</tt> file.
|
@@ -83,7 +83,7 @@ module ActionDispatch
|
|
83
83
|
|
84
84
|
private
|
85
85
|
def set_hsts_header!(headers)
|
86
|
-
headers["Strict-Transport-Security"
|
86
|
+
headers["Strict-Transport-Security"] ||= @hsts_header
|
87
87
|
end
|
88
88
|
|
89
89
|
def normalize_hsts_options(options)
|
@@ -102,23 +102,23 @@ module ActionDispatch
|
|
102
102
|
|
103
103
|
# https://tools.ietf.org/html/rfc6797#section-6.1
|
104
104
|
def build_hsts_header(hsts)
|
105
|
-
value = "max-age=#{hsts[:expires].to_i}"
|
105
|
+
value = +"max-age=#{hsts[:expires].to_i}"
|
106
106
|
value << "; includeSubDomains" if hsts[:subdomains]
|
107
107
|
value << "; preload" if hsts[:preload]
|
108
108
|
value
|
109
109
|
end
|
110
110
|
|
111
111
|
def flag_cookies_as_secure!(headers)
|
112
|
-
if cookies = headers["Set-Cookie"
|
113
|
-
cookies = cookies.split("\n"
|
112
|
+
if cookies = headers["Set-Cookie"]
|
113
|
+
cookies = cookies.split("\n")
|
114
114
|
|
115
|
-
headers["Set-Cookie"
|
116
|
-
if
|
115
|
+
headers["Set-Cookie"] = cookies.map { |cookie|
|
116
|
+
if !/;\s*secure\s*(;|$)/i.match?(cookie)
|
117
117
|
"#{cookie}; secure"
|
118
118
|
else
|
119
119
|
cookie
|
120
120
|
end
|
121
|
-
}.join("\n"
|
121
|
+
}.join("\n")
|
122
122
|
end
|
123
123
|
end
|
124
124
|
|
@@ -141,7 +141,7 @@ module ActionDispatch
|
|
141
141
|
host = @redirect[:host] || request.host
|
142
142
|
port = @redirect[:port] || request.port
|
143
143
|
|
144
|
-
location = "https://#{host}"
|
144
|
+
location = +"https://#{host}"
|
145
145
|
location << ":#{port}" if port != 80 && port != 443
|
146
146
|
location << request.fullpath
|
147
147
|
location
|
@@ -97,8 +97,8 @@ module ActionDispatch
|
|
97
97
|
middlewares.push(build_middleware(klass, args, block))
|
98
98
|
end
|
99
99
|
|
100
|
-
def build(app =
|
101
|
-
middlewares.freeze.reverse.inject(app
|
100
|
+
def build(app = Proc.new)
|
101
|
+
middlewares.freeze.reverse.inject(app) { |a, e| e.build(a) }
|
102
102
|
end
|
103
103
|
|
104
104
|
private
|
@@ -41,7 +41,6 @@ module ActionDispatch
|
|
41
41
|
rescue SystemCallError
|
42
42
|
false
|
43
43
|
end
|
44
|
-
|
45
44
|
}
|
46
45
|
return ::Rack::Utils.escape_path(match).b
|
47
46
|
end
|
@@ -69,7 +68,7 @@ module ActionDispatch
|
|
69
68
|
|
70
69
|
headers["Vary"] = "Accept-Encoding" if gzip_path
|
71
70
|
|
72
|
-
|
71
|
+
[status, headers, body]
|
73
72
|
ensure
|
74
73
|
request.path_info = path
|
75
74
|
end
|
@@ -80,7 +79,7 @@ module ActionDispatch
|
|
80
79
|
end
|
81
80
|
|
82
81
|
def content_type(path)
|
83
|
-
::Rack::Mime.mime_type(::File.extname(path), "text/plain"
|
82
|
+
::Rack::Mime.mime_type(::File.extname(path), "text/plain")
|
84
83
|
end
|
85
84
|
|
86
85
|
def gzip_encoding_accepted?(request)
|
@@ -90,8 +89,8 @@ module ActionDispatch
|
|
90
89
|
def gzip_file_path(path)
|
91
90
|
can_gzip_mime = content_type(path) =~ /\A(?:text\/|application\/javascript)/
|
92
91
|
gzip_path = "#{path}.gz"
|
93
|
-
if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)
|
94
|
-
gzip_path
|
92
|
+
if can_gzip_mime && File.exist?(File.join(@root, ::Rack::Utils.unescape_path(gzip_path)))
|
93
|
+
gzip_path
|
95
94
|
else
|
96
95
|
false
|
97
96
|
end
|
@@ -117,7 +116,7 @@ module ActionDispatch
|
|
117
116
|
req = Rack::Request.new env
|
118
117
|
|
119
118
|
if req.get? || req.head?
|
120
|
-
path = req.path_info.chomp("/"
|
119
|
+
path = req.path_info.chomp("/")
|
121
120
|
if match = @file_handler.match?(path)
|
122
121
|
req.path_info = match
|
123
122
|
return @file_handler.serve(req)
|