actionpack 5.2.6 → 6.1.4.4

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 (155) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +327 -335
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/abstract_controller/base.rb +38 -4
  6. data/lib/abstract_controller/caching/fragments.rb +6 -22
  7. data/lib/abstract_controller/caching.rb +1 -1
  8. data/lib/abstract_controller/callbacks.rb +14 -2
  9. data/lib/abstract_controller/collector.rb +1 -2
  10. data/lib/abstract_controller/helpers.rb +106 -90
  11. data/lib/abstract_controller/railties/routes_helpers.rb +17 -1
  12. data/lib/abstract_controller/rendering.rb +9 -9
  13. data/lib/abstract_controller/translation.rb +11 -5
  14. data/lib/abstract_controller.rb +1 -0
  15. data/lib/action_controller/api.rb +4 -3
  16. data/lib/action_controller/base.rb +6 -9
  17. data/lib/action_controller/caching.rb +1 -3
  18. data/lib/action_controller/log_subscriber.rb +10 -7
  19. data/lib/action_controller/metal/basic_implicit_render.rb +1 -1
  20. data/lib/action_controller/metal/conditional_get.rb +19 -5
  21. data/lib/action_controller/metal/content_security_policy.rb +1 -2
  22. data/lib/action_controller/metal/cookies.rb +3 -1
  23. data/lib/action_controller/metal/data_streaming.rb +6 -7
  24. data/lib/action_controller/metal/default_headers.rb +17 -0
  25. data/lib/action_controller/metal/etag_with_template_digest.rb +4 -6
  26. data/lib/action_controller/metal/exceptions.rb +56 -2
  27. data/lib/action_controller/metal/flash.rb +5 -5
  28. data/lib/action_controller/metal/head.rb +7 -4
  29. data/lib/action_controller/metal/helpers.rb +14 -5
  30. data/lib/action_controller/metal/http_authentication.rb +24 -23
  31. data/lib/action_controller/metal/implicit_render.rb +5 -15
  32. data/lib/action_controller/metal/instrumentation.rb +13 -14
  33. data/lib/action_controller/metal/live.rb +39 -32
  34. data/lib/action_controller/metal/logging.rb +20 -0
  35. data/lib/action_controller/metal/mime_responds.rb +19 -4
  36. data/lib/action_controller/metal/parameter_encoding.rb +35 -4
  37. data/lib/action_controller/metal/params_wrapper.rb +32 -22
  38. data/lib/action_controller/metal/permissions_policy.rb +46 -0
  39. data/lib/action_controller/metal/redirecting.rb +6 -6
  40. data/lib/action_controller/metal/renderers.rb +4 -4
  41. data/lib/action_controller/metal/rendering.rb +8 -3
  42. data/lib/action_controller/metal/request_forgery_protection.rb +26 -49
  43. data/lib/action_controller/metal/rescue.rb +1 -1
  44. data/lib/action_controller/metal/streaming.rb +0 -1
  45. data/lib/action_controller/metal/strong_parameters.rb +167 -58
  46. data/lib/action_controller/metal/url_for.rb +1 -1
  47. data/lib/action_controller/metal.rb +10 -8
  48. data/lib/action_controller/railties/helpers.rb +1 -1
  49. data/lib/action_controller/renderer.rb +37 -13
  50. data/lib/action_controller/template_assertions.rb +1 -1
  51. data/lib/action_controller/test_case.rb +71 -63
  52. data/lib/action_controller.rb +7 -4
  53. data/lib/action_dispatch/http/cache.rb +31 -27
  54. data/lib/action_dispatch/http/content_disposition.rb +45 -0
  55. data/lib/action_dispatch/http/content_security_policy.rb +33 -19
  56. data/lib/action_dispatch/http/filter_parameters.rb +9 -8
  57. data/lib/action_dispatch/http/filter_redirect.rb +2 -3
  58. data/lib/action_dispatch/http/headers.rb +4 -4
  59. data/lib/action_dispatch/http/mime_negotiation.rb +26 -13
  60. data/lib/action_dispatch/http/mime_type.rb +43 -24
  61. data/lib/action_dispatch/http/parameters.rb +14 -23
  62. data/lib/action_dispatch/http/permissions_policy.rb +173 -0
  63. data/lib/action_dispatch/http/request.rb +45 -22
  64. data/lib/action_dispatch/http/response.rb +45 -25
  65. data/lib/action_dispatch/http/upload.rb +9 -1
  66. data/lib/action_dispatch/http/url.rb +82 -82
  67. data/lib/action_dispatch/journey/formatter.rb +55 -31
  68. data/lib/action_dispatch/journey/gtg/builder.rb +22 -37
  69. data/lib/action_dispatch/journey/gtg/simulator.rb +8 -7
  70. data/lib/action_dispatch/journey/gtg/transition_table.rb +6 -5
  71. data/lib/action_dispatch/journey/nfa/dot.rb +0 -11
  72. data/lib/action_dispatch/journey/nodes/node.rb +13 -11
  73. data/lib/action_dispatch/journey/parser.rb +13 -13
  74. data/lib/action_dispatch/journey/parser.y +1 -1
  75. data/lib/action_dispatch/journey/path/pattern.rb +19 -21
  76. data/lib/action_dispatch/journey/route.rb +10 -20
  77. data/lib/action_dispatch/journey/router/utils.rb +14 -12
  78. data/lib/action_dispatch/journey/router.rb +26 -34
  79. data/lib/action_dispatch/journey/routes.rb +0 -2
  80. data/lib/action_dispatch/journey/scanner.rb +10 -4
  81. data/lib/action_dispatch/journey/visitors.rb +1 -4
  82. data/lib/action_dispatch/journey.rb +0 -2
  83. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  84. data/lib/action_dispatch/middleware/callbacks.rb +2 -4
  85. data/lib/action_dispatch/middleware/cookies.rb +128 -109
  86. data/lib/action_dispatch/middleware/debug_exceptions.rb +43 -66
  87. data/lib/action_dispatch/middleware/debug_locks.rb +5 -5
  88. data/lib/action_dispatch/middleware/debug_view.rb +66 -0
  89. data/lib/action_dispatch/middleware/exception_wrapper.rb +75 -30
  90. data/lib/action_dispatch/middleware/flash.rb +1 -1
  91. data/lib/action_dispatch/middleware/host_authorization.rb +141 -0
  92. data/lib/action_dispatch/middleware/public_exceptions.rb +6 -3
  93. data/lib/action_dispatch/middleware/remote_ip.rb +14 -16
  94. data/lib/action_dispatch/middleware/request_id.rb +5 -6
  95. data/lib/action_dispatch/middleware/session/abstract_store.rb +2 -3
  96. data/lib/action_dispatch/middleware/session/cookie_store.rb +3 -9
  97. data/lib/action_dispatch/middleware/show_exceptions.rb +3 -2
  98. data/lib/action_dispatch/middleware/ssl.rb +20 -15
  99. data/lib/action_dispatch/middleware/stack.rb +56 -2
  100. data/lib/action_dispatch/middleware/static.rb +153 -93
  101. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  102. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  103. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  104. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +3 -1
  105. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  106. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +4 -2
  107. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +45 -35
  108. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +7 -0
  109. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +5 -0
  110. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +23 -4
  111. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +1 -1
  112. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +6 -3
  113. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +4 -1
  114. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +104 -8
  115. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -0
  116. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  117. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +2 -2
  118. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +1 -1
  119. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +2 -2
  120. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +1 -1
  121. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +24 -1
  122. data/lib/action_dispatch/railtie.rb +8 -2
  123. data/lib/action_dispatch/request/session.rb +11 -10
  124. data/lib/action_dispatch/request/utils.rb +26 -2
  125. data/lib/action_dispatch/routing/inspector.rb +100 -52
  126. data/lib/action_dispatch/routing/mapper.rb +155 -103
  127. data/lib/action_dispatch/routing/polymorphic_routes.rb +13 -15
  128. data/lib/action_dispatch/routing/redirection.rb +4 -4
  129. data/lib/action_dispatch/routing/route_set.rb +71 -69
  130. data/lib/action_dispatch/routing/url_for.rb +2 -2
  131. data/lib/action_dispatch/routing.rb +21 -20
  132. data/lib/action_dispatch/system_test_case.rb +54 -11
  133. data/lib/action_dispatch/system_testing/browser.rb +53 -16
  134. data/lib/action_dispatch/system_testing/driver.rb +11 -3
  135. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +49 -7
  136. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +8 -10
  137. data/lib/action_dispatch/testing/assertion_response.rb +0 -1
  138. data/lib/action_dispatch/testing/assertions/response.rb +4 -7
  139. data/lib/action_dispatch/testing/assertions/routing.rb +20 -8
  140. data/lib/action_dispatch/testing/assertions.rb +1 -1
  141. data/lib/action_dispatch/testing/integration.rb +60 -28
  142. data/lib/action_dispatch/testing/request_encoder.rb +2 -2
  143. data/lib/action_dispatch/testing/test_process.rb +29 -4
  144. data/lib/action_dispatch/testing/test_request.rb +3 -3
  145. data/lib/action_dispatch/testing/test_response.rb +4 -32
  146. data/lib/action_dispatch.rb +9 -3
  147. data/lib/action_pack/gem_version.rb +4 -4
  148. data/lib/action_pack.rb +1 -1
  149. metadata +35 -23
  150. data/lib/action_controller/metal/force_ssl.rb +0 -99
  151. data/lib/action_dispatch/http/parameter_filter.rb +0 -86
  152. data/lib/action_dispatch/journey/nfa/builder.rb +0 -78
  153. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -49
  154. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -120
  155. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +0 -26
@@ -17,28 +17,30 @@ module ActionDispatch
17
17
  def self.normalize_path(path)
18
18
  path ||= ""
19
19
  encoding = path.encoding
20
- path = "/#{path}".dup
21
- path.squeeze!("/".freeze)
22
- path.sub!(%r{/+\Z}, "".freeze)
23
- path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
24
- path = "/".dup if path == "".freeze
20
+ path = +"/#{path}"
21
+ path.squeeze!("/")
22
+
23
+ unless path == "/"
24
+ path.delete_suffix!("/")
25
+ path.gsub!(/(%[a-f0-9]{2})/) { $1.upcase }
26
+ end
27
+
25
28
  path.force_encoding(encoding)
26
- path
27
29
  end
28
30
 
29
31
  # URI path and fragment escaping
30
32
  # https://tools.ietf.org/html/rfc3986
31
33
  class UriEncoder # :nodoc:
32
- ENCODE = "%%%02X".freeze
34
+ ENCODE = "%%%02X"
33
35
  US_ASCII = Encoding::US_ASCII
34
36
  UTF_8 = Encoding::UTF_8
35
- EMPTY = "".dup.force_encoding(US_ASCII).freeze
37
+ EMPTY = (+"").force_encoding(US_ASCII).freeze
36
38
  DEC2HEX = (0..255).to_a.map { |i| ENCODE % i }.map { |s| s.force_encoding(US_ASCII) }
37
39
 
38
- ALPHA = "a-zA-Z".freeze
39
- DIGIT = "0-9".freeze
40
- UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~".freeze
41
- SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;=".freeze
40
+ ALPHA = "a-zA-Z"
41
+ DIGIT = "0-9"
42
+ UNRESERVED = "#{ALPHA}#{DIGIT}\\-\\._~"
43
+ SUB_DELIMS = "!\\$&'\\(\\)\\*\\+,;="
42
44
 
43
45
  ESCAPED = /%[a-zA-Z0-9]{2}/.freeze
44
46
 
@@ -15,9 +15,6 @@ require "action_dispatch/journey/path/pattern"
15
15
  module ActionDispatch
16
16
  module Journey # :nodoc:
17
17
  class Router # :nodoc:
18
- class RoutingError < ::StandardError # :nodoc:
19
- end
20
-
21
18
  attr_accessor :routes
22
19
 
23
20
  def initialize(routes)
@@ -43,11 +40,12 @@ module ActionDispatch
43
40
  req.path_info = "/" + req.path_info unless req.path_info.start_with? "/"
44
41
  end
45
42
 
46
- parameters = route.defaults.merge parameters.transform_values { |val|
47
- val.dup.force_encoding(::Encoding::UTF_8)
43
+ tmp_params = set_params.merge route.defaults
44
+ parameters.each_pair { |key, val|
45
+ tmp_params[key] = val.force_encoding(::Encoding::UTF_8)
48
46
  }
49
47
 
50
- req.path_parameters = set_params.merge parameters
48
+ req.path_parameters = tmp_params
51
49
 
52
50
  status, headers, body = route.app.serve(req)
53
51
 
@@ -68,7 +66,8 @@ module ActionDispatch
68
66
  find_routes(rails_req).each do |match, parameters, route|
69
67
  unless route.path.anchored
70
68
  rails_req.script_name = match.to_s
71
- rails_req.path_info = match.post_match.sub(/^([^\/])/, '/\1')
69
+ rails_req.path_info = match.post_match
70
+ rails_req.path_info = "/" + rails_req.path_info unless rails_req.path_info.start_with? "/"
72
71
  end
73
72
 
74
73
  parameters = route.defaults.merge parameters
@@ -84,7 +83,6 @@ module ActionDispatch
84
83
  end
85
84
 
86
85
  private
87
-
88
86
  def partitioned_routes
89
87
  routes.partition { |r|
90
88
  r.path.anchored && r.ast.grep(Nodes::Symbol).all? { |n| n.default_regexp? }
@@ -109,23 +107,24 @@ module ActionDispatch
109
107
  end
110
108
 
111
109
  def find_routes(req)
112
- routes = filter_routes(req.path_info).concat custom_routes.find_all { |r|
113
- r.path.match(req.path_info)
110
+ path_info = req.path_info
111
+ routes = filter_routes(path_info).concat custom_routes.find_all { |r|
112
+ r.path.match?(path_info)
114
113
  }
115
114
 
116
- routes =
117
- if req.head?
118
- match_head_routes(routes, req)
119
- else
120
- match_routes(routes, req)
121
- end
115
+ if req.head?
116
+ routes = match_head_routes(routes, req)
117
+ else
118
+ routes.select! { |r| r.matches?(req) }
119
+ end
122
120
 
123
121
  routes.sort_by!(&:precedence)
124
122
 
125
123
  routes.map! { |r|
126
- match_data = r.path.match(req.path_info)
124
+ match_data = r.path.match(path_info)
127
125
  path_parameters = {}
128
- match_data.names.zip(match_data.captures) { |name, val|
126
+ match_data.names.each_with_index { |name, i|
127
+ val = match_data[i + 1]
129
128
  path_parameters[name.to_sym] = Utils.unescape_uri(val) if val
130
129
  }
131
130
  [match_data, path_parameters, r]
@@ -133,24 +132,17 @@ module ActionDispatch
133
132
  end
134
133
 
135
134
  def match_head_routes(routes, req)
136
- verb_specific_routes = routes.select(&:requires_matching_verb?)
137
- head_routes = match_routes(verb_specific_routes, req)
138
-
139
- if head_routes.empty?
140
- begin
141
- req.request_method = "GET"
142
- match_routes(routes, req)
143
- ensure
144
- req.request_method = "HEAD"
145
- end
146
- else
147
- head_routes
135
+ head_routes = routes.select { |r| r.requires_matching_verb? && r.matches?(req) }
136
+ return head_routes unless head_routes.empty?
137
+
138
+ begin
139
+ req.request_method = "GET"
140
+ routes.select! { |r| r.matches?(req) }
141
+ routes
142
+ ensure
143
+ req.request_method = "HEAD"
148
144
  end
149
145
  end
150
-
151
- def match_routes(routes, req)
152
- routes.select { |r| r.matches?(req) }
153
- end
154
146
  end
155
147
  end
156
148
  end
@@ -56,7 +56,6 @@ module ActionDispatch
56
56
  end
57
57
 
58
58
  def simulator
59
- return if ast.nil?
60
59
  @simulator ||= begin
61
60
  gtg = GTG::Builder.new(ast).transition_table
62
61
  GTG::Simulator.new(gtg)
@@ -72,7 +71,6 @@ module ActionDispatch
72
71
  end
73
72
 
74
73
  private
75
-
76
74
  def clear_cache!
77
75
  @ast = nil
78
76
  @simulator = nil
@@ -33,6 +33,12 @@ module ActionDispatch
33
33
  end
34
34
 
35
35
  private
36
+ # takes advantage of String @- deduping capabilities in Ruby 2.5 upwards
37
+ # see: https://bugs.ruby-lang.org/issues/13077
38
+ def dedup_scan(regex)
39
+ r = @ss.scan(regex)
40
+ r ? -r : nil
41
+ end
36
42
 
37
43
  def scan
38
44
  case
@@ -47,15 +53,15 @@ module ActionDispatch
47
53
  [:OR, "|"]
48
54
  when @ss.skip(/\./)
49
55
  [:DOT, "."]
50
- when text = @ss.scan(/:\w+/)
56
+ when text = dedup_scan(/:\w+/)
51
57
  [:SYMBOL, text]
52
- when text = @ss.scan(/\*\w+/)
58
+ when text = dedup_scan(/\*\w+/)
53
59
  [:STAR, text]
54
60
  when text = @ss.scan(/(?:[\w%\-~!$&'*+,;=@]|\\[:()])+/)
55
61
  text.tr! "\\", ""
56
- [:LITERAL, text]
62
+ [:LITERAL, -text]
57
63
  # any char
58
- when text = @ss.scan(/./)
64
+ when text = dedup_scan(/./)
59
65
  [:LITERAL, text]
60
66
  end
61
67
  end
@@ -40,7 +40,7 @@ module ActionDispatch
40
40
  @parameters.each do |index|
41
41
  param = parts[index]
42
42
  value = hash[param.name]
43
- return "".freeze unless value
43
+ return "" if value.nil?
44
44
  parts[index] = param.escape value
45
45
  end
46
46
 
@@ -59,7 +59,6 @@ module ActionDispatch
59
59
  end
60
60
 
61
61
  private
62
-
63
62
  def visit(node)
64
63
  send(DISPATCH_CACHE[node.type], node)
65
64
  end
@@ -168,7 +167,6 @@ module ActionDispatch
168
167
 
169
168
  class String < FunctionalVisitor # :nodoc:
170
169
  private
171
-
172
170
  def binary(node, seed)
173
171
  visit(node.right, visit(node.left, seed))
174
172
  end
@@ -214,7 +212,6 @@ module ActionDispatch
214
212
  end
215
213
 
216
214
  private
217
-
218
215
  def binary(node, seed)
219
216
  seed.last.concat node.children.map { |c|
220
217
  "#{node.object_id} -> #{c.object_id};"
@@ -3,5 +3,3 @@
3
3
  require "action_dispatch/journey/router"
4
4
  require "action_dispatch/journey/gtg/builder"
5
5
  require "action_dispatch/journey/gtg/simulator"
6
- require "action_dispatch/journey/nfa/builder"
7
- require "action_dispatch/journey/nfa/simulator"
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "erb"
4
+ require "uri"
5
+ require "action_dispatch/http/request"
6
+ require "active_support/actionable_error"
7
+
8
+ module ActionDispatch
9
+ class ActionableExceptions # :nodoc:
10
+ cattr_accessor :endpoint, default: "/rails/actions"
11
+
12
+ def initialize(app)
13
+ @app = app
14
+ end
15
+
16
+ def call(env)
17
+ request = ActionDispatch::Request.new(env)
18
+ return @app.call(env) unless actionable_request?(request)
19
+
20
+ ActiveSupport::ActionableError.dispatch(request.params[:error].to_s.safe_constantize, request.params[:action])
21
+
22
+ redirect_to request.params[:location]
23
+ end
24
+
25
+ private
26
+ def actionable_request?(request)
27
+ request.get_header("action_dispatch.show_detailed_exceptions") && request.post? && request.path == endpoint
28
+ end
29
+
30
+ def redirect_to(location)
31
+ uri = URI.parse location
32
+
33
+ if uri.relative? || uri.scheme == "http" || uri.scheme == "https"
34
+ body = "<html><body>You are being <a href=\"#{ERB::Util.unwrapped_html_escape(location)}\">redirected</a>.</body></html>"
35
+ else
36
+ return [400, { "Content-Type" => "text/plain" }, ["Invalid redirection URI"]]
37
+ end
38
+
39
+ [302, {
40
+ "Content-Type" => "text/html; charset=#{Response.default_charset}",
41
+ "Content-Length" => body.bytesize.to_s,
42
+ "Location" => location,
43
+ }, [body]]
44
+ end
45
+ end
46
+ end
@@ -24,10 +24,8 @@ module ActionDispatch
24
24
  def call(env)
25
25
  error = nil
26
26
  result = run_callbacks :call do
27
- begin
28
- @app.call(env)
29
- rescue => error
30
- end
27
+ @app.call(env)
28
+ rescue => error
31
29
  end
32
30
  raise error if error
33
31
  result