actionpack 3.2.22.5 → 5.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +279 -603
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -297
  5. data/lib/abstract_controller/asset_paths.rb +4 -2
  6. data/lib/abstract_controller/base.rb +82 -52
  7. data/lib/abstract_controller/caching/fragments.rb +166 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/callbacks.rb +117 -103
  10. data/lib/abstract_controller/collector.rb +18 -7
  11. data/lib/abstract_controller/error.rb +6 -0
  12. data/lib/abstract_controller/helpers.rb +65 -38
  13. data/lib/abstract_controller/logger.rb +3 -2
  14. data/lib/abstract_controller/railties/routes_helpers.rb +5 -3
  15. data/lib/abstract_controller/rendering.rb +77 -129
  16. data/lib/abstract_controller/translation.rb +21 -3
  17. data/lib/abstract_controller/url_for.rb +9 -7
  18. data/lib/abstract_controller.rb +12 -13
  19. data/lib/action_controller/api/api_rendering.rb +16 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/base.rb +81 -40
  22. data/lib/action_controller/caching.rb +22 -62
  23. data/lib/action_controller/form_builder.rb +50 -0
  24. data/lib/action_controller/log_subscriber.rb +30 -18
  25. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  26. data/lib/action_controller/metal/conditional_get.rb +190 -47
  27. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  28. data/lib/action_controller/metal/cookies.rb +3 -3
  29. data/lib/action_controller/metal/data_streaming.rb +40 -65
  30. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  31. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  32. data/lib/action_controller/metal/exceptions.rb +19 -12
  33. data/lib/action_controller/metal/flash.rb +42 -9
  34. data/lib/action_controller/metal/force_ssl.rb +79 -19
  35. data/lib/action_controller/metal/head.rb +35 -10
  36. data/lib/action_controller/metal/helpers.rb +31 -21
  37. data/lib/action_controller/metal/http_authentication.rb +182 -134
  38. data/lib/action_controller/metal/implicit_render.rb +62 -8
  39. data/lib/action_controller/metal/instrumentation.rb +28 -26
  40. data/lib/action_controller/metal/live.rb +312 -0
  41. data/lib/action_controller/metal/mime_responds.rb +159 -163
  42. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  43. data/lib/action_controller/metal/params_wrapper.rb +146 -93
  44. data/lib/action_controller/metal/redirecting.rb +80 -56
  45. data/lib/action_controller/metal/renderers.rb +119 -47
  46. data/lib/action_controller/metal/rendering.rb +89 -32
  47. data/lib/action_controller/metal/request_forgery_protection.rb +373 -41
  48. data/lib/action_controller/metal/rescue.rb +9 -16
  49. data/lib/action_controller/metal/streaming.rb +39 -45
  50. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  51. data/lib/action_controller/metal/testing.rb +8 -29
  52. data/lib/action_controller/metal/url_for.rb +43 -32
  53. data/lib/action_controller/metal.rb +112 -106
  54. data/lib/action_controller/railtie.rb +56 -18
  55. data/lib/action_controller/railties/helpers.rb +24 -0
  56. data/lib/action_controller/renderer.rb +117 -0
  57. data/lib/action_controller/template_assertions.rb +11 -0
  58. data/lib/action_controller/test_case.rb +402 -347
  59. data/lib/action_controller.rb +31 -30
  60. data/lib/action_dispatch/http/cache.rb +133 -34
  61. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  62. data/lib/action_dispatch/http/filter_parameters.rb +40 -24
  63. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  64. data/lib/action_dispatch/http/headers.rb +117 -16
  65. data/lib/action_dispatch/http/mime_negotiation.rb +98 -33
  66. data/lib/action_dispatch/http/mime_type.rb +198 -146
  67. data/lib/action_dispatch/http/mime_types.rb +22 -7
  68. data/lib/action_dispatch/http/parameter_filter.rb +61 -49
  69. data/lib/action_dispatch/http/parameters.rb +94 -51
  70. data/lib/action_dispatch/http/rack_cache.rb +4 -3
  71. data/lib/action_dispatch/http/request.rb +262 -117
  72. data/lib/action_dispatch/http/response.rb +400 -86
  73. data/lib/action_dispatch/http/upload.rb +66 -29
  74. data/lib/action_dispatch/http/url.rb +232 -60
  75. data/lib/action_dispatch/journey/formatter.rb +189 -0
  76. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  79. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  80. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  81. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  82. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  83. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  84. data/lib/action_dispatch/journey/parser.rb +199 -0
  85. data/lib/action_dispatch/journey/parser.y +50 -0
  86. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  87. data/lib/action_dispatch/journey/path/pattern.rb +199 -0
  88. data/lib/action_dispatch/journey/route.rb +203 -0
  89. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  90. data/lib/action_dispatch/journey/router.rb +156 -0
  91. data/lib/action_dispatch/journey/routes.rb +82 -0
  92. data/lib/action_dispatch/journey/scanner.rb +64 -0
  93. data/lib/action_dispatch/journey/visitors.rb +268 -0
  94. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  95. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  96. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  97. data/lib/action_dispatch/journey.rb +7 -0
  98. data/lib/action_dispatch/middleware/callbacks.rb +17 -13
  99. data/lib/action_dispatch/middleware/cookies.rb +494 -162
  100. data/lib/action_dispatch/middleware/debug_exceptions.rb +176 -53
  101. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  102. data/lib/action_dispatch/middleware/exception_wrapper.rb +103 -38
  103. data/lib/action_dispatch/middleware/executor.rb +21 -0
  104. data/lib/action_dispatch/middleware/flash.rb +128 -91
  105. data/lib/action_dispatch/middleware/public_exceptions.rb +43 -16
  106. data/lib/action_dispatch/middleware/reloader.rb +6 -83
  107. data/lib/action_dispatch/middleware/remote_ip.rb +151 -49
  108. data/lib/action_dispatch/middleware/request_id.rb +19 -15
  109. data/lib/action_dispatch/middleware/session/abstract_store.rb +38 -34
  110. data/lib/action_dispatch/middleware/session/cache_store.rb +14 -9
  111. data/lib/action_dispatch/middleware/session/cookie_store.rb +94 -44
  112. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -4
  113. data/lib/action_dispatch/middleware/show_exceptions.rb +36 -61
  114. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  115. data/lib/action_dispatch/middleware/stack.rb +33 -41
  116. data/lib/action_dispatch/middleware/static.rb +92 -48
  117. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +134 -5
  128. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  136. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  138. data/lib/action_dispatch/railtie.rb +29 -8
  139. data/lib/action_dispatch/request/session.rb +234 -0
  140. data/lib/action_dispatch/request/utils.rb +78 -0
  141. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  142. data/lib/action_dispatch/routing/inspector.rb +225 -0
  143. data/lib/action_dispatch/routing/mapper.rb +1329 -582
  144. data/lib/action_dispatch/routing/polymorphic_routes.rb +237 -94
  145. data/lib/action_dispatch/routing/redirection.rb +120 -50
  146. data/lib/action_dispatch/routing/route_set.rb +545 -322
  147. data/lib/action_dispatch/routing/routes_proxy.rb +37 -7
  148. data/lib/action_dispatch/routing/url_for.rb +103 -34
  149. data/lib/action_dispatch/routing.rb +66 -99
  150. data/lib/action_dispatch/system_test_case.rb +147 -0
  151. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  152. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  153. data/lib/action_dispatch/system_testing/server.rb +31 -0
  154. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  157. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  158. data/lib/action_dispatch/testing/assertions/response.rb +53 -42
  159. data/lib/action_dispatch/testing/assertions/routing.rb +79 -74
  160. data/lib/action_dispatch/testing/assertions.rb +15 -9
  161. data/lib/action_dispatch/testing/integration.rb +361 -207
  162. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  163. data/lib/action_dispatch/testing/test_process.rb +28 -19
  164. data/lib/action_dispatch/testing/test_request.rb +30 -33
  165. data/lib/action_dispatch/testing/test_response.rb +35 -11
  166. data/lib/action_dispatch.rb +42 -32
  167. data/lib/action_pack/gem_version.rb +17 -0
  168. data/lib/action_pack/version.rb +7 -7
  169. data/lib/action_pack.rb +4 -2
  170. metadata +116 -175
  171. data/lib/abstract_controller/layouts.rb +0 -423
  172. data/lib/abstract_controller/view_paths.rb +0 -96
  173. data/lib/action_controller/caching/actions.rb +0 -185
  174. data/lib/action_controller/caching/fragments.rb +0 -127
  175. data/lib/action_controller/caching/pages.rb +0 -187
  176. data/lib/action_controller/caching/sweeping.rb +0 -97
  177. data/lib/action_controller/deprecated/integration_test.rb +0 -2
  178. data/lib/action_controller/deprecated/performance_test.rb +0 -1
  179. data/lib/action_controller/deprecated.rb +0 -3
  180. data/lib/action_controller/metal/compatibility.rb +0 -65
  181. data/lib/action_controller/metal/hide_actions.rb +0 -41
  182. data/lib/action_controller/metal/rack_delegation.rb +0 -26
  183. data/lib/action_controller/metal/responder.rb +0 -286
  184. data/lib/action_controller/metal/session_management.rb +0 -14
  185. data/lib/action_controller/middleware.rb +0 -39
  186. data/lib/action_controller/railties/paths.rb +0 -25
  187. data/lib/action_controller/record_identifier.rb +0 -85
  188. data/lib/action_controller/vendor/html-scanner/html/document.rb +0 -68
  189. data/lib/action_controller/vendor/html-scanner/html/node.rb +0 -532
  190. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +0 -177
  191. data/lib/action_controller/vendor/html-scanner/html/selector.rb +0 -830
  192. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +0 -107
  193. data/lib/action_controller/vendor/html-scanner/html/version.rb +0 -11
  194. data/lib/action_controller/vendor/html-scanner.rb +0 -20
  195. data/lib/action_dispatch/middleware/best_standards_support.rb +0 -30
  196. data/lib/action_dispatch/middleware/body_proxy.rb +0 -30
  197. data/lib/action_dispatch/middleware/head.rb +0 -18
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -75
  199. data/lib/action_dispatch/middleware/rescue.rb +0 -26
  200. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +0 -31
  201. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +0 -26
  202. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +0 -10
  203. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +0 -2
  204. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +0 -15
  205. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +0 -17
  206. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +0 -2
  207. data/lib/action_dispatch/testing/assertions/dom.rb +0 -37
  208. data/lib/action_dispatch/testing/assertions/selector.rb +0 -435
  209. data/lib/action_dispatch/testing/assertions/tag.rb +0 -138
  210. data/lib/action_dispatch/testing/performance_test.rb +0 -10
  211. data/lib/action_view/asset_paths.rb +0 -142
  212. data/lib/action_view/base.rb +0 -220
  213. data/lib/action_view/buffers.rb +0 -43
  214. data/lib/action_view/context.rb +0 -36
  215. data/lib/action_view/flows.rb +0 -79
  216. data/lib/action_view/helpers/active_model_helper.rb +0 -50
  217. data/lib/action_view/helpers/asset_paths.rb +0 -7
  218. data/lib/action_view/helpers/asset_tag_helper.rb +0 -457
  219. data/lib/action_view/helpers/asset_tag_helpers/asset_include_tag.rb +0 -146
  220. data/lib/action_view/helpers/asset_tag_helpers/asset_paths.rb +0 -93
  221. data/lib/action_view/helpers/asset_tag_helpers/javascript_tag_helpers.rb +0 -193
  222. data/lib/action_view/helpers/asset_tag_helpers/stylesheet_tag_helpers.rb +0 -148
  223. data/lib/action_view/helpers/atom_feed_helper.rb +0 -200
  224. data/lib/action_view/helpers/cache_helper.rb +0 -64
  225. data/lib/action_view/helpers/capture_helper.rb +0 -203
  226. data/lib/action_view/helpers/controller_helper.rb +0 -25
  227. data/lib/action_view/helpers/csrf_helper.rb +0 -32
  228. data/lib/action_view/helpers/date_helper.rb +0 -1062
  229. data/lib/action_view/helpers/debug_helper.rb +0 -40
  230. data/lib/action_view/helpers/form_helper.rb +0 -1486
  231. data/lib/action_view/helpers/form_options_helper.rb +0 -658
  232. data/lib/action_view/helpers/form_tag_helper.rb +0 -685
  233. data/lib/action_view/helpers/javascript_helper.rb +0 -110
  234. data/lib/action_view/helpers/number_helper.rb +0 -622
  235. data/lib/action_view/helpers/output_safety_helper.rb +0 -38
  236. data/lib/action_view/helpers/record_tag_helper.rb +0 -111
  237. data/lib/action_view/helpers/rendering_helper.rb +0 -92
  238. data/lib/action_view/helpers/sanitize_helper.rb +0 -259
  239. data/lib/action_view/helpers/tag_helper.rb +0 -167
  240. data/lib/action_view/helpers/text_helper.rb +0 -426
  241. data/lib/action_view/helpers/translation_helper.rb +0 -91
  242. data/lib/action_view/helpers/url_helper.rb +0 -693
  243. data/lib/action_view/helpers.rb +0 -60
  244. data/lib/action_view/locale/en.yml +0 -160
  245. data/lib/action_view/log_subscriber.rb +0 -28
  246. data/lib/action_view/lookup_context.rb +0 -258
  247. data/lib/action_view/path_set.rb +0 -101
  248. data/lib/action_view/railtie.rb +0 -55
  249. data/lib/action_view/renderer/abstract_renderer.rb +0 -41
  250. data/lib/action_view/renderer/partial_renderer.rb +0 -415
  251. data/lib/action_view/renderer/renderer.rb +0 -61
  252. data/lib/action_view/renderer/streaming_template_renderer.rb +0 -106
  253. data/lib/action_view/renderer/template_renderer.rb +0 -95
  254. data/lib/action_view/template/error.rb +0 -128
  255. data/lib/action_view/template/handlers/builder.rb +0 -26
  256. data/lib/action_view/template/handlers/erb.rb +0 -125
  257. data/lib/action_view/template/handlers.rb +0 -50
  258. data/lib/action_view/template/resolver.rb +0 -298
  259. data/lib/action_view/template/text.rb +0 -30
  260. data/lib/action_view/template.rb +0 -337
  261. data/lib/action_view/test_case.rb +0 -246
  262. data/lib/action_view/testing/resolvers.rb +0 -49
  263. data/lib/action_view.rb +0 -84
  264. data/lib/sprockets/assets.rake +0 -99
  265. data/lib/sprockets/bootstrap.rb +0 -37
  266. data/lib/sprockets/compressors.rb +0 -83
  267. data/lib/sprockets/helpers/isolated_helper.rb +0 -13
  268. data/lib/sprockets/helpers/rails_helper.rb +0 -182
  269. data/lib/sprockets/helpers.rb +0 -6
  270. data/lib/sprockets/railtie.rb +0 -62
  271. data/lib/sprockets/static_compiler.rb +0 -56
@@ -1,16 +1,16 @@
1
- require 'active_support/core_ext/object/blank'
2
- require 'active_support/core_ext/hash/keys'
3
- require 'active_support/core_ext/object/duplicable'
1
+ # frozen_string_literal: true
2
+
3
+ require "action_dispatch/http/parameter_filter"
4
4
 
5
5
  module ActionDispatch
6
6
  module Http
7
7
  # Allows you to specify sensitive parameters which will be replaced from
8
8
  # the request log by looking in the query string of the request and all
9
- # subhashes of the params hash to filter. If a block is given, each key and
10
- # value of the params hash and all subhashes is passed to it, the value
11
- # or key can be replaced using String#replace or similar method.
12
- #
13
- # Examples:
9
+ # sub-hashes of the params hash to filter. Filtering only certain sub-keys
10
+ # from a hash is possible by using the dot notation: 'credit_card.number'.
11
+ # If a block is given, each key and value of the params hash and all
12
+ # sub-hashes is passed to it, where the value or the key can be replaced using
13
+ # String#replace or similar method.
14
14
  #
15
15
  # env["action_dispatch.parameter_filter"] = [:password]
16
16
  # => replaces the value to all keys matching /password/i with "[FILTERED]"
@@ -18,51 +18,67 @@ module ActionDispatch
18
18
  # env["action_dispatch.parameter_filter"] = [:foo, "bar"]
19
19
  # => replaces the value to all keys matching /foo|bar/i with "[FILTERED]"
20
20
  #
21
- # env["action_dispatch.parameter_filter"] = lambda do |k,v|
21
+ # env["action_dispatch.parameter_filter"] = [ "credit_card.code" ]
22
+ # => replaces { credit_card: {code: "xxxx"} } with "[FILTERED]", does not
23
+ # change { file: { code: "xxxx"} }
24
+ #
25
+ # env["action_dispatch.parameter_filter"] = -> (k, v) do
22
26
  # v.reverse! if k =~ /secret/i
23
27
  # end
24
28
  # => reverses the value to all keys matching /secret/i
25
- #
26
29
  module FilterParameters
27
- extend ActiveSupport::Concern
30
+ ENV_MATCH = [/RAW_POST_DATA/, "rack.request.form_vars"] # :nodoc:
31
+ NULL_PARAM_FILTER = ParameterFilter.new # :nodoc:
32
+ NULL_ENV_FILTER = ParameterFilter.new ENV_MATCH # :nodoc:
28
33
 
29
- # Return a hash of parameters with all sensitive data replaced.
34
+ def initialize
35
+ super
36
+ @filtered_parameters = nil
37
+ @filtered_env = nil
38
+ @filtered_path = nil
39
+ end
40
+
41
+ # Returns a hash of parameters with all sensitive data replaced.
30
42
  def filtered_parameters
31
43
  @filtered_parameters ||= parameter_filter.filter(parameters)
32
44
  end
33
45
 
34
- # Return a hash of request.env with all sensitive data replaced.
46
+ # Returns a hash of request.env with all sensitive data replaced.
35
47
  def filtered_env
36
48
  @filtered_env ||= env_filter.filter(@env)
37
49
  end
38
50
 
39
- # Reconstructed a path with all sensitive GET parameters replaced.
51
+ # Reconstructs a path with all sensitive GET parameters replaced.
40
52
  def filtered_path
41
53
  @filtered_path ||= query_string.empty? ? path : "#{path}?#{filtered_query_string}"
42
54
  end
43
55
 
44
- protected
56
+ private
45
57
 
46
- def parameter_filter
47
- parameter_filter_for(@env["action_dispatch.parameter_filter"])
58
+ def parameter_filter # :doc:
59
+ parameter_filter_for fetch_header("action_dispatch.parameter_filter") {
60
+ return NULL_PARAM_FILTER
61
+ }
48
62
  end
49
63
 
50
- def env_filter
51
- parameter_filter_for(Array.wrap(@env["action_dispatch.parameter_filter"]) << /RAW_POST_DATA/)
64
+ def env_filter # :doc:
65
+ user_key = fetch_header("action_dispatch.parameter_filter") {
66
+ return NULL_ENV_FILTER
67
+ }
68
+ parameter_filter_for(Array(user_key) + ENV_MATCH)
52
69
  end
53
70
 
54
- def parameter_filter_for(filters)
71
+ def parameter_filter_for(filters) # :doc:
55
72
  ParameterFilter.new(filters)
56
73
  end
57
74
 
58
- KV_RE = '[^&;=]+'
75
+ KV_RE = "[^&;=]+"
59
76
  PAIR_RE = %r{(#{KV_RE})=(#{KV_RE})}
60
- def filtered_query_string
77
+ def filtered_query_string # :doc:
61
78
  query_string.gsub(PAIR_RE) do |_|
62
- parameter_filter.filter([[$1, $2]]).first.join("=")
79
+ parameter_filter.filter($1 => $2).first.join("=")
63
80
  end
64
81
  end
65
-
66
82
  end
67
83
  end
68
84
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Http
5
+ module FilterRedirect
6
+ FILTERED = "[FILTERED]".freeze # :nodoc:
7
+
8
+ def filtered_location # :nodoc:
9
+ if location_filter_match?
10
+ FILTERED
11
+ else
12
+ location
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def location_filters
19
+ if request
20
+ request.get_header("action_dispatch.redirect_filter") || []
21
+ else
22
+ []
23
+ end
24
+ end
25
+
26
+ def location_filter_match?
27
+ location_filters.any? do |filter|
28
+ if String === filter
29
+ location.include?(filter)
30
+ elsif Regexp === filter
31
+ location =~ filter
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -1,30 +1,131 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActionDispatch
2
4
  module Http
3
- class Headers < ::Hash
4
- @@env_cache = Hash.new { |h,k| h[k] = "HTTP_#{k.upcase.gsub(/-/, '_')}" }
5
+ # Provides access to the request's HTTP headers from the environment.
6
+ #
7
+ # env = { "CONTENT_TYPE" => "text/plain", "HTTP_USER_AGENT" => "curl/7.43.0" }
8
+ # headers = ActionDispatch::Http::Headers.from_hash(env)
9
+ # headers["Content-Type"] # => "text/plain"
10
+ # headers["User-Agent"] # => "curl/7.43.0"
11
+ #
12
+ # Also note that when headers are mapped to CGI-like variables by the Rack
13
+ # server, both dashes and underscores are converted to underscores. This
14
+ # ambiguity cannot be resolved at this stage anymore. Both underscores and
15
+ # dashes have to be interpreted as if they were originally sent as dashes.
16
+ #
17
+ # # GET / HTTP/1.1
18
+ # # ...
19
+ # # User-Agent: curl/7.43.0
20
+ # # X_Custom_Header: token
21
+ #
22
+ # headers["X_Custom_Header"] # => nil
23
+ # headers["X-Custom-Header"] # => "token"
24
+ class Headers
25
+ CGI_VARIABLES = Set.new(%W[
26
+ AUTH_TYPE
27
+ CONTENT_LENGTH
28
+ CONTENT_TYPE
29
+ GATEWAY_INTERFACE
30
+ HTTPS
31
+ PATH_INFO
32
+ PATH_TRANSLATED
33
+ QUERY_STRING
34
+ REMOTE_ADDR
35
+ REMOTE_HOST
36
+ REMOTE_IDENT
37
+ REMOTE_USER
38
+ REQUEST_METHOD
39
+ SCRIPT_NAME
40
+ SERVER_NAME
41
+ SERVER_PORT
42
+ SERVER_PROTOCOL
43
+ SERVER_SOFTWARE
44
+ ]).freeze
45
+
46
+ HTTP_HEADER = /\A[A-Za-z0-9-]+\z/
47
+
48
+ include Enumerable
5
49
 
6
- def initialize(*args)
50
+ def self.from_hash(hash)
51
+ new ActionDispatch::Request.new hash
52
+ end
53
+
54
+ def initialize(request) # :nodoc:
55
+ @req = request
56
+ end
7
57
 
8
- if args.size == 1 && args[0].is_a?(Hash)
9
- super()
10
- update(args[0])
11
- else
12
- super
58
+ # Returns the value for the given key mapped to @env.
59
+ def [](key)
60
+ @req.get_header env_name(key)
61
+ end
62
+
63
+ # Sets the given value for the key mapped to @env.
64
+ def []=(key, value)
65
+ @req.set_header env_name(key), value
66
+ end
67
+
68
+ # Add a value to a multivalued header like Vary or Accept-Encoding.
69
+ def add(key, value)
70
+ @req.add_header env_name(key), value
71
+ end
72
+
73
+ def key?(key)
74
+ @req.has_header? env_name(key)
75
+ end
76
+ alias :include? :key?
77
+
78
+ DEFAULT = Object.new # :nodoc:
79
+
80
+ # Returns the value for the given key mapped to @env.
81
+ #
82
+ # If the key is not found and an optional code block is not provided,
83
+ # raises a <tt>KeyError</tt> exception.
84
+ #
85
+ # If the code block is provided, then it will be run and
86
+ # its result returned.
87
+ def fetch(key, default = DEFAULT)
88
+ @req.fetch_header(env_name(key)) do
89
+ return default unless default == DEFAULT
90
+ return yield if block_given?
91
+ raise KeyError, key
13
92
  end
14
93
  end
15
94
 
16
- def [](header_name)
17
- if include?(header_name)
18
- super
19
- else
20
- super(env_name(header_name))
95
+ def each(&block)
96
+ @req.each_header(&block)
97
+ end
98
+
99
+ # Returns a new Http::Headers instance containing the contents of
100
+ # <tt>headers_or_env</tt> and the original instance.
101
+ def merge(headers_or_env)
102
+ headers = @req.dup.headers
103
+ headers.merge!(headers_or_env)
104
+ headers
105
+ end
106
+
107
+ # Adds the contents of <tt>headers_or_env</tt> to original instance
108
+ # entries; duplicate keys are overwritten with the values from
109
+ # <tt>headers_or_env</tt>.
110
+ def merge!(headers_or_env)
111
+ headers_or_env.each do |key, value|
112
+ @req.set_header env_name(key), value
21
113
  end
22
114
  end
23
115
 
116
+ def env; @req.env.dup; end
117
+
24
118
  private
25
- # Converts a HTTP header name to an environment variable name.
26
- def env_name(header_name)
27
- @@env_cache[header_name]
119
+
120
+ # Converts an HTTP header name to an environment variable name if it is
121
+ # not contained within the headers hash.
122
+ def env_name(key)
123
+ key = key.to_s
124
+ if key =~ HTTP_HEADER
125
+ key = key.upcase.tr("-", "_")
126
+ key = "HTTP_" + key unless CGI_VARIABLES.include?(key)
127
+ end
128
+ key
28
129
  end
29
130
  end
30
131
  end
@@ -1,24 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors"
4
+
1
5
  module ActionDispatch
2
6
  module Http
3
7
  module MimeNegotiation
4
8
  extend ActiveSupport::Concern
5
9
 
6
10
  included do
7
- mattr_accessor :ignore_accept_header
8
- self.ignore_accept_header = false
11
+ mattr_accessor :ignore_accept_header, default: false
9
12
  end
10
13
 
11
- # The MIME type of the HTTP request, such as Mime::XML.
12
- #
13
- # For backward compatibility, the post \format is extracted from the
14
- # X-Post-Data-Format HTTP header if present.
14
+ # The MIME type of the HTTP request, such as Mime[:xml].
15
15
  def content_mime_type
16
- @env["action_dispatch.request.content_type"] ||= begin
17
- if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/
16
+ fetch_header("action_dispatch.request.content_type") do |k|
17
+ v = if get_header("CONTENT_TYPE") =~ /^([^,\;]*)/
18
18
  Mime::Type.lookup($1.strip.downcase)
19
19
  else
20
20
  nil
21
21
  end
22
+ set_header k, v
22
23
  end
23
24
  end
24
25
 
@@ -26,47 +27,85 @@ module ActionDispatch
26
27
  content_mime_type && content_mime_type.to_s
27
28
  end
28
29
 
30
+ def has_content_type? # :nodoc:
31
+ get_header "CONTENT_TYPE"
32
+ end
33
+
29
34
  # Returns the accepted MIME type for the request.
30
35
  def accepts
31
- @env["action_dispatch.request.accepts"] ||= begin
32
- header = @env['HTTP_ACCEPT'].to_s.strip
36
+ fetch_header("action_dispatch.request.accepts") do |k|
37
+ header = get_header("HTTP_ACCEPT").to_s.strip
33
38
 
34
- if header.empty?
39
+ v = if header.empty?
35
40
  [content_mime_type]
36
41
  else
37
42
  Mime::Type.parse(header)
38
43
  end
44
+ set_header k, v
39
45
  end
40
46
  end
41
47
 
42
48
  # Returns the MIME type for the \format used in the request.
43
49
  #
44
- # GET /posts/5.xml | request.format => Mime::XML
45
- # GET /posts/5.xhtml | request.format => Mime::HTML
46
- # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first
50
+ # GET /posts/5.xml | request.format => Mime[:xml]
51
+ # GET /posts/5.xhtml | request.format => Mime[:html]
52
+ # GET /posts/5 | request.format => Mime[:html] or Mime[:js], or request.accepts.first
47
53
  #
48
54
  def format(view_path = [])
49
- formats.first
55
+ formats.first || Mime::NullType.instance
50
56
  end
51
57
 
52
58
  def formats
53
- @env["action_dispatch.request.formats"] ||=
54
- if parameters[:format]
59
+ fetch_header("action_dispatch.request.formats") do |k|
60
+ params_readable = begin
61
+ parameters[:format]
62
+ rescue ActionController::BadRequest
63
+ false
64
+ end
65
+
66
+ v = if params_readable
55
67
  Array(Mime[parameters[:format]])
56
68
  elsif use_accept_header && valid_accept_header
57
69
  accepts
70
+ elsif extension_format = format_from_path_extension
71
+ [extension_format]
58
72
  elsif xhr?
59
- [Mime::JS]
73
+ [Mime[:js]]
60
74
  else
61
- [Mime::HTML]
75
+ [Mime[:html]]
76
+ end
77
+
78
+ v = v.select do |format|
79
+ format.symbol || format.ref == "*/*"
62
80
  end
81
+
82
+ set_header k, v
83
+ end
84
+ end
85
+
86
+ # Sets the \variant for template.
87
+ def variant=(variant)
88
+ variant = Array(variant)
89
+
90
+ if variant.all? { |v| v.is_a?(Symbol) }
91
+ @variant = ActiveSupport::ArrayInquirer.new(variant)
92
+ else
93
+ raise ArgumentError, "request.variant must be set to a Symbol or an Array of Symbols. " \
94
+ "For security reasons, never directly set the variant to a user-provided value, " \
95
+ "like params[:variant].to_sym. Check user-provided value against a whitelist first, " \
96
+ "then set the variant: request.variant = :tablet if params[:variant] == 'tablet'"
97
+ end
98
+ end
99
+
100
+ def variant
101
+ @variant ||= ActiveSupport::ArrayInquirer.new
63
102
  end
64
103
 
65
104
  # Sets the \format by string extension, which can be used to force custom formats
66
105
  # that are not controlled by the extension.
67
106
  #
68
107
  # class ApplicationController < ActionController::Base
69
- # before_filter :adjust_format_for_iphone
108
+ # before_action :adjust_format_for_iphone
70
109
  #
71
110
  # private
72
111
  # def adjust_format_for_iphone
@@ -75,12 +114,31 @@ module ActionDispatch
75
114
  # end
76
115
  def format=(extension)
77
116
  parameters[:format] = extension.to_s
78
- @env["action_dispatch.request.formats"] = [Mime::Type.lookup_by_extension(parameters[:format])]
117
+ set_header "action_dispatch.request.formats", [Mime::Type.lookup_by_extension(parameters[:format])]
79
118
  end
80
119
 
81
- # Receives an array of mimes and return the first user sent mime that
82
- # matches the order array.
120
+ # Sets the \formats by string extensions. This differs from #format= by allowing you
121
+ # to set multiple, ordered formats, which is useful when you want to have a fallback.
83
122
  #
123
+ # In this example, the :iphone format will be used if it's available, otherwise it'll fallback
124
+ # to the :html format.
125
+ #
126
+ # class ApplicationController < ActionController::Base
127
+ # before_action :adjust_format_for_iphone_with_html_fallback
128
+ #
129
+ # private
130
+ # def adjust_format_for_iphone_with_html_fallback
131
+ # request.formats = [ :iphone, :html ] if request.env["HTTP_USER_AGENT"][/iPhone/]
132
+ # end
133
+ # end
134
+ def formats=(extensions)
135
+ parameters[:format] = extensions.first.to_s
136
+ set_header "action_dispatch.request.formats", extensions.collect { |extension|
137
+ Mime::Type.lookup_by_extension(extension)
138
+ }
139
+ end
140
+
141
+ # Returns the first MIME type that matches the provided array of MIME types.
84
142
  def negotiate_mime(order)
85
143
  formats.each do |priority|
86
144
  if priority == Mime::ALL
@@ -90,21 +148,28 @@ module ActionDispatch
90
148
  end
91
149
  end
92
150
 
93
- order.include?(Mime::ALL) ? formats.first : nil
151
+ order.include?(Mime::ALL) ? format : nil
94
152
  end
95
153
 
96
- protected
154
+ private
97
155
 
98
- BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
156
+ BROWSER_LIKE_ACCEPTS = /,\s*\*\/\*|\*\/\*\s*,/
99
157
 
100
- def valid_accept_header
101
- (xhr? && (accept.present? || content_mime_type)) ||
102
- (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS)
103
- end
158
+ def valid_accept_header # :doc:
159
+ (xhr? && (accept.present? || content_mime_type)) ||
160
+ (accept.present? && accept !~ BROWSER_LIKE_ACCEPTS)
161
+ end
104
162
 
105
- def use_accept_header
106
- !self.class.ignore_accept_header
107
- end
163
+ def use_accept_header # :doc:
164
+ !self.class.ignore_accept_header
165
+ end
166
+
167
+ def format_from_path_extension # :doc:
168
+ path = get_header("action_dispatch.original_path") || get_header("PATH_INFO")
169
+ if match = path && path.match(/\.(\w+)\z/)
170
+ Mime[match.captures.first]
171
+ end
172
+ end
108
173
  end
109
174
  end
110
175
  end