actionpack 6.1.7.5 → 7.1.3.1

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.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +355 -435
  3. data/MIT-LICENSE +2 -1
  4. data/README.rdoc +6 -7
  5. data/lib/abstract_controller/asset_paths.rb +1 -1
  6. data/lib/abstract_controller/base.rb +33 -37
  7. data/lib/abstract_controller/caching/fragments.rb +4 -2
  8. data/lib/abstract_controller/caching.rb +1 -1
  9. data/lib/abstract_controller/callbacks.rb +50 -11
  10. data/lib/abstract_controller/collector.rb +2 -2
  11. data/lib/abstract_controller/deprecator.rb +7 -0
  12. data/lib/abstract_controller/error.rb +1 -1
  13. data/lib/abstract_controller/helpers.rb +78 -30
  14. data/lib/abstract_controller/logger.rb +1 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +3 -16
  16. data/lib/abstract_controller/rendering.rb +12 -14
  17. data/lib/abstract_controller/translation.rb +26 -7
  18. data/lib/abstract_controller/url_for.rb +6 -6
  19. data/lib/abstract_controller.rb +6 -0
  20. data/lib/action_controller/api.rb +12 -10
  21. data/lib/action_controller/base.rb +8 -21
  22. data/lib/action_controller/caching.rb +2 -0
  23. data/lib/action_controller/deprecator.rb +7 -0
  24. data/lib/action_controller/form_builder.rb +4 -2
  25. data/lib/action_controller/log_subscriber.rb +20 -7
  26. data/lib/action_controller/metal/basic_implicit_render.rb +3 -1
  27. data/lib/action_controller/metal/conditional_get.rb +137 -102
  28. data/lib/action_controller/metal/content_security_policy.rb +37 -3
  29. data/lib/action_controller/metal/cookies.rb +1 -1
  30. data/lib/action_controller/metal/data_streaming.rb +25 -31
  31. data/lib/action_controller/metal/default_headers.rb +2 -0
  32. data/lib/action_controller/metal/etag_with_flash.rb +3 -1
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +2 -0
  34. data/lib/action_controller/metal/exceptions.rb +27 -30
  35. data/lib/action_controller/metal/flash.rb +6 -2
  36. data/lib/action_controller/metal/head.rb +9 -7
  37. data/lib/action_controller/metal/helpers.rb +5 -16
  38. data/lib/action_controller/metal/http_authentication.rb +78 -42
  39. data/lib/action_controller/metal/implicit_render.rb +5 -3
  40. data/lib/action_controller/metal/instrumentation.rb +62 -50
  41. data/lib/action_controller/metal/live.rb +67 -2
  42. data/lib/action_controller/metal/mime_responds.rb +5 -5
  43. data/lib/action_controller/metal/params_wrapper.rb +24 -13
  44. data/lib/action_controller/metal/permissions_policy.rb +20 -29
  45. data/lib/action_controller/metal/redirecting.rb +96 -23
  46. data/lib/action_controller/metal/renderers.rb +14 -15
  47. data/lib/action_controller/metal/rendering.rb +121 -16
  48. data/lib/action_controller/metal/request_forgery_protection.rb +208 -68
  49. data/lib/action_controller/metal/rescue.rb +7 -4
  50. data/lib/action_controller/metal/streaming.rb +74 -36
  51. data/lib/action_controller/metal/strong_parameters.rb +254 -151
  52. data/lib/action_controller/metal/testing.rb +9 -2
  53. data/lib/action_controller/metal/url_for.rb +10 -5
  54. data/lib/action_controller/metal.rb +89 -34
  55. data/lib/action_controller/railtie.rb +66 -9
  56. data/lib/action_controller/renderer.rb +99 -85
  57. data/lib/action_controller/test_case.rb +42 -11
  58. data/lib/action_controller.rb +10 -6
  59. data/lib/action_dispatch/constants.rb +32 -0
  60. data/lib/action_dispatch/deprecator.rb +7 -0
  61. data/lib/action_dispatch/http/cache.rb +21 -16
  62. data/lib/action_dispatch/http/content_security_policy.rb +122 -44
  63. data/lib/action_dispatch/http/filter_parameters.rb +14 -23
  64. data/lib/action_dispatch/http/headers.rb +3 -1
  65. data/lib/action_dispatch/http/mime_negotiation.rb +25 -15
  66. data/lib/action_dispatch/http/mime_type.rb +43 -22
  67. data/lib/action_dispatch/http/mime_types.rb +3 -1
  68. data/lib/action_dispatch/http/parameters.rb +6 -6
  69. data/lib/action_dispatch/http/permissions_policy.rb +57 -19
  70. data/lib/action_dispatch/http/rack_cache.rb +2 -0
  71. data/lib/action_dispatch/http/request.rb +75 -51
  72. data/lib/action_dispatch/http/response.rb +81 -77
  73. data/lib/action_dispatch/http/upload.rb +15 -2
  74. data/lib/action_dispatch/http/url.rb +11 -19
  75. data/lib/action_dispatch/journey/formatter.rb +8 -2
  76. data/lib/action_dispatch/journey/gtg/builder.rb +11 -12
  77. data/lib/action_dispatch/journey/gtg/simulator.rb +10 -4
  78. data/lib/action_dispatch/journey/gtg/transition_table.rb +77 -21
  79. data/lib/action_dispatch/journey/nodes/node.rb +70 -5
  80. data/lib/action_dispatch/journey/path/pattern.rb +36 -27
  81. data/lib/action_dispatch/journey/route.rb +8 -14
  82. data/lib/action_dispatch/journey/router/utils.rb +2 -2
  83. data/lib/action_dispatch/journey/router.rb +10 -9
  84. data/lib/action_dispatch/journey/routes.rb +5 -5
  85. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  86. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  87. data/lib/action_dispatch/log_subscriber.rb +23 -0
  88. data/lib/action_dispatch/middleware/actionable_exceptions.rb +5 -7
  89. data/lib/action_dispatch/middleware/assume_ssl.rb +24 -0
  90. data/lib/action_dispatch/middleware/callbacks.rb +2 -0
  91. data/lib/action_dispatch/middleware/cookies.rb +97 -107
  92. data/lib/action_dispatch/middleware/debug_exceptions.rb +31 -28
  93. data/lib/action_dispatch/middleware/debug_locks.rb +7 -4
  94. data/lib/action_dispatch/middleware/debug_view.rb +7 -2
  95. data/lib/action_dispatch/middleware/exception_wrapper.rb +190 -27
  96. data/lib/action_dispatch/middleware/executor.rb +3 -0
  97. data/lib/action_dispatch/middleware/flash.rb +24 -18
  98. data/lib/action_dispatch/middleware/host_authorization.rb +19 -20
  99. data/lib/action_dispatch/middleware/public_exceptions.rb +5 -3
  100. data/lib/action_dispatch/middleware/reloader.rb +7 -5
  101. data/lib/action_dispatch/middleware/remote_ip.rb +32 -19
  102. data/lib/action_dispatch/middleware/request_id.rb +5 -3
  103. data/lib/action_dispatch/middleware/server_timing.rb +76 -0
  104. data/lib/action_dispatch/middleware/session/abstract_store.rb +6 -1
  105. data/lib/action_dispatch/middleware/session/cache_store.rb +2 -0
  106. data/lib/action_dispatch/middleware/session/cookie_store.rb +19 -13
  107. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +3 -1
  108. data/lib/action_dispatch/middleware/show_exceptions.rb +30 -25
  109. data/lib/action_dispatch/middleware/ssl.rb +18 -6
  110. data/lib/action_dispatch/middleware/stack.rb +34 -11
  111. data/lib/action_dispatch/middleware/static.rb +16 -16
  112. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +2 -2
  113. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +5 -5
  114. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +4 -11
  115. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +8 -1
  116. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +2 -2
  117. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +10 -5
  118. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +7 -3
  119. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +9 -9
  120. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +2 -2
  121. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +3 -3
  122. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +45 -18
  123. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +19 -15
  124. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +4 -4
  125. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +6 -6
  126. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +7 -7
  127. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  128. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  129. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +3 -0
  130. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +64 -55
  131. data/lib/action_dispatch/railtie.rb +20 -4
  132. data/lib/action_dispatch/request/session.rb +59 -19
  133. data/lib/action_dispatch/request/utils.rb +8 -3
  134. data/lib/action_dispatch/routing/inspector.rb +55 -7
  135. data/lib/action_dispatch/routing/mapper.rb +117 -107
  136. data/lib/action_dispatch/routing/polymorphic_routes.rb +2 -0
  137. data/lib/action_dispatch/routing/redirection.rb +20 -8
  138. data/lib/action_dispatch/routing/route_set.rb +67 -27
  139. data/lib/action_dispatch/routing/routes_proxy.rb +11 -16
  140. data/lib/action_dispatch/routing/url_for.rb +29 -26
  141. data/lib/action_dispatch/routing.rb +12 -13
  142. data/lib/action_dispatch/system_test_case.rb +8 -8
  143. data/lib/action_dispatch/system_testing/browser.rb +20 -29
  144. data/lib/action_dispatch/system_testing/driver.rb +34 -18
  145. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +35 -20
  146. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +0 -8
  147. data/lib/action_dispatch/testing/assertion_response.rb +1 -1
  148. data/lib/action_dispatch/testing/assertions/response.rb +14 -7
  149. data/lib/action_dispatch/testing/assertions/routing.rb +70 -30
  150. data/lib/action_dispatch/testing/assertions.rb +3 -4
  151. data/lib/action_dispatch/testing/integration.rb +33 -25
  152. data/lib/action_dispatch/testing/request_encoder.rb +4 -1
  153. data/lib/action_dispatch/testing/test_process.rb +5 -30
  154. data/lib/action_dispatch/testing/test_request.rb +1 -1
  155. data/lib/action_dispatch/testing/test_response.rb +34 -2
  156. data/lib/action_dispatch.rb +38 -4
  157. data/lib/action_pack/gem_version.rb +4 -4
  158. data/lib/action_pack/version.rb +1 -1
  159. data/lib/action_pack.rb +1 -1
  160. metadata +67 -30
@@ -1,11 +1,11 @@
1
- <header>
1
+ <header role="banner">
2
2
  <h1>Template is missing</h1>
3
3
  </header>
4
4
 
5
- <div id="container">
6
- <h2><%= h @exception.message %></h2>
5
+ <main role="main" id="container">
6
+ <h2><%= h @exception_wrapper.message %></h2>
7
7
 
8
8
  <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
9
9
  <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %>
10
10
  <%= render template: "rescues/_request_and_response" %>
11
- </div>
11
+ </main>
@@ -1,13 +1,13 @@
1
- <header>
1
+ <header role="banner">
2
2
  <h1>Routing Error</h1>
3
3
  </header>
4
- <div id="container">
5
- <h2><%= h @exception.message %></h2>
6
- <% unless @exception.failures.empty? %>
4
+ <main role="main" id="container">
5
+ <h2><%= h @exception_wrapper.message %></h2>
6
+ <% unless @exception_wrapper.failures.empty? %>
7
7
  <p>
8
8
  <h2>Failure reasons:</h2>
9
9
  <ol>
10
- <% @exception.failures.each do |route, reason| %>
10
+ <% @exception_wrapper.failures.each do |route, reason| %>
11
11
  <li><code><%= route.inspect.delete('\\') %></code> failed because <%= reason.downcase %></li>
12
12
  <% end %>
13
13
  </ol>
@@ -29,4 +29,4 @@
29
29
  <% end %>
30
30
 
31
31
  <%= render template: "rescues/_request_and_response" %>
32
- </div>
32
+ </main>
@@ -1,20 +1,20 @@
1
- <header>
1
+ <header role="banner">
2
2
  <h1>
3
- <%= @exception.cause.class.to_s %> in
3
+ <%= @exception_wrapper.exception_name %> in
4
4
  <%= @request.parameters["controller"].camelize if @request.parameters["controller"] %>#<%= @request.parameters["action"] %>
5
5
  </h1>
6
6
  </header>
7
7
 
8
- <div id="container">
8
+ <main role="main" id="container">
9
9
  <p>
10
- Showing <i><%= @exception.file_name %></i> where line <b>#<%= @exception.line_number %></b> raised:
10
+ Showing <i><%= @exception_wrapper.file_name %></i> where line <b>#<%= @exception_wrapper.line_number %></b> raised:
11
11
  </p>
12
- <pre><code><%= h @exception.message %></code></pre>
12
+ <pre><code><%= h @exception_wrapper.message %></code></pre>
13
13
 
14
14
  <%= render "rescues/source", source_extracts: @source_extracts, show_source_idx: @show_source_idx %>
15
15
 
16
- <p><%= @exception.sub_template_message %></p>
16
+ <p><%= @exception_wrapper.sub_template_message %></p>
17
17
 
18
18
  <%= render "rescues/trace", traces: @traces, trace_to_show: @trace_to_show %>
19
19
  <%= render template: "rescues/_request_and_response" %>
20
- </div>
20
+ </main>
@@ -1,6 +1,6 @@
1
- <header>
1
+ <header role="banner">
2
2
  <h1>Unknown action</h1>
3
3
  </header>
4
- <div id="container">
5
- <%= render "rescues/message_and_suggestions", exception: @exception %>
6
- </div>
4
+ <main role="main" id="container">
5
+ <%= render "rescues/message_and_suggestions", exception: @exception, exception_wrapper: @exception_wrapper %>
6
+ </main>
@@ -1,3 +1,3 @@
1
1
  Unknown action
2
2
 
3
- <%= @exception.message %>
3
+ <%= @exception_wrapper.message %>
@@ -13,4 +13,7 @@
13
13
  <td>
14
14
  <%=simple_format route[:reqs] %>
15
15
  </td>
16
+ <td>
17
+ <%=simple_format route[:source_location] %>
18
+ </td>
16
19
  </tr>
@@ -1,24 +1,45 @@
1
1
  <% content_for :style do %>
2
+ h2, p {
3
+ padding-left: 30px;
4
+ }
5
+
2
6
  #route_table {
3
7
  margin: 0;
4
8
  border-collapse: collapse;
9
+ word-wrap:break-word;
10
+ table-layout: fixed;
11
+ width:100%;
5
12
  }
6
13
 
7
14
  #route_table thead tr {
8
15
  border-bottom: 2px solid #ddd;
9
16
  }
10
17
 
18
+ #route_table th {
19
+ padding-left: 30px;
20
+ text-align: left;
21
+ }
22
+
11
23
  #route_table thead tr.bottom {
12
24
  border-bottom: none;
13
25
  }
14
26
 
15
27
  #route_table thead tr.bottom th {
16
- padding: 10px 0;
28
+ padding: 10px 30px;
17
29
  line-height: 15px;
18
30
  }
19
31
 
20
- #route_table thead tr.bottom th input#search {
32
+ #route_table #search_container {
33
+ padding: 7px 30px;
34
+ }
35
+
36
+ #route_table thead tr th input#search {
21
37
  -webkit-appearance: textfield;
38
+ width:100%;
39
+ }
40
+
41
+ #route_table thead th.http-verb {
42
+ width: 10%;
22
43
  }
23
44
 
24
45
  #route_table tbody tr {
@@ -45,54 +66,34 @@
45
66
  padding: 4px 30px;
46
67
  }
47
68
 
48
- #path_search {
49
- width: 80%;
50
- font-size: inherit;
51
- }
52
-
53
69
  @media (prefers-color-scheme: dark) {
54
- body {
55
- background-color: #222;
56
- color: #ECECEC;
57
- }
58
-
59
70
  #route_table tbody tr:nth-child(odd) {
60
- background: #333;
61
- }
62
-
63
- #route_table tbody tr:nth-child(even) {
64
- background: #444;
71
+ background: #282828;
65
72
  }
66
73
 
67
- #route_table tbody.exact_matches,
68
- #route_table tbody.fuzzy_matches {
69
- color: #333;
74
+ #route_table tbody.exact_matches tr,
75
+ #route_table tbody.fuzzy_matches tr {
76
+ background: DarkSlateGrey;
70
77
  }
71
78
  }
72
79
  <% end %>
73
80
 
74
- <table id='route_table' class='route_table'>
81
+ <table id='route_table'>
75
82
  <thead>
76
83
  <tr>
77
- <th>Helper</th>
78
- <th>HTTP Verb</th>
79
- <th>Path</th>
80
- <th>Controller#Action</th>
81
- </tr>
82
- <tr class='bottom'>
83
- <th><%# Helper %>
84
- <%= link_to "Path", "#", 'data-route-helper' => '_path',
84
+ <th>Helper
85
+ (<%= link_to "Path", "#", 'data-route-helper' => '_path',
85
86
  title: "Returns a relative path (without the http or domain)" %> /
86
87
  <%= link_to "Url", "#", 'data-route-helper' => '_url',
87
- title: "Returns an absolute URL (with the http and domain)" %>
88
- </th>
89
- <th><%# HTTP Verb %>
90
- </th>
91
- <th><%# Path %>
92
- <%= search_field(:path, nil, id: 'search', placeholder: "Path Match") %>
93
- </th>
94
- <th><%# Controller#action %>
88
+ title: "Returns an absolute URL (with the http and domain)" %>)
95
89
  </th>
90
+ <th class="http-verb">HTTP Verb</th>
91
+ <th>Path</th>
92
+ <th>Controller#Action</th>
93
+ <th>Source Location</th>
94
+ </tr>
95
+ <tr>
96
+ <th colspan="5" id="search_container"><%= search_field(:query, nil, id: 'search', placeholder: "Search") %></th>
96
97
  </tr>
97
98
  </thead>
98
99
  <tbody class='exact_matches' id='exact_matches'>
@@ -104,16 +105,16 @@
104
105
  </tbody>
105
106
  </table>
106
107
 
107
- <script type='text/javascript'>
108
+ <script>
108
109
  // support forEach iterator on NodeList
109
110
  NodeList.prototype.forEach = Array.prototype.forEach;
110
111
 
111
- // Enables path search functionality
112
- function setupMatchPaths() {
112
+ // Enables query search functionality
113
+ function setupMatchingRoutes() {
113
114
  // Check if there are any matched results in a section
114
- function checkNoMatch(section, noMatchText) {
115
+ function checkNoMatch(section, trElement) {
115
116
  if (section.children.length <= 1) {
116
- section.innerHTML += noMatchText;
117
+ section.appendChild(trElement);
117
118
  }
118
119
  }
119
120
 
@@ -137,8 +138,8 @@
137
138
  }
138
139
 
139
140
  // remove params or fragments
140
- function sanitizePath(path) {
141
- return path.replace(/[#?].*/, '');
141
+ function sanitizeQuery(query) {
142
+ return query.replace(/[#?].*/, '');
142
143
  }
143
144
 
144
145
  var pathElements = document.querySelectorAll('#route_table [data-route-path]'),
@@ -154,26 +155,34 @@
154
155
  }
155
156
  }
156
157
 
158
+ function buildTr(string) {
159
+ var tr = document.createElement('tr');
160
+ var th = document.createElement('th');
161
+ th.setAttribute('colspan', 4);
162
+ tr.appendChild(th);
163
+ th.innerText = string;
164
+ return tr;
165
+ }
166
+
157
167
  // On key press perform a search for matching paths
158
168
  delayedKeyup(searchElem, function() {
159
- var path = sanitizePath(searchElem.value),
160
- defaultExactMatch = '<tr><th colspan="4">Paths Matching (' + path +'):</th></tr>',
161
- defaultFuzzyMatch = '<tr><th colspan="4">Paths Containing (' + path +'):</th></tr>',
162
- noExactMatch = '<tr><th colspan="4">No Exact Matches Found</th></tr>',
163
- noFuzzyMatch = '<tr><th colspan="4">No Fuzzy Matches Found</th></tr>';
169
+ var query = sanitizeQuery(searchElem.value),
170
+ defaultExactMatch = buildTr("Routes matching '" + query + "':"),
171
+ defaultFuzzyMatch = buildTr("Routes containing '" + query + "':"),
172
+ noExactMatch = buildTr('No exact matches found'),
173
+ noFuzzyMatch = buildTr('No fuzzy matches found');
164
174
 
165
- if (!path)
175
+ if (!query)
166
176
  return searchElem.onblur();
167
177
 
168
- getJSON('/rails/info/routes?path=' + path, function(matches){
178
+ getJSON('/rails/info/routes?query=' + query, function(matches){
169
179
  // Clear out results section
170
- exactSection.innerHTML = defaultExactMatch;
171
- fuzzySection.innerHTML = defaultFuzzyMatch;
180
+ exactSection.replaceChildren(defaultExactMatch);
181
+ fuzzySection.replaceChildren(defaultFuzzyMatch);
172
182
 
173
183
  // Display exact matches and fuzzy matches
174
184
  pathElements.forEach(function(elem) {
175
185
  var elemPath = elem.getAttribute('data-route-path');
176
-
177
186
  if (matches['exact'].indexOf(elemPath) != -1)
178
187
  exactSection.appendChild(elem.parentNode.cloneNode(true));
179
188
 
@@ -215,7 +224,7 @@
215
224
  });
216
225
  }
217
226
 
218
- setupMatchPaths();
227
+ setupMatchingRoutes();
219
228
  setupRouteToggleHelperLinks();
220
229
 
221
230
  // Focus the search input after page has loaded
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "action_dispatch"
4
+ require "action_dispatch/log_subscriber"
4
5
  require "active_support/messages/rotation_configuration"
5
6
 
6
7
  module ActionDispatch
@@ -8,7 +9,7 @@ module ActionDispatch
8
9
  config.action_dispatch = ActiveSupport::OrderedOptions.new
9
10
  config.action_dispatch.x_sendfile_header = nil
10
11
  config.action_dispatch.ip_spoofing_check = true
11
- config.action_dispatch.show_exceptions = true
12
+ config.action_dispatch.show_exceptions = :all
12
13
  config.action_dispatch.tld_length = 1
13
14
  config.action_dispatch.ignore_accept_header = false
14
15
  config.action_dispatch.rescue_templates = {}
@@ -23,7 +24,9 @@ module ActionDispatch
23
24
  config.action_dispatch.use_authenticated_cookie_encryption = false
24
25
  config.action_dispatch.use_cookies_with_metadata = false
25
26
  config.action_dispatch.perform_deep_munge = true
26
- config.action_dispatch.request_id_header = "X-Request-Id"
27
+ config.action_dispatch.request_id_header = ActionDispatch::Constants::X_REQUEST_ID
28
+ config.action_dispatch.log_rescued_responses = true
29
+ config.action_dispatch.debug_exception_log_level = :fatal
27
30
 
28
31
  config.action_dispatch.default_headers = {
29
32
  "X-Frame-Options" => "SAMEORIGIN",
@@ -38,11 +41,21 @@ module ActionDispatch
38
41
 
39
42
  config.eager_load_namespaces << ActionDispatch
40
43
 
44
+ initializer "action_dispatch.deprecator", before: :load_environment_config do |app|
45
+ app.deprecators[:action_dispatch] = ActionDispatch.deprecator
46
+ end
47
+
41
48
  initializer "action_dispatch.configure" do |app|
42
49
  ActionDispatch::Http::URL.secure_protocol = app.config.force_ssl
43
50
  ActionDispatch::Http::URL.tld_length = app.config.action_dispatch.tld_length
44
- ActionDispatch::Request.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
45
- ActionDispatch::Request::Utils.perform_deep_munge = app.config.action_dispatch.perform_deep_munge
51
+
52
+ ActiveSupport.on_load(:action_dispatch_request) do
53
+ self.ignore_accept_header = app.config.action_dispatch.ignore_accept_header
54
+ unless app.config.action_dispatch.respond_to?(:return_only_request_media_type_on_content_type)
55
+ self.return_only_media_type_on_content_type = app.config.action_dispatch.return_only_request_media_type_on_content_type
56
+ end
57
+ ActionDispatch::Request::Utils.perform_deep_munge = app.config.action_dispatch.perform_deep_munge
58
+ end
46
59
 
47
60
  ActiveSupport.on_load(:action_dispatch_response) do
48
61
  self.default_charset = app.config.action_dispatch.default_charset || app.config.encoding
@@ -55,6 +68,9 @@ module ActionDispatch
55
68
  config.action_dispatch.always_write_cookie = Rails.env.development? if config.action_dispatch.always_write_cookie.nil?
56
69
  ActionDispatch::Cookies::CookieJar.always_write_cookie = config.action_dispatch.always_write_cookie
57
70
 
71
+ ActionDispatch::Routing::Mapper.route_source_locations = Rails.env.development?
72
+ ActionDispatch::Routing::Mapper.backtrace_cleaner = Rails.backtrace_cleaner
73
+
58
74
  ActionDispatch.test_app = app
59
75
  end
60
76
  end
@@ -6,6 +6,7 @@ module ActionDispatch
6
6
  class Request
7
7
  # Session is responsible for lazily loading the session from store.
8
8
  class Session # :nodoc:
9
+ DisabledSessionError = Class.new(StandardError)
9
10
  ENV_SESSION_KEY = Rack::RACK_SESSION # :nodoc:
10
11
  ENV_SESSION_OPTIONS_KEY = Rack::RACK_SESSION_OPTIONS # :nodoc:
11
12
 
@@ -23,6 +24,12 @@ module ActionDispatch
23
24
  session
24
25
  end
25
26
 
27
+ def self.disabled(req)
28
+ new(nil, req, enabled: false).tap do
29
+ Session::Options.set(req, Session::Options.new(nil, { id: nil }))
30
+ end
31
+ end
32
+
26
33
  def self.find(req)
27
34
  req.get_header ENV_SESSION_KEY
28
35
  end
@@ -31,7 +38,11 @@ module ActionDispatch
31
38
  req.set_header ENV_SESSION_KEY, session
32
39
  end
33
40
 
34
- class Options #:nodoc:
41
+ def self.delete(req)
42
+ req.delete_header ENV_SESSION_KEY
43
+ end
44
+
45
+ class Options # :nodoc:
35
46
  def self.set(req, options)
36
47
  req.set_header ENV_SESSION_OPTIONS_KEY, options
37
48
  end
@@ -60,30 +71,40 @@ module ActionDispatch
60
71
  def values_at(*args); @delegate.values_at(*args); end
61
72
  end
62
73
 
63
- def initialize(by, req)
74
+ def initialize(by, req, enabled: true)
64
75
  @by = by
65
76
  @req = req
66
77
  @delegate = {}
67
78
  @loaded = false
68
79
  @exists = nil # We haven't checked yet.
80
+ @enabled = enabled
81
+ @id_was = nil
82
+ @id_was_initialized = false
69
83
  end
70
84
 
71
85
  def id
72
86
  options.id(@req)
73
87
  end
74
88
 
89
+ def enabled?
90
+ @enabled
91
+ end
92
+
75
93
  def options
76
94
  Options.find @req
77
95
  end
78
96
 
79
97
  def destroy
80
98
  clear
81
- options = self.options || {}
82
- @by.send(:delete_session, @req, options.id(@req), options)
83
99
 
84
- # Load the new sid to be written with the response.
85
- @loaded = false
86
- load_for_write!
100
+ if enabled?
101
+ options = self.options || {}
102
+ @by.send(:delete_session, @req, options.id(@req), options)
103
+
104
+ # Load the new sid to be written with the response.
105
+ @loaded = false
106
+ load_for_write!
107
+ end
87
108
  end
88
109
 
89
110
  # Returns value of the key stored in the session or
@@ -135,7 +156,7 @@ module ActionDispatch
135
156
 
136
157
  # Clears the session.
137
158
  def clear
138
- load_for_write!
159
+ load_for_delete!
139
160
  @delegate.clear
140
161
  end
141
162
 
@@ -157,13 +178,18 @@ module ActionDispatch
157
178
  # session.to_hash
158
179
  # # => {"session_id"=>"e29b9ea315edf98aad94cc78c34cc9b2", "foo" => "bar"}
159
180
  def update(hash)
181
+ unless hash.respond_to?(:to_hash)
182
+ raise TypeError, "no implicit conversion of #{hash.class.name} into Hash"
183
+ end
184
+
160
185
  load_for_write!
161
- @delegate.update hash.stringify_keys
186
+ @delegate.update hash.to_hash.stringify_keys
162
187
  end
188
+ alias :merge! :update
163
189
 
164
190
  # Deletes given key from the session.
165
191
  def delete(key)
166
- load_for_write!
192
+ load_for_delete!
167
193
  @delegate.delete key.to_s
168
194
  end
169
195
 
@@ -199,6 +225,7 @@ module ActionDispatch
199
225
  end
200
226
 
201
227
  def exists?
228
+ return false unless enabled?
202
229
  return @exists unless @exists.nil?
203
230
  @exists = @by.send(:session_exists?, @req)
204
231
  end
@@ -212,28 +239,41 @@ module ActionDispatch
212
239
  @delegate.empty?
213
240
  end
214
241
 
215
- def merge!(other)
216
- load_for_write!
217
- @delegate.merge!(other)
218
- end
219
-
220
242
  def each(&block)
221
243
  to_hash.each(&block)
222
244
  end
223
245
 
246
+ def id_was
247
+ load_for_read!
248
+ @id_was
249
+ end
250
+
224
251
  private
225
252
  def load_for_read!
226
253
  load! if !loaded? && exists?
227
254
  end
228
255
 
229
256
  def load_for_write!
230
- load! unless loaded?
257
+ if enabled?
258
+ load! unless loaded?
259
+ else
260
+ raise DisabledSessionError, "Your application has sessions disabled. To write to the session you must first configure a session store"
261
+ end
262
+ end
263
+
264
+ def load_for_delete!
265
+ load! if enabled? && !loaded?
231
266
  end
232
267
 
233
268
  def load!
234
- id, session = @by.load_session @req
235
- options[:id] = id
236
- @delegate.replace(session.stringify_keys)
269
+ if enabled?
270
+ @id_was_initialized = true unless exists?
271
+ id, session = @by.load_session @req
272
+ options[:id] = id
273
+ @delegate.replace(session.stringify_keys)
274
+ @id_was = id unless @id_was_initialized
275
+ end
276
+ @id_was_initialized = true
237
277
  @loaded = true
238
278
  end
239
279
  end
@@ -55,9 +55,11 @@ module ActionDispatch
55
55
  if params.has_key?(:tempfile)
56
56
  ActionDispatch::Http::UploadedFile.new(params)
57
57
  else
58
- params.transform_values do |val|
59
- normalize_encode_params(val)
60
- end.with_indifferent_access
58
+ hwia = ActiveSupport::HashWithIndifferentAccess.new
59
+ params.each_pair do |key, val|
60
+ hwia[key] = normalize_encode_params(val)
61
+ end
62
+ hwia
61
63
  end
62
64
  else
63
65
  params
@@ -83,6 +85,9 @@ module ActionDispatch
83
85
  return params unless controller && controller.valid_encoding? && encoding_template = action_encoding_template(request, controller, action)
84
86
  params.except(:controller, :action).each do |key, value|
85
87
  ActionDispatch::Request::Utils.each_param_value(value) do |param|
88
+ # If `param` is frozen, it comes from the router defaults
89
+ next if param.frozen?
90
+
86
91
  if encoding_template[key.to_s]
87
92
  param.force_encoding(encoding_template[key.to_s])
88
93
  end
@@ -5,9 +5,22 @@ require "io/console/size"
5
5
 
6
6
  module ActionDispatch
7
7
  module Routing
8
- class RouteWrapper < SimpleDelegator
8
+ class RouteWrapper < SimpleDelegator # :nodoc:
9
+ def matches_filter?(filter, value)
10
+ return __getobj__.path.match(value) if filter == :exact_path_match
11
+
12
+ value.match?(public_send(filter))
13
+ end
14
+
9
15
  def endpoint
10
- app.dispatcher? ? "#{controller}##{action}" : rack_app.inspect
16
+ case
17
+ when app.dispatcher?
18
+ "#{controller}##{action}"
19
+ when rack_app.is_a?(Proc)
20
+ "Inline handler (Proc/Lambda)"
21
+ else
22
+ rack_app.inspect
23
+ end
11
24
  end
12
25
 
13
26
  def constraints
@@ -85,8 +98,18 @@ module ActionDispatch
85
98
  if filter[:controller]
86
99
  { controller: /#{filter[:controller].underscore.sub(/_?controller\z/, "")}/ }
87
100
  elsif filter[:grep]
88
- { controller: /#{filter[:grep]}/, action: /#{filter[:grep]}/,
89
- verb: /#{filter[:grep]}/, name: /#{filter[:grep]}/, path: /#{filter[:grep]}/ }
101
+ grep_pattern = Regexp.new(filter[:grep])
102
+ path = URI::DEFAULT_PARSER.escape(filter[:grep])
103
+ normalized_path = ("/" + path).squeeze("/")
104
+
105
+ {
106
+ controller: grep_pattern,
107
+ action: grep_pattern,
108
+ verb: grep_pattern,
109
+ name: grep_pattern,
110
+ path: grep_pattern,
111
+ exact_path_match: normalized_path,
112
+ }
90
113
  end
91
114
  end
92
115
 
@@ -94,7 +117,7 @@ module ActionDispatch
94
117
  if filter
95
118
  @routes.select do |route|
96
119
  route_wrapper = RouteWrapper.new(route)
97
- filter.any? { |default, value| value.match?(route_wrapper.send(default)) }
120
+ filter.any? { |filter_type, value| route_wrapper.matches_filter?(filter_type, value) }
98
121
  end
99
122
  else
100
123
  @routes
@@ -110,7 +133,8 @@ module ActionDispatch
110
133
  { name: route.name,
111
134
  verb: route.verb,
112
135
  path: route.path,
113
- reqs: route.reqs }
136
+ reqs: route.reqs,
137
+ source_location: route.source_location }
114
138
  end
115
139
  end
116
140
 
@@ -216,13 +240,16 @@ module ActionDispatch
216
240
  private
217
241
  def draw_expanded_section(routes)
218
242
  routes.map.each_with_index do |r, i|
219
- <<~MESSAGE.chomp
243
+ route_rows = <<~MESSAGE.chomp
220
244
  #{route_header(index: i + 1)}
221
245
  Prefix | #{r[:name]}
222
246
  Verb | #{r[:verb]}
223
247
  URI | #{r[:path]}
224
248
  Controller#Action | #{r[:reqs]}
225
249
  MESSAGE
250
+ source_location = "\nSource Location | #{r[:source_location]}"
251
+ route_rows += source_location if r[:source_location].present?
252
+ route_rows
226
253
  end
227
254
  end
228
255
 
@@ -230,6 +257,27 @@ module ActionDispatch
230
257
  "--[ Route #{index} ]".ljust(@width, "-")
231
258
  end
232
259
  end
260
+
261
+ class Unused < Sheet
262
+ def header(routes)
263
+ @buffer << <<~MSG
264
+ Found #{routes.count} unused #{"route".pluralize(routes.count)}:
265
+ MSG
266
+
267
+ super
268
+ end
269
+
270
+ def no_routes(routes, filter)
271
+ @buffer <<
272
+ if filter.none?
273
+ "No unused routes found."
274
+ elsif filter.key?(:controller)
275
+ "No unused routes found for this controller."
276
+ elsif filter.key?(:grep)
277
+ "No unused routes found for this grep pattern."
278
+ end
279
+ end
280
+ end
233
281
  end
234
282
 
235
283
  class HtmlTableFormatter