actionpack 4.2.10 → 7.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


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

Files changed (202) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +86 -600
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +13 -14
  5. data/lib/abstract_controller/asset_paths.rb +5 -1
  6. data/lib/abstract_controller/base.rb +166 -136
  7. data/lib/abstract_controller/caching/fragments.rb +149 -0
  8. data/lib/abstract_controller/caching.rb +68 -0
  9. data/lib/abstract_controller/callbacks.rb +126 -57
  10. data/lib/abstract_controller/collector.rb +13 -15
  11. data/lib/abstract_controller/deprecator.rb +9 -0
  12. data/lib/abstract_controller/error.rb +8 -0
  13. data/lib/abstract_controller/helpers.rb +181 -132
  14. data/lib/abstract_controller/logger.rb +5 -1
  15. data/lib/abstract_controller/railties/routes_helpers.rb +10 -3
  16. data/lib/abstract_controller/rendering.rb +56 -56
  17. data/lib/abstract_controller/translation.rb +29 -15
  18. data/lib/abstract_controller/url_for.rb +15 -11
  19. data/lib/abstract_controller.rb +21 -5
  20. data/lib/action_controller/api/api_rendering.rb +18 -0
  21. data/lib/action_controller/api.rb +154 -0
  22. data/lib/action_controller/base.rb +219 -155
  23. data/lib/action_controller/caching.rb +28 -68
  24. data/lib/action_controller/deprecator.rb +9 -0
  25. data/lib/action_controller/form_builder.rb +55 -0
  26. data/lib/action_controller/log_subscriber.rb +35 -22
  27. data/lib/action_controller/metal/allow_browser.rb +119 -0
  28. data/lib/action_controller/metal/basic_implicit_render.rb +17 -0
  29. data/lib/action_controller/metal/conditional_get.rb +259 -122
  30. data/lib/action_controller/metal/content_security_policy.rb +86 -0
  31. data/lib/action_controller/metal/cookies.rb +9 -5
  32. data/lib/action_controller/metal/data_streaming.rb +87 -104
  33. data/lib/action_controller/metal/default_headers.rb +21 -0
  34. data/lib/action_controller/metal/etag_with_flash.rb +22 -0
  35. data/lib/action_controller/metal/etag_with_template_digest.rb +35 -26
  36. data/lib/action_controller/metal/exceptions.rb +71 -24
  37. data/lib/action_controller/metal/flash.rb +26 -19
  38. data/lib/action_controller/metal/head.rb +45 -36
  39. data/lib/action_controller/metal/helpers.rb +80 -64
  40. data/lib/action_controller/metal/http_authentication.rb +297 -244
  41. data/lib/action_controller/metal/implicit_render.rb +57 -9
  42. data/lib/action_controller/metal/instrumentation.rb +76 -64
  43. data/lib/action_controller/metal/live.rb +238 -176
  44. data/lib/action_controller/metal/logging.rb +22 -0
  45. data/lib/action_controller/metal/mime_responds.rb +177 -166
  46. data/lib/action_controller/metal/parameter_encoding.rb +84 -0
  47. data/lib/action_controller/metal/params_wrapper.rb +145 -118
  48. data/lib/action_controller/metal/permissions_policy.rb +38 -0
  49. data/lib/action_controller/metal/rate_limiting.rb +62 -0
  50. data/lib/action_controller/metal/redirecting.rb +203 -64
  51. data/lib/action_controller/metal/renderers.rb +108 -65
  52. data/lib/action_controller/metal/rendering.rb +216 -56
  53. data/lib/action_controller/metal/request_forgery_protection.rb +496 -163
  54. data/lib/action_controller/metal/rescue.rb +19 -21
  55. data/lib/action_controller/metal/streaming.rb +179 -138
  56. data/lib/action_controller/metal/strong_parameters.rb +1058 -382
  57. data/lib/action_controller/metal/testing.rb +11 -17
  58. data/lib/action_controller/metal/url_for.rb +37 -21
  59. data/lib/action_controller/metal.rb +236 -138
  60. data/lib/action_controller/railtie.rb +89 -11
  61. data/lib/action_controller/railties/helpers.rb +5 -1
  62. data/lib/action_controller/renderer.rb +161 -0
  63. data/lib/action_controller/template_assertions.rb +13 -0
  64. data/lib/action_controller/test_case.rb +425 -497
  65. data/lib/action_controller.rb +44 -22
  66. data/lib/action_dispatch/constants.rb +34 -0
  67. data/lib/action_dispatch/deprecator.rb +9 -0
  68. data/lib/action_dispatch/http/cache.rb +119 -63
  69. data/lib/action_dispatch/http/content_disposition.rb +47 -0
  70. data/lib/action_dispatch/http/content_security_policy.rb +364 -0
  71. data/lib/action_dispatch/http/filter_parameters.rb +36 -34
  72. data/lib/action_dispatch/http/filter_redirect.rb +24 -12
  73. data/lib/action_dispatch/http/headers.rb +66 -31
  74. data/lib/action_dispatch/http/mime_negotiation.rb +106 -75
  75. data/lib/action_dispatch/http/mime_type.rb +196 -136
  76. data/lib/action_dispatch/http/mime_types.rb +25 -7
  77. data/lib/action_dispatch/http/parameters.rb +97 -45
  78. data/lib/action_dispatch/http/permissions_policy.rb +187 -0
  79. data/lib/action_dispatch/http/rack_cache.rb +6 -0
  80. data/lib/action_dispatch/http/request.rb +299 -170
  81. data/lib/action_dispatch/http/response.rb +311 -160
  82. data/lib/action_dispatch/http/upload.rb +52 -23
  83. data/lib/action_dispatch/http/url.rb +201 -125
  84. data/lib/action_dispatch/journey/formatter.rb +110 -50
  85. data/lib/action_dispatch/journey/gtg/builder.rb +37 -50
  86. data/lib/action_dispatch/journey/gtg/simulator.rb +20 -17
  87. data/lib/action_dispatch/journey/gtg/transition_table.rb +96 -36
  88. data/lib/action_dispatch/journey/nfa/dot.rb +5 -14
  89. data/lib/action_dispatch/journey/nodes/node.rb +100 -20
  90. data/lib/action_dispatch/journey/parser.rb +19 -17
  91. data/lib/action_dispatch/journey/parser.y +4 -3
  92. data/lib/action_dispatch/journey/parser_extras.rb +14 -4
  93. data/lib/action_dispatch/journey/path/pattern.rb +79 -63
  94. data/lib/action_dispatch/journey/route.rb +108 -44
  95. data/lib/action_dispatch/journey/router/utils.rb +41 -29
  96. data/lib/action_dispatch/journey/router.rb +64 -57
  97. data/lib/action_dispatch/journey/routes.rb +23 -21
  98. data/lib/action_dispatch/journey/scanner.rb +28 -17
  99. data/lib/action_dispatch/journey/visitors.rb +100 -54
  100. data/lib/action_dispatch/journey/visualizer/fsm.js +49 -24
  101. data/lib/action_dispatch/journey/visualizer/index.html.erb +1 -1
  102. data/lib/action_dispatch/journey.rb +7 -5
  103. data/lib/action_dispatch/log_subscriber.rb +25 -0
  104. data/lib/action_dispatch/middleware/actionable_exceptions.rb +46 -0
  105. data/lib/action_dispatch/middleware/assume_ssl.rb +27 -0
  106. data/lib/action_dispatch/middleware/callbacks.rb +7 -6
  107. data/lib/action_dispatch/middleware/cookies.rb +471 -328
  108. data/lib/action_dispatch/middleware/debug_exceptions.rb +149 -66
  109. data/lib/action_dispatch/middleware/debug_locks.rb +129 -0
  110. data/lib/action_dispatch/middleware/debug_view.rb +73 -0
  111. data/lib/action_dispatch/middleware/exception_wrapper.rb +275 -73
  112. data/lib/action_dispatch/middleware/executor.rb +32 -0
  113. data/lib/action_dispatch/middleware/flash.rb +143 -101
  114. data/lib/action_dispatch/middleware/host_authorization.rb +171 -0
  115. data/lib/action_dispatch/middleware/public_exceptions.rb +36 -27
  116. data/lib/action_dispatch/middleware/reloader.rb +10 -92
  117. data/lib/action_dispatch/middleware/remote_ip.rb +133 -107
  118. data/lib/action_dispatch/middleware/request_id.rb +29 -15
  119. data/lib/action_dispatch/middleware/server_timing.rb +78 -0
  120. data/lib/action_dispatch/middleware/session/abstract_store.rb +49 -27
  121. data/lib/action_dispatch/middleware/session/cache_store.rb +33 -16
  122. data/lib/action_dispatch/middleware/session/cookie_store.rb +86 -80
  123. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +15 -3
  124. data/lib/action_dispatch/middleware/show_exceptions.rb +66 -36
  125. data/lib/action_dispatch/middleware/ssl.rb +134 -36
  126. data/lib/action_dispatch/middleware/stack.rb +109 -44
  127. data/lib/action_dispatch/middleware/static.rb +159 -90
  128. data/lib/action_dispatch/middleware/templates/rescues/_actions.html.erb +13 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/_actions.text.erb +0 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/_message_and_suggestions.html.erb +22 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +7 -24
  132. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +1 -1
  133. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +36 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +46 -36
  136. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +12 -0
  137. data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +9 -0
  138. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +26 -7
  139. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +3 -3
  140. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +24 -0
  141. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +16 -0
  142. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +139 -15
  143. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.html.erb +23 -0
  144. data/lib/action_dispatch/middleware/templates/rescues/missing_exact_template.text.erb +3 -0
  145. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +6 -6
  146. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +7 -7
  147. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +9 -9
  148. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +1 -1
  149. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +4 -4
  150. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +1 -1
  151. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +7 -4
  152. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +125 -93
  153. data/lib/action_dispatch/railtie.rb +44 -16
  154. data/lib/action_dispatch/request/session.rb +159 -69
  155. data/lib/action_dispatch/request/utils.rb +97 -23
  156. data/lib/action_dispatch/routing/endpoint.rb +11 -2
  157. data/lib/action_dispatch/routing/inspector.rb +195 -106
  158. data/lib/action_dispatch/routing/mapper.rb +1338 -955
  159. data/lib/action_dispatch/routing/polymorphic_routes.rb +234 -201
  160. data/lib/action_dispatch/routing/redirection.rb +78 -51
  161. data/lib/action_dispatch/routing/route_set.rb +460 -374
  162. data/lib/action_dispatch/routing/routes_proxy.rb +36 -12
  163. data/lib/action_dispatch/routing/url_for.rb +172 -124
  164. data/lib/action_dispatch/routing.rb +159 -158
  165. data/lib/action_dispatch/system_test_case.rb +206 -0
  166. data/lib/action_dispatch/system_testing/browser.rb +84 -0
  167. data/lib/action_dispatch/system_testing/driver.rb +85 -0
  168. data/lib/action_dispatch/system_testing/server.rb +33 -0
  169. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +164 -0
  170. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +23 -0
  171. data/lib/action_dispatch/testing/assertion_response.rb +48 -0
  172. data/lib/action_dispatch/testing/assertions/response.rb +71 -39
  173. data/lib/action_dispatch/testing/assertions/routing.rb +228 -103
  174. data/lib/action_dispatch/testing/assertions.rb +9 -6
  175. data/lib/action_dispatch/testing/integration.rb +486 -306
  176. data/lib/action_dispatch/testing/request_encoder.rb +60 -0
  177. data/lib/action_dispatch/testing/test_helpers/page_dump_helper.rb +35 -0
  178. data/lib/action_dispatch/testing/test_process.rb +35 -22
  179. data/lib/action_dispatch/testing/test_request.rb +29 -34
  180. data/lib/action_dispatch/testing/test_response.rb +48 -15
  181. data/lib/action_dispatch.rb +82 -40
  182. data/lib/action_pack/gem_version.rb +8 -4
  183. data/lib/action_pack/version.rb +6 -2
  184. data/lib/action_pack.rb +21 -18
  185. metadata +146 -56
  186. data/lib/action_controller/caching/fragments.rb +0 -103
  187. data/lib/action_controller/metal/force_ssl.rb +0 -97
  188. data/lib/action_controller/metal/hide_actions.rb +0 -40
  189. data/lib/action_controller/metal/rack_delegation.rb +0 -32
  190. data/lib/action_controller/middleware.rb +0 -39
  191. data/lib/action_controller/model_naming.rb +0 -12
  192. data/lib/action_dispatch/http/parameter_filter.rb +0 -72
  193. data/lib/action_dispatch/journey/backwards.rb +0 -5
  194. data/lib/action_dispatch/journey/nfa/builder.rb +0 -76
  195. data/lib/action_dispatch/journey/nfa/simulator.rb +0 -47
  196. data/lib/action_dispatch/journey/nfa/transition_table.rb +0 -163
  197. data/lib/action_dispatch/journey/router/strexp.rb +0 -27
  198. data/lib/action_dispatch/middleware/params_parser.rb +0 -60
  199. data/lib/action_dispatch/middleware/templates/rescues/_source.erb +0 -27
  200. data/lib/action_dispatch/testing/assertions/dom.rb +0 -3
  201. data/lib/action_dispatch/testing/assertions/selector.rb +0 -3
  202. data/lib/action_dispatch/testing/assertions/tag.rb +0 -3
@@ -1,23 +1,45 @@
1
- require 'set'
2
- require 'singleton'
3
- require 'active_support/core_ext/module/attribute_accessors'
4
- require 'active_support/core_ext/string/starts_ends_with'
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ require "singleton"
5
6
 
6
7
  module Mime
7
- class Mimes < Array
8
- def symbols
9
- @symbols ||= map { |m| m.to_sym }
8
+ class Mimes
9
+ attr_reader :symbols
10
+
11
+ include Enumerable
12
+
13
+ def initialize
14
+ @mimes = []
15
+ @symbols = []
16
+ @symbols_set = Set.new
10
17
  end
11
18
 
12
- %w(<< concat shift unshift push pop []= clear compact! collect!
13
- delete delete_at delete_if flatten! map! insert reject! reverse!
14
- replace slice! sort! uniq!).each do |method|
15
- module_eval <<-CODE, __FILE__, __LINE__ + 1
16
- def #{method}(*)
17
- @symbols = nil
18
- super
19
+ def each(&block)
20
+ @mimes.each(&block)
21
+ end
22
+
23
+ def <<(type)
24
+ @mimes << type
25
+ sym_type = type.to_sym
26
+ @symbols << sym_type
27
+ @symbols_set << sym_type
28
+ end
29
+
30
+ def delete_if
31
+ @mimes.delete_if do |x|
32
+ if yield x
33
+ sym_type = x.to_sym
34
+ @symbols.delete(sym_type)
35
+ @symbols_set.delete(sym_type)
36
+ true
19
37
  end
20
- CODE
38
+ end
39
+ end
40
+
41
+ def valid_symbols?(symbols) # :nodoc
42
+ symbols.all? { |s| @symbols_set.include?(s) }
21
43
  end
22
44
  end
23
45
 
@@ -31,42 +53,48 @@ module Mime
31
53
  Type.lookup_by_extension(type)
32
54
  end
33
55
 
34
- def fetch(type)
56
+ def symbols
57
+ SET.symbols
58
+ end
59
+
60
+ def valid_symbols?(symbols) # :nodoc:
61
+ SET.valid_symbols?(symbols)
62
+ end
63
+
64
+ def fetch(type, &block)
35
65
  return type if type.is_a?(Type)
36
- EXTENSION_LOOKUP.fetch(type.to_s) { |k| yield k }
66
+ EXTENSION_LOOKUP.fetch(type.to_s, &block)
37
67
  end
38
68
  end
39
69
 
40
- # Encapsulates the notion of a mime type. Can be used at render time, for example, with:
70
+ # Encapsulates the notion of a MIME type. Can be used at render time, for
71
+ # example, with:
41
72
  #
42
- # class PostsController < ActionController::Base
43
- # def show
44
- # @post = Post.find(params[:id])
73
+ # class PostsController < ActionController::Base
74
+ # def show
75
+ # @post = Post.find(params[:id])
45
76
  #
46
- # respond_to do |format|
47
- # format.html
48
- # format.ics { render text: @post.to_ics, mime_type: Mime::Type["text/calendar"] }
49
- # format.xml { render xml: @post }
77
+ # respond_to do |format|
78
+ # format.html
79
+ # format.ics { render body: @post.to_ics, mime_type: Mime::Type.lookup("text/calendar") }
80
+ # format.xml { render xml: @post }
81
+ # end
50
82
  # end
51
83
  # end
52
- # end
53
84
  class Type
54
- @@html_types = Set.new [:html, :all]
55
- cattr_reader :html_types
56
-
57
85
  attr_reader :symbol
58
86
 
59
87
  @register_callbacks = []
60
88
 
61
- # A simple helper class used in parsing the accept header
62
- class AcceptItem #:nodoc:
89
+ # A simple helper class used in parsing the accept header.
90
+ class AcceptItem # :nodoc:
63
91
  attr_accessor :index, :name, :q
64
92
  alias :to_s :name
65
93
 
66
94
  def initialize(index, name, q = nil)
67
95
  @index = index
68
96
  @name = name
69
- q ||= 0.0 if @name == Mime::ALL.to_s # default wildcard match to end of list
97
+ q ||= 0.0 if @name == "*/*" # Default wildcard match to end of list.
70
98
  @q = ((q || 1.0).to_f * 100).to_i
71
99
  end
72
100
 
@@ -75,77 +103,72 @@ module Mime
75
103
  result = @index <=> item.index if result == 0
76
104
  result
77
105
  end
78
-
79
- def ==(item)
80
- @name == item.to_s
81
- end
82
106
  end
83
107
 
84
- class AcceptList < Array #:nodoc:
85
- def assort!
86
- sort!
108
+ class AcceptList # :nodoc:
109
+ def self.sort!(list)
110
+ list.sort!
87
111
 
88
- # Take care of the broken text/xml entry by renaming or deleting it
112
+ text_xml_idx = find_item_by_name list, "text/xml"
113
+ app_xml_idx = find_item_by_name list, Mime[:xml].to_s
114
+
115
+ # Take care of the broken text/xml entry by renaming or deleting it.
89
116
  if text_xml_idx && app_xml_idx
90
- app_xml.q = [text_xml.q, app_xml.q].max # set the q value to the max of the two
91
- exchange_xml_items if app_xml_idx > text_xml_idx # make sure app_xml is ahead of text_xml in the list
92
- delete_at(text_xml_idx) # delete text_xml from the list
117
+ app_xml = list[app_xml_idx]
118
+ text_xml = list[text_xml_idx]
119
+
120
+ app_xml.q = [text_xml.q, app_xml.q].max # Set the q value to the max of the two.
121
+ if app_xml_idx > text_xml_idx # Make sure app_xml is ahead of text_xml in the list.
122
+ list[app_xml_idx], list[text_xml_idx] = text_xml, app_xml
123
+ app_xml_idx, text_xml_idx = text_xml_idx, app_xml_idx
124
+ end
125
+ list.delete_at(text_xml_idx) # Delete text_xml from the list.
93
126
  elsif text_xml_idx
94
- text_xml.name = Mime::XML.to_s
127
+ list[text_xml_idx].name = Mime[:xml].to_s
95
128
  end
96
129
 
97
- # Look for more specific XML-based types and sort them ahead of app/xml
130
+ # Look for more specific XML-based types and sort them ahead of app/xml.
98
131
  if app_xml_idx
132
+ app_xml = list[app_xml_idx]
99
133
  idx = app_xml_idx
100
134
 
101
- while idx < length
102
- type = self[idx]
135
+ while idx < list.length
136
+ type = list[idx]
103
137
  break if type.q < app_xml.q
104
138
 
105
- if type.name.ends_with? '+xml'
106
- self[app_xml_idx], self[idx] = self[idx], app_xml
107
- @app_xml_idx = idx
139
+ if type.name.end_with? "+xml"
140
+ list[app_xml_idx], list[idx] = list[idx], app_xml
141
+ app_xml_idx = idx
108
142
  end
109
143
  idx += 1
110
144
  end
111
145
  end
112
146
 
113
- map! { |i| Mime::Type.lookup(i.name) }.uniq!
114
- to_a
147
+ list.map! { |i| Mime::Type.lookup(i.name) }.uniq!
148
+ list
115
149
  end
116
150
 
117
- private
118
- def text_xml_idx
119
- @text_xml_idx ||= index('text/xml')
120
- end
121
-
122
- def app_xml_idx
123
- @app_xml_idx ||= index(Mime::XML.to_s)
124
- end
125
-
126
- def text_xml
127
- self[text_xml_idx]
128
- end
129
-
130
- def app_xml
131
- self[app_xml_idx]
132
- end
133
-
134
- def exchange_xml_items
135
- self[app_xml_idx], self[text_xml_idx] = text_xml, app_xml
136
- @app_xml_idx, @text_xml_idx = text_xml_idx, app_xml_idx
137
- end
151
+ def self.find_item_by_name(array, name)
152
+ array.index { |item| item.name == name }
153
+ end
138
154
  end
139
155
 
140
156
  class << self
141
- TRAILING_STAR_REGEXP = /(text|application)\/\*/
142
- PARAMETER_SEPARATOR_REGEXP = /;\s*\w+="?\w+"?/
157
+ TRAILING_STAR_REGEXP = /^(text|application)\/\*/
158
+ # all media-type parameters need to be before the q-parameter
159
+ # https://www.rfc-editor.org/rfc/rfc7231#section-5.3.2
160
+ PARAMETER_SEPARATOR_REGEXP = /;\s*q="?/
161
+ ACCEPT_HEADER_REGEXP = /[^,\s"](?:[^,"]|"[^"]*")*/
143
162
 
144
163
  def register_callback(&block)
145
164
  @register_callbacks << block
146
165
  end
147
166
 
148
167
  def lookup(string)
168
+ return LOOKUP[string] if LOOKUP.key?(string)
169
+
170
+ # fallback to the media-type without parameters if it was not found
171
+ string = string.split(";", 2)[0]&.rstrip
149
172
  LOOKUP[string] || Type.new(string)
150
173
  end
151
174
 
@@ -153,46 +176,51 @@ module Mime
153
176
  EXTENSION_LOOKUP[extension.to_s]
154
177
  end
155
178
 
156
- # Registers an alias that's not used on mime type lookup, but can be referenced directly. Especially useful for
157
- # rendering different HTML versions depending on the user agent, like an iPhone.
179
+ # Registers an alias that's not used on MIME type lookup, but can be referenced
180
+ # directly. Especially useful for rendering different HTML versions depending on
181
+ # the user agent, like an iPhone.
158
182
  def register_alias(string, symbol, extension_synonyms = [])
159
183
  register(string, symbol, [], extension_synonyms, true)
160
184
  end
161
185
 
162
186
  def register(string, symbol, mime_type_synonyms = [], extension_synonyms = [], skip_lookup = false)
163
- Mime.const_set(symbol.upcase, Type.new(string, symbol, mime_type_synonyms))
187
+ new_mime = Type.new(string, symbol, mime_type_synonyms)
164
188
 
165
- new_mime = Mime.const_get(symbol.upcase)
166
189
  SET << new_mime
167
190
 
168
- ([string] + mime_type_synonyms).each { |str| LOOKUP[str] = SET.last } unless skip_lookup
169
- ([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = SET.last }
191
+ ([string] + mime_type_synonyms).each { |str| LOOKUP[str] = new_mime } unless skip_lookup
192
+ ([symbol] + extension_synonyms).each { |ext| EXTENSION_LOOKUP[ext.to_s] = new_mime }
170
193
 
171
194
  @register_callbacks.each do |callback|
172
195
  callback.call(new_mime)
173
196
  end
197
+ new_mime
174
198
  end
175
199
 
176
200
  def parse(accept_header)
177
- if !accept_header.include?(',')
178
- accept_header = accept_header.split(PARAMETER_SEPARATOR_REGEXP).first
179
- parse_trailing_star(accept_header) || [Mime::Type.lookup(accept_header)].compact
201
+ if !accept_header.include?(",")
202
+ if (index = accept_header.index(PARAMETER_SEPARATOR_REGEXP))
203
+ accept_header = accept_header[0, index].strip
204
+ end
205
+ return [] if accept_header.blank?
206
+ parse_trailing_star(accept_header) || Array(Mime::Type.lookup(accept_header))
180
207
  else
181
- list, index = AcceptList.new, 0
182
- accept_header.split(',').each do |header|
208
+ list, index = [], 0
209
+ accept_header.scan(ACCEPT_HEADER_REGEXP).each do |header|
183
210
  params, q = header.split(PARAMETER_SEPARATOR_REGEXP)
184
- if params.present?
185
- params.strip!
186
211
 
187
- params = parse_trailing_star(params) || [params]
212
+ next unless params
213
+ params.strip!
214
+ next if params.empty?
215
+
216
+ params = parse_trailing_star(params) || [params]
188
217
 
189
- params.each do |m|
190
- list << AcceptItem.new(index, m.to_s, q)
191
- index += 1
192
- end
218
+ params.each do |m|
219
+ list << AcceptItem.new(index, m.to_s, q)
220
+ index += 1
193
221
  end
194
222
  end
195
- list.assort!
223
+ AcceptList.sort! list
196
224
  end
197
225
  end
198
226
 
@@ -200,34 +228,43 @@ module Mime
200
228
  parse_data_with_trailing_star($1) if accept_header =~ TRAILING_STAR_REGEXP
201
229
  end
202
230
 
203
- # For an input of <tt>'text'</tt>, returns <tt>[Mime::JSON, Mime::XML, Mime::ICS,
204
- # Mime::HTML, Mime::CSS, Mime::CSV, Mime::JS, Mime::YAML, Mime::TEXT]</tt>.
231
+ # For an input of `'text'`, returns `[Mime[:json], Mime[:xml], Mime[:ics],
232
+ # Mime[:html], Mime[:css], Mime[:csv], Mime[:js], Mime[:yaml], Mime[:text]]`.
205
233
  #
206
- # For an input of <tt>'application'</tt>, returns <tt>[Mime::HTML, Mime::JS,
207
- # Mime::XML, Mime::YAML, Mime::ATOM, Mime::JSON, Mime::RSS, Mime::URL_ENCODED_FORM]</tt>.
208
- def parse_data_with_trailing_star(input)
209
- Mime::SET.select { |m| m =~ input }
234
+ # For an input of `'application'`, returns `[Mime[:html], Mime[:js], Mime[:xml],
235
+ # Mime[:yaml], Mime[:atom], Mime[:json], Mime[:rss], Mime[:url_encoded_form]]`.
236
+ def parse_data_with_trailing_star(type)
237
+ Mime::SET.select { |m| m.match?(type) }
210
238
  end
211
239
 
212
240
  # This method is opposite of register method.
213
241
  #
214
- # Usage:
242
+ # To unregister a MIME type:
215
243
  #
216
- # Mime::Type.unregister(:mobile)
244
+ # Mime::Type.unregister(:mobile)
217
245
  def unregister(symbol)
218
- symbol = symbol.upcase
219
- mime = Mime.const_get(symbol)
220
- Mime.instance_eval { remove_const(symbol) }
221
-
222
- SET.delete_if { |v| v.eql?(mime) }
223
- LOOKUP.delete_if { |_,v| v.eql?(mime) }
224
- EXTENSION_LOOKUP.delete_if { |_,v| v.eql?(mime) }
246
+ symbol = symbol.downcase
247
+ if mime = Mime[symbol]
248
+ SET.delete_if { |v| v.eql?(mime) }
249
+ LOOKUP.delete_if { |_, v| v.eql?(mime) }
250
+ EXTENSION_LOOKUP.delete_if { |_, v| v.eql?(mime) }
251
+ end
225
252
  end
226
253
  end
227
254
 
228
255
  attr_reader :hash
229
256
 
257
+ MIME_NAME = "[a-zA-Z0-9][a-zA-Z0-9#{Regexp.escape('!#$&-^_.+')}]{0,126}"
258
+ MIME_PARAMETER_VALUE = "(?:#{MIME_NAME}|\"[^\"\r\\\\]*\")"
259
+ MIME_PARAMETER = "\s*;\s*#{MIME_NAME}(?:=#{MIME_PARAMETER_VALUE})?"
260
+ MIME_REGEXP = /\A(?:\*\/\*|#{MIME_NAME}\/(?:\*|#{MIME_NAME})(?>#{MIME_PARAMETER})*\s*)\z/
261
+
262
+ class InvalidMimeType < StandardError; end
263
+
230
264
  def initialize(string, symbol = nil, synonyms = [])
265
+ unless MIME_REGEXP.match?(string)
266
+ raise InvalidMimeType, "#{string.inspect} is not a valid MIME type"
267
+ end
231
268
  @symbol, @synonyms = symbol, synonyms
232
269
  @string = string
233
270
  @hash = [@string, @synonyms, @symbol].hash
@@ -246,7 +283,7 @@ module Mime
246
283
  end
247
284
 
248
285
  def ref
249
- to_sym || to_s
286
+ symbol || to_s
250
287
  end
251
288
 
252
289
  def ===(list)
@@ -258,7 +295,7 @@ module Mime
258
295
  end
259
296
 
260
297
  def ==(mime_type)
261
- return false if mime_type.blank?
298
+ return false unless mime_type
262
299
  (@synonyms + [ self ]).any? do |synonym|
263
300
  synonym.to_s == mime_type.to_s || synonym.to_sym == mime_type.to_sym
264
301
  end
@@ -272,40 +309,59 @@ module Mime
272
309
  end
273
310
 
274
311
  def =~(mime_type)
275
- return false if mime_type.blank?
312
+ return false unless mime_type
276
313
  regexp = Regexp.new(Regexp.quote(mime_type.to_s))
277
- (@synonyms + [ self ]).any? do |synonym|
278
- synonym.to_s =~ regexp
279
- end
314
+ @synonyms.any? { |synonym| synonym.to_s =~ regexp } || @string =~ regexp
315
+ end
316
+
317
+ def match?(mime_type)
318
+ return false unless mime_type
319
+ regexp = Regexp.new(Regexp.quote(mime_type.to_s))
320
+ @synonyms.any? { |synonym| synonym.to_s.match?(regexp) } || @string.match?(regexp)
280
321
  end
281
322
 
282
323
  def html?
283
- @@html_types.include?(to_sym) || @string =~ /html/
324
+ (symbol == :html) || @string.include?("html")
284
325
  end
285
326
 
327
+ def all?; false; end
286
328
 
287
329
  protected
288
-
289
- attr_reader :string, :synonyms
330
+ attr_reader :string, :synonyms
290
331
 
291
332
  private
333
+ def to_ary; end
334
+ def to_a; end
292
335
 
293
- def to_ary; end
294
- def to_a; end
336
+ def method_missing(method, ...)
337
+ if method.end_with?("?")
338
+ method[0..-2].downcase.to_sym == to_sym
339
+ else
340
+ super
341
+ end
342
+ end
295
343
 
296
- def method_missing(method, *args)
297
- if method.to_s.ends_with? '?'
298
- method[0..-2].downcase.to_sym == to_sym
299
- else
300
- super
344
+ def respond_to_missing?(method, include_private = false)
345
+ method.end_with?("?") || super
301
346
  end
302
- end
347
+ end
303
348
 
304
- def respond_to_missing?(method, include_private = false) #:nodoc:
305
- method.to_s.ends_with? '?'
349
+ class AllType < Type
350
+ include Singleton
351
+
352
+ def initialize
353
+ super "*/*", nil
306
354
  end
355
+
356
+ def all?; true; end
357
+ def html?; true; end
307
358
  end
308
359
 
360
+ # ALL isn't a real MIME type, so we don't register it for lookup with the other
361
+ # concrete types. It's a wildcard match that we use for `respond_to` negotiation
362
+ # internals.
363
+ ALL = AllType.instance
364
+
309
365
  class NullType
310
366
  include Singleton
311
367
 
@@ -313,17 +369,21 @@ module Mime
313
369
  true
314
370
  end
315
371
 
316
- def ref; end
317
-
318
- def respond_to_missing?(method, include_private = false)
319
- method.to_s.ends_with? '?'
372
+ def to_s
373
+ ""
320
374
  end
321
375
 
376
+ def ref; end
377
+
322
378
  private
323
- def method_missing(method, *args)
324
- false if method.to_s.ends_with? '?'
325
- end
379
+ def respond_to_missing?(method, _)
380
+ method.end_with?("?")
381
+ end
382
+
383
+ def method_missing(method, ...)
384
+ false if method.end_with?("?")
385
+ end
326
386
  end
327
387
  end
328
388
 
329
- require 'action_dispatch/http/mime_types'
389
+ require "action_dispatch/http/mime_types"
@@ -1,5 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Build list of Mime types for HTTP responses
2
- # http://www.iana.org/assignments/media-types/
4
+ # https://www.iana.org/assignments/media-types/
5
+
6
+ # :markup: markdown
3
7
 
4
8
  Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
5
9
  Mime::Type.register "text/plain", :text, [], %w(txt)
@@ -8,29 +12,43 @@ Mime::Type.register "text/css", :css
8
12
  Mime::Type.register "text/calendar", :ics
9
13
  Mime::Type.register "text/csv", :csv
10
14
  Mime::Type.register "text/vcard", :vcf
15
+ Mime::Type.register "text/vtt", :vtt, %w(vtt)
11
16
 
12
17
  Mime::Type.register "image/png", :png, [], %w(png)
13
18
  Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg)
14
19
  Mime::Type.register "image/gif", :gif, [], %w(gif)
15
20
  Mime::Type.register "image/bmp", :bmp, [], %w(bmp)
16
21
  Mime::Type.register "image/tiff", :tiff, [], %w(tif tiff)
22
+ Mime::Type.register "image/svg+xml", :svg
23
+ Mime::Type.register "image/webp", :webp, [], %w(webp)
17
24
 
18
25
  Mime::Type.register "video/mpeg", :mpeg, [], %w(mpg mpeg mpe)
19
26
 
27
+ Mime::Type.register "audio/mpeg", :mp3, [], %w(mp1 mp2 mp3)
28
+ Mime::Type.register "audio/ogg", :ogg, [], %w(oga ogg spx opus)
29
+ Mime::Type.register "audio/aac", :m4a, %w( audio/mp4 ), %w(m4a mpg4 aac)
30
+
31
+ Mime::Type.register "video/webm", :webm, [], %w(webm)
32
+ Mime::Type.register "video/mp4", :mp4, [], %w(mp4 m4v)
33
+
34
+ Mime::Type.register "font/otf", :otf, [], %w(otf)
35
+ Mime::Type.register "font/ttf", :ttf, [], %w(ttf)
36
+ Mime::Type.register "font/woff", :woff, [], %w(woff)
37
+ Mime::Type.register "font/woff2", :woff2, [], %w(woff2)
38
+
20
39
  Mime::Type.register "application/xml", :xml, %w( text/xml application/x-xml )
21
40
  Mime::Type.register "application/rss+xml", :rss
22
41
  Mime::Type.register "application/atom+xml", :atom
23
- Mime::Type.register "application/x-yaml", :yaml, %w( text/yaml )
42
+ Mime::Type.register "application/x-yaml", :yaml, %w( text/yaml ), %w(yml yaml)
24
43
 
25
44
  Mime::Type.register "multipart/form-data", :multipart_form
26
45
  Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
27
46
 
28
- # http://www.ietf.org/rfc/rfc4627.txt
47
+ # https://www.ietf.org/rfc/rfc4627.txt
29
48
  # http://www.json.org/JSONRequest.html
30
- Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
49
+ # https://www.ietf.org/rfc/rfc7807.txt
50
+ Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest application/problem+json )
31
51
 
32
52
  Mime::Type.register "application/pdf", :pdf, [], %w(pdf)
33
53
  Mime::Type.register "application/zip", :zip, [], %w(zip)
34
-
35
- # Create Mime::ALL but do not add it to the SET.
36
- Mime::ALL = Mime::Type.new("*/*", :all, [])
54
+ Mime::Type.register "application/gzip", :gzip, %w(application/x-gzip), %w(gz)