halorgium-actionpack 3.0.pre

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. data/CHANGELOG +5179 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/lib/abstract_controller.rb +16 -0
  5. data/lib/abstract_controller/base.rb +158 -0
  6. data/lib/abstract_controller/callbacks.rb +113 -0
  7. data/lib/abstract_controller/exceptions.rb +12 -0
  8. data/lib/abstract_controller/helpers.rb +151 -0
  9. data/lib/abstract_controller/layouts.rb +250 -0
  10. data/lib/abstract_controller/localized_cache.rb +49 -0
  11. data/lib/abstract_controller/logger.rb +61 -0
  12. data/lib/abstract_controller/rendering_controller.rb +188 -0
  13. data/lib/action_controller.rb +72 -0
  14. data/lib/action_controller/base.rb +168 -0
  15. data/lib/action_controller/caching.rb +80 -0
  16. data/lib/action_controller/caching/actions.rb +163 -0
  17. data/lib/action_controller/caching/fragments.rb +116 -0
  18. data/lib/action_controller/caching/pages.rb +154 -0
  19. data/lib/action_controller/caching/sweeping.rb +97 -0
  20. data/lib/action_controller/deprecated.rb +4 -0
  21. data/lib/action_controller/deprecated/integration_test.rb +2 -0
  22. data/lib/action_controller/deprecated/performance_test.rb +1 -0
  23. data/lib/action_controller/dispatch/dispatcher.rb +57 -0
  24. data/lib/action_controller/metal.rb +129 -0
  25. data/lib/action_controller/metal/benchmarking.rb +73 -0
  26. data/lib/action_controller/metal/compatibility.rb +145 -0
  27. data/lib/action_controller/metal/conditional_get.rb +86 -0
  28. data/lib/action_controller/metal/configuration.rb +28 -0
  29. data/lib/action_controller/metal/cookies.rb +105 -0
  30. data/lib/action_controller/metal/exceptions.rb +55 -0
  31. data/lib/action_controller/metal/filter_parameter_logging.rb +77 -0
  32. data/lib/action_controller/metal/flash.rb +162 -0
  33. data/lib/action_controller/metal/head.rb +27 -0
  34. data/lib/action_controller/metal/helpers.rb +115 -0
  35. data/lib/action_controller/metal/hide_actions.rb +47 -0
  36. data/lib/action_controller/metal/http_authentication.rb +312 -0
  37. data/lib/action_controller/metal/layouts.rb +171 -0
  38. data/lib/action_controller/metal/mime_responds.rb +317 -0
  39. data/lib/action_controller/metal/rack_convenience.rb +27 -0
  40. data/lib/action_controller/metal/redirector.rb +22 -0
  41. data/lib/action_controller/metal/render_options.rb +103 -0
  42. data/lib/action_controller/metal/rendering_controller.rb +57 -0
  43. data/lib/action_controller/metal/request_forgery_protection.rb +108 -0
  44. data/lib/action_controller/metal/rescuable.rb +13 -0
  45. data/lib/action_controller/metal/responder.rb +200 -0
  46. data/lib/action_controller/metal/session.rb +15 -0
  47. data/lib/action_controller/metal/session_management.rb +45 -0
  48. data/lib/action_controller/metal/streaming.rb +188 -0
  49. data/lib/action_controller/metal/testing.rb +39 -0
  50. data/lib/action_controller/metal/url_for.rb +41 -0
  51. data/lib/action_controller/metal/verification.rb +130 -0
  52. data/lib/action_controller/middleware.rb +38 -0
  53. data/lib/action_controller/notifications.rb +10 -0
  54. data/lib/action_controller/polymorphic_routes.rb +183 -0
  55. data/lib/action_controller/record_identifier.rb +91 -0
  56. data/lib/action_controller/testing/process.rb +111 -0
  57. data/lib/action_controller/testing/test_case.rb +345 -0
  58. data/lib/action_controller/translation.rb +13 -0
  59. data/lib/action_controller/url_rewriter.rb +204 -0
  60. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  61. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  62. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  63. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +176 -0
  64. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  65. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  66. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  67. data/lib/action_dispatch.rb +70 -0
  68. data/lib/action_dispatch/http/headers.rb +33 -0
  69. data/lib/action_dispatch/http/mime_type.rb +231 -0
  70. data/lib/action_dispatch/http/mime_types.rb +23 -0
  71. data/lib/action_dispatch/http/request.rb +539 -0
  72. data/lib/action_dispatch/http/response.rb +290 -0
  73. data/lib/action_dispatch/http/status_codes.rb +42 -0
  74. data/lib/action_dispatch/http/utils.rb +20 -0
  75. data/lib/action_dispatch/middleware/callbacks.rb +50 -0
  76. data/lib/action_dispatch/middleware/params_parser.rb +79 -0
  77. data/lib/action_dispatch/middleware/rescue.rb +26 -0
  78. data/lib/action_dispatch/middleware/session/abstract_store.rb +208 -0
  79. data/lib/action_dispatch/middleware/session/cookie_store.rb +235 -0
  80. data/lib/action_dispatch/middleware/session/mem_cache_store.rb +47 -0
  81. data/lib/action_dispatch/middleware/show_exceptions.rb +143 -0
  82. data/lib/action_dispatch/middleware/stack.rb +116 -0
  83. data/lib/action_dispatch/middleware/static.rb +44 -0
  84. data/lib/action_dispatch/middleware/string_coercion.rb +29 -0
  85. data/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb +24 -0
  86. data/lib/action_dispatch/middleware/templates/rescues/_trace.erb +26 -0
  87. data/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb +10 -0
  88. data/lib/action_dispatch/middleware/templates/rescues/layout.erb +29 -0
  89. data/lib/action_dispatch/middleware/templates/rescues/missing_template.erb +2 -0
  90. data/lib/action_dispatch/middleware/templates/rescues/routing_error.erb +10 -0
  91. data/lib/action_dispatch/middleware/templates/rescues/template_error.erb +21 -0
  92. data/lib/action_dispatch/middleware/templates/rescues/unknown_action.erb +2 -0
  93. data/lib/action_dispatch/routing.rb +381 -0
  94. data/lib/action_dispatch/routing/deprecated_mapper.rb +878 -0
  95. data/lib/action_dispatch/routing/mapper.rb +327 -0
  96. data/lib/action_dispatch/routing/route.rb +49 -0
  97. data/lib/action_dispatch/routing/route_set.rb +497 -0
  98. data/lib/action_dispatch/testing/assertions.rb +8 -0
  99. data/lib/action_dispatch/testing/assertions/dom.rb +35 -0
  100. data/lib/action_dispatch/testing/assertions/model.rb +19 -0
  101. data/lib/action_dispatch/testing/assertions/response.rb +145 -0
  102. data/lib/action_dispatch/testing/assertions/routing.rb +144 -0
  103. data/lib/action_dispatch/testing/assertions/selector.rb +639 -0
  104. data/lib/action_dispatch/testing/assertions/tag.rb +123 -0
  105. data/lib/action_dispatch/testing/integration.rb +504 -0
  106. data/lib/action_dispatch/testing/performance_test.rb +15 -0
  107. data/lib/action_dispatch/testing/test_request.rb +83 -0
  108. data/lib/action_dispatch/testing/test_response.rb +131 -0
  109. data/lib/action_pack.rb +24 -0
  110. data/lib/action_pack/version.rb +9 -0
  111. data/lib/action_view.rb +58 -0
  112. data/lib/action_view/base.rb +308 -0
  113. data/lib/action_view/context.rb +44 -0
  114. data/lib/action_view/erb/util.rb +48 -0
  115. data/lib/action_view/helpers.rb +62 -0
  116. data/lib/action_view/helpers/active_model_helper.rb +306 -0
  117. data/lib/action_view/helpers/ajax_helper.rb +68 -0
  118. data/lib/action_view/helpers/asset_tag_helper.rb +830 -0
  119. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  120. data/lib/action_view/helpers/cache_helper.rb +39 -0
  121. data/lib/action_view/helpers/capture_helper.rb +168 -0
  122. data/lib/action_view/helpers/date_helper.rb +988 -0
  123. data/lib/action_view/helpers/debug_helper.rb +38 -0
  124. data/lib/action_view/helpers/form_helper.rb +1102 -0
  125. data/lib/action_view/helpers/form_options_helper.rb +600 -0
  126. data/lib/action_view/helpers/form_tag_helper.rb +495 -0
  127. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  128. data/lib/action_view/helpers/number_helper.rb +311 -0
  129. data/lib/action_view/helpers/prototype_helper.rb +1309 -0
  130. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  131. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  132. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  133. data/lib/action_view/helpers/sanitize_helper.rb +259 -0
  134. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  135. data/lib/action_view/helpers/tag_helper.rb +151 -0
  136. data/lib/action_view/helpers/text_helper.rb +594 -0
  137. data/lib/action_view/helpers/translation_helper.rb +39 -0
  138. data/lib/action_view/helpers/url_helper.rb +639 -0
  139. data/lib/action_view/locale/en.yml +117 -0
  140. data/lib/action_view/paths.rb +80 -0
  141. data/lib/action_view/render/partials.rb +342 -0
  142. data/lib/action_view/render/rendering.rb +134 -0
  143. data/lib/action_view/safe_buffer.rb +28 -0
  144. data/lib/action_view/template/error.rb +101 -0
  145. data/lib/action_view/template/handler.rb +36 -0
  146. data/lib/action_view/template/handlers.rb +52 -0
  147. data/lib/action_view/template/handlers/builder.rb +17 -0
  148. data/lib/action_view/template/handlers/erb.rb +53 -0
  149. data/lib/action_view/template/handlers/rjs.rb +18 -0
  150. data/lib/action_view/template/resolver.rb +165 -0
  151. data/lib/action_view/template/template.rb +131 -0
  152. data/lib/action_view/template/text.rb +38 -0
  153. data/lib/action_view/test_case.rb +163 -0
  154. metadata +236 -0
@@ -0,0 +1,290 @@
1
+ require 'digest/md5'
2
+ require 'active_support/core_ext/module/delegation'
3
+
4
+ module ActionDispatch # :nodoc:
5
+ # Represents an HTTP response generated by a controller action. One can use
6
+ # an ActionDispatch::Response object to retrieve the current state
7
+ # of the response, or customize the response. An Response object can
8
+ # either represent a "real" HTTP response (i.e. one that is meant to be sent
9
+ # back to the web browser) or a test response (i.e. one that is generated
10
+ # from integration tests). See CgiResponse and TestResponse, respectively.
11
+ #
12
+ # Response is mostly a Ruby on Rails framework implement detail, and
13
+ # should never be used directly in controllers. Controllers should use the
14
+ # methods defined in ActionController::Base instead. For example, if you want
15
+ # to set the HTTP response's content MIME type, then use
16
+ # ActionControllerBase#headers instead of Response#headers.
17
+ #
18
+ # Nevertheless, integration tests may want to inspect controller responses in
19
+ # more detail, and that's when Response can be useful for application
20
+ # developers. Integration test methods such as
21
+ # ActionDispatch::Integration::Session#get and
22
+ # ActionDispatch::Integration::Session#post return objects of type
23
+ # TestResponse (which are of course also of type Response).
24
+ #
25
+ # For example, the following demo integration "test" prints the body of the
26
+ # controller response to the console:
27
+ #
28
+ # class DemoControllerTest < ActionDispatch::IntegrationTest
29
+ # def test_print_root_path_to_console
30
+ # get('/')
31
+ # puts @response.body
32
+ # end
33
+ # end
34
+ class Response < Rack::Response
35
+ attr_accessor :request, :blank
36
+ attr_reader :cache_control
37
+
38
+ attr_writer :header, :sending_file
39
+ alias_method :headers=, :header=
40
+
41
+ def initialize
42
+ @status = 200
43
+ @header = {}
44
+ @cache_control = {}
45
+
46
+ @writer = lambda { |x| @body << x }
47
+ @block = nil
48
+ @length = 0
49
+
50
+ @body, @cookie = [], []
51
+ @sending_file = false
52
+
53
+ yield self if block_given?
54
+ end
55
+
56
+ def cache_control
57
+ @cache_control ||= {}
58
+ end
59
+
60
+ def write(str)
61
+ s = str.to_s
62
+ @writer.call s
63
+ str
64
+ end
65
+
66
+ def status=(status)
67
+ @status = status.to_i
68
+ end
69
+
70
+ # The response code of the request
71
+ def response_code
72
+ @status
73
+ end
74
+
75
+ # Returns a String to ensure compatibility with Net::HTTPResponse
76
+ def code
77
+ @status.to_s
78
+ end
79
+
80
+ def message
81
+ StatusCodes::STATUS_CODES[@status]
82
+ end
83
+ alias_method :status_message, :message
84
+
85
+ def body
86
+ str = ''
87
+ each { |part| str << part.to_s }
88
+ str
89
+ end
90
+
91
+ EMPTY = " "
92
+
93
+ def body=(body)
94
+ @blank = true if body == EMPTY
95
+ @body = body.respond_to?(:to_str) ? [body] : body
96
+ end
97
+
98
+ def body_parts
99
+ @body
100
+ end
101
+
102
+ def location
103
+ headers['Location']
104
+ end
105
+ alias_method :redirect_url, :location
106
+
107
+ def location=(url)
108
+ headers['Location'] = url
109
+ end
110
+
111
+ # Sets the HTTP response's content MIME type. For example, in the controller
112
+ # you could write this:
113
+ #
114
+ # response.content_type = "text/plain"
115
+ #
116
+ # If a character set has been defined for this response (see charset=) then
117
+ # the character set information will also be included in the content type
118
+ # information.
119
+ attr_accessor :charset, :content_type
120
+
121
+ def last_modified
122
+ if last = headers['Last-Modified']
123
+ Time.httpdate(last)
124
+ end
125
+ end
126
+
127
+ def last_modified?
128
+ headers.include?('Last-Modified')
129
+ end
130
+
131
+ def last_modified=(utc_time)
132
+ headers['Last-Modified'] = utc_time.httpdate
133
+ end
134
+
135
+ def etag
136
+ @etag
137
+ end
138
+
139
+ def etag?
140
+ @etag
141
+ end
142
+
143
+ def etag=(etag)
144
+ key = ActiveSupport::Cache.expand_cache_key(etag)
145
+ @etag = %("#{Digest::MD5.hexdigest(key)}")
146
+ end
147
+
148
+ CONTENT_TYPE = "Content-Type"
149
+
150
+ cattr_accessor(:default_charset) { "utf-8" }
151
+
152
+ def assign_default_content_type_and_charset!
153
+ return if headers[CONTENT_TYPE].present?
154
+
155
+ @content_type ||= Mime::HTML
156
+ @charset ||= self.class.default_charset
157
+
158
+ type = @content_type.to_s.dup
159
+ type << "; charset=#{@charset}" unless @sending_file
160
+
161
+ headers[CONTENT_TYPE] = type
162
+ end
163
+
164
+ def to_a
165
+ assign_default_content_type_and_charset!
166
+ handle_conditional_get!
167
+ self["Set-Cookie"] = @cookie.join("\n")
168
+ self["ETag"] = @etag if @etag
169
+ super
170
+ end
171
+
172
+ alias prepare! to_a
173
+
174
+ def each(&callback)
175
+ if @body.respond_to?(:call)
176
+ @writer = lambda { |x| callback.call(x) }
177
+ @body.call(self, self)
178
+ else
179
+ @body.each { |part| callback.call(part.to_s) }
180
+ end
181
+
182
+ @writer = callback
183
+ @block.call(self) if @block
184
+ end
185
+
186
+ def write(str)
187
+ str = str.to_s
188
+ @writer.call str
189
+ str
190
+ end
191
+
192
+ # Returns the response cookies, converted to a Hash of (name => value) pairs
193
+ #
194
+ # assert_equal 'AuthorOfNewPage', r.cookies['author']
195
+ def cookies
196
+ cookies = {}
197
+ if header = @cookie
198
+ header = header.split("\n") if header.respond_to?(:to_str)
199
+ header.each do |cookie|
200
+ if pair = cookie.split(';').first
201
+ key, value = pair.split("=").map { |v| Rack::Utils.unescape(v) }
202
+ cookies[key] = value
203
+ end
204
+ end
205
+ end
206
+ cookies
207
+ end
208
+
209
+ def set_cookie(key, value)
210
+ case value
211
+ when Hash
212
+ domain = "; domain=" + value[:domain] if value[:domain]
213
+ path = "; path=" + value[:path] if value[:path]
214
+ # According to RFC 2109, we need dashes here.
215
+ # N.B.: cgi.rb uses spaces...
216
+ expires = "; expires=" + value[:expires].clone.gmtime.
217
+ strftime("%a, %d-%b-%Y %H:%M:%S GMT") if value[:expires]
218
+ secure = "; secure" if value[:secure]
219
+ httponly = "; HttpOnly" if value[:httponly]
220
+ value = value[:value]
221
+ end
222
+ value = [value] unless Array === value
223
+ cookie = Rack::Utils.escape(key) + "=" +
224
+ value.map { |v| Rack::Utils.escape v }.join("&") +
225
+ "#{domain}#{path}#{expires}#{secure}#{httponly}"
226
+
227
+ @cookie << cookie
228
+ end
229
+
230
+ def delete_cookie(key, value={})
231
+ @cookie.reject! { |cookie|
232
+ cookie =~ /\A#{Rack::Utils.escape(key)}=/
233
+ }
234
+
235
+ set_cookie(key,
236
+ {:value => '', :path => nil, :domain => nil,
237
+ :expires => Time.at(0) }.merge(value))
238
+ end
239
+
240
+ private
241
+ def handle_conditional_get!
242
+ if etag? || last_modified? || !@cache_control.empty?
243
+ set_conditional_cache_control!
244
+ elsif nonempty_ok_response?
245
+ self.etag = @body
246
+
247
+ if request && request.etag_matches?(etag)
248
+ self.status = 304
249
+ self.body = []
250
+ end
251
+
252
+ set_conditional_cache_control!
253
+ else
254
+ headers["Cache-Control"] = "no-cache"
255
+ end
256
+ end
257
+
258
+ def nonempty_ok_response?
259
+ @status == 200 && string_body?
260
+ end
261
+
262
+ def string_body?
263
+ !@blank && @body.respond_to?(:all?) && @body.all? { |part| part.is_a?(String) }
264
+ end
265
+
266
+ DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate"
267
+
268
+ def set_conditional_cache_control!
269
+ control = @cache_control
270
+
271
+ if control.empty?
272
+ headers["Cache-Control"] = DEFAULT_CACHE_CONTROL
273
+ elsif @cache_control[:no_cache]
274
+ headers["Cache-Control"] = "no-cache"
275
+ else
276
+ extras = control[:extras]
277
+ max_age = control[:max_age]
278
+
279
+ options = []
280
+ options << "max-age=#{max_age}" if max_age
281
+ options << (control[:public] ? "public" : "private")
282
+ options << "must-revalidate" if control[:must_revalidate]
283
+ options.concat(extras) if extras
284
+
285
+ headers["Cache-Control"] = options.join(", ")
286
+ end
287
+
288
+ end
289
+ end
290
+ end
@@ -0,0 +1,42 @@
1
+ require 'active_support/inflector'
2
+
3
+ module ActionDispatch
4
+ module StatusCodes #:nodoc:
5
+ STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES.merge({
6
+ 102 => "Processing",
7
+ 207 => "Multi-Status",
8
+ 226 => "IM Used",
9
+ 422 => "Unprocessable Entity",
10
+ 423 => "Locked",
11
+ 424 => "Failed Dependency",
12
+ 426 => "Upgrade Required",
13
+ 507 => "Insufficient Storage",
14
+ 510 => "Not Extended"
15
+ }).freeze
16
+
17
+ # Provides a symbol-to-fixnum lookup for converting a symbol (like
18
+ # :created or :not_implemented) into its corresponding HTTP status
19
+ # code (like 200 or 501).
20
+ SYMBOL_TO_STATUS_CODE = STATUS_CODES.inject({}) { |hash, (code, message)|
21
+ hash[ActiveSupport::Inflector.underscore(message.gsub(/ /, "")).to_sym] = code
22
+ hash
23
+ }.freeze
24
+
25
+ private
26
+ # Given a status parameter, determine whether it needs to be converted
27
+ # to a string. If it is a fixnum, use the STATUS_CODES hash to lookup
28
+ # the default message. If it is a symbol, use the SYMBOL_TO_STATUS_CODE
29
+ # hash to convert it.
30
+ def interpret_status(status)
31
+ case status
32
+ when Fixnum then
33
+ "#{status} #{STATUS_CODES[status]}".strip
34
+ when Symbol then
35
+ interpret_status(SYMBOL_TO_STATUS_CODE[status] ||
36
+ "500 Unknown Status #{status.inspect}")
37
+ else
38
+ status.to_s
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,20 @@
1
+ module ActionDispatch
2
+ module Utils
3
+ # TODO: Pull this into rack core
4
+ # http://github.com/halorgium/rack/commit/feaf071c1de743fbd10bc316830180a9af607278
5
+ def parse_config(config)
6
+ if config =~ /\.ru$/
7
+ cfgfile = ::File.read(config)
8
+ if cfgfile[/^#\\(.*)/]
9
+ opts.parse! $1.split(/\s+/)
10
+ end
11
+ inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
12
+ nil, config
13
+ else
14
+ require config
15
+ inner_app = Object.const_get(::File.basename(config, '.rb').capitalize)
16
+ end
17
+ end
18
+ module_function :parse_config
19
+ end
20
+ end
@@ -0,0 +1,50 @@
1
+ module ActionDispatch
2
+ class Callbacks
3
+ include ActiveSupport::Callbacks
4
+
5
+ define_callbacks :call, :terminator => "result == false", :rescuable => true
6
+ define_callbacks :prepare, :scope => :name
7
+
8
+ # Add a preparation callback. Preparation callbacks are run before every
9
+ # request in development mode, and before the first request in production mode.
10
+ #
11
+ # If a symbol with a block is given, the symbol is used as an identifier.
12
+ # That allows to_prepare to be called again with the same identifier to
13
+ # replace the existing callback. Passing an identifier is a suggested
14
+ # practice if the code adding a preparation block may be reloaded.
15
+ def self.to_prepare(*args, &block)
16
+ if args.first.is_a?(Symbol) && block_given?
17
+ define_method :"__#{args.first}", &block
18
+ set_callback(:prepare, :"__#{args.first}")
19
+ else
20
+ set_callback(:prepare, *args, &block)
21
+ end
22
+ end
23
+
24
+ def self.before(*args, &block)
25
+ set_callback(:call, :before, *args, &block)
26
+ end
27
+
28
+ def self.after(*args, &block)
29
+ set_callback(:call, :after, *args, &block)
30
+ end
31
+
32
+ class << self
33
+ # DEPRECATED
34
+ alias_method :before_dispatch, :before
35
+ alias_method :after_dispatch, :after
36
+ end
37
+
38
+ def initialize(app, prepare_each_request = false)
39
+ @app, @prepare_each_request = app, prepare_each_request
40
+ run_callbacks(:prepare)
41
+ end
42
+
43
+ def call(env)
44
+ run_callbacks(:call) do
45
+ run_callbacks(:prepare) if @prepare_each_request
46
+ @app.call(env)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,79 @@
1
+ require 'active_support/json'
2
+
3
+ module ActionDispatch
4
+ class ParamsParser
5
+ DEFAULT_PARSERS = {
6
+ Mime::XML => :xml_simple,
7
+ Mime::JSON => :json
8
+ }
9
+
10
+ def initialize(app, parsers = {})
11
+ @app, @parsers = app, DEFAULT_PARSERS.merge(parsers)
12
+ end
13
+
14
+ def call(env)
15
+ if params = parse_formatted_parameters(env)
16
+ env["action_dispatch.request.request_parameters"] = params
17
+ end
18
+
19
+ @app.call(env)
20
+ end
21
+
22
+ private
23
+ def parse_formatted_parameters(env)
24
+ request = Request.new(env)
25
+
26
+ return false if request.content_length.zero?
27
+
28
+ mime_type = content_type_from_legacy_post_data_format_header(env) || request.content_type
29
+ strategy = @parsers[mime_type]
30
+
31
+ return false unless strategy
32
+
33
+ case strategy
34
+ when Proc
35
+ strategy.call(request.raw_post)
36
+ when :xml_simple, :xml_node
37
+ request.body.size == 0 ? {} : Hash.from_xml(request.body).with_indifferent_access
38
+ when :yaml
39
+ YAML.load(request.body)
40
+ when :json
41
+ if request.body.size == 0
42
+ {}
43
+ else
44
+ data = ActiveSupport::JSON.decode(request.body)
45
+ data = {:_json => data} unless data.is_a?(Hash)
46
+ data.with_indifferent_access
47
+ end
48
+ else
49
+ false
50
+ end
51
+ rescue Exception => e # YAML, XML or Ruby code block errors
52
+ logger.debug "Error occurred while parsing request parameters.\nContents:\n\n#{request.raw_post}"
53
+
54
+ raise
55
+ { "body" => request.raw_post,
56
+ "content_type" => request.content_type,
57
+ "content_length" => request.content_length,
58
+ "exception" => "#{e.message} (#{e.class})",
59
+ "backtrace" => e.backtrace }
60
+ end
61
+
62
+ def content_type_from_legacy_post_data_format_header(env)
63
+ if x_post_format = env['HTTP_X_POST_DATA_FORMAT']
64
+ case x_post_format.to_s.downcase
65
+ when 'yaml'
66
+ return Mime::YAML
67
+ when 'xml'
68
+ return Mime::XML
69
+ end
70
+ end
71
+
72
+ nil
73
+ end
74
+
75
+ def logger
76
+ defined?(Rails.logger) ? Rails.logger : Logger.new($stderr)
77
+ end
78
+ end
79
+ end