actionpack 3.1.12 → 3.2.0.rc1
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.
- data/CHANGELOG.md +5503 -108
- data/README.rdoc +3 -3
- data/lib/abstract_controller/asset_paths.rb +1 -1
- data/lib/abstract_controller/base.rb +1 -1
- data/lib/abstract_controller/callbacks.rb +102 -18
- data/lib/abstract_controller/helpers.rb +1 -1
- data/lib/abstract_controller/layouts.rb +116 -50
- data/lib/abstract_controller/logger.rb +1 -1
- data/lib/abstract_controller/railties/routes_helpers.rb +2 -2
- data/lib/abstract_controller/rendering.rb +1 -6
- data/lib/abstract_controller/view_paths.rb +6 -5
- data/lib/action_controller.rb +0 -15
- data/lib/action_controller/caching.rb +0 -1
- data/lib/action_controller/caching/actions.rb +5 -6
- data/lib/action_controller/caching/fragments.rb +18 -18
- data/lib/action_controller/caching/pages.rb +7 -6
- data/lib/action_controller/caching/sweeping.rb +1 -1
- data/lib/action_controller/log_subscriber.rb +8 -4
- data/lib/action_controller/metal.rb +7 -1
- data/lib/action_controller/metal/conditional_get.rb +49 -4
- data/lib/action_controller/metal/data_streaming.rb +17 -5
- data/lib/action_controller/metal/force_ssl.rb +8 -5
- data/lib/action_controller/metal/helpers.rb +7 -4
- data/lib/action_controller/metal/http_authentication.rb +9 -12
- data/lib/action_controller/metal/instrumentation.rb +9 -4
- data/lib/action_controller/metal/mime_responds.rb +4 -4
- data/lib/action_controller/metal/params_wrapper.rb +12 -8
- data/lib/action_controller/metal/redirecting.rb +7 -6
- data/lib/action_controller/metal/renderers.rb +9 -11
- data/lib/action_controller/metal/request_forgery_protection.rb +2 -1
- data/lib/action_controller/metal/rescue.rb +13 -0
- data/lib/action_controller/metal/responder.rb +11 -23
- data/lib/action_controller/metal/streaming.rb +0 -25
- data/lib/action_controller/railtie.rb +1 -0
- data/lib/action_controller/railties/paths.rb +4 -3
- data/lib/action_controller/record_identifier.rb +4 -4
- data/lib/action_controller/test_case.rb +60 -56
- data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +6 -6
- data/lib/action_dispatch.rb +5 -1
- data/lib/action_dispatch/http/cache.rb +27 -15
- data/lib/action_dispatch/http/filter_parameters.rb +3 -1
- data/lib/action_dispatch/http/headers.rb +3 -5
- data/lib/action_dispatch/http/mime_negotiation.rb +2 -1
- data/lib/action_dispatch/http/mime_type.rb +7 -3
- data/lib/action_dispatch/http/mime_types.rb +12 -0
- data/lib/action_dispatch/http/parameter_filter.rb +3 -1
- data/lib/action_dispatch/http/parameters.rb +0 -4
- data/lib/action_dispatch/http/request.rb +18 -68
- data/lib/action_dispatch/http/response.rb +11 -32
- data/lib/action_dispatch/http/upload.rb +3 -14
- data/lib/action_dispatch/http/url.rb +1 -1
- data/lib/action_dispatch/middleware/callbacks.rb +1 -2
- data/lib/action_dispatch/middleware/cookies.rb +20 -16
- data/lib/action_dispatch/middleware/debug_exceptions.rb +82 -0
- data/lib/action_dispatch/middleware/exception_wrapper.rb +78 -0
- data/lib/action_dispatch/middleware/flash.rb +6 -9
- data/lib/action_dispatch/middleware/params_parser.rb +6 -11
- data/lib/action_dispatch/middleware/public_exceptions.rb +30 -0
- data/lib/action_dispatch/middleware/reloader.rb +38 -14
- data/lib/action_dispatch/middleware/remote_ip.rb +66 -36
- data/lib/action_dispatch/middleware/request_id.rb +39 -0
- data/lib/action_dispatch/middleware/session/abstract_store.rb +4 -16
- data/lib/action_dispatch/middleware/session/cache_store.rb +50 -0
- data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
- data/lib/action_dispatch/middleware/show_exceptions.rb +58 -142
- data/lib/action_dispatch/middleware/static.rb +2 -10
- data/lib/action_dispatch/middleware/templates/rescues/layout.erb +1 -0
- data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +13 -8
- data/lib/action_dispatch/railtie.rb +15 -1
- data/lib/action_dispatch/routing.rb +1 -2
- data/lib/action_dispatch/routing/mapper.rb +108 -107
- data/lib/action_dispatch/routing/redirection.rb +63 -69
- data/lib/action_dispatch/routing/route_set.rb +75 -43
- data/lib/action_dispatch/routing/routes_proxy.rb +0 -4
- data/lib/action_dispatch/routing/url_for.rb +3 -3
- data/lib/action_dispatch/testing/assertions/response.rb +5 -7
- data/lib/action_dispatch/testing/assertions/routing.rb +10 -9
- data/lib/action_dispatch/testing/integration.rb +8 -25
- data/lib/action_dispatch/testing/test_process.rb +3 -2
- data/lib/action_dispatch/testing/test_request.rb +4 -23
- data/lib/action_pack/version.rb +3 -3
- data/lib/action_view.rb +1 -5
- data/lib/action_view/asset_paths.rb +7 -8
- data/lib/action_view/base.rb +7 -5
- data/lib/action_view/helpers/asset_paths.rb +1 -1
- data/lib/action_view/helpers/asset_tag_helper.rb +4 -8
- data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +3 -0
- data/lib/action_view/helpers/atom_feed_helper.rb +2 -2
- data/lib/action_view/helpers/capture_helper.rb +3 -3
- data/lib/action_view/helpers/controller_helper.rb +1 -1
- data/lib/action_view/helpers/date_helper.rb +26 -18
- data/lib/action_view/helpers/debug_helper.rb +1 -1
- data/lib/action_view/helpers/form_helper.rb +71 -13
- data/lib/action_view/helpers/form_options_helper.rb +65 -34
- data/lib/action_view/helpers/form_tag_helper.rb +24 -18
- data/lib/action_view/helpers/javascript_helper.rb +12 -3
- data/lib/action_view/helpers/number_helper.rb +3 -2
- data/lib/action_view/helpers/record_tag_helper.rb +51 -5
- data/lib/action_view/helpers/rendering_helper.rb +2 -2
- data/lib/action_view/helpers/sanitize_helper.rb +6 -7
- data/lib/action_view/helpers/tag_helper.rb +1 -1
- data/lib/action_view/helpers/text_helper.rb +5 -4
- data/lib/action_view/helpers/url_helper.rb +19 -11
- data/lib/action_view/locale/en.yml +6 -0
- data/lib/action_view/log_subscriber.rb +1 -1
- data/lib/action_view/lookup_context.rb +123 -125
- data/lib/action_view/path_set.rb +60 -13
- data/lib/action_view/renderer/abstract_renderer.rb +16 -11
- data/lib/action_view/renderer/partial_renderer.rb +59 -40
- data/lib/action_view/renderer/template_renderer.rb +29 -17
- data/lib/action_view/template.rb +0 -1
- data/lib/action_view/template/error.rb +6 -5
- data/lib/action_view/template/handlers.rb +0 -6
- data/lib/action_view/template/handlers/builder.rb +10 -1
- data/lib/action_view/template/handlers/erb.rb +2 -2
- data/lib/action_view/template/resolver.rb +20 -31
- data/lib/action_view/test_case.rb +7 -10
- data/lib/sprockets/assets.rake +1 -1
- data/lib/sprockets/bootstrap.rb +3 -31
- data/lib/sprockets/compressors.rb +69 -7
- data/lib/sprockets/helpers/rails_helper.rb +6 -11
- data/lib/sprockets/railtie.rb +1 -0
- data/lib/sprockets/static_compiler.rb +0 -3
- metadata +57 -86
- checksums.yaml +0 -7
- data/lib/action_dispatch/middleware/closed_error.rb +0 -7
- data/lib/action_dispatch/routing/route.rb +0 -67
- data/lib/action_view/template/handler.rb +0 -49
@@ -1,4 +1,5 @@
|
|
1
|
-
require
|
1
|
+
require 'active_support/core_ext/object/blank'
|
2
|
+
require 'active_support/core_ext/hash/keys'
|
2
3
|
|
3
4
|
module ActionDispatch
|
4
5
|
class Request
|
@@ -59,7 +60,7 @@ module ActionDispatch
|
|
59
60
|
# The option symbols for setting cookies are:
|
60
61
|
#
|
61
62
|
# * <tt>:value</tt> - The cookie's value or list of values (as an array).
|
62
|
-
# * <tt>:path</tt> - The path for which this cookie applies.
|
63
|
+
# * <tt>:path</tt> - The path for which this cookie applies. Defaults to the root
|
63
64
|
# of the application.
|
64
65
|
# * <tt>:domain</tt> - The domain for which this cookie applies so you can
|
65
66
|
# restrict to the domain level. If you use a schema like www.example.com
|
@@ -120,10 +121,6 @@ module ActionDispatch
|
|
120
121
|
@cookies = {}
|
121
122
|
end
|
122
123
|
|
123
|
-
attr_reader :closed
|
124
|
-
alias :closed? :closed
|
125
|
-
def close!; @closed = true end
|
126
|
-
|
127
124
|
def each(&block)
|
128
125
|
@cookies.each(&block)
|
129
126
|
end
|
@@ -139,7 +136,7 @@ module ActionDispatch
|
|
139
136
|
alias :has_key? :key?
|
140
137
|
|
141
138
|
def update(other_hash)
|
142
|
-
@cookies.update other_hash
|
139
|
+
@cookies.update other_hash.stringify_keys
|
143
140
|
self
|
144
141
|
end
|
145
142
|
|
@@ -164,7 +161,6 @@ module ActionDispatch
|
|
164
161
|
# Sets the cookie named +name+. The second argument may be the very cookie
|
165
162
|
# value, or a hash of options as documented above.
|
166
163
|
def []=(key, options)
|
167
|
-
raise ClosedError, :cookies if closed?
|
168
164
|
if options.is_a?(Hash)
|
169
165
|
options.symbolize_keys!
|
170
166
|
value = options[:value]
|
@@ -173,7 +169,7 @@ module ActionDispatch
|
|
173
169
|
options = { :value => value }
|
174
170
|
end
|
175
171
|
|
176
|
-
|
172
|
+
@cookies[key.to_s] = value
|
177
173
|
|
178
174
|
handle_options(options)
|
179
175
|
|
@@ -195,6 +191,11 @@ module ActionDispatch
|
|
195
191
|
value
|
196
192
|
end
|
197
193
|
|
194
|
+
# Removes all cookies on the client machine by calling <tt>delete</tt> for each cookie
|
195
|
+
def clear(options = {})
|
196
|
+
@cookies.each_key{ |k| delete(k, options) }
|
197
|
+
end
|
198
|
+
|
198
199
|
# Returns a jar that'll automatically set the assigned cookies to have an expiration date 20 years from now. Example:
|
199
200
|
#
|
200
201
|
# cookies.permanent[:prefers_open_id] = true
|
@@ -232,10 +233,18 @@ module ActionDispatch
|
|
232
233
|
@delete_cookies.each { |k, v| ::Rack::Utils.delete_cookie_header!(headers, k, v) }
|
233
234
|
end
|
234
235
|
|
236
|
+
def recycle! #:nodoc:
|
237
|
+
@set_cookies.clear
|
238
|
+
@delete_cookies.clear
|
239
|
+
end
|
240
|
+
|
241
|
+
mattr_accessor :always_write_cookie
|
242
|
+
self.always_write_cookie = false
|
243
|
+
|
235
244
|
private
|
236
245
|
|
237
246
|
def write_cookie?(cookie)
|
238
|
-
@secure || !cookie[:secure] ||
|
247
|
+
@secure || !cookie[:secure] || always_write_cookie
|
239
248
|
end
|
240
249
|
end
|
241
250
|
|
@@ -245,7 +254,6 @@ module ActionDispatch
|
|
245
254
|
end
|
246
255
|
|
247
256
|
def []=(key, options)
|
248
|
-
raise ClosedError, :cookies if closed?
|
249
257
|
if options.is_a?(Hash)
|
250
258
|
options.symbolize_keys!
|
251
259
|
else
|
@@ -284,7 +292,6 @@ module ActionDispatch
|
|
284
292
|
end
|
285
293
|
|
286
294
|
def []=(key, options)
|
287
|
-
raise ClosedError, :cookies if closed?
|
288
295
|
if options.is_a?(Hash)
|
289
296
|
options.symbolize_keys!
|
290
297
|
options[:value] = @verifier.generate(options[:value])
|
@@ -315,7 +322,7 @@ module ActionDispatch
|
|
315
322
|
|
316
323
|
if secret.length < SECRET_MIN_LENGTH
|
317
324
|
raise ArgumentError, "Secret should be something secure, " +
|
318
|
-
"like \"#{SecureRandom.hex(16)}\".
|
325
|
+
"like \"#{SecureRandom.hex(16)}\". The value you " +
|
319
326
|
"provided, \"#{secret}\", is shorter than the minimum length " +
|
320
327
|
"of #{SECRET_MIN_LENGTH} characters"
|
321
328
|
end
|
@@ -338,9 +345,6 @@ module ActionDispatch
|
|
338
345
|
end
|
339
346
|
|
340
347
|
[status, headers, body]
|
341
|
-
ensure
|
342
|
-
cookie_jar = ActionDispatch::Request.new(env).cookie_jar unless cookie_jar
|
343
|
-
cookie_jar.close!
|
344
348
|
end
|
345
349
|
end
|
346
350
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'action_dispatch/http/request'
|
2
|
+
require 'action_dispatch/middleware/exception_wrapper'
|
3
|
+
|
4
|
+
module ActionDispatch
|
5
|
+
# This middleware is responsible for logging exceptions and
|
6
|
+
# showing a debugging page in case the request is local.
|
7
|
+
class DebugExceptions
|
8
|
+
RESCUES_TEMPLATE_PATH = File.join(File.dirname(__FILE__), 'templates')
|
9
|
+
|
10
|
+
def initialize(app)
|
11
|
+
@app = app
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
begin
|
16
|
+
response = @app.call(env)
|
17
|
+
|
18
|
+
if response[1]['X-Cascade'] == 'pass'
|
19
|
+
body = response[2]
|
20
|
+
body.close if body.respond_to?(:close)
|
21
|
+
raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}"
|
22
|
+
end
|
23
|
+
rescue Exception => exception
|
24
|
+
raise exception if env['action_dispatch.show_exceptions'] == false
|
25
|
+
end
|
26
|
+
|
27
|
+
exception ? render_exception(env, exception) : response
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def render_exception(env, exception)
|
33
|
+
wrapper = ExceptionWrapper.new(env, exception)
|
34
|
+
log_error(env, wrapper)
|
35
|
+
|
36
|
+
if env['action_dispatch.show_detailed_exceptions']
|
37
|
+
template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
|
38
|
+
:request => Request.new(env),
|
39
|
+
:exception => wrapper.exception,
|
40
|
+
:application_trace => wrapper.application_trace,
|
41
|
+
:framework_trace => wrapper.framework_trace,
|
42
|
+
:full_trace => wrapper.full_trace
|
43
|
+
)
|
44
|
+
|
45
|
+
file = "rescues/#{wrapper.rescue_template}"
|
46
|
+
body = template.render(:template => file, :layout => 'rescues/layout')
|
47
|
+
render(wrapper.status_code, body)
|
48
|
+
else
|
49
|
+
raise exception
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def render(status, body)
|
54
|
+
[status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
|
55
|
+
end
|
56
|
+
|
57
|
+
def log_error(env, wrapper)
|
58
|
+
logger = logger(env)
|
59
|
+
return unless logger
|
60
|
+
|
61
|
+
exception = wrapper.exception
|
62
|
+
|
63
|
+
trace = wrapper.application_trace
|
64
|
+
trace = wrapper.framework_trace if trace.empty?
|
65
|
+
|
66
|
+
ActiveSupport::Deprecation.silence do
|
67
|
+
message = "\n#{exception.class} (#{exception.message}):\n"
|
68
|
+
message << exception.annoted_source_code.to_s if exception.respond_to?(:annoted_source_code)
|
69
|
+
message << " " << trace.join("\n ")
|
70
|
+
logger.fatal("#{message}\n\n")
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def logger(env)
|
75
|
+
env['action_dispatch.logger'] || stderr_logger
|
76
|
+
end
|
77
|
+
|
78
|
+
def stderr_logger
|
79
|
+
@stderr_logger ||= Logger.new($stderr)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'action_controller/metal/exceptions'
|
2
|
+
require 'active_support/core_ext/exception'
|
3
|
+
|
4
|
+
module ActionDispatch
|
5
|
+
class ExceptionWrapper
|
6
|
+
cattr_accessor :rescue_responses
|
7
|
+
@@rescue_responses = Hash.new(:internal_server_error)
|
8
|
+
@@rescue_responses.merge!(
|
9
|
+
'ActionController::RoutingError' => :not_found,
|
10
|
+
'AbstractController::ActionNotFound' => :not_found,
|
11
|
+
'ActionController::MethodNotAllowed' => :method_not_allowed,
|
12
|
+
'ActionController::NotImplemented' => :not_implemented,
|
13
|
+
'ActionController::InvalidAuthenticityToken' => :unprocessable_entity
|
14
|
+
)
|
15
|
+
|
16
|
+
cattr_accessor :rescue_templates
|
17
|
+
@@rescue_templates = Hash.new('diagnostics')
|
18
|
+
@@rescue_templates.merge!(
|
19
|
+
'ActionView::MissingTemplate' => 'missing_template',
|
20
|
+
'ActionController::RoutingError' => 'routing_error',
|
21
|
+
'AbstractController::ActionNotFound' => 'unknown_action',
|
22
|
+
'ActionView::Template::Error' => 'template_error'
|
23
|
+
)
|
24
|
+
|
25
|
+
attr_reader :env, :exception
|
26
|
+
|
27
|
+
def initialize(env, exception)
|
28
|
+
@env = env
|
29
|
+
@exception = original_exception(exception)
|
30
|
+
end
|
31
|
+
|
32
|
+
def rescue_template
|
33
|
+
@@rescue_templates[@exception.class.name]
|
34
|
+
end
|
35
|
+
|
36
|
+
def status_code
|
37
|
+
Rack::Utils.status_code(@@rescue_responses[@exception.class.name])
|
38
|
+
end
|
39
|
+
|
40
|
+
def application_trace
|
41
|
+
clean_backtrace(:silent)
|
42
|
+
end
|
43
|
+
|
44
|
+
def framework_trace
|
45
|
+
clean_backtrace(:noise)
|
46
|
+
end
|
47
|
+
|
48
|
+
def full_trace
|
49
|
+
clean_backtrace(:all)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def original_exception(exception)
|
55
|
+
if registered_original_exception?(exception)
|
56
|
+
exception.original_exception
|
57
|
+
else
|
58
|
+
exception
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def registered_original_exception?(exception)
|
63
|
+
exception.respond_to?(:original_exception) && @@rescue_responses.has_key?(exception.original_exception.class.name)
|
64
|
+
end
|
65
|
+
|
66
|
+
def clean_backtrace(*args)
|
67
|
+
if backtrace_cleaner
|
68
|
+
backtrace_cleaner.clean(@exception.backtrace, *args)
|
69
|
+
else
|
70
|
+
@exception.backtrace
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def backtrace_cleaner
|
75
|
+
@backtrace_cleaner ||= @env['action_dispatch.backtrace_cleaner']
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -4,7 +4,7 @@ module ActionDispatch
|
|
4
4
|
# read a notice you put there or <tt>flash["notice"] = "hello"</tt>
|
5
5
|
# to put a new one.
|
6
6
|
def flash
|
7
|
-
@env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new)
|
7
|
+
@env[Flash::KEY] ||= (session["flash"] || Flash::FlashHash.new)
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
@@ -93,7 +93,6 @@ module ActionDispatch
|
|
93
93
|
end
|
94
94
|
|
95
95
|
def []=(k, v) #:nodoc:
|
96
|
-
raise ClosedError, :flash if closed?
|
97
96
|
keep(k)
|
98
97
|
@flashes[k] = v
|
99
98
|
end
|
@@ -159,10 +158,6 @@ module ActionDispatch
|
|
159
158
|
@now ||= FlashNow.new(self)
|
160
159
|
end
|
161
160
|
|
162
|
-
attr_reader :closed
|
163
|
-
alias :closed? :closed
|
164
|
-
def close!; @closed = true; end
|
165
|
-
|
166
161
|
# Keeps either the entire current flash or a specific flash entry available for the next action:
|
167
162
|
#
|
168
163
|
# flash.keep # keeps the entire flash
|
@@ -240,6 +235,10 @@ module ActionDispatch
|
|
240
235
|
end
|
241
236
|
|
242
237
|
def call(env)
|
238
|
+
if (session = env['rack.session']) && (flash = session['flash'])
|
239
|
+
flash.sweep
|
240
|
+
end
|
241
|
+
|
243
242
|
@app.call(env)
|
244
243
|
ensure
|
245
244
|
session = env['rack.session'] || {}
|
@@ -254,11 +253,9 @@ module ActionDispatch
|
|
254
253
|
end
|
255
254
|
|
256
255
|
env[KEY] = new_hash
|
257
|
-
new_hash.close!
|
258
256
|
end
|
259
257
|
|
260
|
-
if
|
261
|
-
session.key?('flash') && session['flash'].empty?
|
258
|
+
if session.key?('flash') && session['flash'].empty?
|
262
259
|
session.delete('flash')
|
263
260
|
end
|
264
261
|
end
|
@@ -38,7 +38,7 @@ module ActionDispatch
|
|
38
38
|
when Proc
|
39
39
|
strategy.call(request.raw_post)
|
40
40
|
when :xml_simple, :xml_node
|
41
|
-
data =
|
41
|
+
data = Hash.from_xml(request.body.read) || {}
|
42
42
|
request.body.rewind if request.body.respond_to?(:rewind)
|
43
43
|
data.with_indifferent_access
|
44
44
|
when :yaml
|
@@ -47,19 +47,14 @@ module ActionDispatch
|
|
47
47
|
data = ActiveSupport::JSON.decode(request.body)
|
48
48
|
request.body.rewind if request.body.respond_to?(:rewind)
|
49
49
|
data = {:_json => data} unless data.is_a?(Hash)
|
50
|
-
|
50
|
+
data.with_indifferent_access
|
51
51
|
else
|
52
52
|
false
|
53
53
|
end
|
54
54
|
rescue Exception => e # YAML, XML or Ruby code block errors
|
55
|
-
logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
|
55
|
+
logger(env).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
|
56
56
|
|
57
|
-
raise
|
58
|
-
{ "body" => request.raw_post,
|
59
|
-
"content_type" => request.content_mime_type,
|
60
|
-
"content_length" => request.content_length,
|
61
|
-
"exception" => "#{e.message} (#{e.class})",
|
62
|
-
"backtrace" => e.backtrace }
|
57
|
+
raise e
|
63
58
|
end
|
64
59
|
|
65
60
|
def content_type_from_legacy_post_data_format_header(env)
|
@@ -73,8 +68,8 @@ module ActionDispatch
|
|
73
68
|
nil
|
74
69
|
end
|
75
70
|
|
76
|
-
def logger
|
77
|
-
|
71
|
+
def logger(env)
|
72
|
+
env['action_dispatch.logger'] || Logger.new($stderr)
|
78
73
|
end
|
79
74
|
end
|
80
75
|
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ActionDispatch
|
2
|
+
# A simple Rack application that renders exceptions in the given public path.
|
3
|
+
class PublicExceptions
|
4
|
+
attr_accessor :public_path
|
5
|
+
|
6
|
+
def initialize(public_path)
|
7
|
+
@public_path = public_path
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
status = env["PATH_INFO"][1..-1]
|
12
|
+
locale_path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
|
13
|
+
path = "#{public_path}/#{status}.html"
|
14
|
+
|
15
|
+
if locale_path && File.exist?(locale_path)
|
16
|
+
render(status, File.read(locale_path))
|
17
|
+
elsif File.exist?(path)
|
18
|
+
render(status, File.read(path))
|
19
|
+
else
|
20
|
+
[404, { "X-Cascade" => "pass" }, []]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def render(status, body)
|
27
|
+
[status, {'Content-Type' => "text/html; charset=#{Response.default_charset}", 'Content-Length' => body.bytesize.to_s}, [body]]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -43,34 +43,58 @@ module ActionDispatch
|
|
43
43
|
|
44
44
|
# Execute all prepare callbacks.
|
45
45
|
def self.prepare!
|
46
|
-
new(nil).
|
46
|
+
new(nil).prepare!
|
47
47
|
end
|
48
48
|
|
49
49
|
# Execute all cleanup callbacks.
|
50
50
|
def self.cleanup!
|
51
|
-
new(nil).
|
51
|
+
new(nil).cleanup!
|
52
52
|
end
|
53
53
|
|
54
|
-
def initialize(app)
|
54
|
+
def initialize(app, condition=nil)
|
55
55
|
@app = app
|
56
|
-
|
57
|
-
|
58
|
-
module CleanupOnClose
|
59
|
-
def close
|
60
|
-
super if defined?(super)
|
61
|
-
ensure
|
62
|
-
ActionDispatch::Reloader.cleanup!
|
63
|
-
end
|
56
|
+
@condition = condition || lambda { true }
|
57
|
+
@validated = true
|
64
58
|
end
|
65
59
|
|
66
60
|
def call(env)
|
67
|
-
|
61
|
+
@validated = @condition.call
|
62
|
+
prepare!
|
68
63
|
response = @app.call(env)
|
69
|
-
response[2].extend(
|
64
|
+
response[2].extend(module_hook)
|
70
65
|
response
|
71
66
|
rescue Exception
|
72
|
-
|
67
|
+
cleanup!
|
73
68
|
raise
|
74
69
|
end
|
70
|
+
|
71
|
+
def prepare! #:nodoc:
|
72
|
+
run_callbacks :prepare if validated?
|
73
|
+
end
|
74
|
+
|
75
|
+
def cleanup! #:nodoc:
|
76
|
+
run_callbacks :cleanup if validated?
|
77
|
+
ensure
|
78
|
+
@validated = true
|
79
|
+
end
|
80
|
+
|
81
|
+
private
|
82
|
+
|
83
|
+
def validated? #:nodoc:
|
84
|
+
@validated
|
85
|
+
end
|
86
|
+
|
87
|
+
def module_hook #:nodoc:
|
88
|
+
middleware = self
|
89
|
+
Module.new do
|
90
|
+
define_method :close do
|
91
|
+
begin
|
92
|
+
super() if defined?(super)
|
93
|
+
ensure
|
94
|
+
middleware.cleanup!
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
75
99
|
end
|
76
100
|
end
|