eactionpack 2.1.2

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 (338) hide show
  1. data/CHANGELOG +7 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +469 -0
  4. data/RUNNING_UNIT_TESTS +24 -0
  5. data/Rakefile +146 -0
  6. data/install.rb +30 -0
  7. data/lib/action_controller.rb +79 -0
  8. data/lib/action_controller/assertions.rb +69 -0
  9. data/lib/action_controller/assertions/dom_assertions.rb +39 -0
  10. data/lib/action_controller/assertions/model_assertions.rb +20 -0
  11. data/lib/action_controller/assertions/response_assertions.rb +172 -0
  12. data/lib/action_controller/assertions/routing_assertions.rb +146 -0
  13. data/lib/action_controller/assertions/selector_assertions.rb +491 -0
  14. data/lib/action_controller/assertions/tag_assertions.rb +130 -0
  15. data/lib/action_controller/base.rb +1288 -0
  16. data/lib/action_controller/benchmarking.rb +94 -0
  17. data/lib/action_controller/caching.rb +72 -0
  18. data/lib/action_controller/caching/actions.rb +144 -0
  19. data/lib/action_controller/caching/fragments.rb +138 -0
  20. data/lib/action_controller/caching/pages.rb +154 -0
  21. data/lib/action_controller/caching/sql_cache.rb +18 -0
  22. data/lib/action_controller/caching/sweeping.rb +97 -0
  23. data/lib/action_controller/cgi_ext.rb +16 -0
  24. data/lib/action_controller/cgi_ext/cookie.rb +110 -0
  25. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  26. data/lib/action_controller/cgi_ext/session.rb +73 -0
  27. data/lib/action_controller/cgi_ext/stdinput.rb +24 -0
  28. data/lib/action_controller/cgi_process.rb +223 -0
  29. data/lib/action_controller/components.rb +166 -0
  30. data/lib/action_controller/cookies.rb +96 -0
  31. data/lib/action_controller/dispatcher.rb +162 -0
  32. data/lib/action_controller/filters.rb +642 -0
  33. data/lib/action_controller/flash.rb +172 -0
  34. data/lib/action_controller/headers.rb +31 -0
  35. data/lib/action_controller/helpers.rb +221 -0
  36. data/lib/action_controller/http_authentication.rb +124 -0
  37. data/lib/action_controller/integration.rb +634 -0
  38. data/lib/action_controller/layout.rb +309 -0
  39. data/lib/action_controller/mime_responds.rb +173 -0
  40. data/lib/action_controller/mime_type.rb +186 -0
  41. data/lib/action_controller/mime_types.rb +20 -0
  42. data/lib/action_controller/polymorphic_routes.rb +191 -0
  43. data/lib/action_controller/record_identifier.rb +102 -0
  44. data/lib/action_controller/request.rb +764 -0
  45. data/lib/action_controller/request_forgery_protection.rb +140 -0
  46. data/lib/action_controller/request_profiler.rb +169 -0
  47. data/lib/action_controller/rescue.rb +258 -0
  48. data/lib/action_controller/resources.rb +572 -0
  49. data/lib/action_controller/response.rb +76 -0
  50. data/lib/action_controller/routing.rb +387 -0
  51. data/lib/action_controller/routing/builder.rb +203 -0
  52. data/lib/action_controller/routing/optimisations.rb +120 -0
  53. data/lib/action_controller/routing/recognition_optimisation.rb +162 -0
  54. data/lib/action_controller/routing/route.rb +240 -0
  55. data/lib/action_controller/routing/route_set.rb +436 -0
  56. data/lib/action_controller/routing/routing_ext.rb +46 -0
  57. data/lib/action_controller/routing/segments.rb +283 -0
  58. data/lib/action_controller/session/active_record_store.rb +340 -0
  59. data/lib/action_controller/session/cookie_store.rb +166 -0
  60. data/lib/action_controller/session/drb_server.rb +32 -0
  61. data/lib/action_controller/session/drb_store.rb +35 -0
  62. data/lib/action_controller/session/mem_cache_store.rb +98 -0
  63. data/lib/action_controller/session_management.rb +158 -0
  64. data/lib/action_controller/status_codes.rb +88 -0
  65. data/lib/action_controller/streaming.rb +155 -0
  66. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  67. data/lib/action_controller/templates/rescues/_trace.erb +26 -0
  68. data/lib/action_controller/templates/rescues/diagnostics.erb +11 -0
  69. data/lib/action_controller/templates/rescues/layout.erb +29 -0
  70. data/lib/action_controller/templates/rescues/missing_template.erb +2 -0
  71. data/lib/action_controller/templates/rescues/routing_error.erb +10 -0
  72. data/lib/action_controller/templates/rescues/template_error.erb +21 -0
  73. data/lib/action_controller/templates/rescues/unknown_action.erb +2 -0
  74. data/lib/action_controller/test_case.rb +83 -0
  75. data/lib/action_controller/test_process.rb +526 -0
  76. data/lib/action_controller/url_rewriter.rb +142 -0
  77. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  78. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  79. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  80. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  81. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  82. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  83. data/lib/action_controller/verification.rb +130 -0
  84. data/lib/action_pack.rb +24 -0
  85. data/lib/action_pack/version.rb +9 -0
  86. data/lib/action_view.rb +44 -0
  87. data/lib/action_view/base.rb +335 -0
  88. data/lib/action_view/helpers/active_record_helper.rb +276 -0
  89. data/lib/action_view/helpers/asset_tag_helper.rb +599 -0
  90. data/lib/action_view/helpers/atom_feed_helper.rb +143 -0
  91. data/lib/action_view/helpers/benchmark_helper.rb +33 -0
  92. data/lib/action_view/helpers/cache_helper.rb +40 -0
  93. data/lib/action_view/helpers/capture_helper.rb +161 -0
  94. data/lib/action_view/helpers/date_helper.rb +711 -0
  95. data/lib/action_view/helpers/debug_helper.rb +31 -0
  96. data/lib/action_view/helpers/form_helper.rb +767 -0
  97. data/lib/action_view/helpers/form_options_helper.rb +458 -0
  98. data/lib/action_view/helpers/form_tag_helper.rb +458 -0
  99. data/lib/action_view/helpers/javascript_helper.rb +148 -0
  100. data/lib/action_view/helpers/number_helper.rb +186 -0
  101. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  102. data/lib/action_view/helpers/record_tag_helper.rb +59 -0
  103. data/lib/action_view/helpers/sanitize_helper.rb +229 -0
  104. data/lib/action_view/helpers/tag_helper.rb +134 -0
  105. data/lib/action_view/helpers/text_helper.rb +507 -0
  106. data/lib/action_view/helpers/url_helper.rb +573 -0
  107. data/lib/action_view/inline_template.rb +20 -0
  108. data/lib/action_view/partial_template.rb +70 -0
  109. data/lib/action_view/partials.rb +158 -0
  110. data/lib/action_view/template.rb +125 -0
  111. data/lib/action_view/template_error.rb +110 -0
  112. data/lib/action_view/template_finder.rb +176 -0
  113. data/lib/action_view/template_handler.rb +34 -0
  114. data/lib/action_view/template_handlers/builder.rb +27 -0
  115. data/lib/action_view/template_handlers/compilable.rb +128 -0
  116. data/lib/action_view/template_handlers/erb.rb +56 -0
  117. data/lib/action_view/test_case.rb +58 -0
  118. data/lib/actionpack.rb +1 -0
  119. data/test/abstract_unit.rb +36 -0
  120. data/test/active_record_unit.rb +105 -0
  121. data/test/activerecord/active_record_store_test.rb +141 -0
  122. data/test/activerecord/render_partial_with_record_identification_test.rb +191 -0
  123. data/test/adv_attr_test.rb +20 -0
  124. data/test/controller/action_pack_assertions_test.rb +543 -0
  125. data/test/controller/addresses_render_test.rb +43 -0
  126. data/test/controller/assert_select_test.rb +331 -0
  127. data/test/controller/base_test.rb +219 -0
  128. data/test/controller/benchmark_test.rb +32 -0
  129. data/test/controller/caching_test.rb +581 -0
  130. data/test/controller/capture_test.rb +89 -0
  131. data/test/controller/cgi_test.rb +116 -0
  132. data/test/controller/components_test.rb +140 -0
  133. data/test/controller/content_type_test.rb +139 -0
  134. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  135. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  136. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  137. data/test/controller/cookie_test.rb +146 -0
  138. data/test/controller/custom_handler_test.rb +45 -0
  139. data/test/controller/deprecation/deprecated_base_methods_test.rb +37 -0
  140. data/test/controller/dispatcher_test.rb +105 -0
  141. data/test/controller/fake_controllers.rb +33 -0
  142. data/test/controller/fake_models.rb +11 -0
  143. data/test/controller/filter_params_test.rb +49 -0
  144. data/test/controller/filters_test.rb +881 -0
  145. data/test/controller/flash_test.rb +146 -0
  146. data/test/controller/header_test.rb +14 -0
  147. data/test/controller/helper_test.rb +210 -0
  148. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  149. data/test/controller/html-scanner/document_test.rb +148 -0
  150. data/test/controller/html-scanner/node_test.rb +89 -0
  151. data/test/controller/html-scanner/sanitizer_test.rb +269 -0
  152. data/test/controller/html-scanner/tag_node_test.rb +238 -0
  153. data/test/controller/html-scanner/text_node_test.rb +50 -0
  154. data/test/controller/html-scanner/tokenizer_test.rb +131 -0
  155. data/test/controller/http_authentication_test.rb +54 -0
  156. data/test/controller/integration_test.rb +252 -0
  157. data/test/controller/integration_upload_test.rb +43 -0
  158. data/test/controller/layout_test.rb +255 -0
  159. data/test/controller/mime_responds_test.rb +514 -0
  160. data/test/controller/mime_type_test.rb +84 -0
  161. data/test/controller/new_render_test.rb +843 -0
  162. data/test/controller/polymorphic_routes_test.rb +174 -0
  163. data/test/controller/record_identifier_test.rb +139 -0
  164. data/test/controller/redirect_test.rb +289 -0
  165. data/test/controller/render_test.rb +484 -0
  166. data/test/controller/request_forgery_protection_test.rb +305 -0
  167. data/test/controller/request_test.rb +928 -0
  168. data/test/controller/rescue_test.rb +517 -0
  169. data/test/controller/resources_test.rb +873 -0
  170. data/test/controller/routing_test.rb +2464 -0
  171. data/test/controller/selector_test.rb +628 -0
  172. data/test/controller/send_file_test.rb +138 -0
  173. data/test/controller/session/cookie_store_test.rb +258 -0
  174. data/test/controller/session/mem_cache_store_test.rb +181 -0
  175. data/test/controller/session_fixation_test.rb +89 -0
  176. data/test/controller/session_management_test.rb +178 -0
  177. data/test/controller/test_test.rb +695 -0
  178. data/test/controller/url_rewriter_test.rb +310 -0
  179. data/test/controller/verification_test.rb +270 -0
  180. data/test/controller/view_paths_test.rb +140 -0
  181. data/test/controller/webservice_test.rb +229 -0
  182. data/test/fixtures/addresses/list.erb +1 -0
  183. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  184. data/test/fixtures/companies.yml +24 -0
  185. data/test/fixtures/company.rb +10 -0
  186. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  187. data/test/fixtures/content_type/render_default_for_js.js.erb +1 -0
  188. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  189. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  190. data/test/fixtures/customers/_customer.html.erb +1 -0
  191. data/test/fixtures/db_definitions/sqlite.sql +49 -0
  192. data/test/fixtures/developer.rb +9 -0
  193. data/test/fixtures/developers.yml +21 -0
  194. data/test/fixtures/developers_projects.yml +13 -0
  195. data/test/fixtures/fun/games/hello_world.erb +1 -0
  196. data/test/fixtures/functional_caching/_partial.erb +3 -0
  197. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  198. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  199. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  200. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  201. data/test/fixtures/helpers/abc_helper.rb +5 -0
  202. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  203. data/test/fixtures/helpers/fun/pdf_helper.rb +3 -0
  204. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  205. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  206. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  207. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  208. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  209. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  210. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  211. data/test/fixtures/layouts/block_with_layout.erb +3 -0
  212. data/test/fixtures/layouts/builder.builder +3 -0
  213. data/test/fixtures/layouts/partial_with_layout.erb +3 -0
  214. data/test/fixtures/layouts/standard.erb +1 -0
  215. data/test/fixtures/layouts/talk_from_action.erb +2 -0
  216. data/test/fixtures/layouts/yield.erb +2 -0
  217. data/test/fixtures/mascot.rb +3 -0
  218. data/test/fixtures/mascots.yml +4 -0
  219. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  220. data/test/fixtures/multipart/binary_file +0 -0
  221. data/test/fixtures/multipart/boundary_problem_file +10 -0
  222. data/test/fixtures/multipart/bracketed_param +5 -0
  223. data/test/fixtures/multipart/large_text_file +10 -0
  224. data/test/fixtures/multipart/mixed_files +0 -0
  225. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  226. data/test/fixtures/multipart/single_parameter +5 -0
  227. data/test/fixtures/multipart/text_file +10 -0
  228. data/test/fixtures/override/test/hello_world.erb +1 -0
  229. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  230. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  231. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  232. data/test/fixtures/post_test/post/index.html.erb +1 -0
  233. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  234. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  235. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  236. data/test/fixtures/project.rb +3 -0
  237. data/test/fixtures/projects.yml +7 -0
  238. data/test/fixtures/public/404.html +1 -0
  239. data/test/fixtures/public/500.html +1 -0
  240. data/test/fixtures/public/images/rails.png +0 -0
  241. data/test/fixtures/public/javascripts/application.js +1 -0
  242. data/test/fixtures/public/javascripts/bank.js +1 -0
  243. data/test/fixtures/public/javascripts/robber.js +1 -0
  244. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  245. data/test/fixtures/public/stylesheets/bank.css +1 -0
  246. data/test/fixtures/public/stylesheets/robber.css +1 -0
  247. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  248. data/test/fixtures/replies.yml +15 -0
  249. data/test/fixtures/reply.rb +7 -0
  250. data/test/fixtures/respond_to/all_types_with_layout.html.erb +1 -0
  251. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  252. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  253. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  254. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  255. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  256. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  257. data/test/fixtures/respond_to/using_defaults.html.erb +1 -0
  258. data/test/fixtures/respond_to/using_defaults.js.rjs +1 -0
  259. data/test/fixtures/respond_to/using_defaults.xml.builder +1 -0
  260. data/test/fixtures/respond_to/using_defaults_with_type_list.html.erb +1 -0
  261. data/test/fixtures/respond_to/using_defaults_with_type_list.js.rjs +1 -0
  262. data/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder +1 -0
  263. data/test/fixtures/scope/test/modgreet.erb +1 -0
  264. data/test/fixtures/shared.html.erb +1 -0
  265. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  266. data/test/fixtures/test/_customer.erb +1 -0
  267. data/test/fixtures/test/_customer_counter.erb +1 -0
  268. data/test/fixtures/test/_customer_greeting.erb +1 -0
  269. data/test/fixtures/test/_form.erb +1 -0
  270. data/test/fixtures/test/_hash_greeting.erb +1 -0
  271. data/test/fixtures/test/_hash_object.erb +2 -0
  272. data/test/fixtures/test/_hello.builder +1 -0
  273. data/test/fixtures/test/_labelling_form.erb +1 -0
  274. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  275. data/test/fixtures/test/_partial.erb +1 -0
  276. data/test/fixtures/test/_partial.html.erb +1 -0
  277. data/test/fixtures/test/_partial.js.erb +1 -0
  278. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  279. data/test/fixtures/test/_partial_only.erb +1 -0
  280. data/test/fixtures/test/_person.erb +2 -0
  281. data/test/fixtures/test/_raise.html.erb +1 -0
  282. data/test/fixtures/test/action_talk_to_layout.erb +2 -0
  283. data/test/fixtures/test/block_content_for.erb +2 -0
  284. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  285. data/test/fixtures/test/capturing.erb +4 -0
  286. data/test/fixtures/test/content_for.erb +2 -0
  287. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  288. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  289. data/test/fixtures/test/delete_with_js.rjs +2 -0
  290. data/test/fixtures/test/dot.directory/render_file_with_ivar.erb +1 -0
  291. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  292. data/test/fixtures/test/erb_content_for.erb +2 -0
  293. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  294. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  295. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  296. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  297. data/test/fixtures/test/greeting.erb +1 -0
  298. data/test/fixtures/test/greeting.js.rjs +1 -0
  299. data/test/fixtures/test/hello.builder +4 -0
  300. data/test/fixtures/test/hello_world.erb +1 -0
  301. data/test/fixtures/test/hello_world_container.builder +3 -0
  302. data/test/fixtures/test/hello_world_from_rxml.builder +4 -0
  303. data/test/fixtures/test/hello_world_with_layout_false.erb +1 -0
  304. data/test/fixtures/test/hello_xml_world.builder +11 -0
  305. data/test/fixtures/test/list.erb +1 -0
  306. data/test/fixtures/test/non_erb_block_content_for.builder +4 -0
  307. data/test/fixtures/test/potential_conflicts.erb +4 -0
  308. data/test/fixtures/test/render_file_from_template.html.erb +1 -0
  309. data/test/fixtures/test/render_file_with_ivar.erb +1 -0
  310. data/test/fixtures/test/render_file_with_locals.erb +1 -0
  311. data/test/fixtures/test/render_to_string_test.erb +1 -0
  312. data/test/fixtures/test/update_element_with_capture.erb +9 -0
  313. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  314. data/test/fixtures/topic.rb +3 -0
  315. data/test/fixtures/topics.yml +22 -0
  316. data/test/fixtures/topics/_topic.html.erb +1 -0
  317. data/test/template/active_record_helper_test.rb +268 -0
  318. data/test/template/asset_tag_helper_test.rb +514 -0
  319. data/test/template/atom_feed_helper_test.rb +179 -0
  320. data/test/template/benchmark_helper_test.rb +60 -0
  321. data/test/template/date_helper_test.rb +1791 -0
  322. data/test/template/deprecated_erb_variable_test.rb +9 -0
  323. data/test/template/erb_util_test.rb +24 -0
  324. data/test/template/form_helper_test.rb +885 -0
  325. data/test/template/form_options_helper_test.rb +1333 -0
  326. data/test/template/form_tag_helper_test.rb +272 -0
  327. data/test/template/javascript_helper_test.rb +73 -0
  328. data/test/template/number_helper_test.rb +97 -0
  329. data/test/template/record_tag_helper_test.rb +54 -0
  330. data/test/template/sanitize_helper_test.rb +48 -0
  331. data/test/template/tag_helper_test.rb +77 -0
  332. data/test/template/template_finder_test.rb +73 -0
  333. data/test/template/template_object_test.rb +95 -0
  334. data/test/template/test_test.rb +56 -0
  335. data/test/template/text_helper_test.rb +367 -0
  336. data/test/template/url_helper_test.rb +544 -0
  337. data/test/testing_sandbox.rb +15 -0
  338. metadata +469 -0
@@ -0,0 +1,305 @@
1
+ require 'abstract_unit'
2
+ require 'digest/sha1'
3
+
4
+ ActionController::Routing::Routes.draw do |map|
5
+ map.connect ':controller/:action/:id'
6
+ end
7
+
8
+ # simulates cookie session store
9
+ class FakeSessionDbMan
10
+ def self.generate_digest(data)
11
+ Digest::SHA1.hexdigest("secure")
12
+ end
13
+ end
14
+
15
+ # common controller actions
16
+ module RequestForgeryProtectionActions
17
+ def index
18
+ render :inline => "<%= form_tag('/') {} %>"
19
+ end
20
+
21
+ def show_button
22
+ render :inline => "<%= button_to('New', '/') {} %>"
23
+ end
24
+
25
+
26
+ def unsafe
27
+ render :text => 'pwn'
28
+ end
29
+
30
+ def rescue_action(e) raise e end
31
+ end
32
+
33
+ # sample controllers
34
+ class RequestForgeryProtectionController < ActionController::Base
35
+ include RequestForgeryProtectionActions
36
+ protect_from_forgery :only => :index, :secret => 'abc'
37
+ end
38
+
39
+ class RequestForgeryProtectionWithoutSecretController < ActionController::Base
40
+ include RequestForgeryProtectionActions
41
+ protect_from_forgery
42
+ end
43
+
44
+ # no token is given, assume the cookie store is used
45
+ class CsrfCookieMonsterController < ActionController::Base
46
+ include RequestForgeryProtectionActions
47
+ protect_from_forgery :only => :index
48
+ end
49
+
50
+ # sessions are turned off
51
+ class SessionOffController < ActionController::Base
52
+ protect_from_forgery :secret => 'foobar'
53
+ session :off
54
+ def rescue_action(e) raise e end
55
+ include RequestForgeryProtectionActions
56
+ end
57
+
58
+ class FreeCookieController < CsrfCookieMonsterController
59
+ self.allow_forgery_protection = false
60
+
61
+ def index
62
+ render :inline => "<%= form_tag('/') {} %>"
63
+ end
64
+
65
+ def show_button
66
+ render :inline => "<%= button_to('New', '/') {} %>"
67
+ end
68
+ end
69
+
70
+ # common test methods
71
+
72
+ module RequestForgeryProtectionTests
73
+ def teardown
74
+ ActionController::Base.request_forgery_protection_token = nil
75
+ end
76
+
77
+ def test_should_render_form_with_token_tag
78
+ get :index
79
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
80
+ end
81
+
82
+ def test_should_render_button_to_with_token_tag
83
+ get :show_button
84
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token
85
+ end
86
+
87
+ def test_should_allow_get
88
+ get :index
89
+ assert_response :success
90
+ end
91
+
92
+ def test_should_allow_post_without_token_on_unsafe_action
93
+ post :unsafe
94
+ assert_response :success
95
+ end
96
+
97
+ def test_should_not_allow_post_without_token
98
+ assert_raises(ActionController::InvalidAuthenticityToken) { post :index }
99
+ end
100
+
101
+ def test_should_not_allow_put_without_token
102
+ assert_raises(ActionController::InvalidAuthenticityToken) { put :index }
103
+ end
104
+
105
+ def test_should_not_allow_delete_without_token
106
+ assert_raises(ActionController::InvalidAuthenticityToken) { delete :index }
107
+ end
108
+
109
+ def test_should_not_allow_api_formatted_post_without_token
110
+ assert_raises(ActionController::InvalidAuthenticityToken) do
111
+ post :index, :format => 'xml'
112
+ end
113
+ end
114
+
115
+ def test_should_not_allow_api_formatted_put_without_token
116
+ assert_raises(ActionController::InvalidAuthenticityToken) do
117
+ put :index, :format => 'xml'
118
+ end
119
+ end
120
+
121
+ def test_should_not_allow_api_formatted_delete_without_token
122
+ assert_raises(ActionController::InvalidAuthenticityToken) do
123
+ delete :index, :format => 'xml'
124
+ end
125
+ end
126
+
127
+ def test_should_not_allow_api_formatted_post_sent_as_url_encoded_form_without_token
128
+ assert_raises(ActionController::InvalidAuthenticityToken) do
129
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
130
+ post :index, :format => 'xml'
131
+ end
132
+ end
133
+
134
+ def test_should_not_allow_api_formatted_put_sent_as_url_encoded_form_without_token
135
+ assert_raises(ActionController::InvalidAuthenticityToken) do
136
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
137
+ put :index, :format => 'xml'
138
+ end
139
+ end
140
+
141
+ def test_should_not_allow_api_formatted_delete_sent_as_url_encoded_form_without_token
142
+ assert_raises(ActionController::InvalidAuthenticityToken) do
143
+ @request.env['CONTENT_TYPE'] = Mime::URL_ENCODED_FORM.to_s
144
+ delete :index, :format => 'xml'
145
+ end
146
+ end
147
+
148
+ def test_should_not_allow_api_formatted_post_sent_as_multipart_form_without_token
149
+ assert_raises(ActionController::InvalidAuthenticityToken) do
150
+ @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
151
+ post :index, :format => 'xml'
152
+ end
153
+ end
154
+
155
+ def test_should_not_allow_api_formatted_put_sent_as_multipart_form_without_token
156
+ assert_raises(ActionController::InvalidAuthenticityToken) do
157
+ @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
158
+ put :index, :format => 'xml'
159
+ end
160
+ end
161
+
162
+ def test_should_not_allow_api_formatted_delete_sent_as_multipart_form_without_token
163
+ assert_raises(ActionController::InvalidAuthenticityToken) do
164
+ @request.env['CONTENT_TYPE'] = Mime::MULTIPART_FORM.to_s
165
+ delete :index, :format => 'xml'
166
+ end
167
+ end
168
+
169
+ def test_should_not_allow_xhr_post_without_token
170
+ assert_raises(ActionController::InvalidAuthenticityToken) { xhr :post, :index }
171
+ end
172
+
173
+ def test_should_not_allow_xhr_put_without_token
174
+ assert_raises(ActionController::InvalidAuthenticityToken) { xhr :put, :index }
175
+ end
176
+
177
+ def test_should_not_allow_xhr_delete_without_token
178
+ assert_raises(ActionController::InvalidAuthenticityToken) { xhr :delete, :index }
179
+ end
180
+
181
+ def test_should_allow_post_with_token
182
+ post :index, :authenticity_token => @token
183
+ assert_response :success
184
+ end
185
+
186
+ def test_should_allow_put_with_token
187
+ put :index, :authenticity_token => @token
188
+ assert_response :success
189
+ end
190
+
191
+ def test_should_allow_delete_with_token
192
+ delete :index, :authenticity_token => @token
193
+ assert_response :success
194
+ end
195
+
196
+ def test_should_allow_post_with_xml
197
+ @request.env['CONTENT_TYPE'] = Mime::XML.to_s
198
+ post :index, :format => 'xml'
199
+ assert_response :success
200
+ end
201
+
202
+ def test_should_allow_put_with_xml
203
+ @request.env['CONTENT_TYPE'] = Mime::XML.to_s
204
+ put :index, :format => 'xml'
205
+ assert_response :success
206
+ end
207
+
208
+ def test_should_allow_delete_with_xml
209
+ @request.env['CONTENT_TYPE'] = Mime::XML.to_s
210
+ delete :index, :format => 'xml'
211
+ assert_response :success
212
+ end
213
+ end
214
+
215
+ # OK let's get our test on
216
+
217
+ class RequestForgeryProtectionControllerTest < Test::Unit::TestCase
218
+ include RequestForgeryProtectionTests
219
+ def setup
220
+ @controller = RequestForgeryProtectionController.new
221
+ @request = ActionController::TestRequest.new
222
+ @response = ActionController::TestResponse.new
223
+ class << @request.session
224
+ def session_id() '123' end
225
+ end
226
+ @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
227
+ ActionController::Base.request_forgery_protection_token = :authenticity_token
228
+ end
229
+ end
230
+
231
+ class RequestForgeryProtectionWithoutSecretControllerTest < Test::Unit::TestCase
232
+ def setup
233
+ @controller = RequestForgeryProtectionWithoutSecretController.new
234
+ @request = ActionController::TestRequest.new
235
+ @response = ActionController::TestResponse.new
236
+ class << @request.session
237
+ def session_id() '123' end
238
+ end
239
+ @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
240
+ ActionController::Base.request_forgery_protection_token = :authenticity_token
241
+ end
242
+
243
+ def test_should_raise_error_without_secret
244
+ assert_raises ActionController::InvalidAuthenticityToken do
245
+ get :index
246
+ end
247
+ end
248
+ end
249
+
250
+ class CsrfCookieMonsterControllerTest < Test::Unit::TestCase
251
+ include RequestForgeryProtectionTests
252
+ def setup
253
+ @controller = CsrfCookieMonsterController.new
254
+ @request = ActionController::TestRequest.new
255
+ @response = ActionController::TestResponse.new
256
+ class << @request.session
257
+ attr_accessor :dbman
258
+ end
259
+ # simulate a cookie session store
260
+ @request.session.dbman = FakeSessionDbMan
261
+ @token = Digest::SHA1.hexdigest("secure")
262
+ ActionController::Base.request_forgery_protection_token = :authenticity_token
263
+ end
264
+ end
265
+
266
+ class FreeCookieControllerTest < Test::Unit::TestCase
267
+ def setup
268
+ @controller = FreeCookieController.new
269
+ @request = ActionController::TestRequest.new
270
+ @response = ActionController::TestResponse.new
271
+ @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
272
+ end
273
+
274
+ def test_should_not_render_form_with_token_tag
275
+ get :index
276
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
277
+ end
278
+
279
+ def test_should_not_render_button_to_with_token_tag
280
+ get :show_button
281
+ assert_select 'form>div>input[name=?][value=?]', 'authenticity_token', @token, false
282
+ end
283
+
284
+ def test_should_allow_all_methods_without_token
285
+ [:post, :put, :delete].each do |method|
286
+ assert_nothing_raised { send(method, :index)}
287
+ end
288
+ end
289
+ end
290
+
291
+ class SessionOffControllerTest < Test::Unit::TestCase
292
+ def setup
293
+ @controller = SessionOffController.new
294
+ @request = ActionController::TestRequest.new
295
+ @response = ActionController::TestResponse.new
296
+ @token = OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new('SHA1'), 'abc', '123')
297
+ end
298
+
299
+ def test_should_raise_correct_exception
300
+ @request.session = {} # session(:off) doesn't appear to work with controller tests
301
+ assert_raises(ActionController::InvalidAuthenticityToken) do
302
+ post :index, :authenticity_token => @token
303
+ end
304
+ end
305
+ end
@@ -0,0 +1,928 @@
1
+ require 'abstract_unit'
2
+ require 'action_controller/integration'
3
+
4
+ class RequestTest < Test::Unit::TestCase
5
+ def setup
6
+ @request = ActionController::TestRequest.new
7
+ end
8
+
9
+ def test_remote_ip
10
+ assert_equal '0.0.0.0', @request.remote_ip
11
+
12
+ @request.remote_addr = '1.2.3.4'
13
+ assert_equal '1.2.3.4', @request.remote_ip
14
+
15
+ @request.remote_addr = '1.2.3.4,3.4.5.6'
16
+ assert_equal '1.2.3.4', @request.remote_ip
17
+
18
+ @request.env['HTTP_CLIENT_IP'] = '2.3.4.5'
19
+ assert_equal '1.2.3.4', @request.remote_ip
20
+
21
+ @request.remote_addr = '192.168.0.1'
22
+ assert_equal '2.3.4.5', @request.remote_ip
23
+ @request.env.delete 'HTTP_CLIENT_IP'
24
+
25
+ @request.remote_addr = '1.2.3.4'
26
+ @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
27
+ assert_equal '1.2.3.4', @request.remote_ip
28
+
29
+ @request.remote_addr = '127.0.0.1'
30
+ @request.env['HTTP_X_FORWARDED_FOR'] = '3.4.5.6'
31
+ assert_equal '3.4.5.6', @request.remote_ip
32
+
33
+ @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,3.4.5.6'
34
+ assert_equal '3.4.5.6', @request.remote_ip
35
+
36
+ @request.env['HTTP_X_FORWARDED_FOR'] = '172.16.0.1,3.4.5.6'
37
+ assert_equal '3.4.5.6', @request.remote_ip
38
+
39
+ @request.env['HTTP_X_FORWARDED_FOR'] = '192.168.0.1,3.4.5.6'
40
+ assert_equal '3.4.5.6', @request.remote_ip
41
+
42
+ @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1,3.4.5.6'
43
+ assert_equal '3.4.5.6', @request.remote_ip
44
+
45
+ @request.env['HTTP_X_FORWARDED_FOR'] = '10.0.0.1, 10.0.0.1, 3.4.5.6'
46
+ assert_equal '3.4.5.6', @request.remote_ip
47
+
48
+ @request.env['HTTP_X_FORWARDED_FOR'] = '127.0.0.1,3.4.5.6'
49
+ assert_equal '3.4.5.6', @request.remote_ip
50
+
51
+ @request.env['HTTP_X_FORWARDED_FOR'] = 'unknown,192.168.0.1'
52
+ assert_equal 'unknown', @request.remote_ip
53
+
54
+ @request.env['HTTP_X_FORWARDED_FOR'] = '9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4'
55
+ assert_equal '3.4.5.6', @request.remote_ip
56
+
57
+ @request.env['HTTP_CLIENT_IP'] = '8.8.8.8'
58
+ e = assert_raises(ActionController::ActionControllerError) {
59
+ @request.remote_ip
60
+ }
61
+ assert_match /IP spoofing attack/, e.message
62
+ assert_match /HTTP_X_FORWARDED_FOR="9.9.9.9, 3.4.5.6, 10.0.0.1, 172.31.4.4"/, e.message
63
+ assert_match /HTTP_CLIENT_IP="8.8.8.8"/, e.message
64
+
65
+ @request.env['HTTP_X_FORWARDED_FOR'] = '8.8.8.8, 9.9.9.9'
66
+ assert_equal '8.8.8.8', @request.remote_ip
67
+
68
+ @request.env.delete 'HTTP_CLIENT_IP'
69
+ @request.env.delete 'HTTP_X_FORWARDED_FOR'
70
+ end
71
+
72
+ def test_domains
73
+ @request.host = "www.rubyonrails.org"
74
+ assert_equal "rubyonrails.org", @request.domain
75
+
76
+ @request.host = "www.rubyonrails.co.uk"
77
+ assert_equal "rubyonrails.co.uk", @request.domain(2)
78
+
79
+ @request.host = "192.168.1.200"
80
+ assert_nil @request.domain
81
+
82
+ @request.host = "foo.192.168.1.200"
83
+ assert_nil @request.domain
84
+
85
+ @request.host = "192.168.1.200.com"
86
+ assert_equal "200.com", @request.domain
87
+
88
+ @request.host = nil
89
+ assert_nil @request.domain
90
+ end
91
+
92
+ def test_subdomains
93
+ @request.host = "www.rubyonrails.org"
94
+ assert_equal %w( www ), @request.subdomains
95
+
96
+ @request.host = "www.rubyonrails.co.uk"
97
+ assert_equal %w( www ), @request.subdomains(2)
98
+
99
+ @request.host = "dev.www.rubyonrails.co.uk"
100
+ assert_equal %w( dev www ), @request.subdomains(2)
101
+
102
+ @request.host = "foobar.foobar.com"
103
+ assert_equal %w( foobar ), @request.subdomains
104
+
105
+ @request.host = "192.168.1.200"
106
+ assert_equal [], @request.subdomains
107
+
108
+ @request.host = "foo.192.168.1.200"
109
+ assert_equal [], @request.subdomains
110
+
111
+ @request.host = "192.168.1.200.com"
112
+ assert_equal %w( 192 168 1 ), @request.subdomains
113
+
114
+ @request.host = nil
115
+ assert_equal [], @request.subdomains
116
+ end
117
+
118
+ def test_port_string
119
+ @request.port = 80
120
+ assert_equal "", @request.port_string
121
+
122
+ @request.port = 8080
123
+ assert_equal ":8080", @request.port_string
124
+ end
125
+
126
+ def test_relative_url_root
127
+ @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
128
+ @request.env['SERVER_SOFTWARE'] = 'lighttpd/1.2.3'
129
+ assert_equal '', @request.relative_url_root, "relative_url_root should be disabled on lighttpd"
130
+
131
+ @request.env['SERVER_SOFTWARE'] = 'apache/1.2.3 some random text'
132
+
133
+ @request.env['SCRIPT_NAME'] = nil
134
+ assert_equal "", @request.relative_url_root
135
+
136
+ @request.env['SCRIPT_NAME'] = "/dispatch.cgi"
137
+ assert_equal "", @request.relative_url_root
138
+
139
+ @request.env['SCRIPT_NAME'] = "/myapp.rb"
140
+ assert_equal "", @request.relative_url_root
141
+
142
+ @request.relative_url_root = nil
143
+ @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
144
+ assert_equal "/hieraki", @request.relative_url_root
145
+
146
+ @request.relative_url_root = nil
147
+ @request.env['SCRIPT_NAME'] = "/collaboration/hieraki/dispatch.cgi"
148
+ assert_equal "/collaboration/hieraki", @request.relative_url_root
149
+
150
+ # apache/scgi case
151
+ @request.relative_url_root = nil
152
+ @request.env['SCRIPT_NAME'] = "/collaboration/hieraki"
153
+ assert_equal "/collaboration/hieraki", @request.relative_url_root
154
+
155
+ @request.relative_url_root = nil
156
+ @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
157
+ @request.env['SERVER_SOFTWARE'] = 'lighttpd/1.2.3'
158
+ @request.env['RAILS_RELATIVE_URL_ROOT'] = "/hieraki"
159
+ assert_equal "/hieraki", @request.relative_url_root
160
+
161
+ # @env overrides path guess
162
+ @request.relative_url_root = nil
163
+ @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
164
+ @request.env['SERVER_SOFTWARE'] = 'apache/1.2.3 some random text'
165
+ @request.env['RAILS_RELATIVE_URL_ROOT'] = "/real_url"
166
+ assert_equal "/real_url", @request.relative_url_root
167
+ end
168
+
169
+ def test_request_uri
170
+ @request.env['SERVER_SOFTWARE'] = 'Apache 42.342.3432'
171
+
172
+ @request.relative_url_root = nil
173
+ @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri?mapped=1"
174
+ assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
175
+ assert_equal "/path/of/some/uri", @request.path
176
+
177
+ @request.relative_url_root = nil
178
+ @request.set_REQUEST_URI "http://www.rubyonrails.org/path/of/some/uri"
179
+ assert_equal "/path/of/some/uri", @request.request_uri
180
+ assert_equal "/path/of/some/uri", @request.path
181
+
182
+ @request.relative_url_root = nil
183
+ @request.set_REQUEST_URI "/path/of/some/uri"
184
+ assert_equal "/path/of/some/uri", @request.request_uri
185
+ assert_equal "/path/of/some/uri", @request.path
186
+
187
+ @request.relative_url_root = nil
188
+ @request.set_REQUEST_URI "/"
189
+ assert_equal "/", @request.request_uri
190
+ assert_equal "/", @request.path
191
+
192
+ @request.relative_url_root = nil
193
+ @request.set_REQUEST_URI "/?m=b"
194
+ assert_equal "/?m=b", @request.request_uri
195
+ assert_equal "/", @request.path
196
+
197
+ @request.relative_url_root = nil
198
+ @request.set_REQUEST_URI "/"
199
+ @request.env['SCRIPT_NAME'] = "/dispatch.cgi"
200
+ assert_equal "/", @request.request_uri
201
+ assert_equal "/", @request.path
202
+
203
+ @request.relative_url_root = nil
204
+ @request.set_REQUEST_URI "/hieraki/"
205
+ @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
206
+ assert_equal "/hieraki/", @request.request_uri
207
+ assert_equal "/", @request.path
208
+
209
+ @request.relative_url_root = nil
210
+ @request.set_REQUEST_URI "/collaboration/hieraki/books/edit/2"
211
+ @request.env['SCRIPT_NAME'] = "/collaboration/hieraki/dispatch.cgi"
212
+ assert_equal "/collaboration/hieraki/books/edit/2", @request.request_uri
213
+ assert_equal "/books/edit/2", @request.path
214
+
215
+ # The following tests are for when REQUEST_URI is not supplied (as in IIS)
216
+ @request.relative_url_root = nil
217
+ @request.set_REQUEST_URI nil
218
+ @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1"
219
+ @request.env['SCRIPT_NAME'] = nil #"/path/dispatch.rb"
220
+ assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
221
+ assert_equal "/path/of/some/uri", @request.path
222
+
223
+ @request.set_REQUEST_URI nil
224
+ @request.relative_url_root = nil
225
+ @request.env['PATH_INFO'] = "/path/of/some/uri?mapped=1"
226
+ @request.env['SCRIPT_NAME'] = "/path/dispatch.rb"
227
+ assert_equal "/path/of/some/uri?mapped=1", @request.request_uri
228
+ assert_equal "/of/some/uri", @request.path
229
+
230
+ @request.set_REQUEST_URI nil
231
+ @request.relative_url_root = nil
232
+ @request.env['PATH_INFO'] = "/path/of/some/uri"
233
+ @request.env['SCRIPT_NAME'] = nil
234
+ assert_equal "/path/of/some/uri", @request.request_uri
235
+ assert_equal "/path/of/some/uri", @request.path
236
+
237
+ @request.set_REQUEST_URI nil
238
+ @request.relative_url_root = nil
239
+ @request.env['PATH_INFO'] = "/"
240
+ assert_equal "/", @request.request_uri
241
+ assert_equal "/", @request.path
242
+
243
+ @request.set_REQUEST_URI nil
244
+ @request.relative_url_root = nil
245
+ @request.env['PATH_INFO'] = "/?m=b"
246
+ assert_equal "/?m=b", @request.request_uri
247
+ assert_equal "/", @request.path
248
+
249
+ @request.set_REQUEST_URI nil
250
+ @request.relative_url_root = nil
251
+ @request.env['PATH_INFO'] = "/"
252
+ @request.env['SCRIPT_NAME'] = "/dispatch.cgi"
253
+ assert_equal "/", @request.request_uri
254
+ assert_equal "/", @request.path
255
+
256
+ @request.set_REQUEST_URI nil
257
+ @request.relative_url_root = nil
258
+ @request.env['PATH_INFO'] = "/hieraki/"
259
+ @request.env['SCRIPT_NAME'] = "/hieraki/dispatch.cgi"
260
+ assert_equal "/hieraki/", @request.request_uri
261
+ assert_equal "/", @request.path
262
+
263
+ @request.set_REQUEST_URI '/hieraki/dispatch.cgi'
264
+ @request.relative_url_root = '/hieraki'
265
+ assert_equal "/dispatch.cgi", @request.path
266
+ @request.relative_url_root = nil
267
+
268
+ @request.set_REQUEST_URI '/hieraki/dispatch.cgi'
269
+ @request.relative_url_root = '/foo'
270
+ assert_equal "/hieraki/dispatch.cgi", @request.path
271
+ @request.relative_url_root = nil
272
+
273
+ # This test ensures that Rails uses REQUEST_URI over PATH_INFO
274
+ @request.relative_url_root = nil
275
+ @request.env['REQUEST_URI'] = "/some/path"
276
+ @request.env['PATH_INFO'] = "/another/path"
277
+ @request.env['SCRIPT_NAME'] = "/dispatch.cgi"
278
+ assert_equal "/some/path", @request.request_uri
279
+ assert_equal "/some/path", @request.path
280
+ end
281
+
282
+
283
+ def test_host_with_default_port
284
+ @request.host = "rubyonrails.org"
285
+ @request.port = 80
286
+ assert_equal "rubyonrails.org", @request.host_with_port
287
+ end
288
+
289
+ def test_host_with_non_default_port
290
+ @request.host = "rubyonrails.org"
291
+ @request.port = 81
292
+ assert_equal "rubyonrails.org:81", @request.host_with_port
293
+ end
294
+
295
+ def test_server_software
296
+ assert_equal nil, @request.server_software
297
+
298
+ @request.env['SERVER_SOFTWARE'] = 'Apache3.422'
299
+ assert_equal 'apache', @request.server_software
300
+
301
+ @request.env['SERVER_SOFTWARE'] = 'lighttpd(1.1.4)'
302
+ assert_equal 'lighttpd', @request.server_software
303
+ end
304
+
305
+ def test_xml_http_request
306
+ assert !@request.xml_http_request?
307
+ assert !@request.xhr?
308
+
309
+ @request.env['HTTP_X_REQUESTED_WITH'] = "DefinitelyNotAjax1.0"
310
+ assert !@request.xml_http_request?
311
+ assert !@request.xhr?
312
+
313
+ @request.env['HTTP_X_REQUESTED_WITH'] = "XMLHttpRequest"
314
+ assert @request.xml_http_request?
315
+ assert @request.xhr?
316
+ end
317
+
318
+ def test_reports_ssl
319
+ assert !@request.ssl?
320
+ @request.env['HTTPS'] = 'on'
321
+ assert @request.ssl?
322
+ end
323
+
324
+ def test_reports_ssl_when_proxied_via_lighttpd
325
+ assert !@request.ssl?
326
+ @request.env['HTTP_X_FORWARDED_PROTO'] = 'https'
327
+ assert @request.ssl?
328
+ end
329
+
330
+ def test_symbolized_request_methods
331
+ [:get, :post, :put, :delete].each do |method|
332
+ set_request_method_to method
333
+ assert_equal method, @request.method
334
+ end
335
+ end
336
+
337
+ def test_invalid_http_method_raises_exception
338
+ set_request_method_to :random_method
339
+ assert_raises(ActionController::UnknownHttpMethod) do
340
+ @request.method
341
+ end
342
+ end
343
+
344
+ def test_allow_method_hacking_on_post
345
+ set_request_method_to :post
346
+ [:get, :head, :options, :put, :post, :delete].each do |method|
347
+ @request.instance_eval { @parameters = { :_method => method } ; @request_method = nil }
348
+ assert_equal(method == :head ? :get : method, @request.method)
349
+ end
350
+ end
351
+
352
+ def test_invalid_method_hacking_on_post_raises_exception
353
+ set_request_method_to :post
354
+ @request.instance_eval { @parameters = { :_method => :random_method } ; @request_method = nil }
355
+ assert_raises(ActionController::UnknownHttpMethod) do
356
+ @request.method
357
+ end
358
+ end
359
+
360
+ def test_restrict_method_hacking
361
+ @request.instance_eval { @parameters = { :_method => 'put' } }
362
+ [:get, :put, :delete].each do |method|
363
+ set_request_method_to method
364
+ assert_equal method, @request.method
365
+ end
366
+ end
367
+
368
+ def test_head_masquarading_as_get
369
+ set_request_method_to :head
370
+ assert_equal :get, @request.method
371
+ assert @request.get?
372
+ assert @request.head?
373
+ end
374
+
375
+ def test_xml_format
376
+ @request.instance_eval { @parameters = { :format => 'xml' } }
377
+ assert_equal Mime::XML, @request.format
378
+ end
379
+
380
+ def test_xhtml_format
381
+ @request.instance_eval { @parameters = { :format => 'xhtml' } }
382
+ assert_equal Mime::HTML, @request.format
383
+ end
384
+
385
+ def test_txt_format
386
+ @request.instance_eval { @parameters = { :format => 'txt' } }
387
+ assert_equal Mime::TEXT, @request.format
388
+ end
389
+
390
+ def test_nil_format
391
+ @request.instance_eval { @parameters = { :format => nil } }
392
+ @request.env["HTTP_ACCEPT"] = "text/javascript"
393
+ assert_equal Mime::JS, @request.format
394
+ end
395
+
396
+ def test_content_type
397
+ @request.env["CONTENT_TYPE"] = "text/html"
398
+ assert_equal Mime::HTML, @request.content_type
399
+ end
400
+
401
+ def test_format_assignment_should_set_format
402
+ @request.instance_eval { self.format = :txt }
403
+ assert !@request.format.xml?
404
+ @request.instance_eval { self.format = :xml }
405
+ assert @request.format.xml?
406
+ end
407
+
408
+ def test_content_no_type
409
+ assert_equal nil, @request.content_type
410
+ end
411
+
412
+ def test_content_type_xml
413
+ @request.env["CONTENT_TYPE"] = "application/xml"
414
+ assert_equal Mime::XML, @request.content_type
415
+ end
416
+
417
+ def test_content_type_with_charset
418
+ @request.env["CONTENT_TYPE"] = "application/xml; charset=UTF-8"
419
+ assert_equal Mime::XML, @request.content_type
420
+ end
421
+
422
+ def test_user_agent
423
+ assert_not_nil @request.user_agent
424
+ end
425
+
426
+ def test_parameters
427
+ @request.instance_eval { @request_parameters = { "foo" => 1 } }
428
+ @request.instance_eval { @query_parameters = { "bar" => 2 } }
429
+
430
+ assert_equal({"foo" => 1, "bar" => 2}, @request.parameters)
431
+ assert_equal({"foo" => 1}, @request.request_parameters)
432
+ assert_equal({"bar" => 2}, @request.query_parameters)
433
+ end
434
+
435
+ protected
436
+ def set_request_method_to(method)
437
+ @request.env['REQUEST_METHOD'] = method.to_s.upcase
438
+ @request.instance_eval { @request_method = nil }
439
+ end
440
+ end
441
+
442
+
443
+ class UrlEncodedRequestParameterParsingTest < Test::Unit::TestCase
444
+ def setup
445
+ @query_string = "action=create_customer&full_name=David%20Heinemeier%20Hansson&customerId=1"
446
+ @query_string_with_empty = "action=create_customer&full_name="
447
+ @query_string_with_array = "action=create_customer&selected[]=1&selected[]=2&selected[]=3"
448
+ @query_string_with_amps = "action=create_customer&name=Don%27t+%26+Does"
449
+ @query_string_with_multiple_of_same_name =
450
+ "action=update_order&full_name=Lau%20Taarnskov&products=4&products=2&products=3"
451
+ @query_string_with_many_equal = "action=create_customer&full_name=abc=def=ghi"
452
+ @query_string_without_equal = "action"
453
+ @query_string_with_many_ampersands =
454
+ "&action=create_customer&&&full_name=David%20Heinemeier%20Hansson"
455
+ @query_string_with_empty_key = "action=create_customer&full_name=David%20Heinemeier%20Hansson&=Save"
456
+ end
457
+
458
+ def test_query_string
459
+ assert_equal(
460
+ { "action" => "create_customer", "full_name" => "David Heinemeier Hansson", "customerId" => "1"},
461
+ ActionController::AbstractRequest.parse_query_parameters(@query_string)
462
+ )
463
+ end
464
+
465
+ def test_deep_query_string
466
+ expected = {'x' => {'y' => {'z' => '10'}}}
467
+ assert_equal(expected, ActionController::AbstractRequest.parse_query_parameters('x[y][z]=10'))
468
+ end
469
+
470
+ def test_deep_query_string_with_array
471
+ assert_equal({'x' => {'y' => {'z' => ['10']}}}, ActionController::AbstractRequest.parse_query_parameters('x[y][z][]=10'))
472
+ assert_equal({'x' => {'y' => {'z' => ['10', '5']}}}, ActionController::AbstractRequest.parse_query_parameters('x[y][z][]=10&x[y][z][]=5'))
473
+ end
474
+
475
+ def test_deep_query_string_with_array_of_hash
476
+ assert_equal({'x' => {'y' => [{'z' => '10'}]}}, ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10'))
477
+ assert_equal({'x' => {'y' => [{'z' => '10', 'w' => '10'}]}}, ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][w]=10'))
478
+ end
479
+
480
+ def test_deep_query_string_with_array_of_hashes_with_one_pair
481
+ assert_equal({'x' => {'y' => [{'z' => '10'}, {'z' => '20'}]}}, ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][z]=20'))
482
+ assert_equal("10", ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][z]=20')["x"]["y"].first["z"])
483
+ assert_equal("10", ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][z]=20').with_indifferent_access[:x][:y].first[:z])
484
+ end
485
+
486
+ def test_deep_query_string_with_array_of_hashes_with_multiple_pairs
487
+ assert_equal(
488
+ {'x' => {'y' => [{'z' => '10', 'w' => 'a'}, {'z' => '20', 'w' => 'b'}]}},
489
+ ActionController::AbstractRequest.parse_query_parameters('x[y][][z]=10&x[y][][w]=a&x[y][][z]=20&x[y][][w]=b')
490
+ )
491
+ end
492
+
493
+ def test_query_string_with_nil
494
+ assert_equal(
495
+ { "action" => "create_customer", "full_name" => ''},
496
+ ActionController::AbstractRequest.parse_query_parameters(@query_string_with_empty)
497
+ )
498
+ end
499
+
500
+ def test_query_string_with_array
501
+ assert_equal(
502
+ { "action" => "create_customer", "selected" => ["1", "2", "3"]},
503
+ ActionController::AbstractRequest.parse_query_parameters(@query_string_with_array)
504
+ )
505
+ end
506
+
507
+ def test_query_string_with_amps
508
+ assert_equal(
509
+ { "action" => "create_customer", "name" => "Don't & Does"},
510
+ ActionController::AbstractRequest.parse_query_parameters(@query_string_with_amps)
511
+ )
512
+ end
513
+
514
+ def test_query_string_with_many_equal
515
+ assert_equal(
516
+ { "action" => "create_customer", "full_name" => "abc=def=ghi"},
517
+ ActionController::AbstractRequest.parse_query_parameters(@query_string_with_many_equal)
518
+ )
519
+ end
520
+
521
+ def test_query_string_without_equal
522
+ assert_equal(
523
+ { "action" => nil },
524
+ ActionController::AbstractRequest.parse_query_parameters(@query_string_without_equal)
525
+ )
526
+ end
527
+
528
+ def test_query_string_with_empty_key
529
+ assert_equal(
530
+ { "action" => "create_customer", "full_name" => "David Heinemeier Hansson" },
531
+ ActionController::AbstractRequest.parse_query_parameters(@query_string_with_empty_key)
532
+ )
533
+ end
534
+
535
+ def test_query_string_with_many_ampersands
536
+ assert_equal(
537
+ { "action" => "create_customer", "full_name" => "David Heinemeier Hansson"},
538
+ ActionController::AbstractRequest.parse_query_parameters(@query_string_with_many_ampersands)
539
+ )
540
+ end
541
+
542
+ def test_unbalanced_query_string_with_array
543
+ assert_equal(
544
+ {'location' => ["1", "2"], 'age_group' => ["2"]},
545
+ ActionController::AbstractRequest.parse_query_parameters("location[]=1&location[]=2&age_group[]=2")
546
+ )
547
+ assert_equal(
548
+ {'location' => ["1", "2"], 'age_group' => ["2"]},
549
+ ActionController::AbstractRequest.parse_request_parameters({'location[]' => ["1", "2"],
550
+ 'age_group[]' => ["2"]})
551
+ )
552
+ end
553
+
554
+
555
+ def test_request_hash_parsing
556
+ query = {
557
+ "note[viewers][viewer][][type]" => ["User", "Group"],
558
+ "note[viewers][viewer][][id]" => ["1", "2"]
559
+ }
560
+
561
+ expected = { "note" => { "viewers"=>{"viewer"=>[{ "id"=>"1", "type"=>"User"}, {"type"=>"Group", "id"=>"2"} ]} } }
562
+
563
+ assert_equal(expected, ActionController::AbstractRequest.parse_request_parameters(query))
564
+ end
565
+
566
+
567
+ def test_parse_params
568
+ input = {
569
+ "customers[boston][first][name]" => [ "David" ],
570
+ "customers[boston][first][url]" => [ "http://David" ],
571
+ "customers[boston][second][name]" => [ "Allan" ],
572
+ "customers[boston][second][url]" => [ "http://Allan" ],
573
+ "something_else" => [ "blah" ],
574
+ "something_nil" => [ nil ],
575
+ "something_empty" => [ "" ],
576
+ "products[first]" => [ "Apple Computer" ],
577
+ "products[second]" => [ "Pc" ],
578
+ "" => [ 'Save' ]
579
+ }
580
+
581
+ expected_output = {
582
+ "customers" => {
583
+ "boston" => {
584
+ "first" => {
585
+ "name" => "David",
586
+ "url" => "http://David"
587
+ },
588
+ "second" => {
589
+ "name" => "Allan",
590
+ "url" => "http://Allan"
591
+ }
592
+ }
593
+ },
594
+ "something_else" => "blah",
595
+ "something_empty" => "",
596
+ "something_nil" => "",
597
+ "products" => {
598
+ "first" => "Apple Computer",
599
+ "second" => "Pc"
600
+ }
601
+ }
602
+
603
+ assert_equal expected_output, ActionController::AbstractRequest.parse_request_parameters(input)
604
+ end
605
+
606
+ UploadedStringIO = ActionController::UploadedStringIO
607
+ class MockUpload < UploadedStringIO
608
+ def initialize(content_type, original_path, *args)
609
+ self.content_type = content_type
610
+ self.original_path = original_path
611
+ super *args
612
+ end
613
+ end
614
+
615
+ def test_parse_params_from_multipart_upload
616
+ file = MockUpload.new('img/jpeg', 'foo.jpg')
617
+ ie_file = MockUpload.new('img/jpeg', 'c:\\Documents and Settings\\foo\\Desktop\\bar.jpg')
618
+ non_file_text_part = MockUpload.new('text/plain', '', 'abc')
619
+
620
+ input = {
621
+ "something" => [ UploadedStringIO.new("") ],
622
+ "array_of_stringios" => [[ UploadedStringIO.new("One"), UploadedStringIO.new("Two") ]],
623
+ "mixed_types_array" => [[ UploadedStringIO.new("Three"), "NotStringIO" ]],
624
+ "mixed_types_as_checkboxes[strings][nested]" => [[ file, "String", UploadedStringIO.new("StringIO")]],
625
+ "ie_mixed_types_as_checkboxes[strings][nested]" => [[ ie_file, "String", UploadedStringIO.new("StringIO")]],
626
+ "products[string]" => [ UploadedStringIO.new("Apple Computer") ],
627
+ "products[file]" => [ file ],
628
+ "ie_products[string]" => [ UploadedStringIO.new("Microsoft") ],
629
+ "ie_products[file]" => [ ie_file ],
630
+ "text_part" => [non_file_text_part]
631
+ }
632
+
633
+ expected_output = {
634
+ "something" => "",
635
+ "array_of_stringios" => ["One", "Two"],
636
+ "mixed_types_array" => [ "Three", "NotStringIO" ],
637
+ "mixed_types_as_checkboxes" => {
638
+ "strings" => {
639
+ "nested" => [ file, "String", "StringIO" ]
640
+ },
641
+ },
642
+ "ie_mixed_types_as_checkboxes" => {
643
+ "strings" => {
644
+ "nested" => [ ie_file, "String", "StringIO" ]
645
+ },
646
+ },
647
+ "products" => {
648
+ "string" => "Apple Computer",
649
+ "file" => file
650
+ },
651
+ "ie_products" => {
652
+ "string" => "Microsoft",
653
+ "file" => ie_file
654
+ },
655
+ "text_part" => "abc"
656
+ }
657
+
658
+ params = ActionController::AbstractRequest.parse_request_parameters(input)
659
+ assert_equal expected_output, params
660
+
661
+ # Lone filenames are preserved.
662
+ assert_equal 'foo.jpg', params['mixed_types_as_checkboxes']['strings']['nested'].first.original_filename
663
+ assert_equal 'foo.jpg', params['products']['file'].original_filename
664
+
665
+ # But full Windows paths are reduced to their basename.
666
+ assert_equal 'bar.jpg', params['ie_mixed_types_as_checkboxes']['strings']['nested'].first.original_filename
667
+ assert_equal 'bar.jpg', params['ie_products']['file'].original_filename
668
+ end
669
+
670
+ def test_parse_params_with_file
671
+ input = {
672
+ "customers[boston][first][name]" => [ "David" ],
673
+ "something_else" => [ "blah" ],
674
+ "logo" => [ File.new(File.dirname(__FILE__) + "/cgi_test.rb").path ]
675
+ }
676
+
677
+ expected_output = {
678
+ "customers" => {
679
+ "boston" => {
680
+ "first" => {
681
+ "name" => "David"
682
+ }
683
+ }
684
+ },
685
+ "something_else" => "blah",
686
+ "logo" => File.new(File.dirname(__FILE__) + "/cgi_test.rb").path,
687
+ }
688
+
689
+ assert_equal expected_output, ActionController::AbstractRequest.parse_request_parameters(input)
690
+ end
691
+
692
+ def test_parse_params_with_array
693
+ input = { "selected[]" => [ "1", "2", "3" ] }
694
+
695
+ expected_output = { "selected" => [ "1", "2", "3" ] }
696
+
697
+ assert_equal expected_output, ActionController::AbstractRequest.parse_request_parameters(input)
698
+ end
699
+
700
+ def test_parse_params_with_non_alphanumeric_name
701
+ input = { "a/b[c]" => %w(d) }
702
+ expected = { "a/b" => { "c" => "d" }}
703
+ assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
704
+ end
705
+
706
+ def test_parse_params_with_single_brackets_in_middle
707
+ input = { "a/b[c]d" => %w(e) }
708
+ expected = { "a/b" => {} }
709
+ assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
710
+ end
711
+
712
+ def test_parse_params_with_separated_brackets
713
+ input = { "a/b@[c]d[e]" => %w(f) }
714
+ expected = { "a/b@" => { }}
715
+ assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
716
+ end
717
+
718
+ def test_parse_params_with_separated_brackets_and_array
719
+ input = { "a/b@[c]d[e][]" => %w(f) }
720
+ expected = { "a/b@" => { }}
721
+ assert_equal expected , ActionController::AbstractRequest.parse_request_parameters(input)
722
+ end
723
+
724
+ def test_parse_params_with_unmatched_brackets_and_array
725
+ input = { "a/b@[c][d[e][]" => %w(f) }
726
+ expected = { "a/b@" => { "c" => { }}}
727
+ assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
728
+ end
729
+
730
+ def test_parse_params_with_nil_key
731
+ input = { nil => nil, "test2" => %w(value1) }
732
+ expected = { "test2" => "value1" }
733
+ assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
734
+ end
735
+
736
+ def test_parse_params_with_array_prefix_and_hashes
737
+ input = { "a[][b][c]" => %w(d) }
738
+ expected = {"a" => [{"b" => {"c" => "d"}}]}
739
+ assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
740
+ end
741
+
742
+ def test_parse_params_with_complex_nesting
743
+ input = { "a[][b][c][][d][]" => %w(e) }
744
+ expected = {"a" => [{"b" => {"c" => [{"d" => ["e"]}]}}]}
745
+ assert_equal expected, ActionController::AbstractRequest.parse_request_parameters(input)
746
+ end
747
+ end
748
+
749
+
750
+ class MultipartRequestParameterParsingTest < Test::Unit::TestCase
751
+ FIXTURE_PATH = File.dirname(__FILE__) + '/../fixtures/multipart'
752
+
753
+ def test_single_parameter
754
+ params = process('single_parameter')
755
+ assert_equal({ 'foo' => 'bar' }, params)
756
+ end
757
+
758
+ def test_bracketed_param
759
+ assert_equal({ 'foo' => { 'baz' => 'bar'}}, process('bracketed_param'))
760
+ end
761
+
762
+ def test_text_file
763
+ params = process('text_file')
764
+ assert_equal %w(file foo), params.keys.sort
765
+ assert_equal 'bar', params['foo']
766
+
767
+ file = params['file']
768
+ assert_kind_of StringIO, file
769
+ assert_equal 'file.txt', file.original_filename
770
+ assert_equal "text/plain", file.content_type
771
+ assert_equal 'contents', file.read
772
+ end
773
+
774
+ def test_boundary_problem_file
775
+ params = process('boundary_problem_file')
776
+ assert_equal %w(file foo), params.keys.sort
777
+
778
+ file = params['file']
779
+ foo = params['foo']
780
+
781
+ if RUBY_VERSION > '1.9'
782
+ assert_kind_of File, file
783
+ else
784
+ assert_kind_of Tempfile, file
785
+ end
786
+
787
+ assert_equal 'file.txt', file.original_filename
788
+ assert_equal "text/plain", file.content_type
789
+
790
+ assert_equal 'bar', foo
791
+ end
792
+
793
+ def test_large_text_file
794
+ params = process('large_text_file')
795
+ assert_equal %w(file foo), params.keys.sort
796
+ assert_equal 'bar', params['foo']
797
+
798
+ file = params['file']
799
+ if RUBY_VERSION > '1.9'
800
+ assert_kind_of File, file
801
+ else
802
+ assert_kind_of Tempfile, file
803
+ end
804
+ assert_equal 'file.txt', file.original_filename
805
+ assert_equal "text/plain", file.content_type
806
+ assert ('a' * 20480) == file.read
807
+ end
808
+
809
+ uses_mocha "test_no_rewind_stream" do
810
+ def test_no_rewind_stream
811
+ # Ensures that parse_multipart_form_parameters works with streams that cannot be rewound
812
+ file = File.open(File.join(FIXTURE_PATH, 'large_text_file'), 'rb')
813
+ file.expects(:rewind).raises(Errno::ESPIPE)
814
+ params = ActionController::AbstractRequest.parse_multipart_form_parameters(file, 'AaB03x', file.stat.size, {})
815
+ assert_not_equal 0, file.pos # file was not rewound after reading
816
+ end
817
+ end
818
+
819
+ def test_binary_file
820
+ params = process('binary_file')
821
+ assert_equal %w(file flowers foo), params.keys.sort
822
+ assert_equal 'bar', params['foo']
823
+
824
+ file = params['file']
825
+ assert_kind_of StringIO, file
826
+ assert_equal 'file.csv', file.original_filename
827
+ assert_nil file.content_type
828
+ assert_equal 'contents', file.read
829
+
830
+ file = params['flowers']
831
+ assert_kind_of StringIO, file
832
+ assert_equal 'flowers.jpg', file.original_filename
833
+ assert_equal "image/jpeg", file.content_type
834
+ assert_equal 19512, file.size
835
+ #assert_equal File.read(File.dirname(__FILE__) + '/../../../activerecord/test/fixtures/flowers.jpg'), file.read
836
+ end
837
+
838
+ def test_mixed_files
839
+ params = process('mixed_files')
840
+ assert_equal %w(files foo), params.keys.sort
841
+ assert_equal 'bar', params['foo']
842
+
843
+ # Ruby CGI doesn't handle multipart/mixed for us.
844
+ files = params['files']
845
+ assert_kind_of String, files
846
+ files.force_encoding('ASCII-8BIT') if files.respond_to?(:force_encoding)
847
+ assert_equal 19756, files.size
848
+ end
849
+
850
+ private
851
+ def process(name)
852
+ File.open(File.join(FIXTURE_PATH, name), 'rb') do |file|
853
+ params = ActionController::AbstractRequest.parse_multipart_form_parameters(file, 'AaB03x', file.stat.size, {})
854
+ assert_equal 0, file.pos # file was rewound after reading
855
+ params
856
+ end
857
+ end
858
+ end
859
+
860
+ class XmlParamsParsingTest < Test::Unit::TestCase
861
+ def test_hash_params
862
+ person = parse_body("<person><name>David</name></person>")[:person]
863
+ assert_kind_of Hash, person
864
+ assert_equal 'David', person['name']
865
+ end
866
+
867
+ def test_single_file
868
+ person = parse_body("<person><name>David</name><avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar></person>")
869
+
870
+ assert_equal "image/jpg", person['person']['avatar'].content_type
871
+ assert_equal "me.jpg", person['person']['avatar'].original_filename
872
+ assert_equal "ABC", person['person']['avatar'].read
873
+ end
874
+
875
+ def test_multiple_files
876
+ person = parse_body(<<-end_body)
877
+ <person>
878
+ <name>David</name>
879
+ <avatars>
880
+ <avatar type='file' name='me.jpg' content_type='image/jpg'>#{ActiveSupport::Base64.encode64('ABC')}</avatar>
881
+ <avatar type='file' name='you.gif' content_type='image/gif'>#{ActiveSupport::Base64.encode64('DEF')}</avatar>
882
+ </avatars>
883
+ </person>
884
+ end_body
885
+
886
+ assert_equal "image/jpg", person['person']['avatars']['avatar'].first.content_type
887
+ assert_equal "me.jpg", person['person']['avatars']['avatar'].first.original_filename
888
+ assert_equal "ABC", person['person']['avatars']['avatar'].first.read
889
+
890
+ assert_equal "image/gif", person['person']['avatars']['avatar'].last.content_type
891
+ assert_equal "you.gif", person['person']['avatars']['avatar'].last.original_filename
892
+ assert_equal "DEF", person['person']['avatars']['avatar'].last.read
893
+ end
894
+
895
+ private
896
+ def parse_body(body)
897
+ env = { 'CONTENT_TYPE' => 'application/xml',
898
+ 'CONTENT_LENGTH' => body.size.to_s }
899
+ cgi = ActionController::Integration::Session::StubCGI.new(env, body)
900
+ ActionController::CgiRequest.new(cgi).request_parameters
901
+ end
902
+ end
903
+
904
+ class LegacyXmlParamsParsingTest < XmlParamsParsingTest
905
+ private
906
+ def parse_body(body)
907
+ env = { 'HTTP_X_POST_DATA_FORMAT' => 'xml',
908
+ 'CONTENT_LENGTH' => body.size.to_s }
909
+ cgi = ActionController::Integration::Session::StubCGI.new(env, body)
910
+ ActionController::CgiRequest.new(cgi).request_parameters
911
+ end
912
+ end
913
+
914
+ class JsonParamsParsingTest < Test::Unit::TestCase
915
+ def test_hash_params
916
+ person = parse_body({:person => {:name => "David"}}.to_json)[:person]
917
+ assert_kind_of Hash, person
918
+ assert_equal 'David', person['name']
919
+ end
920
+
921
+ private
922
+ def parse_body(body)
923
+ env = { 'CONTENT_TYPE' => 'application/json',
924
+ 'CONTENT_LENGTH' => body.size.to_s }
925
+ cgi = ActionController::Integration::Session::StubCGI.new(env, body)
926
+ ActionController::CgiRequest.new(cgi).request_parameters
927
+ end
928
+ end