actionpack 5.2.3

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 (170) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +429 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +57 -0
  5. data/lib/abstract_controller.rb +27 -0
  6. data/lib/abstract_controller/asset_paths.rb +12 -0
  7. data/lib/abstract_controller/base.rb +265 -0
  8. data/lib/abstract_controller/caching.rb +66 -0
  9. data/lib/abstract_controller/caching/fragments.rb +166 -0
  10. data/lib/abstract_controller/callbacks.rb +212 -0
  11. data/lib/abstract_controller/collector.rb +43 -0
  12. data/lib/abstract_controller/error.rb +6 -0
  13. data/lib/abstract_controller/helpers.rb +194 -0
  14. data/lib/abstract_controller/logger.rb +14 -0
  15. data/lib/abstract_controller/railties/routes_helpers.rb +20 -0
  16. data/lib/abstract_controller/rendering.rb +127 -0
  17. data/lib/abstract_controller/translation.rb +31 -0
  18. data/lib/abstract_controller/url_for.rb +35 -0
  19. data/lib/action_controller.rb +66 -0
  20. data/lib/action_controller/api.rb +149 -0
  21. data/lib/action_controller/api/api_rendering.rb +16 -0
  22. data/lib/action_controller/base.rb +276 -0
  23. data/lib/action_controller/caching.rb +46 -0
  24. data/lib/action_controller/form_builder.rb +50 -0
  25. data/lib/action_controller/log_subscriber.rb +78 -0
  26. data/lib/action_controller/metal.rb +256 -0
  27. data/lib/action_controller/metal/basic_implicit_render.rb +13 -0
  28. data/lib/action_controller/metal/conditional_get.rb +274 -0
  29. data/lib/action_controller/metal/content_security_policy.rb +52 -0
  30. data/lib/action_controller/metal/cookies.rb +16 -0
  31. data/lib/action_controller/metal/data_streaming.rb +152 -0
  32. data/lib/action_controller/metal/etag_with_flash.rb +18 -0
  33. data/lib/action_controller/metal/etag_with_template_digest.rb +57 -0
  34. data/lib/action_controller/metal/exceptions.rb +53 -0
  35. data/lib/action_controller/metal/flash.rb +61 -0
  36. data/lib/action_controller/metal/force_ssl.rb +99 -0
  37. data/lib/action_controller/metal/head.rb +60 -0
  38. data/lib/action_controller/metal/helpers.rb +123 -0
  39. data/lib/action_controller/metal/http_authentication.rb +519 -0
  40. data/lib/action_controller/metal/implicit_render.rb +73 -0
  41. data/lib/action_controller/metal/instrumentation.rb +107 -0
  42. data/lib/action_controller/metal/live.rb +312 -0
  43. data/lib/action_controller/metal/mime_responds.rb +313 -0
  44. data/lib/action_controller/metal/parameter_encoding.rb +51 -0
  45. data/lib/action_controller/metal/params_wrapper.rb +293 -0
  46. data/lib/action_controller/metal/redirecting.rb +133 -0
  47. data/lib/action_controller/metal/renderers.rb +181 -0
  48. data/lib/action_controller/metal/rendering.rb +122 -0
  49. data/lib/action_controller/metal/request_forgery_protection.rb +445 -0
  50. data/lib/action_controller/metal/rescue.rb +28 -0
  51. data/lib/action_controller/metal/streaming.rb +223 -0
  52. data/lib/action_controller/metal/strong_parameters.rb +1086 -0
  53. data/lib/action_controller/metal/testing.rb +16 -0
  54. data/lib/action_controller/metal/url_for.rb +58 -0
  55. data/lib/action_controller/railtie.rb +89 -0
  56. data/lib/action_controller/railties/helpers.rb +24 -0
  57. data/lib/action_controller/renderer.rb +117 -0
  58. data/lib/action_controller/template_assertions.rb +11 -0
  59. data/lib/action_controller/test_case.rb +629 -0
  60. data/lib/action_dispatch.rb +112 -0
  61. data/lib/action_dispatch/http/cache.rb +222 -0
  62. data/lib/action_dispatch/http/content_security_policy.rb +272 -0
  63. data/lib/action_dispatch/http/filter_parameters.rb +84 -0
  64. data/lib/action_dispatch/http/filter_redirect.rb +37 -0
  65. data/lib/action_dispatch/http/headers.rb +132 -0
  66. data/lib/action_dispatch/http/mime_negotiation.rb +175 -0
  67. data/lib/action_dispatch/http/mime_type.rb +342 -0
  68. data/lib/action_dispatch/http/mime_types.rb +50 -0
  69. data/lib/action_dispatch/http/parameter_filter.rb +86 -0
  70. data/lib/action_dispatch/http/parameters.rb +126 -0
  71. data/lib/action_dispatch/http/rack_cache.rb +63 -0
  72. data/lib/action_dispatch/http/request.rb +430 -0
  73. data/lib/action_dispatch/http/response.rb +519 -0
  74. data/lib/action_dispatch/http/upload.rb +84 -0
  75. data/lib/action_dispatch/http/url.rb +350 -0
  76. data/lib/action_dispatch/journey.rb +7 -0
  77. data/lib/action_dispatch/journey/formatter.rb +189 -0
  78. data/lib/action_dispatch/journey/gtg/builder.rb +164 -0
  79. data/lib/action_dispatch/journey/gtg/simulator.rb +41 -0
  80. data/lib/action_dispatch/journey/gtg/transition_table.rb +158 -0
  81. data/lib/action_dispatch/journey/nfa/builder.rb +78 -0
  82. data/lib/action_dispatch/journey/nfa/dot.rb +36 -0
  83. data/lib/action_dispatch/journey/nfa/simulator.rb +49 -0
  84. data/lib/action_dispatch/journey/nfa/transition_table.rb +120 -0
  85. data/lib/action_dispatch/journey/nodes/node.rb +140 -0
  86. data/lib/action_dispatch/journey/parser.rb +199 -0
  87. data/lib/action_dispatch/journey/parser.y +50 -0
  88. data/lib/action_dispatch/journey/parser_extras.rb +31 -0
  89. data/lib/action_dispatch/journey/path/pattern.rb +198 -0
  90. data/lib/action_dispatch/journey/route.rb +203 -0
  91. data/lib/action_dispatch/journey/router.rb +156 -0
  92. data/lib/action_dispatch/journey/router/utils.rb +102 -0
  93. data/lib/action_dispatch/journey/routes.rb +82 -0
  94. data/lib/action_dispatch/journey/scanner.rb +64 -0
  95. data/lib/action_dispatch/journey/visitors.rb +268 -0
  96. data/lib/action_dispatch/journey/visualizer/fsm.css +30 -0
  97. data/lib/action_dispatch/journey/visualizer/fsm.js +134 -0
  98. data/lib/action_dispatch/journey/visualizer/index.html.erb +52 -0
  99. data/lib/action_dispatch/middleware/callbacks.rb +36 -0
  100. data/lib/action_dispatch/middleware/cookies.rb +685 -0
  101. data/lib/action_dispatch/middleware/debug_exceptions.rb +205 -0
  102. data/lib/action_dispatch/middleware/debug_locks.rb +124 -0
  103. data/lib/action_dispatch/middleware/exception_wrapper.rb +147 -0
  104. data/lib/action_dispatch/middleware/executor.rb +21 -0
  105. data/lib/action_dispatch/middleware/flash.rb +300 -0
  106. data/lib/action_dispatch/middleware/public_exceptions.rb +57 -0
  107. data/lib/action_dispatch/middleware/reloader.rb +12 -0
  108. data/lib/action_dispatch/middleware/remote_ip.rb +183 -0
  109. data/lib/action_dispatch/middleware/request_id.rb +43 -0
  110. data/lib/action_dispatch/middleware/session/abstract_store.rb +92 -0
  111. data/lib/action_dispatch/middleware/session/cache_store.rb +54 -0
  112. data/lib/action_dispatch/middleware/session/cookie_store.rb +118 -0
  113. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +28 -0
  114. data/lib/action_dispatch/middleware/show_exceptions.rb +62 -0
  115. data/lib/action_dispatch/middleware/ssl.rb +150 -0
  116. data/lib/action_dispatch/middleware/stack.rb +116 -0
  117. data/lib/action_dispatch/middleware/static.rb +130 -0
  118. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb +22 -0
  119. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.text.erb +23 -0
  120. data/lib/action_dispatch/middleware/templates/rescues/_source.html.erb +27 -0
  121. data/lib/action_dispatch/middleware/templates/rescues/_source.text.erb +8 -0
  122. data/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb +52 -0
  123. data/lib/action_dispatch/middleware/templates/rescues/_trace.text.erb +9 -0
  124. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb +16 -0
  125. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.text.erb +9 -0
  126. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.html.erb +21 -0
  127. data/lib/action_dispatch/middleware/templates/rescues/invalid_statement.text.erb +13 -0
  128. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +161 -0
  129. data/lib/action_dispatch/middleware/templates/rescues/missing_template.html.erb +11 -0
  130. data/lib/action_dispatch/middleware/templates/rescues/missing_template.text.erb +3 -0
  131. data/lib/action_dispatch/middleware/templates/rescues/routing_error.html.erb +32 -0
  132. data/lib/action_dispatch/middleware/templates/rescues/routing_error.text.erb +11 -0
  133. data/lib/action_dispatch/middleware/templates/rescues/template_error.html.erb +20 -0
  134. data/lib/action_dispatch/middleware/templates/rescues/template_error.text.erb +7 -0
  135. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.html.erb +6 -0
  136. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.text.erb +3 -0
  137. data/lib/action_dispatch/middleware/templates/routes/_route.html.erb +16 -0
  138. data/lib/action_dispatch/middleware/templates/routes/_table.html.erb +200 -0
  139. data/lib/action_dispatch/railtie.rb +55 -0
  140. data/lib/action_dispatch/request/session.rb +234 -0
  141. data/lib/action_dispatch/request/utils.rb +78 -0
  142. data/lib/action_dispatch/routing.rb +260 -0
  143. data/lib/action_dispatch/routing/endpoint.rb +17 -0
  144. data/lib/action_dispatch/routing/inspector.rb +225 -0
  145. data/lib/action_dispatch/routing/mapper.rb +2267 -0
  146. data/lib/action_dispatch/routing/polymorphic_routes.rb +352 -0
  147. data/lib/action_dispatch/routing/redirection.rb +201 -0
  148. data/lib/action_dispatch/routing/route_set.rb +890 -0
  149. data/lib/action_dispatch/routing/routes_proxy.rb +69 -0
  150. data/lib/action_dispatch/routing/url_for.rb +236 -0
  151. data/lib/action_dispatch/system_test_case.rb +147 -0
  152. data/lib/action_dispatch/system_testing/browser.rb +49 -0
  153. data/lib/action_dispatch/system_testing/driver.rb +59 -0
  154. data/lib/action_dispatch/system_testing/server.rb +31 -0
  155. data/lib/action_dispatch/system_testing/test_helpers/screenshot_helper.rb +96 -0
  156. data/lib/action_dispatch/system_testing/test_helpers/setup_and_teardown.rb +31 -0
  157. data/lib/action_dispatch/system_testing/test_helpers/undef_methods.rb +26 -0
  158. data/lib/action_dispatch/testing/assertion_response.rb +47 -0
  159. data/lib/action_dispatch/testing/assertions.rb +24 -0
  160. data/lib/action_dispatch/testing/assertions/response.rb +107 -0
  161. data/lib/action_dispatch/testing/assertions/routing.rb +222 -0
  162. data/lib/action_dispatch/testing/integration.rb +652 -0
  163. data/lib/action_dispatch/testing/request_encoder.rb +55 -0
  164. data/lib/action_dispatch/testing/test_process.rb +50 -0
  165. data/lib/action_dispatch/testing/test_request.rb +71 -0
  166. data/lib/action_dispatch/testing/test_response.rb +53 -0
  167. data/lib/action_pack.rb +26 -0
  168. data/lib/action_pack/gem_version.rb +17 -0
  169. data/lib/action_pack/version.rb +10 -0
  170. metadata +318 -0
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Build list of Mime types for HTTP responses
4
+ # https://www.iana.org/assignments/media-types/
5
+
6
+ Mime::Type.register "text/html", :html, %w( application/xhtml+xml ), %w( xhtml )
7
+ Mime::Type.register "text/plain", :text, [], %w(txt)
8
+ Mime::Type.register "text/javascript", :js, %w( application/javascript application/x-javascript )
9
+ Mime::Type.register "text/css", :css
10
+ Mime::Type.register "text/calendar", :ics
11
+ Mime::Type.register "text/csv", :csv
12
+ Mime::Type.register "text/vcard", :vcf
13
+ Mime::Type.register "text/vtt", :vtt, %w(vtt)
14
+
15
+ Mime::Type.register "image/png", :png, [], %w(png)
16
+ Mime::Type.register "image/jpeg", :jpeg, [], %w(jpg jpeg jpe pjpeg)
17
+ Mime::Type.register "image/gif", :gif, [], %w(gif)
18
+ Mime::Type.register "image/bmp", :bmp, [], %w(bmp)
19
+ Mime::Type.register "image/tiff", :tiff, [], %w(tif tiff)
20
+ Mime::Type.register "image/svg+xml", :svg
21
+
22
+ Mime::Type.register "video/mpeg", :mpeg, [], %w(mpg mpeg mpe)
23
+
24
+ Mime::Type.register "audio/mpeg", :mp3, [], %w(mp1 mp2 mp3)
25
+ Mime::Type.register "audio/ogg", :ogg, [], %w(oga ogg spx opus)
26
+ Mime::Type.register "audio/aac", :m4a, %w( audio/mp4 ), %w(m4a mpg4 aac)
27
+
28
+ Mime::Type.register "video/webm", :webm, [], %w(webm)
29
+ Mime::Type.register "video/mp4", :mp4, [], %w(mp4 m4v)
30
+
31
+ Mime::Type.register "font/otf", :otf, [], %w(otf)
32
+ Mime::Type.register "font/ttf", :ttf, [], %w(ttf)
33
+ Mime::Type.register "font/woff", :woff, [], %w(woff)
34
+ Mime::Type.register "font/woff2", :woff2, [], %w(woff2)
35
+
36
+ Mime::Type.register "application/xml", :xml, %w( text/xml application/x-xml )
37
+ Mime::Type.register "application/rss+xml", :rss
38
+ Mime::Type.register "application/atom+xml", :atom
39
+ Mime::Type.register "application/x-yaml", :yaml, %w( text/yaml ), %w(yml yaml)
40
+
41
+ Mime::Type.register "multipart/form-data", :multipart_form
42
+ Mime::Type.register "application/x-www-form-urlencoded", :url_encoded_form
43
+
44
+ # https://www.ietf.org/rfc/rfc4627.txt
45
+ # http://www.json.org/JSONRequest.html
46
+ Mime::Type.register "application/json", :json, %w( text/x-json application/jsonrequest )
47
+
48
+ Mime::Type.register "application/pdf", :pdf, [], %w(pdf)
49
+ Mime::Type.register "application/zip", :zip, [], %w(zip)
50
+ Mime::Type.register "application/gzip", :gzip, %w(application/x-gzip), %w(gz)
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/duplicable"
4
+
5
+ module ActionDispatch
6
+ module Http
7
+ class ParameterFilter
8
+ FILTERED = "[FILTERED]".freeze # :nodoc:
9
+
10
+ def initialize(filters = [])
11
+ @filters = filters
12
+ end
13
+
14
+ def filter(params)
15
+ compiled_filter.call(params)
16
+ end
17
+
18
+ private
19
+
20
+ def compiled_filter
21
+ @compiled_filter ||= CompiledFilter.compile(@filters)
22
+ end
23
+
24
+ class CompiledFilter # :nodoc:
25
+ def self.compile(filters)
26
+ return lambda { |params| params.dup } if filters.empty?
27
+
28
+ strings, regexps, blocks = [], [], []
29
+
30
+ filters.each do |item|
31
+ case item
32
+ when Proc
33
+ blocks << item
34
+ when Regexp
35
+ regexps << item
36
+ else
37
+ strings << Regexp.escape(item.to_s)
38
+ end
39
+ end
40
+
41
+ deep_regexps, regexps = regexps.partition { |r| r.to_s.include?("\\.".freeze) }
42
+ deep_strings, strings = strings.partition { |s| s.include?("\\.".freeze) }
43
+
44
+ regexps << Regexp.new(strings.join("|".freeze), true) unless strings.empty?
45
+ deep_regexps << Regexp.new(deep_strings.join("|".freeze), true) unless deep_strings.empty?
46
+
47
+ new regexps, deep_regexps, blocks
48
+ end
49
+
50
+ attr_reader :regexps, :deep_regexps, :blocks
51
+
52
+ def initialize(regexps, deep_regexps, blocks)
53
+ @regexps = regexps
54
+ @deep_regexps = deep_regexps.any? ? deep_regexps : nil
55
+ @blocks = blocks
56
+ end
57
+
58
+ def call(original_params, parents = [])
59
+ filtered_params = original_params.class.new
60
+
61
+ original_params.each do |key, value|
62
+ parents.push(key) if deep_regexps
63
+ if regexps.any? { |r| key =~ r }
64
+ value = FILTERED
65
+ elsif deep_regexps && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
66
+ value = FILTERED
67
+ elsif value.is_a?(Hash)
68
+ value = call(value, parents)
69
+ elsif value.is_a?(Array)
70
+ value = value.map { |v| v.is_a?(Hash) ? call(v, parents) : v }
71
+ elsif blocks.any?
72
+ key = key.dup if key.duplicable?
73
+ value = value.dup if value.duplicable?
74
+ blocks.each { |b| b.call(key, value) }
75
+ end
76
+ parents.pop if deep_regexps
77
+
78
+ filtered_params[key] = value
79
+ end
80
+
81
+ filtered_params
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActionDispatch
4
+ module Http
5
+ module Parameters
6
+ extend ActiveSupport::Concern
7
+
8
+ PARAMETERS_KEY = "action_dispatch.request.path_parameters"
9
+
10
+ DEFAULT_PARSERS = {
11
+ Mime[:json].symbol => -> (raw_post) {
12
+ data = ActiveSupport::JSON.decode(raw_post)
13
+ data.is_a?(Hash) ? data : { _json: data }
14
+ }
15
+ }
16
+
17
+ # Raised when raw data from the request cannot be parsed by the parser
18
+ # defined for request's content MIME type.
19
+ class ParseError < StandardError
20
+ def initialize
21
+ super($!.message)
22
+ end
23
+ end
24
+
25
+ included do
26
+ class << self
27
+ # Returns the parameter parsers.
28
+ attr_reader :parameter_parsers
29
+ end
30
+
31
+ self.parameter_parsers = DEFAULT_PARSERS
32
+ end
33
+
34
+ module ClassMethods
35
+ # Configure the parameter parser for a given MIME type.
36
+ #
37
+ # It accepts a hash where the key is the symbol of the MIME type
38
+ # and the value is a proc.
39
+ #
40
+ # original_parsers = ActionDispatch::Request.parameter_parsers
41
+ # xml_parser = -> (raw_post) { Hash.from_xml(raw_post) || {} }
42
+ # new_parsers = original_parsers.merge(xml: xml_parser)
43
+ # ActionDispatch::Request.parameter_parsers = new_parsers
44
+ def parameter_parsers=(parsers)
45
+ @parameter_parsers = parsers.transform_keys { |key| key.respond_to?(:symbol) ? key.symbol : key }
46
+ end
47
+ end
48
+
49
+ # Returns both GET and POST \parameters in a single hash.
50
+ def parameters
51
+ params = get_header("action_dispatch.request.parameters")
52
+ return params if params
53
+
54
+ params = begin
55
+ request_parameters.merge(query_parameters)
56
+ rescue EOFError
57
+ query_parameters.dup
58
+ end
59
+ params.merge!(path_parameters)
60
+ params = set_binary_encoding(params, params[:controller], params[:action])
61
+ set_header("action_dispatch.request.parameters", params)
62
+ params
63
+ end
64
+ alias :params :parameters
65
+
66
+ def path_parameters=(parameters) #:nodoc:
67
+ delete_header("action_dispatch.request.parameters")
68
+
69
+ parameters = set_binary_encoding(parameters, parameters[:controller], parameters[:action])
70
+ # If any of the path parameters has an invalid encoding then
71
+ # raise since it's likely to trigger errors further on.
72
+ Request::Utils.check_param_encoding(parameters)
73
+
74
+ set_header PARAMETERS_KEY, parameters
75
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
76
+ raise ActionController::BadRequest.new("Invalid path parameters: #{e.message}")
77
+ end
78
+
79
+ # Returns a hash with the \parameters used to form the \path of the request.
80
+ # Returned hash keys are strings:
81
+ #
82
+ # {'action' => 'my_action', 'controller' => 'my_controller'}
83
+ def path_parameters
84
+ get_header(PARAMETERS_KEY) || set_header(PARAMETERS_KEY, {})
85
+ end
86
+
87
+ private
88
+
89
+ def set_binary_encoding(params, controller, action)
90
+ return params unless controller && controller.valid_encoding?
91
+
92
+ if binary_params_for?(controller, action)
93
+ ActionDispatch::Request::Utils.each_param_value(params) do |param|
94
+ param.force_encoding ::Encoding::ASCII_8BIT
95
+ end
96
+ end
97
+ params
98
+ end
99
+
100
+ def binary_params_for?(controller, action)
101
+ controller_class_for(controller).binary_params_for?(action)
102
+ rescue NameError
103
+ false
104
+ end
105
+
106
+ def parse_formatted_parameters(parsers)
107
+ return yield if content_length.zero? || content_mime_type.nil?
108
+
109
+ strategy = parsers.fetch(content_mime_type.symbol) { return yield }
110
+
111
+ begin
112
+ strategy.call(raw_post)
113
+ rescue # JSON or Ruby code block errors.
114
+ my_logger = logger || ActiveSupport::Logger.new($stderr)
115
+ my_logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{raw_post}"
116
+
117
+ raise ParseError
118
+ end
119
+ end
120
+
121
+ def params_parsers
122
+ ActionDispatch::Request.parameter_parsers
123
+ end
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rack/cache"
4
+ require "rack/cache/context"
5
+ require "active_support/cache"
6
+
7
+ module ActionDispatch
8
+ class RailsMetaStore < Rack::Cache::MetaStore
9
+ def self.resolve(uri)
10
+ new
11
+ end
12
+
13
+ def initialize(store = Rails.cache)
14
+ @store = store
15
+ end
16
+
17
+ def read(key)
18
+ if data = @store.read(key)
19
+ Marshal.load(data)
20
+ else
21
+ []
22
+ end
23
+ end
24
+
25
+ def write(key, value)
26
+ @store.write(key, Marshal.dump(value))
27
+ end
28
+
29
+ ::Rack::Cache::MetaStore::RAILS = self
30
+ end
31
+
32
+ class RailsEntityStore < Rack::Cache::EntityStore
33
+ def self.resolve(uri)
34
+ new
35
+ end
36
+
37
+ def initialize(store = Rails.cache)
38
+ @store = store
39
+ end
40
+
41
+ def exist?(key)
42
+ @store.exist?(key)
43
+ end
44
+
45
+ def open(key)
46
+ @store.read(key)
47
+ end
48
+
49
+ def read(key)
50
+ body = open(key)
51
+ body.join if body
52
+ end
53
+
54
+ def write(body)
55
+ buf = []
56
+ key, size = slurp(body) { |part| buf << part }
57
+ @store.write(key, buf)
58
+ [key, size]
59
+ end
60
+
61
+ ::Rack::Cache::EntityStore::RAILS = self
62
+ end
63
+ end
@@ -0,0 +1,430 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "stringio"
4
+
5
+ require "active_support/inflector"
6
+ require "action_dispatch/http/headers"
7
+ require "action_controller/metal/exceptions"
8
+ require "rack/request"
9
+ require "action_dispatch/http/cache"
10
+ require "action_dispatch/http/mime_negotiation"
11
+ require "action_dispatch/http/parameters"
12
+ require "action_dispatch/http/filter_parameters"
13
+ require "action_dispatch/http/upload"
14
+ require "action_dispatch/http/url"
15
+ require "active_support/core_ext/array/conversions"
16
+
17
+ module ActionDispatch
18
+ class Request
19
+ include Rack::Request::Helpers
20
+ include ActionDispatch::Http::Cache::Request
21
+ include ActionDispatch::Http::MimeNegotiation
22
+ include ActionDispatch::Http::Parameters
23
+ include ActionDispatch::Http::FilterParameters
24
+ include ActionDispatch::Http::URL
25
+ include ActionDispatch::ContentSecurityPolicy::Request
26
+ include Rack::Request::Env
27
+
28
+ autoload :Session, "action_dispatch/request/session"
29
+ autoload :Utils, "action_dispatch/request/utils"
30
+
31
+ LOCALHOST = Regexp.union [/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/, /^::1$/, /^0:0:0:0:0:0:0:1(%.*)?$/]
32
+
33
+ ENV_METHODS = %w[ AUTH_TYPE GATEWAY_INTERFACE
34
+ PATH_TRANSLATED REMOTE_HOST
35
+ REMOTE_IDENT REMOTE_USER REMOTE_ADDR
36
+ SERVER_NAME SERVER_PROTOCOL
37
+ ORIGINAL_SCRIPT_NAME
38
+
39
+ HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
40
+ HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
41
+ HTTP_NEGOTIATE HTTP_PRAGMA HTTP_CLIENT_IP
42
+ HTTP_X_FORWARDED_FOR HTTP_ORIGIN HTTP_VERSION
43
+ HTTP_X_CSRF_TOKEN HTTP_X_REQUEST_ID HTTP_X_FORWARDED_HOST
44
+ SERVER_ADDR
45
+ ].freeze
46
+
47
+ ENV_METHODS.each do |env|
48
+ class_eval <<-METHOD, __FILE__, __LINE__ + 1
49
+ def #{env.sub(/^HTTP_/n, '').downcase} # def accept_charset
50
+ get_header "#{env}".freeze # get_header "HTTP_ACCEPT_CHARSET".freeze
51
+ end # end
52
+ METHOD
53
+ end
54
+
55
+ def self.empty
56
+ new({})
57
+ end
58
+
59
+ def initialize(env)
60
+ super
61
+ @method = nil
62
+ @request_method = nil
63
+ @remote_ip = nil
64
+ @original_fullpath = nil
65
+ @fullpath = nil
66
+ @ip = nil
67
+ end
68
+
69
+ def commit_cookie_jar! # :nodoc:
70
+ end
71
+
72
+ PASS_NOT_FOUND = Class.new { # :nodoc:
73
+ def self.action(_); self; end
74
+ def self.call(_); [404, { "X-Cascade" => "pass" }, []]; end
75
+ def self.binary_params_for?(action); false; end
76
+ }
77
+
78
+ def controller_class
79
+ params = path_parameters
80
+ params[:action] ||= "index"
81
+ controller_class_for(params[:controller])
82
+ end
83
+
84
+ def controller_class_for(name)
85
+ if name
86
+ controller_param = name.underscore
87
+ const_name = "#{controller_param.camelize}Controller"
88
+ ActiveSupport::Dependencies.constantize(const_name)
89
+ else
90
+ PASS_NOT_FOUND
91
+ end
92
+ end
93
+
94
+ # Returns true if the request has a header matching the given key parameter.
95
+ #
96
+ # request.key? :ip_spoofing_check # => true
97
+ def key?(key)
98
+ has_header? key
99
+ end
100
+
101
+ # List of HTTP request methods from the following RFCs:
102
+ # Hypertext Transfer Protocol -- HTTP/1.1 (https://www.ietf.org/rfc/rfc2616.txt)
103
+ # HTTP Extensions for Distributed Authoring -- WEBDAV (https://www.ietf.org/rfc/rfc2518.txt)
104
+ # Versioning Extensions to WebDAV (https://www.ietf.org/rfc/rfc3253.txt)
105
+ # Ordered Collections Protocol (WebDAV) (https://www.ietf.org/rfc/rfc3648.txt)
106
+ # Web Distributed Authoring and Versioning (WebDAV) Access Control Protocol (https://www.ietf.org/rfc/rfc3744.txt)
107
+ # Web Distributed Authoring and Versioning (WebDAV) SEARCH (https://www.ietf.org/rfc/rfc5323.txt)
108
+ # Calendar Extensions to WebDAV (https://www.ietf.org/rfc/rfc4791.txt)
109
+ # PATCH Method for HTTP (https://www.ietf.org/rfc/rfc5789.txt)
110
+ RFC2616 = %w(OPTIONS GET HEAD POST PUT DELETE TRACE CONNECT)
111
+ RFC2518 = %w(PROPFIND PROPPATCH MKCOL COPY MOVE LOCK UNLOCK)
112
+ RFC3253 = %w(VERSION-CONTROL REPORT CHECKOUT CHECKIN UNCHECKOUT MKWORKSPACE UPDATE LABEL MERGE BASELINE-CONTROL MKACTIVITY)
113
+ RFC3648 = %w(ORDERPATCH)
114
+ RFC3744 = %w(ACL)
115
+ RFC5323 = %w(SEARCH)
116
+ RFC4791 = %w(MKCALENDAR)
117
+ RFC5789 = %w(PATCH)
118
+
119
+ HTTP_METHODS = RFC2616 + RFC2518 + RFC3253 + RFC3648 + RFC3744 + RFC5323 + RFC4791 + RFC5789
120
+
121
+ HTTP_METHOD_LOOKUP = {}
122
+
123
+ # Populate the HTTP method lookup cache.
124
+ HTTP_METHODS.each { |method|
125
+ HTTP_METHOD_LOOKUP[method] = method.underscore.to_sym
126
+ }
127
+
128
+ # Returns the HTTP \method that the application should see.
129
+ # In the case where the \method was overridden by a middleware
130
+ # (for instance, if a HEAD request was converted to a GET,
131
+ # or if a _method parameter was used to determine the \method
132
+ # the application should use), this \method returns the overridden
133
+ # value, not the original.
134
+ def request_method
135
+ @request_method ||= check_method(super)
136
+ end
137
+
138
+ def routes # :nodoc:
139
+ get_header("action_dispatch.routes".freeze)
140
+ end
141
+
142
+ def routes=(routes) # :nodoc:
143
+ set_header("action_dispatch.routes".freeze, routes)
144
+ end
145
+
146
+ def engine_script_name(_routes) # :nodoc:
147
+ get_header(_routes.env_key)
148
+ end
149
+
150
+ def engine_script_name=(name) # :nodoc:
151
+ set_header(routes.env_key, name.dup)
152
+ end
153
+
154
+ def request_method=(request_method) #:nodoc:
155
+ if check_method(request_method)
156
+ @request_method = set_header("REQUEST_METHOD", request_method)
157
+ end
158
+ end
159
+
160
+ def controller_instance # :nodoc:
161
+ get_header("action_controller.instance".freeze)
162
+ end
163
+
164
+ def controller_instance=(controller) # :nodoc:
165
+ set_header("action_controller.instance".freeze, controller)
166
+ end
167
+
168
+ def http_auth_salt
169
+ get_header "action_dispatch.http_auth_salt"
170
+ end
171
+
172
+ def show_exceptions? # :nodoc:
173
+ # We're treating `nil` as "unset", and we want the default setting to be
174
+ # `true`. This logic should be extracted to `env_config` and calculated
175
+ # once.
176
+ !(get_header("action_dispatch.show_exceptions".freeze) == false)
177
+ end
178
+
179
+ # Returns a symbol form of the #request_method.
180
+ def request_method_symbol
181
+ HTTP_METHOD_LOOKUP[request_method]
182
+ end
183
+
184
+ # Returns the original value of the environment's REQUEST_METHOD,
185
+ # even if it was overridden by middleware. See #request_method for
186
+ # more information.
187
+ def method
188
+ @method ||= check_method(get_header("rack.methodoverride.original_method") || get_header("REQUEST_METHOD"))
189
+ end
190
+
191
+ # Returns a symbol form of the #method.
192
+ def method_symbol
193
+ HTTP_METHOD_LOOKUP[method]
194
+ end
195
+
196
+ # Provides access to the request's HTTP headers, for example:
197
+ #
198
+ # request.headers["Content-Type"] # => "text/plain"
199
+ def headers
200
+ @headers ||= Http::Headers.new(self)
201
+ end
202
+
203
+ # Early Hints is an HTTP/2 status code that indicates hints to help a client start
204
+ # making preparations for processing the final response.
205
+ #
206
+ # If the env contains +rack.early_hints+ then the server accepts HTTP2 push for Link headers.
207
+ #
208
+ # The +send_early_hints+ method accepts a hash of links as follows:
209
+ #
210
+ # send_early_hints("Link" => "</style.css>; rel=preload; as=style\n</script.js>; rel=preload")
211
+ #
212
+ # If you are using +javascript_include_tag+ or +stylesheet_link_tag+ the
213
+ # Early Hints headers are included by default if supported.
214
+ def send_early_hints(links)
215
+ return unless env["rack.early_hints"]
216
+
217
+ env["rack.early_hints"].call(links)
218
+ end
219
+
220
+ # Returns a +String+ with the last requested path including their params.
221
+ #
222
+ # # get '/foo'
223
+ # request.original_fullpath # => '/foo'
224
+ #
225
+ # # get '/foo?bar'
226
+ # request.original_fullpath # => '/foo?bar'
227
+ def original_fullpath
228
+ @original_fullpath ||= (get_header("ORIGINAL_FULLPATH") || fullpath)
229
+ end
230
+
231
+ # Returns the +String+ full path including params of the last URL requested.
232
+ #
233
+ # # get "/articles"
234
+ # request.fullpath # => "/articles"
235
+ #
236
+ # # get "/articles?page=2"
237
+ # request.fullpath # => "/articles?page=2"
238
+ def fullpath
239
+ @fullpath ||= super
240
+ end
241
+
242
+ # Returns the original request URL as a +String+.
243
+ #
244
+ # # get "/articles?page=2"
245
+ # request.original_url # => "http://www.example.com/articles?page=2"
246
+ def original_url
247
+ base_url + original_fullpath
248
+ end
249
+
250
+ # The +String+ MIME type of the request.
251
+ #
252
+ # # get "/articles"
253
+ # request.media_type # => "application/x-www-form-urlencoded"
254
+ def media_type
255
+ content_mime_type.to_s
256
+ end
257
+
258
+ # Returns the content length of the request as an integer.
259
+ def content_length
260
+ super.to_i
261
+ end
262
+
263
+ # Returns true if the "X-Requested-With" header contains "XMLHttpRequest"
264
+ # (case-insensitive), which may need to be manually added depending on the
265
+ # choice of JavaScript libraries and frameworks.
266
+ def xml_http_request?
267
+ get_header("HTTP_X_REQUESTED_WITH") =~ /XMLHttpRequest/i
268
+ end
269
+ alias :xhr? :xml_http_request?
270
+
271
+ # Returns the IP address of client as a +String+.
272
+ def ip
273
+ @ip ||= super
274
+ end
275
+
276
+ # Returns the IP address of client as a +String+,
277
+ # usually set by the RemoteIp middleware.
278
+ def remote_ip
279
+ @remote_ip ||= (get_header("action_dispatch.remote_ip") || ip).to_s
280
+ end
281
+
282
+ def remote_ip=(remote_ip)
283
+ set_header "action_dispatch.remote_ip".freeze, remote_ip
284
+ end
285
+
286
+ ACTION_DISPATCH_REQUEST_ID = "action_dispatch.request_id".freeze # :nodoc:
287
+
288
+ # Returns the unique request id, which is based on either the X-Request-Id header that can
289
+ # be generated by a firewall, load balancer, or web server or by the RequestId middleware
290
+ # (which sets the action_dispatch.request_id environment variable).
291
+ #
292
+ # This unique ID is useful for tracing a request from end-to-end as part of logging or debugging.
293
+ # This relies on the Rack variable set by the ActionDispatch::RequestId middleware.
294
+ def request_id
295
+ get_header ACTION_DISPATCH_REQUEST_ID
296
+ end
297
+
298
+ def request_id=(id) # :nodoc:
299
+ set_header ACTION_DISPATCH_REQUEST_ID, id
300
+ end
301
+
302
+ alias_method :uuid, :request_id
303
+
304
+ # Returns the lowercase name of the HTTP server software.
305
+ def server_software
306
+ (get_header("SERVER_SOFTWARE") && /^([a-zA-Z]+)/ =~ get_header("SERVER_SOFTWARE")) ? $1.downcase : nil
307
+ end
308
+
309
+ # Read the request \body. This is useful for web services that need to
310
+ # work with raw requests directly.
311
+ def raw_post
312
+ unless has_header? "RAW_POST_DATA"
313
+ raw_post_body = body
314
+ set_header("RAW_POST_DATA", raw_post_body.read(content_length))
315
+ raw_post_body.rewind if raw_post_body.respond_to?(:rewind)
316
+ end
317
+ get_header "RAW_POST_DATA"
318
+ end
319
+
320
+ # The request body is an IO input stream. If the RAW_POST_DATA environment
321
+ # variable is already set, wrap it in a StringIO.
322
+ def body
323
+ if raw_post = get_header("RAW_POST_DATA")
324
+ raw_post = raw_post.dup.force_encoding(Encoding::BINARY)
325
+ StringIO.new(raw_post)
326
+ else
327
+ body_stream
328
+ end
329
+ end
330
+
331
+ # Determine whether the request body contains form-data by checking
332
+ # the request Content-Type for one of the media-types:
333
+ # "application/x-www-form-urlencoded" or "multipart/form-data". The
334
+ # list of form-data media types can be modified through the
335
+ # +FORM_DATA_MEDIA_TYPES+ array.
336
+ #
337
+ # A request body is not assumed to contain form-data when no
338
+ # Content-Type header is provided and the request_method is POST.
339
+ def form_data?
340
+ FORM_DATA_MEDIA_TYPES.include?(media_type)
341
+ end
342
+
343
+ def body_stream #:nodoc:
344
+ get_header("rack.input")
345
+ end
346
+
347
+ # TODO This should be broken apart into AD::Request::Session and probably
348
+ # be included by the session middleware.
349
+ def reset_session
350
+ if session && session.respond_to?(:destroy)
351
+ session.destroy
352
+ else
353
+ self.session = {}
354
+ end
355
+ end
356
+
357
+ def session=(session) #:nodoc:
358
+ Session.set self, session
359
+ end
360
+
361
+ def session_options=(options)
362
+ Session::Options.set self, options
363
+ end
364
+
365
+ # Override Rack's GET method to support indifferent access.
366
+ def GET
367
+ fetch_header("action_dispatch.request.query_parameters") do |k|
368
+ rack_query_params = super || {}
369
+ # Check for non UTF-8 parameter values, which would cause errors later
370
+ Request::Utils.check_param_encoding(rack_query_params)
371
+ set_header k, Request::Utils.normalize_encode_params(rack_query_params)
372
+ end
373
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
374
+ raise ActionController::BadRequest.new("Invalid query parameters: #{e.message}")
375
+ end
376
+ alias :query_parameters :GET
377
+
378
+ # Override Rack's POST method to support indifferent access.
379
+ def POST
380
+ fetch_header("action_dispatch.request.request_parameters") do
381
+ pr = parse_formatted_parameters(params_parsers) do |params|
382
+ super || {}
383
+ end
384
+ self.request_parameters = Request::Utils.normalize_encode_params(pr)
385
+ end
386
+ rescue Http::Parameters::ParseError # one of the parse strategies blew up
387
+ self.request_parameters = Request::Utils.normalize_encode_params(super || {})
388
+ raise
389
+ rescue Rack::Utils::ParameterTypeError, Rack::Utils::InvalidParameterError => e
390
+ raise ActionController::BadRequest.new("Invalid request parameters: #{e.message}")
391
+ end
392
+ alias :request_parameters :POST
393
+
394
+ # Returns the authorization header regardless of whether it was specified directly or through one of the
395
+ # proxy alternatives.
396
+ def authorization
397
+ get_header("HTTP_AUTHORIZATION") ||
398
+ get_header("X-HTTP_AUTHORIZATION") ||
399
+ get_header("X_HTTP_AUTHORIZATION") ||
400
+ get_header("REDIRECT_X_HTTP_AUTHORIZATION")
401
+ end
402
+
403
+ # True if the request came from localhost, 127.0.0.1, or ::1.
404
+ def local?
405
+ LOCALHOST =~ remote_addr && LOCALHOST =~ remote_ip
406
+ end
407
+
408
+ def request_parameters=(params)
409
+ raise if params.nil?
410
+ set_header("action_dispatch.request.request_parameters".freeze, params)
411
+ end
412
+
413
+ def logger
414
+ get_header("action_dispatch.logger".freeze)
415
+ end
416
+
417
+ def commit_flash
418
+ end
419
+
420
+ def ssl?
421
+ super || scheme == "wss".freeze
422
+ end
423
+
424
+ private
425
+ def check_method(name)
426
+ HTTP_METHOD_LOOKUP[name] || raise(ActionController::UnknownHttpMethod, "#{name}, accepted HTTP methods are #{HTTP_METHODS[0...-1].join(', ')}, and #{HTTP_METHODS[-1]}")
427
+ name
428
+ end
429
+ end
430
+ end