actionpack 4.1.7 → 4.2.11

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.

Files changed (112) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +404 -451
  3. data/README.rdoc +7 -2
  4. data/lib/abstract_controller/base.rb +16 -6
  5. data/lib/abstract_controller/callbacks.rb +28 -51
  6. data/lib/abstract_controller/helpers.rb +11 -4
  7. data/lib/abstract_controller/railties/routes_helpers.rb +3 -3
  8. data/lib/abstract_controller/rendering.rb +7 -1
  9. data/lib/abstract_controller/url_for.rb +1 -1
  10. data/lib/action_controller/base.rb +3 -2
  11. data/lib/action_controller/caching/fragments.rb +7 -1
  12. data/lib/action_controller/caching.rb +1 -1
  13. data/lib/action_controller/log_subscriber.rb +26 -26
  14. data/lib/action_controller/metal/conditional_get.rb +37 -12
  15. data/lib/action_controller/metal/etag_with_template_digest.rb +50 -0
  16. data/lib/action_controller/metal/exceptions.rb +1 -1
  17. data/lib/action_controller/metal/force_ssl.rb +1 -1
  18. data/lib/action_controller/metal/head.rb +7 -3
  19. data/lib/action_controller/metal/http_authentication.rb +20 -10
  20. data/lib/action_controller/metal/instrumentation.rb +8 -5
  21. data/lib/action_controller/metal/live.rb +57 -6
  22. data/lib/action_controller/metal/mime_responds.rb +25 -246
  23. data/lib/action_controller/metal/params_wrapper.rb +5 -5
  24. data/lib/action_controller/metal/rack_delegation.rb +1 -1
  25. data/lib/action_controller/metal/redirecting.rb +14 -8
  26. data/lib/action_controller/metal/renderers.rb +29 -11
  27. data/lib/action_controller/metal/rendering.rb +2 -6
  28. data/lib/action_controller/metal/request_forgery_protection.rb +78 -7
  29. data/lib/action_controller/metal/streaming.rb +1 -1
  30. data/lib/action_controller/metal/strong_parameters.rb +129 -14
  31. data/lib/action_controller/metal/url_for.rb +11 -12
  32. data/lib/action_controller/metal.rb +12 -11
  33. data/lib/action_controller/model_naming.rb +1 -1
  34. data/lib/action_controller/railtie.rb +4 -0
  35. data/lib/action_controller/test_case.rb +119 -75
  36. data/lib/action_controller.rb +1 -1
  37. data/lib/action_dispatch/http/cache.rb +5 -4
  38. data/lib/action_dispatch/http/filter_parameters.rb +2 -2
  39. data/lib/action_dispatch/http/headers.rb +43 -9
  40. data/lib/action_dispatch/http/mime_negotiation.rb +10 -3
  41. data/lib/action_dispatch/http/mime_type.rb +18 -4
  42. data/lib/action_dispatch/http/parameter_filter.rb +1 -1
  43. data/lib/action_dispatch/http/parameters.rb +11 -26
  44. data/lib/action_dispatch/http/request.rb +37 -11
  45. data/lib/action_dispatch/http/response.rb +74 -23
  46. data/lib/action_dispatch/http/upload.rb +9 -8
  47. data/lib/action_dispatch/http/url.rb +89 -70
  48. data/lib/action_dispatch/journey/formatter.rb +34 -18
  49. data/lib/action_dispatch/journey/gtg/builder.rb +3 -3
  50. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -7
  51. data/lib/action_dispatch/journey/gtg/transition_table.rb +20 -28
  52. data/lib/action_dispatch/journey/nfa/dot.rb +2 -2
  53. data/lib/action_dispatch/journey/nfa/simulator.rb +1 -1
  54. data/lib/action_dispatch/journey/nfa/transition_table.rb +5 -5
  55. data/lib/action_dispatch/journey/nodes/node.rb +4 -0
  56. data/lib/action_dispatch/journey/parser.rb +52 -60
  57. data/lib/action_dispatch/journey/parser.y +11 -10
  58. data/lib/action_dispatch/journey/path/pattern.rb +16 -19
  59. data/lib/action_dispatch/journey/route.rb +4 -19
  60. data/lib/action_dispatch/journey/router/strexp.rb +9 -6
  61. data/lib/action_dispatch/journey/router/utils.rb +1 -1
  62. data/lib/action_dispatch/journey/router.rb +53 -77
  63. data/lib/action_dispatch/journey/routes.rb +4 -0
  64. data/lib/action_dispatch/journey/scanner.rb +5 -5
  65. data/lib/action_dispatch/journey/visitors.rb +81 -92
  66. data/lib/action_dispatch/journey/visualizer/fsm.css +0 -4
  67. data/lib/action_dispatch/journey/visualizer/index.html.erb +2 -2
  68. data/lib/action_dispatch/middleware/callbacks.rb +1 -1
  69. data/lib/action_dispatch/middleware/cookies.rb +34 -34
  70. data/lib/action_dispatch/middleware/debug_exceptions.rb +15 -4
  71. data/lib/action_dispatch/middleware/exception_wrapper.rb +50 -18
  72. data/lib/action_dispatch/middleware/flash.rb +13 -7
  73. data/lib/action_dispatch/middleware/params_parser.rb +1 -1
  74. data/lib/action_dispatch/middleware/public_exceptions.rb +12 -3
  75. data/lib/action_dispatch/middleware/remote_ip.rb +40 -54
  76. data/lib/action_dispatch/middleware/request_id.rb +1 -1
  77. data/lib/action_dispatch/middleware/session/cookie_store.rb +1 -1
  78. data/lib/action_dispatch/middleware/show_exceptions.rb +1 -0
  79. data/lib/action_dispatch/middleware/ssl.rb +1 -1
  80. data/lib/action_dispatch/middleware/static.rb +75 -39
  81. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +21 -19
  82. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +37 -9
  83. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +2 -8
  84. data/lib/action_dispatch/middleware/templates/rescues/{diagnostics.erb → diagnostics.html.erb} +0 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  86. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +6 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +2 -0
  89. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +1 -24
  90. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +0 -1
  91. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +120 -64
  92. data/lib/action_dispatch/railtie.rb +2 -0
  93. data/lib/action_dispatch/routing/endpoint.rb +10 -0
  94. data/lib/action_dispatch/routing/inspector.rb +5 -12
  95. data/lib/action_dispatch/routing/mapper.rb +414 -283
  96. data/lib/action_dispatch/routing/polymorphic_routes.rb +191 -79
  97. data/lib/action_dispatch/routing/redirection.rb +10 -12
  98. data/lib/action_dispatch/routing/route_set.rb +300 -173
  99. data/lib/action_dispatch/routing/routes_proxy.rb +5 -4
  100. data/lib/action_dispatch/routing/url_for.rb +17 -5
  101. data/lib/action_dispatch/testing/assertions/dom.rb +2 -26
  102. data/lib/action_dispatch/testing/assertions/response.rb +2 -7
  103. data/lib/action_dispatch/testing/assertions/routing.rb +22 -22
  104. data/lib/action_dispatch/testing/assertions/selector.rb +2 -429
  105. data/lib/action_dispatch/testing/assertions/tag.rb +2 -134
  106. data/lib/action_dispatch/testing/assertions.rb +11 -7
  107. data/lib/action_dispatch/testing/integration.rb +28 -20
  108. data/lib/action_dispatch/testing/test_request.rb +1 -1
  109. data/lib/action_dispatch/testing/test_response.rb +1 -5
  110. data/lib/action_pack/gem_version.rb +3 -3
  111. metadata +55 -13
  112. data/lib/action_controller/metal/responder.rb +0 -297
@@ -16,10 +16,6 @@ h2 {
16
16
  font-size: 0.5em;
17
17
  }
18
18
 
19
- div#chart-2 {
20
- height: 350px;
21
- }
22
-
23
19
  .clearfix {display: inline-block; }
24
20
  .input { overflow: show;}
25
21
  .instruction { color: #666; padding: 0 30px 20px; font-size: 0.9em}
@@ -2,13 +2,13 @@
2
2
  <html>
3
3
  <head>
4
4
  <title><%= title %></title>
5
- <link rel="stylesheet" href="https://raw.github.com/gist/1706081/af944401f75ea20515a02ddb3fb43d23ecb8c662/reset.css" type="text/css">
5
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.css" type="text/css">
6
6
  <style>
7
7
  <% stylesheets.each do |style| %>
8
8
  <%= style %>
9
9
  <% end %>
10
10
  </style>
11
- <script src="https://raw.github.com/gist/1706081/df464722a05c3c2bec450b7b5c8240d9c31fa52d/d3.min.js" type="text/javascript"></script>
11
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.8/d3.min.js" type="text/javascript"></script>
12
12
  </head>
13
13
  <body>
14
14
  <div id="wrapper">
@@ -1,6 +1,6 @@
1
1
 
2
2
  module ActionDispatch
3
- # Provide callbacks to be executed before and after the request dispatch.
3
+ # Provides callbacks to be executed before and after dispatching the request.
4
4
  class Callbacks
5
5
  include ActiveSupport::Callbacks
6
6
 
@@ -3,6 +3,7 @@ require 'active_support/core_ext/module/attribute_accessors'
3
3
  require 'active_support/core_ext/object/blank'
4
4
  require 'active_support/key_generator'
5
5
  require 'active_support/message_verifier'
6
+ require 'active_support/json'
6
7
 
7
8
  module ActionDispatch
8
9
  class Request < Rack::Request
@@ -70,11 +71,13 @@ module ActionDispatch
70
71
  # restrict to the domain level. If you use a schema like www.example.com
71
72
  # and want to share session with user.example.com set <tt>:domain</tt>
72
73
  # to <tt>:all</tt>. Make sure to specify the <tt>:domain</tt> option with
73
- # <tt>:all</tt> again when deleting cookies.
74
+ # <tt>:all</tt> or <tt>Array</tt> again when deleting cookies.
74
75
  #
75
76
  # domain: nil # Does not sets cookie domain. (default)
76
77
  # domain: :all # Allow the cookie for the top most level
77
- # domain and subdomains.
78
+ # # domain and subdomains.
79
+ # domain: %w(.example.com .example.org) # Allow the cookie
80
+ # # for concrete domain names.
78
81
  #
79
82
  # * <tt>:expires</tt> - The time at which this cookie expires, as a \Time object.
80
83
  # * <tt>:secure</tt> - Whether this cookie is only transmitted to HTTPS servers.
@@ -90,6 +93,7 @@ module ActionDispatch
90
93
  SECRET_TOKEN = "action_dispatch.secret_token".freeze
91
94
  SECRET_KEY_BASE = "action_dispatch.secret_key_base".freeze
92
95
  COOKIES_SERIALIZER = "action_dispatch.cookies_serializer".freeze
96
+ COOKIES_DIGEST = "action_dispatch.cookies_digest".freeze
93
97
 
94
98
  # Cookies can typically store 4096 bytes.
95
99
  MAX_COOKIE_SIZE = 4096
@@ -118,7 +122,7 @@ module ActionDispatch
118
122
  # the cookie again. This is useful for creating cookies with values that the user is not supposed to change. If a signed
119
123
  # cookie was tampered with by the user (or a 3rd party), nil will be returned.
120
124
  #
121
- # If +secrets.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
125
+ # If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
122
126
  # legacy cookies signed with the old key generator will be transparently upgraded.
123
127
  #
124
128
  # This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+.
@@ -141,7 +145,7 @@ module ActionDispatch
141
145
  # Returns a jar that'll automatically encrypt cookie values before sending them to the client and will decrypt them for read.
142
146
  # If the cookie was tampered with by the user (or a 3rd party), nil will be returned.
143
147
  #
144
- # If +secrets.secret_key_base+ and +config.secret_token+ (deprecated) are both set,
148
+ # If +secrets.secret_key_base+ and +secrets.secret_token+ (deprecated) are both set,
145
149
  # legacy cookies signed with the old key generator will be transparently upgraded.
146
150
  #
147
151
  # This jar requires that you set a suitable secret for the verification on your app's +secrets.secret_key_base+.
@@ -173,10 +177,14 @@ module ActionDispatch
173
177
  end
174
178
  end
175
179
 
176
- module VerifyAndUpgradeLegacySignedMessage
180
+ # Passing the ActiveSupport::MessageEncryptor::NullSerializer downstream
181
+ # to the Message{Encryptor,Verifier} allows us to handle the
182
+ # (de)serialization step within the cookie jar, which gives us the
183
+ # opportunity to detect and migrate legacy cookies.
184
+ module VerifyAndUpgradeLegacySignedMessage # :nodoc:
177
185
  def initialize(*args)
178
186
  super
179
- @legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token], serializer: NullSerializer)
187
+ @legacy_verifier = ActiveSupport::MessageVerifier.new(@options[:secret_token], serializer: ActiveSupport::MessageEncryptor::NullSerializer)
180
188
  end
181
189
 
182
190
  def verify_and_upgrade_legacy_signed_message(name, signed_message)
@@ -212,7 +220,8 @@ module ActionDispatch
212
220
  secret_token: env[SECRET_TOKEN],
213
221
  secret_key_base: env[SECRET_KEY_BASE],
214
222
  upgrade_legacy_signed_cookies: env[SECRET_TOKEN].present? && env[SECRET_KEY_BASE].present?,
215
- serializer: env[COOKIES_SERIALIZER]
223
+ serializer: env[COOKIES_SERIALIZER],
224
+ digest: env[COOKIES_DIGEST]
216
225
  }
217
226
  end
218
227
 
@@ -289,8 +298,8 @@ module ActionDispatch
289
298
  end
290
299
  end
291
300
 
292
- # Sets the cookie named +name+. The second argument may be the very cookie
293
- # value, or a hash of options as documented above.
301
+ # Sets the cookie named +name+. The second argument may be the cookie's
302
+ # value or a hash of options as documented above.
294
303
  def []=(name, options)
295
304
  if options.is_a?(Hash)
296
305
  options.symbolize_keys!
@@ -302,7 +311,7 @@ module ActionDispatch
302
311
 
303
312
  handle_options(options)
304
313
 
305
- if @cookies[name.to_s] != value or options[:expires]
314
+ if @cookies[name.to_s] != value || options[:expires]
306
315
  @cookies[name.to_s] = value
307
316
  @set_cookies[name.to_s] = options
308
317
  @delete_cookies.delete(name.to_s)
@@ -383,30 +392,17 @@ module ActionDispatch
383
392
  end
384
393
  end
385
394
 
386
- class JsonSerializer
395
+ class JsonSerializer # :nodoc:
387
396
  def self.load(value)
388
- JSON.parse(value, quirks_mode: true)
397
+ ActiveSupport::JSON.decode(value)
389
398
  end
390
399
 
391
400
  def self.dump(value)
392
- JSON.generate(value, quirks_mode: true)
401
+ ActiveSupport::JSON.encode(value)
393
402
  end
394
403
  end
395
404
 
396
- # Passing the NullSerializer downstream to the Message{Encryptor,Verifier}
397
- # allows us to handle the (de)serialization step within the cookie jar,
398
- # which gives us the opportunity to detect and migrate legacy cookies.
399
- class NullSerializer
400
- def self.load(value)
401
- value
402
- end
403
-
404
- def self.dump(value)
405
- value
406
- end
407
- end
408
-
409
- module SerializedCookieJars
405
+ module SerializedCookieJars # :nodoc:
410
406
  MARSHAL_SIGNATURE = "\x04\x08".freeze
411
407
 
412
408
  protected
@@ -441,6 +437,10 @@ module ActionDispatch
441
437
  serializer
442
438
  end
443
439
  end
440
+
441
+ def digest
442
+ @options[:digest] || 'SHA1'
443
+ end
444
444
  end
445
445
 
446
446
  class SignedCookieJar #:nodoc:
@@ -451,7 +451,7 @@ module ActionDispatch
451
451
  @parent_jar = parent_jar
452
452
  @options = options
453
453
  secret = key_generator.generate_key(@options[:signed_cookie_salt])
454
- @verifier = ActiveSupport::MessageVerifier.new(secret, serializer: NullSerializer)
454
+ @verifier = ActiveSupport::MessageVerifier.new(secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
455
455
  end
456
456
 
457
457
  def [](name)
@@ -468,7 +468,7 @@ module ActionDispatch
468
468
  options = { :value => @verifier.generate(serialize(name, options)) }
469
469
  end
470
470
 
471
- raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
471
+ raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
472
472
  @parent_jar[name] = options
473
473
  end
474
474
 
@@ -481,7 +481,7 @@ module ActionDispatch
481
481
  end
482
482
 
483
483
  # UpgradeLegacySignedCookieJar is used instead of SignedCookieJar if
484
- # config.secret_token and secrets.secret_key_base are both set. It reads
484
+ # secrets.secret_token and secrets.secret_key_base are both set. It reads
485
485
  # legacy cookies signed with the old dummy key generator and re-saves
486
486
  # them using the new key generator to provide a smooth upgrade path.
487
487
  class UpgradeLegacySignedCookieJar < SignedCookieJar #:nodoc:
@@ -506,9 +506,9 @@ module ActionDispatch
506
506
 
507
507
  @parent_jar = parent_jar
508
508
  @options = options
509
- secret = key_generator.generate_key(@options[:encrypted_cookie_salt])
509
+ secret = key_generator.generate_key(@options[:encrypted_cookie_salt])[0, ActiveSupport::MessageEncryptor.key_len]
510
510
  sign_secret = key_generator.generate_key(@options[:encrypted_signed_cookie_salt])
511
- @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: NullSerializer)
511
+ @encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, digest: digest, serializer: ActiveSupport::MessageEncryptor::NullSerializer)
512
512
  end
513
513
 
514
514
  def [](name)
@@ -526,7 +526,7 @@ module ActionDispatch
526
526
 
527
527
  options[:value] = @encryptor.encrypt_and_sign(serialize(name, options[:value]))
528
528
 
529
- raise CookieOverflow if options[:value].size > MAX_COOKIE_SIZE
529
+ raise CookieOverflow if options[:value].bytesize > MAX_COOKIE_SIZE
530
530
  @parent_jar[name] = options
531
531
  end
532
532
 
@@ -539,7 +539,7 @@ module ActionDispatch
539
539
  end
540
540
 
541
541
  # UpgradeLegacyEncryptedCookieJar is used by ActionDispatch::Session::CookieStore
542
- # instead of EncryptedCookieJar if config.secret_token and secrets.secret_key_base
542
+ # instead of EncryptedCookieJar if secrets.secret_token and secrets.secret_key_base
543
543
  # are both set. It reads legacy cookies signed with the old dummy key generator and
544
544
  # encrypts and re-saves them using the new key generator to provide a smooth upgrade path.
545
545
  class UpgradeLegacyEncryptedCookieJar < EncryptedCookieJar #:nodoc:
@@ -35,14 +35,25 @@ module ActionDispatch
35
35
 
36
36
  if env['action_dispatch.show_detailed_exceptions']
37
37
  request = Request.new(env)
38
+ traces = wrapper.traces
39
+
40
+ trace_to_show = 'Application Trace'
41
+ if traces[trace_to_show].empty? && wrapper.rescue_template != 'routing_error'
42
+ trace_to_show = 'Full Trace'
43
+ end
44
+
45
+ if source_to_show = traces[trace_to_show].first
46
+ source_to_show_id = source_to_show[:id]
47
+ end
48
+
38
49
  template = ActionView::Base.new([RESCUES_TEMPLATE_PATH],
39
50
  request: request,
40
51
  exception: wrapper.exception,
41
- application_trace: wrapper.application_trace,
42
- framework_trace: wrapper.framework_trace,
43
- full_trace: wrapper.full_trace,
52
+ traces: traces,
53
+ show_source_idx: source_to_show_id,
54
+ trace_to_show: trace_to_show,
44
55
  routes_inspector: routes_inspector(exception),
45
- source_extract: wrapper.source_extract,
56
+ source_extracts: wrapper.source_extracts,
46
57
  line_number: wrapper.line_number,
47
58
  file: wrapper.file
48
59
  )
@@ -6,16 +6,17 @@ module ActionDispatch
6
6
  cattr_accessor :rescue_responses
7
7
  @@rescue_responses = Hash.new(:internal_server_error)
8
8
  @@rescue_responses.merge!(
9
- 'ActionController::RoutingError' => :not_found,
10
- 'AbstractController::ActionNotFound' => :not_found,
11
- 'ActionController::MethodNotAllowed' => :method_not_allowed,
12
- 'ActionController::UnknownHttpMethod' => :method_not_allowed,
13
- 'ActionController::NotImplemented' => :not_implemented,
14
- 'ActionController::UnknownFormat' => :not_acceptable,
15
- 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
16
- 'ActionDispatch::ParamsParser::ParseError' => :bad_request,
17
- 'ActionController::BadRequest' => :bad_request,
18
- 'ActionController::ParameterMissing' => :bad_request
9
+ 'ActionController::RoutingError' => :not_found,
10
+ 'AbstractController::ActionNotFound' => :not_found,
11
+ 'ActionController::MethodNotAllowed' => :method_not_allowed,
12
+ 'ActionController::UnknownHttpMethod' => :method_not_allowed,
13
+ 'ActionController::NotImplemented' => :not_implemented,
14
+ 'ActionController::UnknownFormat' => :not_acceptable,
15
+ 'ActionController::InvalidAuthenticityToken' => :unprocessable_entity,
16
+ 'ActionController::InvalidCrossOriginRequest' => :unprocessable_entity,
17
+ 'ActionDispatch::ParamsParser::ParseError' => :bad_request,
18
+ 'ActionController::BadRequest' => :bad_request,
19
+ 'ActionController::ParameterMissing' => :bad_request
19
20
  )
20
21
 
21
22
  cattr_accessor :rescue_templates
@@ -56,21 +57,52 @@ module ActionDispatch
56
57
  clean_backtrace(:all)
57
58
  end
58
59
 
60
+ def traces
61
+ appplication_trace_with_ids = []
62
+ framework_trace_with_ids = []
63
+ full_trace_with_ids = []
64
+
65
+ full_trace.each_with_index do |trace, idx|
66
+ trace_with_id = { id: idx, trace: trace }
67
+
68
+ if application_trace.include?(trace)
69
+ appplication_trace_with_ids << trace_with_id
70
+ else
71
+ framework_trace_with_ids << trace_with_id
72
+ end
73
+
74
+ full_trace_with_ids << trace_with_id
75
+ end
76
+
77
+ {
78
+ "Application Trace" => appplication_trace_with_ids,
79
+ "Framework Trace" => framework_trace_with_ids,
80
+ "Full Trace" => full_trace_with_ids
81
+ }
82
+ end
83
+
59
84
  def self.status_code_for_exception(class_name)
60
85
  Rack::Utils.status_code(@@rescue_responses[class_name])
61
86
  end
62
87
 
63
- def source_extract
64
- if application_trace && trace = application_trace.first
65
- file, line, _ = trace.split(":")
66
- @file = file
67
- @line_number = line.to_i
68
- source_fragment(@file, @line_number)
88
+ def source_extracts
89
+ backtrace.map do |trace|
90
+ file, line = trace.split(":")
91
+ line_number = line.to_i
92
+
93
+ {
94
+ code: source_fragment(file, line_number),
95
+ line_number: line_number
96
+ }
69
97
  end
70
98
  end
71
99
 
72
100
  private
73
101
 
102
+ def backtrace
103
+ Array(@exception.backtrace)
104
+ end
105
+
74
106
  def original_exception(exception)
75
107
  if registered_original_exception?(exception)
76
108
  exception.original_exception
@@ -85,9 +117,9 @@ module ActionDispatch
85
117
 
86
118
  def clean_backtrace(*args)
87
119
  if backtrace_cleaner
88
- backtrace_cleaner.clean(@exception.backtrace, *args)
120
+ backtrace_cleaner.clean(backtrace, *args)
89
121
  else
90
- @exception.backtrace
122
+ backtrace
91
123
  end
92
124
  end
93
125
 
@@ -10,7 +10,7 @@ module ActionDispatch
10
10
  end
11
11
  end
12
12
 
13
- # The flash provides a way to pass temporary objects between actions. Anything you place in the flash will be exposed
13
+ # The flash provides a way to pass temporary primitive-types (String, Array, Hash) between actions. Anything you place in the flash will be exposed
14
14
  # to the very next action and then cleared out. This is a great way of doing notices and alerts, such as a create
15
15
  # action that sets <tt>flash[:notice] = "Post successfully created"</tt> before redirecting to a display action that can
16
16
  # then expose the flash to its template. Actually, that exposure is automatically done.
@@ -37,8 +37,11 @@ module ActionDispatch
37
37
  # flash.alert = "You must be logged in"
38
38
  # flash.notice = "Post successfully created"
39
39
  #
40
- # This example just places a string in the flash, but you can put any object in there. And of course, you can put as
41
- # many as you like at a time too. Just remember: They'll be gone by the time the next action has been performed.
40
+ # This example places a string in the flash. And of course, you can put as many as you like at a time too. If you want to pass
41
+ # non-primitive types, you will have to handle that in your application. Example: To show messages with links, you will have to
42
+ # use sanitize helper.
43
+ #
44
+ # Just remember: They'll be gone by the time the next action has been performed.
42
45
  #
43
46
  # See docs on the FlashHash class for more details about the flash.
44
47
  class Flash
@@ -76,7 +79,7 @@ module ActionDispatch
76
79
  class FlashHash
77
80
  include Enumerable
78
81
 
79
- def self.from_session_value(value)
82
+ def self.from_session_value(value) #:nodoc:
80
83
  flash = case value
81
84
  when FlashHash # Rails 3.1, 3.2
82
85
  new(value.instance_variable_get(:@flashes), value.instance_variable_get(:@used))
@@ -88,8 +91,11 @@ module ActionDispatch
88
91
 
89
92
  flash.tap(&:sweep)
90
93
  end
91
-
92
- def to_session_value
94
+
95
+ # Builds a hash containing the discarded values and the hashes
96
+ # representing the flashes.
97
+ # If there are no values in @flashes, returns nil.
98
+ def to_session_value #:nodoc:
93
99
  return nil if empty?
94
100
  {'discard' => @discard.to_a, 'flashes' => @flashes}
95
101
  end
@@ -129,7 +135,7 @@ module ActionDispatch
129
135
  end
130
136
 
131
137
  def key?(name)
132
- @flashes.key? name
138
+ @flashes.key? name.to_s
133
139
  end
134
140
 
135
141
  def delete(key)
@@ -47,7 +47,7 @@ module ActionDispatch
47
47
  else
48
48
  false
49
49
  end
50
- rescue Exception => e # JSON or Ruby code block errors
50
+ rescue => e # JSON or Ruby code block errors
51
51
  logger(env).debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
52
52
 
53
53
  raise ParseError.new(e.message, e)
@@ -1,4 +1,14 @@
1
1
  module ActionDispatch
2
+ # When called, this middleware renders an error page. By default if an HTML
3
+ # response is expected it will render static error pages from the `/public`
4
+ # directory. For example when this middleware receives a 500 response it will
5
+ # render the template found in `/public/500.html`.
6
+ # If an internationalized locale is set, this middleware will attempt to render
7
+ # the template in `/public/500.<locale>.html`. If an internationalized template
8
+ # is not found it will fall back on `/public/500.html`.
9
+ #
10
+ # When a request with a content type other than HTML is made, this middleware
11
+ # will attempt to convert error information into the appropriate response type.
2
12
  class PublicExceptions
3
13
  attr_accessor :public_path
4
14
 
@@ -32,9 +42,8 @@ module ActionDispatch
32
42
  end
33
43
 
34
44
  def render_html(status)
35
- found = false
36
- path = "#{public_path}/#{status}.#{I18n.locale}.html" if I18n.locale
37
- path = "#{public_path}/#{status}.html" unless path && (found = File.exist?(path))
45
+ path = "#{public_path}/#{status}.#{I18n.locale}.html"
46
+ path = "#{public_path}/#{status}.html" unless (found = File.exist?(path))
38
47
 
39
48
  if found || File.exist?(path)
40
49
  render_format(status, 'text/html', File.read(path))