actionpack_csi 2.3.5.p6

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 (429) hide show
  1. data/CHANGELOG +5184 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/RUNNING_UNIT_TESTS +24 -0
  5. data/Rakefile +160 -0
  6. data/install.rb +30 -0
  7. data/lib/action_controller/assertions/dom_assertions.rb +55 -0
  8. data/lib/action_controller/assertions/model_assertions.rb +21 -0
  9. data/lib/action_controller/assertions/response_assertions.rb +160 -0
  10. data/lib/action_controller/assertions/routing_assertions.rb +146 -0
  11. data/lib/action_controller/assertions/selector_assertions.rb +638 -0
  12. data/lib/action_controller/assertions/tag_assertions.rb +127 -0
  13. data/lib/action_controller/base.rb +1423 -0
  14. data/lib/action_controller/benchmarking.rb +107 -0
  15. data/lib/action_controller/caching/actions.rb +177 -0
  16. data/lib/action_controller/caching/fragments.rb +120 -0
  17. data/lib/action_controller/caching/pages.rb +152 -0
  18. data/lib/action_controller/caching/sweeper.rb +45 -0
  19. data/lib/action_controller/caching/sweeping.rb +55 -0
  20. data/lib/action_controller/caching.rb +71 -0
  21. data/lib/action_controller/cgi_ext/cookie.rb +112 -0
  22. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  23. data/lib/action_controller/cgi_ext/stdinput.rb +24 -0
  24. data/lib/action_controller/cgi_ext.rb +15 -0
  25. data/lib/action_controller/cgi_process.rb +77 -0
  26. data/lib/action_controller/cookies.rb +95 -0
  27. data/lib/action_controller/dispatcher.rb +133 -0
  28. data/lib/action_controller/failsafe.rb +86 -0
  29. data/lib/action_controller/filters.rb +680 -0
  30. data/lib/action_controller/flash.rb +171 -0
  31. data/lib/action_controller/headers.rb +33 -0
  32. data/lib/action_controller/helpers.rb +225 -0
  33. data/lib/action_controller/http_authentication.rb +309 -0
  34. data/lib/action_controller/integration.rb +692 -0
  35. data/lib/action_controller/layout.rb +286 -0
  36. data/lib/action_controller/middleware_stack.rb +119 -0
  37. data/lib/action_controller/middlewares.rb +14 -0
  38. data/lib/action_controller/mime_responds.rb +193 -0
  39. data/lib/action_controller/mime_type.rb +212 -0
  40. data/lib/action_controller/mime_types.rb +21 -0
  41. data/lib/action_controller/params_parser.rb +77 -0
  42. data/lib/action_controller/performance_test.rb +15 -0
  43. data/lib/action_controller/polymorphic_routes.rb +189 -0
  44. data/lib/action_controller/rack_lint_patch.rb +36 -0
  45. data/lib/action_controller/record_identifier.rb +104 -0
  46. data/lib/action_controller/reloader.rb +54 -0
  47. data/lib/action_controller/request.rb +493 -0
  48. data/lib/action_controller/request_forgery_protection.rb +113 -0
  49. data/lib/action_controller/rescue.rb +183 -0
  50. data/lib/action_controller/resources.rb +682 -0
  51. data/lib/action_controller/response.rb +239 -0
  52. data/lib/action_controller/routing/builder.rb +197 -0
  53. data/lib/action_controller/routing/optimisations.rb +130 -0
  54. data/lib/action_controller/routing/recognition_optimisation.rb +167 -0
  55. data/lib/action_controller/routing/route.rb +265 -0
  56. data/lib/action_controller/routing/route_set.rb +502 -0
  57. data/lib/action_controller/routing/routing_ext.rb +49 -0
  58. data/lib/action_controller/routing/segments.rb +343 -0
  59. data/lib/action_controller/routing.rb +388 -0
  60. data/lib/action_controller/session/abstract_store.rb +181 -0
  61. data/lib/action_controller/session/cookie_store.rb +221 -0
  62. data/lib/action_controller/session/mem_cache_store.rb +51 -0
  63. data/lib/action_controller/session_management.rb +54 -0
  64. data/lib/action_controller/status_codes.rb +88 -0
  65. data/lib/action_controller/streaming.rb +181 -0
  66. data/lib/action_controller/string_coercion.rb +29 -0
  67. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  68. data/lib/action_controller/templates/rescues/_trace.erb +26 -0
  69. data/lib/action_controller/templates/rescues/diagnostics.erb +11 -0
  70. data/lib/action_controller/templates/rescues/layout.erb +29 -0
  71. data/lib/action_controller/templates/rescues/missing_template.erb +2 -0
  72. data/lib/action_controller/templates/rescues/routing_error.erb +10 -0
  73. data/lib/action_controller/templates/rescues/template_error.erb +21 -0
  74. data/lib/action_controller/templates/rescues/unknown_action.erb +2 -0
  75. data/lib/action_controller/test_case.rb +209 -0
  76. data/lib/action_controller/test_process.rb +580 -0
  77. data/lib/action_controller/translation.rb +13 -0
  78. data/lib/action_controller/uploaded_file.rb +44 -0
  79. data/lib/action_controller/url_rewriter.rb +216 -0
  80. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  81. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  82. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  83. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  84. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  85. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  86. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  87. data/lib/action_controller/verification.rb +130 -0
  88. data/lib/action_controller.rb +113 -0
  89. data/lib/action_pack/version.rb +9 -0
  90. data/lib/action_pack.rb +24 -0
  91. data/lib/action_view/base.rb +362 -0
  92. data/lib/action_view/erb/util.rb +44 -0
  93. data/lib/action_view/helpers/active_record_helper.rb +305 -0
  94. data/lib/action_view/helpers/asset_tag_helper.rb +694 -0
  95. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  96. data/lib/action_view/helpers/benchmark_helper.rb +54 -0
  97. data/lib/action_view/helpers/cache_helper.rb +39 -0
  98. data/lib/action_view/helpers/capture_helper.rb +136 -0
  99. data/lib/action_view/helpers/date_helper.rb +988 -0
  100. data/lib/action_view/helpers/debug_helper.rb +38 -0
  101. data/lib/action_view/helpers/form_helper.rb +1074 -0
  102. data/lib/action_view/helpers/form_options_helper.rb +600 -0
  103. data/lib/action_view/helpers/form_tag_helper.rb +487 -0
  104. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  105. data/lib/action_view/helpers/number_helper.rb +308 -0
  106. data/lib/action_view/helpers/prototype_helper.rb +1305 -0
  107. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  108. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  109. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  110. data/lib/action_view/helpers/sanitize_helper.rb +259 -0
  111. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  112. data/lib/action_view/helpers/tag_helper.rb +150 -0
  113. data/lib/action_view/helpers/text_helper.rb +587 -0
  114. data/lib/action_view/helpers/translation_helper.rb +39 -0
  115. data/lib/action_view/helpers/url_helper.rb +639 -0
  116. data/lib/action_view/helpers.rb +59 -0
  117. data/lib/action_view/inline_template.rb +19 -0
  118. data/lib/action_view/locale/en.yml +117 -0
  119. data/lib/action_view/partials.rb +240 -0
  120. data/lib/action_view/paths.rb +69 -0
  121. data/lib/action_view/reloadable_template.rb +117 -0
  122. data/lib/action_view/renderable.rb +95 -0
  123. data/lib/action_view/renderable_partial.rb +47 -0
  124. data/lib/action_view/safe_buffer.rb +28 -0
  125. data/lib/action_view/template.rb +252 -0
  126. data/lib/action_view/template_error.rb +99 -0
  127. data/lib/action_view/template_handler.rb +34 -0
  128. data/lib/action_view/template_handlers/builder.rb +17 -0
  129. data/lib/action_view/template_handlers/erb.rb +22 -0
  130. data/lib/action_view/template_handlers/rjs.rb +13 -0
  131. data/lib/action_view/template_handlers.rb +48 -0
  132. data/lib/action_view/test_case.rb +162 -0
  133. data/lib/action_view.rb +58 -0
  134. data/lib/actionpack.rb +2 -0
  135. data/test/abstract_unit.rb +61 -0
  136. data/test/active_record_unit.rb +104 -0
  137. data/test/activerecord/active_record_store_test.rb +174 -0
  138. data/test/activerecord/render_partial_with_record_identification_test.rb +188 -0
  139. data/test/adv_attr_test.rb +20 -0
  140. data/test/controller/action_pack_assertions_test.rb +543 -0
  141. data/test/controller/addresses_render_test.rb +37 -0
  142. data/test/controller/assert_select_test.rb +734 -0
  143. data/test/controller/base_test.rb +217 -0
  144. data/test/controller/benchmark_test.rb +32 -0
  145. data/test/controller/caching_test.rb +729 -0
  146. data/test/controller/capture_test.rb +66 -0
  147. data/test/controller/content_type_test.rb +168 -0
  148. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  149. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  150. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  151. data/test/controller/cookie_test.rb +134 -0
  152. data/test/controller/deprecation/deprecated_base_methods_test.rb +32 -0
  153. data/test/controller/dispatcher_test.rb +144 -0
  154. data/test/controller/dom_assertions_test.rb +53 -0
  155. data/test/controller/failsafe_test.rb +60 -0
  156. data/test/controller/fake_controllers.rb +33 -0
  157. data/test/controller/fake_models.rb +19 -0
  158. data/test/controller/filter_params_test.rb +52 -0
  159. data/test/controller/filters_test.rb +885 -0
  160. data/test/controller/flash_test.rb +147 -0
  161. data/test/controller/header_test.rb +14 -0
  162. data/test/controller/helper_test.rb +224 -0
  163. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  164. data/test/controller/html-scanner/document_test.rb +148 -0
  165. data/test/controller/html-scanner/node_test.rb +89 -0
  166. data/test/controller/html-scanner/sanitizer_test.rb +274 -0
  167. data/test/controller/html-scanner/tag_node_test.rb +238 -0
  168. data/test/controller/html-scanner/text_node_test.rb +50 -0
  169. data/test/controller/html-scanner/tokenizer_test.rb +131 -0
  170. data/test/controller/http_basic_authentication_test.rb +113 -0
  171. data/test/controller/http_digest_authentication_test.rb +254 -0
  172. data/test/controller/integration_test.rb +483 -0
  173. data/test/controller/layout_test.rb +215 -0
  174. data/test/controller/logging_test.rb +46 -0
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +536 -0
  177. data/test/controller/mime_type_test.rb +93 -0
  178. data/test/controller/polymorphic_routes_test.rb +297 -0
  179. data/test/controller/rack_test.rb +311 -0
  180. data/test/controller/record_identifier_test.rb +139 -0
  181. data/test/controller/redirect_test.rb +285 -0
  182. data/test/controller/reloader_test.rb +124 -0
  183. data/test/controller/render_test.rb +1762 -0
  184. data/test/controller/request/json_params_parsing_test.rb +65 -0
  185. data/test/controller/request/multipart_params_parsing_test.rb +162 -0
  186. data/test/controller/request/query_string_parsing_test.rb +120 -0
  187. data/test/controller/request/test_request_test.rb +35 -0
  188. data/test/controller/request/url_encoded_params_parsing_test.rb +146 -0
  189. data/test/controller/request/xml_params_parsing_test.rb +103 -0
  190. data/test/controller/request_forgery_protection_test.rb +265 -0
  191. data/test/controller/request_test.rb +395 -0
  192. data/test/controller/rescue_test.rb +536 -0
  193. data/test/controller/resources_test.rb +1393 -0
  194. data/test/controller/routing_test.rb +2591 -0
  195. data/test/controller/selector_test.rb +628 -0
  196. data/test/controller/send_file_test.rb +171 -0
  197. data/test/controller/session/cookie_store_test.rb +216 -0
  198. data/test/controller/session/mem_cache_store_test.rb +127 -0
  199. data/test/controller/session/test_session_test.rb +58 -0
  200. data/test/controller/test_test.rb +700 -0
  201. data/test/controller/translation_test.rb +26 -0
  202. data/test/controller/url_rewriter_test.rb +385 -0
  203. data/test/controller/verification_test.rb +270 -0
  204. data/test/controller/view_paths_test.rb +141 -0
  205. data/test/controller/webservice_test.rb +273 -0
  206. data/test/fixtures/_top_level_partial.html.erb +1 -0
  207. data/test/fixtures/_top_level_partial_only.erb +1 -0
  208. data/test/fixtures/addresses/list.erb +1 -0
  209. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  210. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  211. data/test/fixtures/companies.yml +24 -0
  212. data/test/fixtures/company.rb +10 -0
  213. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  214. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  215. data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
  216. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  217. data/test/fixtures/customers/_customer.html.erb +1 -0
  218. data/test/fixtures/db_definitions/sqlite.sql +49 -0
  219. data/test/fixtures/developer.rb +9 -0
  220. data/test/fixtures/developers/_developer.erb +1 -0
  221. data/test/fixtures/developers.yml +21 -0
  222. data/test/fixtures/developers_projects.yml +13 -0
  223. data/test/fixtures/failsafe/500.html +1 -0
  224. data/test/fixtures/fun/games/_game.erb +1 -0
  225. data/test/fixtures/fun/games/hello_world.erb +1 -0
  226. data/test/fixtures/fun/serious/games/_game.erb +1 -0
  227. data/test/fixtures/functional_caching/_partial.erb +3 -0
  228. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
  229. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
  230. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
  231. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  232. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  233. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
  234. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  235. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  236. data/test/fixtures/helpers/abc_helper.rb +5 -0
  237. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  238. data/test/fixtures/helpers/fun/pdf_helper.rb +3 -0
  239. data/test/fixtures/layout_tests/abs_path_layout.rhtml +1 -0
  240. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  241. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  242. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  243. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  244. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  245. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  246. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  247. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  248. data/test/fixtures/layouts/_column.html.erb +2 -0
  249. data/test/fixtures/layouts/block_with_layout.erb +3 -0
  250. data/test/fixtures/layouts/builder.builder +3 -0
  251. data/test/fixtures/layouts/default_html.html.erb +1 -0
  252. data/test/fixtures/layouts/partial_with_layout.erb +3 -0
  253. data/test/fixtures/layouts/standard.erb +1 -0
  254. data/test/fixtures/layouts/talk_from_action.erb +2 -0
  255. data/test/fixtures/layouts/xhr.html.erb +2 -0
  256. data/test/fixtures/layouts/yield.erb +2 -0
  257. data/test/fixtures/mascot.rb +3 -0
  258. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  259. data/test/fixtures/mascots.yml +4 -0
  260. data/test/fixtures/multipart/binary_file +0 -0
  261. data/test/fixtures/multipart/boundary_problem_file +10 -0
  262. data/test/fixtures/multipart/bracketed_param +5 -0
  263. data/test/fixtures/multipart/empty +10 -0
  264. data/test/fixtures/multipart/hello.txt +1 -0
  265. data/test/fixtures/multipart/large_text_file +10 -0
  266. data/test/fixtures/multipart/mixed_files +0 -0
  267. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  268. data/test/fixtures/multipart/none +9 -0
  269. data/test/fixtures/multipart/single_parameter +5 -0
  270. data/test/fixtures/multipart/text_file +10 -0
  271. data/test/fixtures/override/test/hello_world.erb +1 -0
  272. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  273. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  274. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  275. data/test/fixtures/post_test/post/index.html.erb +1 -0
  276. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  277. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  278. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  279. data/test/fixtures/project.rb +3 -0
  280. data/test/fixtures/projects/_project.erb +1 -0
  281. data/test/fixtures/projects.yml +7 -0
  282. data/test/fixtures/public/404.html +1 -0
  283. data/test/fixtures/public/500.da.html +1 -0
  284. data/test/fixtures/public/500.html +1 -0
  285. data/test/fixtures/public/absolute/test.css +23 -0
  286. data/test/fixtures/public/absolute/test.js +63 -0
  287. data/test/fixtures/public/images/rails.png +0 -0
  288. data/test/fixtures/public/javascripts/application.js +1 -0
  289. data/test/fixtures/public/javascripts/bank.js +1 -0
  290. data/test/fixtures/public/javascripts/controls.js +1 -0
  291. data/test/fixtures/public/javascripts/dragdrop.js +1 -0
  292. data/test/fixtures/public/javascripts/effects.js +1 -0
  293. data/test/fixtures/public/javascripts/prototype.js +1 -0
  294. data/test/fixtures/public/javascripts/robber.js +1 -0
  295. data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
  296. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  297. data/test/fixtures/public/stylesheets/bank.css +1 -0
  298. data/test/fixtures/public/stylesheets/robber.css +1 -0
  299. data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
  300. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  301. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  302. data/test/fixtures/replies/_reply.erb +1 -0
  303. data/test/fixtures/replies.yml +15 -0
  304. data/test/fixtures/reply.rb +7 -0
  305. data/test/fixtures/respond_to/all_types_with_layout.html.erb +1 -0
  306. data/test/fixtures/respond_to/all_types_with_layout.js.rjs +1 -0
  307. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  308. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  309. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  310. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  311. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  312. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  313. data/test/fixtures/respond_to/using_defaults.html.erb +1 -0
  314. data/test/fixtures/respond_to/using_defaults.js.rjs +1 -0
  315. data/test/fixtures/respond_to/using_defaults.xml.builder +1 -0
  316. data/test/fixtures/respond_to/using_defaults_with_type_list.html.erb +1 -0
  317. data/test/fixtures/respond_to/using_defaults_with_type_list.js.rjs +1 -0
  318. data/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder +1 -0
  319. data/test/fixtures/scope/test/modgreet.erb +1 -0
  320. data/test/fixtures/shared.html.erb +1 -0
  321. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  322. data/test/fixtures/test/_counter.html.erb +1 -0
  323. data/test/fixtures/test/_customer.erb +1 -0
  324. data/test/fixtures/test/_customer_counter.erb +1 -0
  325. data/test/fixtures/test/_customer_greeting.erb +1 -0
  326. data/test/fixtures/test/_customer_with_var.erb +1 -0
  327. data/test/fixtures/test/_form.erb +1 -0
  328. data/test/fixtures/test/_from_helper.erb +1 -0
  329. data/test/fixtures/test/_hash_greeting.erb +1 -0
  330. data/test/fixtures/test/_hash_object.erb +2 -0
  331. data/test/fixtures/test/_hello.builder +1 -0
  332. data/test/fixtures/test/_labelling_form.erb +1 -0
  333. data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
  334. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  335. data/test/fixtures/test/_local_inspector.html.erb +1 -0
  336. data/test/fixtures/test/_one.html.erb +1 -0
  337. data/test/fixtures/test/_partial.erb +1 -0
  338. data/test/fixtures/test/_partial.html.erb +1 -0
  339. data/test/fixtures/test/_partial.js.erb +1 -0
  340. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  341. data/test/fixtures/test/_partial_only.erb +1 -0
  342. data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
  343. data/test/fixtures/test/_person.erb +2 -0
  344. data/test/fixtures/test/_raise.html.erb +1 -0
  345. data/test/fixtures/test/_two.html.erb +1 -0
  346. data/test/fixtures/test/action_talk_to_layout.erb +2 -0
  347. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  348. data/test/fixtures/test/capturing.erb +4 -0
  349. data/test/fixtures/test/content_for.erb +2 -0
  350. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  351. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  352. data/test/fixtures/test/delete_with_js.rjs +2 -0
  353. data/test/fixtures/test/dont_pick_me +1 -0
  354. data/test/fixtures/test/dot.directory/render_file_with_ivar.erb +1 -0
  355. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  356. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  357. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  358. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  359. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  360. data/test/fixtures/test/greeting.erb +1 -0
  361. data/test/fixtures/test/greeting.js.rjs +1 -0
  362. data/test/fixtures/test/hello.builder +4 -0
  363. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  364. data/test/fixtures/test/hello_world.erb +1 -0
  365. data/test/fixtures/test/hello_world.erb~ +1 -0
  366. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  367. data/test/fixtures/test/hello_world_container.builder +3 -0
  368. data/test/fixtures/test/hello_world_from_rxml.builder +4 -0
  369. data/test/fixtures/test/hello_world_with_layout_false.erb +1 -0
  370. data/test/fixtures/test/hello_xml_world.builder +11 -0
  371. data/test/fixtures/test/hyphen-ated.erb +1 -0
  372. data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
  373. data/test/fixtures/test/list.erb +1 -0
  374. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  375. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  376. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  377. data/test/fixtures/test/nested_layout.erb +3 -0
  378. data/test/fixtures/test/non_erb_block_content_for.builder +4 -0
  379. data/test/fixtures/test/potential_conflicts.erb +4 -0
  380. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  381. data/test/fixtures/test/render_file_from_template.html.erb +1 -0
  382. data/test/fixtures/test/render_file_with_ivar.erb +1 -0
  383. data/test/fixtures/test/render_file_with_locals.erb +1 -0
  384. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  385. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  386. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  387. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  388. data/test/fixtures/test/render_to_string_test.erb +1 -0
  389. data/test/fixtures/test/sub_template_raise.html.erb +1 -0
  390. data/test/fixtures/test/template.erb +1 -0
  391. data/test/fixtures/test/update_element_with_capture.erb +9 -0
  392. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  393. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
  394. data/test/fixtures/test/utf8.html.erb +2 -0
  395. data/test/fixtures/topic.rb +3 -0
  396. data/test/fixtures/topics/_topic.html.erb +1 -0
  397. data/test/fixtures/topics.yml +22 -0
  398. data/test/template/active_record_helper_i18n_test.rb +44 -0
  399. data/test/template/active_record_helper_test.rb +302 -0
  400. data/test/template/asset_tag_helper_test.rb +771 -0
  401. data/test/template/atom_feed_helper_test.rb +315 -0
  402. data/test/template/benchmark_helper_test.rb +86 -0
  403. data/test/template/compiled_templates_test.rb +204 -0
  404. data/test/template/date_helper_i18n_test.rb +121 -0
  405. data/test/template/date_helper_test.rb +2485 -0
  406. data/test/template/erb_util_test.rb +24 -0
  407. data/test/template/form_helper_test.rb +1393 -0
  408. data/test/template/form_options_helper_i18n_test.rb +27 -0
  409. data/test/template/form_options_helper_test.rb +807 -0
  410. data/test/template/form_tag_helper_test.rb +344 -0
  411. data/test/template/javascript_helper_test.rb +106 -0
  412. data/test/template/number_helper_i18n_test.rb +69 -0
  413. data/test/template/number_helper_test.rb +132 -0
  414. data/test/template/prototype_helper_test.rb +639 -0
  415. data/test/template/raw_output_helper_test.rb +21 -0
  416. data/test/template/record_tag_helper_test.rb +58 -0
  417. data/test/template/render_test.rb +290 -0
  418. data/test/template/sanitize_helper_test.rb +57 -0
  419. data/test/template/scriptaculous_helper_test.rb +90 -0
  420. data/test/template/tag_helper_test.rb +98 -0
  421. data/test/template/template_test.rb +32 -0
  422. data/test/template/test_test.rb +54 -0
  423. data/test/template/text_helper_test.rb +543 -0
  424. data/test/template/translation_helper_test.rb +32 -0
  425. data/test/template/url_helper_test.rb +622 -0
  426. data/test/testing_sandbox.rb +15 -0
  427. data/test/view/safe_buffer_test.rb +36 -0
  428. data/test/view/test_case_test.rb +176 -0
  429. metadata +531 -0
@@ -0,0 +1,54 @@
1
+ require 'thread'
2
+
3
+ module ActionController
4
+ class Reloader
5
+ @@default_lock = Mutex.new
6
+ cattr_accessor :default_lock
7
+
8
+ class BodyWrapper
9
+ def initialize(body, lock)
10
+ @body = body
11
+ @lock = lock
12
+ end
13
+
14
+ def close
15
+ @body.close if @body.respond_to?(:close)
16
+ ensure
17
+ Dispatcher.cleanup_application
18
+ @lock.unlock
19
+ end
20
+
21
+ def method_missing(*args, &block)
22
+ @body.send(*args, &block)
23
+ end
24
+
25
+ def respond_to?(symbol, include_private = false)
26
+ symbol == :close || @body.respond_to?(symbol, include_private)
27
+ end
28
+ end
29
+
30
+ def self.run(lock = @@default_lock)
31
+ lock.lock
32
+ begin
33
+ Dispatcher.reload_application
34
+ status, headers, body = yield
35
+ # We do not want to call 'cleanup_application' in an ensure block
36
+ # because the returned Rack response body may lazily generate its data. This
37
+ # is for example the case if one calls
38
+ #
39
+ # render :text => lambda { ... code here which refers to application models ... }
40
+ #
41
+ # in an ActionController.
42
+ #
43
+ # Instead, we will want to cleanup the application code after the request is
44
+ # completely finished. So we wrap the body in a BodyWrapper class so that
45
+ # when the Rack handler calls #close during the end of the request, we get to
46
+ # run our cleanup code.
47
+ [status, headers, BodyWrapper.new(body, lock)]
48
+ rescue Exception
49
+ lock.unlock
50
+ raise
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,493 @@
1
+ require 'tempfile'
2
+ require 'stringio'
3
+ require 'strscan'
4
+
5
+ require 'active_support/memoizable'
6
+ require 'action_controller/cgi_ext'
7
+
8
+ module ActionController
9
+ class Request < Rack::Request
10
+
11
+ %w[ AUTH_TYPE GATEWAY_INTERFACE
12
+ PATH_TRANSLATED REMOTE_HOST
13
+ REMOTE_IDENT REMOTE_USER REMOTE_ADDR
14
+ SERVER_NAME SERVER_PROTOCOL
15
+
16
+ HTTP_ACCEPT HTTP_ACCEPT_CHARSET HTTP_ACCEPT_ENCODING
17
+ HTTP_ACCEPT_LANGUAGE HTTP_CACHE_CONTROL HTTP_FROM
18
+ HTTP_NEGOTIATE HTTP_PRAGMA HTTP_REFERER HTTP_USER_AGENT ].each do |env|
19
+ define_method(env.sub(/^HTTP_/n, '').downcase) do
20
+ @env[env]
21
+ end
22
+ end
23
+
24
+ def key?(key)
25
+ @env.key?(key)
26
+ end
27
+
28
+ HTTP_METHODS = %w(get head put post delete options)
29
+ HTTP_METHOD_LOOKUP = HTTP_METHODS.inject({}) { |h, m| h[m] = h[m.upcase] = m.to_sym; h }
30
+
31
+ # Returns the true HTTP request \method as a lowercase symbol, such as
32
+ # <tt>:get</tt>. If the request \method is not listed in the HTTP_METHODS
33
+ # constant above, an UnknownHttpMethod exception is raised.
34
+ def request_method
35
+ @request_method ||= HTTP_METHOD_LOOKUP[super] || raise(UnknownHttpMethod, "#{super}, accepted HTTP methods are #{HTTP_METHODS.to_sentence(:locale => :en)}")
36
+ end
37
+
38
+ # Returns the HTTP request \method used for action processing as a
39
+ # lowercase symbol, such as <tt>:post</tt>. (Unlike #request_method, this
40
+ # method returns <tt>:get</tt> for a HEAD request because the two are
41
+ # functionally equivalent from the application's perspective.)
42
+ def method
43
+ request_method == :head ? :get : request_method
44
+ end
45
+
46
+ # Is this a GET (or HEAD) request? Equivalent to <tt>request.method == :get</tt>.
47
+ def get?
48
+ method == :get
49
+ end
50
+
51
+ # Is this a POST request? Equivalent to <tt>request.method == :post</tt>.
52
+ def post?
53
+ request_method == :post
54
+ end
55
+
56
+ # Is this a PUT request? Equivalent to <tt>request.method == :put</tt>.
57
+ def put?
58
+ request_method == :put
59
+ end
60
+
61
+ # Is this a DELETE request? Equivalent to <tt>request.method == :delete</tt>.
62
+ def delete?
63
+ request_method == :delete
64
+ end
65
+
66
+ # Is this a HEAD request? Since <tt>request.method</tt> sees HEAD as <tt>:get</tt>,
67
+ # this \method checks the actual HTTP \method directly.
68
+ def head?
69
+ request_method == :head
70
+ end
71
+
72
+ # Provides access to the request's HTTP headers, for example:
73
+ #
74
+ # request.headers["Content-Type"] # => "text/plain"
75
+ def headers
76
+ @headers ||= ActionController::Http::Headers.new(@env)
77
+ end
78
+
79
+ # Returns the content length of the request as an integer.
80
+ def content_length
81
+ super.to_i
82
+ end
83
+
84
+ # The MIME type of the HTTP request, such as Mime::XML.
85
+ #
86
+ # For backward compatibility, the post \format is extracted from the
87
+ # X-Post-Data-Format HTTP header if present.
88
+ def content_type
89
+ @content_type ||= begin
90
+ if @env['CONTENT_TYPE'] =~ /^([^,\;]*)/
91
+ Mime::Type.lookup($1.strip.downcase)
92
+ else
93
+ nil
94
+ end
95
+ end
96
+ end
97
+
98
+ def media_type
99
+ content_type.to_s
100
+ end
101
+
102
+ # Returns the accepted MIME type for the request.
103
+ def accepts
104
+ @accepts ||= begin
105
+ header = @env['HTTP_ACCEPT'].to_s.strip
106
+
107
+ if header.empty?
108
+ [content_type, Mime::ALL].compact
109
+ else
110
+ Mime::Type.parse(header)
111
+ end
112
+ end
113
+ end
114
+
115
+ def if_modified_since
116
+ if since = env['HTTP_IF_MODIFIED_SINCE']
117
+ Time.rfc2822(since) rescue nil
118
+ end
119
+ end
120
+
121
+ def if_none_match
122
+ env['HTTP_IF_NONE_MATCH']
123
+ end
124
+
125
+ def not_modified?(modified_at)
126
+ if_modified_since && modified_at && if_modified_since >= modified_at
127
+ end
128
+
129
+ def etag_matches?(etag)
130
+ if_none_match && if_none_match == etag
131
+ end
132
+
133
+ # Check response freshness (Last-Modified and ETag) against request
134
+ # If-Modified-Since and If-None-Match conditions. If both headers are
135
+ # supplied, both must match, or the request is not considered fresh.
136
+ def fresh?(response)
137
+ case
138
+ when if_modified_since && if_none_match
139
+ not_modified?(response.last_modified) && etag_matches?(response.etag)
140
+ when if_modified_since
141
+ not_modified?(response.last_modified)
142
+ when if_none_match
143
+ etag_matches?(response.etag)
144
+ else
145
+ false
146
+ end
147
+ end
148
+
149
+ # Returns the Mime type for the \format used in the request.
150
+ #
151
+ # GET /posts/5.xml | request.format => Mime::XML
152
+ # GET /posts/5.xhtml | request.format => Mime::HTML
153
+ # GET /posts/5 | request.format => Mime::HTML or MIME::JS, or request.accepts.first depending on the value of <tt>ActionController::Base.use_accept_header</tt>
154
+ def format
155
+ @format ||=
156
+ if parameters[:format]
157
+ Mime::Type.lookup_by_extension(parameters[:format])
158
+ elsif ActionController::Base.use_accept_header
159
+ accepts.first
160
+ elsif xhr?
161
+ Mime::Type.lookup_by_extension("js")
162
+ else
163
+ Mime::Type.lookup_by_extension("html")
164
+ end
165
+ end
166
+
167
+
168
+ # Sets the \format by string extension, which can be used to force custom formats
169
+ # that are not controlled by the extension.
170
+ #
171
+ # class ApplicationController < ActionController::Base
172
+ # before_filter :adjust_format_for_iphone
173
+ #
174
+ # private
175
+ # def adjust_format_for_iphone
176
+ # request.format = :iphone if request.env["HTTP_USER_AGENT"][/iPhone/]
177
+ # end
178
+ # end
179
+ def format=(extension)
180
+ parameters[:format] = extension.to_s
181
+ @format = Mime::Type.lookup_by_extension(parameters[:format])
182
+ end
183
+
184
+ # Returns a symbolized version of the <tt>:format</tt> parameter of the request.
185
+ # If no \format is given it returns <tt>:js</tt>for Ajax requests and <tt>:html</tt>
186
+ # otherwise.
187
+ def template_format
188
+ parameter_format = parameters[:format]
189
+
190
+ if parameter_format
191
+ parameter_format
192
+ elsif xhr?
193
+ :js
194
+ else
195
+ :html
196
+ end
197
+ end
198
+
199
+ def cache_format
200
+ parameters[:format]
201
+ end
202
+
203
+ # Returns true if the request's "X-Requested-With" header contains
204
+ # "XMLHttpRequest". (The Prototype Javascript library sends this header with
205
+ # every Ajax request.)
206
+ def xml_http_request?
207
+ !(@env['HTTP_X_REQUESTED_WITH'] !~ /XMLHttpRequest/i)
208
+ end
209
+ alias xhr? :xml_http_request?
210
+
211
+ # Which IP addresses are "trusted proxies" that can be stripped from
212
+ # the right-hand-side of X-Forwarded-For
213
+ TRUSTED_PROXIES = /^127\.0\.0\.1$|^(10|172\.(1[6-9]|2[0-9]|30|31)|192\.168)\./i
214
+
215
+ # Determines originating IP address. REMOTE_ADDR is the standard
216
+ # but will fail if the user is behind a proxy. HTTP_CLIENT_IP and/or
217
+ # HTTP_X_FORWARDED_FOR are set by proxies so check for these if
218
+ # REMOTE_ADDR is a proxy. HTTP_X_FORWARDED_FOR may be a comma-
219
+ # delimited list in the case of multiple chained proxies; the last
220
+ # address which is not trusted is the originating IP.
221
+ def remote_ip
222
+ remote_addr_list = @env['REMOTE_ADDR'] && @env['REMOTE_ADDR'].scan(/[^,\s]+/)
223
+
224
+ unless remote_addr_list.blank?
225
+ not_trusted_addrs = remote_addr_list.reject {|addr| addr =~ TRUSTED_PROXIES}
226
+ return not_trusted_addrs.first unless not_trusted_addrs.empty?
227
+ end
228
+ remote_ips = @env['HTTP_X_FORWARDED_FOR'] && @env['HTTP_X_FORWARDED_FOR'].split(',')
229
+
230
+ if @env.include? 'HTTP_CLIENT_IP'
231
+ if ActionController::Base.ip_spoofing_check && remote_ips && !remote_ips.include?(@env['HTTP_CLIENT_IP'])
232
+ # We don't know which came from the proxy, and which from the user
233
+ raise ActionControllerError.new(<<EOM)
234
+ IP spoofing attack?!
235
+ HTTP_CLIENT_IP=#{@env['HTTP_CLIENT_IP'].inspect}
236
+ HTTP_X_FORWARDED_FOR=#{@env['HTTP_X_FORWARDED_FOR'].inspect}
237
+ EOM
238
+ end
239
+
240
+ return @env['HTTP_CLIENT_IP']
241
+ end
242
+
243
+ if remote_ips
244
+ while remote_ips.size > 1 && TRUSTED_PROXIES =~ remote_ips.last.strip
245
+ remote_ips.pop
246
+ end
247
+
248
+ return remote_ips.last.strip
249
+ end
250
+
251
+ @env['REMOTE_ADDR']
252
+ end
253
+
254
+ # Returns the lowercase name of the HTTP server software.
255
+ def server_software
256
+ (@env['SERVER_SOFTWARE'] && /^([a-zA-Z]+)/ =~ @env['SERVER_SOFTWARE']) ? $1.downcase : nil
257
+ end
258
+
259
+ # Returns the complete URL used for this request.
260
+ def url
261
+ protocol + host_with_port + request_uri
262
+ end
263
+
264
+ # Returns 'https://' if this is an SSL request and 'http://' otherwise.
265
+ def protocol
266
+ ssl? ? 'https://' : 'http://'
267
+ end
268
+
269
+ # Is this an SSL request?
270
+ def ssl?
271
+ @env['HTTPS'] == 'on' || @env['HTTP_X_FORWARDED_PROTO'] == 'https'
272
+ end
273
+
274
+ # Returns the \host for this request, such as "example.com".
275
+ def raw_host_with_port
276
+ if forwarded = env["HTTP_X_FORWARDED_HOST"]
277
+ forwarded.split(/,\s?/).last
278
+ else
279
+ env['HTTP_HOST'] || "#{env['SERVER_NAME'] || env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
280
+ end
281
+ end
282
+
283
+ # Returns the host for this request, such as example.com.
284
+ def host
285
+ raw_host_with_port.sub(/:\d+$/, '')
286
+ end
287
+
288
+ # Returns a \host:\port string for this request, such as "example.com" or
289
+ # "example.com:8080".
290
+ def host_with_port
291
+ "#{host}#{port_string}"
292
+ end
293
+
294
+ # Returns the port number of this request as an integer.
295
+ def port
296
+ if raw_host_with_port =~ /:(\d+)$/
297
+ $1.to_i
298
+ else
299
+ standard_port
300
+ end
301
+ end
302
+
303
+ # Returns the standard \port number for this request's protocol.
304
+ def standard_port
305
+ case protocol
306
+ when 'https://' then 443
307
+ else 80
308
+ end
309
+ end
310
+
311
+ # Returns a \port suffix like ":8080" if the \port number of this request
312
+ # is not the default HTTP \port 80 or HTTPS \port 443.
313
+ def port_string
314
+ port == standard_port ? '' : ":#{port}"
315
+ end
316
+
317
+ # Returns the \domain part of a \host, such as "rubyonrails.org" in "www.rubyonrails.org". You can specify
318
+ # a different <tt>tld_length</tt>, such as 2 to catch rubyonrails.co.uk in "www.rubyonrails.co.uk".
319
+ def domain(tld_length = 1)
320
+ return nil unless named_host?(host)
321
+
322
+ host.split('.').last(1 + tld_length).join('.')
323
+ end
324
+
325
+ # Returns all the \subdomains as an array, so <tt>["dev", "www"]</tt> would be
326
+ # returned for "dev.www.rubyonrails.org". You can specify a different <tt>tld_length</tt>,
327
+ # such as 2 to catch <tt>["www"]</tt> instead of <tt>["www", "rubyonrails"]</tt>
328
+ # in "www.rubyonrails.co.uk".
329
+ def subdomains(tld_length = 1)
330
+ return [] unless named_host?(host)
331
+ parts = host.split('.')
332
+ parts[0..-(tld_length+2)]
333
+ end
334
+
335
+ # Returns the query string, accounting for server idiosyncrasies.
336
+ def query_string
337
+ @env['QUERY_STRING'].present? ? @env['QUERY_STRING'] : (@env['REQUEST_URI'].split('?', 2)[1] || '')
338
+ end
339
+
340
+ # Returns the request URI, accounting for server idiosyncrasies.
341
+ # WEBrick includes the full URL. IIS leaves REQUEST_URI blank.
342
+ def request_uri
343
+ if uri = @env['REQUEST_URI']
344
+ # Remove domain, which webrick puts into the request_uri.
345
+ (%r{^\w+\://[^/]+(/.*|$)$} =~ uri) ? $1 : uri
346
+ else
347
+ # Construct IIS missing REQUEST_URI from SCRIPT_NAME and PATH_INFO.
348
+ uri = @env['PATH_INFO'].to_s
349
+
350
+ if script_filename = @env['SCRIPT_NAME'].to_s.match(%r{[^/]+$})
351
+ uri = uri.sub(/#{script_filename}\//, '')
352
+ end
353
+
354
+ env_qs = @env['QUERY_STRING'].to_s
355
+ uri += "?#{env_qs}" unless env_qs.empty?
356
+
357
+ if uri.blank?
358
+ @env.delete('REQUEST_URI')
359
+ else
360
+ @env['REQUEST_URI'] = uri
361
+ end
362
+ end
363
+ end
364
+
365
+ # Returns the interpreted \path to requested resource after all the installation
366
+ # directory of this application was taken into account.
367
+ def path
368
+ path = request_uri.to_s[/\A[^\?]*/]
369
+ path.sub!(/\A#{ActionController::Base.relative_url_root}/, '')
370
+ path
371
+ end
372
+
373
+ # Read the request \body. This is useful for web services that need to
374
+ # work with raw requests directly.
375
+ def raw_post
376
+ unless @env.include? 'RAW_POST_DATA'
377
+ @env['RAW_POST_DATA'] = body.read(@env['CONTENT_LENGTH'].to_i)
378
+ body.rewind if body.respond_to?(:rewind)
379
+ end
380
+ @env['RAW_POST_DATA']
381
+ end
382
+
383
+ # Returns both GET and POST \parameters in a single hash.
384
+ def parameters
385
+ @parameters ||= request_parameters.merge(query_parameters).update(path_parameters).with_indifferent_access
386
+ end
387
+ alias_method :params, :parameters
388
+
389
+ def path_parameters=(parameters) #:nodoc:
390
+ @env["action_controller.request.path_parameters"] = parameters
391
+ @symbolized_path_parameters = @parameters = nil
392
+ end
393
+
394
+ # The same as <tt>path_parameters</tt> with explicitly symbolized keys.
395
+ def symbolized_path_parameters
396
+ @symbolized_path_parameters ||= path_parameters.symbolize_keys
397
+ end
398
+
399
+ # Returns a hash with the \parameters used to form the \path of the request.
400
+ # Returned hash keys are strings:
401
+ #
402
+ # {'action' => 'my_action', 'controller' => 'my_controller'}
403
+ #
404
+ # See <tt>symbolized_path_parameters</tt> for symbolized keys.
405
+ def path_parameters
406
+ @env["action_controller.request.path_parameters"] ||= {}
407
+ end
408
+
409
+ # The request body is an IO input stream. If the RAW_POST_DATA environment
410
+ # variable is already set, wrap it in a StringIO.
411
+ def body
412
+ if raw_post = @env['RAW_POST_DATA']
413
+ raw_post.force_encoding(Encoding::BINARY) if raw_post.respond_to?(:force_encoding)
414
+ StringIO.new(raw_post)
415
+ else
416
+ @env['rack.input']
417
+ end
418
+ end
419
+
420
+ def form_data?
421
+ FORM_DATA_MEDIA_TYPES.include?(content_type.to_s)
422
+ end
423
+
424
+ # Override Rack's GET method to support indifferent access
425
+ def GET
426
+ @env["action_controller.request.query_parameters"] ||= normalize_parameters(super)
427
+ end
428
+ alias_method :query_parameters, :GET
429
+
430
+ # Override Rack's POST method to support indifferent access
431
+ def POST
432
+ @env["action_controller.request.request_parameters"] ||= normalize_parameters(super)
433
+ end
434
+ alias_method :request_parameters, :POST
435
+
436
+ def body_stream #:nodoc:
437
+ @env['rack.input']
438
+ end
439
+
440
+ def session
441
+ @env['rack.session'] ||= {}
442
+ end
443
+
444
+ def session=(session) #:nodoc:
445
+ @env['rack.session'] = session
446
+ end
447
+
448
+ def reset_session
449
+ @env['rack.session.options'].delete(:id)
450
+ @env['rack.session'] = {}
451
+ end
452
+
453
+ def session_options
454
+ @env['rack.session.options'] ||= {}
455
+ end
456
+
457
+ def session_options=(options)
458
+ @env['rack.session.options'] = options
459
+ end
460
+
461
+ def server_port
462
+ @env['SERVER_PORT'].to_i
463
+ end
464
+
465
+ private
466
+ def named_host?(host)
467
+ !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
468
+ end
469
+
470
+ # Convert nested Hashs to HashWithIndifferentAccess and replace
471
+ # file upload hashs with UploadedFile objects
472
+ def normalize_parameters(value)
473
+ case value
474
+ when Hash
475
+ if value.has_key?(:tempfile)
476
+ upload = value[:tempfile]
477
+ upload.extend(UploadedFile)
478
+ upload.original_path = value[:filename]
479
+ upload.content_type = value[:type]
480
+ upload
481
+ else
482
+ h = {}
483
+ value.each { |k, v| h[k] = normalize_parameters(v) }
484
+ h.with_indifferent_access
485
+ end
486
+ when Array
487
+ value.map { |e| normalize_parameters(e) }
488
+ else
489
+ value
490
+ end
491
+ end
492
+ end
493
+ end
@@ -0,0 +1,113 @@
1
+ module ActionController #:nodoc:
2
+ class InvalidAuthenticityToken < ActionControllerError #:nodoc:
3
+ end
4
+
5
+ module RequestForgeryProtection
6
+ def self.included(base)
7
+ base.class_eval do
8
+ helper_method :form_authenticity_token
9
+ helper_method :protect_against_forgery?
10
+ end
11
+ base.extend(ClassMethods)
12
+ end
13
+
14
+ # Protecting controller actions from CSRF attacks by ensuring that all forms are coming from the current web application, not a
15
+ # forged link from another site, is done by embedding a token based on a random string stored in the session (which an attacker wouldn't know) in all
16
+ # forms and Ajax requests generated by Rails and then verifying the authenticity of that token in the controller. Only
17
+ # HTML/JavaScript requests are checked, so this will not protect your XML API (presumably you'll have a different authentication
18
+ # scheme there anyway). Also, GET requests are not protected as these should be idempotent anyway.
19
+ #
20
+ # This is turned on with the <tt>protect_from_forgery</tt> method, which will check the token and raise an
21
+ # ActionController::InvalidAuthenticityToken if it doesn't match what was expected. You can customize the error message in
22
+ # production by editing public/422.html. A call to this method in ApplicationController is generated by default in post-Rails 2.0
23
+ # applications.
24
+ #
25
+ # The token parameter is named <tt>authenticity_token</tt> by default. If you are generating an HTML form manually (without the
26
+ # use of Rails' <tt>form_for</tt>, <tt>form_tag</tt> or other helpers), you have to include a hidden field named like that and
27
+ # set its value to what is returned by <tt>form_authenticity_token</tt>. Same applies to manually constructed Ajax requests. To
28
+ # make the token available through a global variable to scripts on a certain page, you could add something like this to a view:
29
+ #
30
+ # <%= javascript_tag "window._token = '#{form_authenticity_token}'" %>
31
+ #
32
+ # Request forgery protection is disabled by default in test environment. If you are upgrading from Rails 1.x, add this to
33
+ # config/environments/test.rb:
34
+ #
35
+ # # Disable request forgery protection in test environment
36
+ # config.action_controller.allow_forgery_protection = false
37
+ #
38
+ # == Learn more about CSRF (Cross-Site Request Forgery) attacks
39
+ #
40
+ # Here are some resources:
41
+ # * http://isc.sans.org/diary.html?storyid=1750
42
+ # * http://en.wikipedia.org/wiki/Cross-site_request_forgery
43
+ #
44
+ # Keep in mind, this is NOT a silver-bullet, plug 'n' play, warm security blanket for your rails application.
45
+ # There are a few guidelines you should follow:
46
+ #
47
+ # * Keep your GET requests safe and idempotent. More reading material:
48
+ # * http://www.xml.com/pub/a/2002/04/24/deviant.html
49
+ # * http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9.1.1
50
+ # * Make sure the session cookies that Rails creates are non-persistent. Check in Firefox and look for "Expires: at end of session"
51
+ #
52
+ module ClassMethods
53
+ # Turn on request forgery protection. Bear in mind that only non-GET, HTML/JavaScript requests are checked.
54
+ #
55
+ # Example:
56
+ #
57
+ # class FooController < ApplicationController
58
+ # protect_from_forgery :except => :index
59
+ #
60
+ # # you can disable csrf protection on controller-by-controller basis:
61
+ # skip_before_filter :verify_authenticity_token
62
+ # end
63
+ #
64
+ # Valid Options:
65
+ #
66
+ # * <tt>:only/:except</tt> - Passed to the <tt>before_filter</tt> call. Set which actions are verified.
67
+ def protect_from_forgery(options = {})
68
+ self.request_forgery_protection_token ||= :authenticity_token
69
+ before_filter :verify_authenticity_token, :only => options.delete(:only), :except => options.delete(:except)
70
+ if options[:secret] || options[:digest]
71
+ ActiveSupport::Deprecation.warn("protect_from_forgery only takes :only and :except options now. :digest and :secret have no effect", caller)
72
+ end
73
+ end
74
+ end
75
+
76
+ protected
77
+ # The actual before_filter that is used. Modify this to change how you handle unverified requests.
78
+ def verify_authenticity_token
79
+ verified_request? || raise(ActionController::InvalidAuthenticityToken)
80
+ end
81
+
82
+ # Returns true or false if a request is verified. Checks:
83
+ #
84
+ # * is the format restricted? By default, only HTML requests are checked.
85
+ # * is it a GET request? Gets should be safe and idempotent
86
+ # * Does the form_authenticity_token match the given token value from the params?
87
+ def verified_request?
88
+ !protect_against_forgery? ||
89
+ request.method == :get ||
90
+ request.xhr? ||
91
+ !verifiable_request_format? ||
92
+ form_authenticity_token == form_authenticity_param
93
+ end
94
+
95
+ def form_authenticity_param
96
+ params[request_forgery_protection_token]
97
+ end
98
+
99
+ def verifiable_request_format?
100
+ !request.content_type.nil? && request.content_type.verify_request?
101
+ end
102
+
103
+ # Sets the token value for the current session. Pass a <tt>:secret</tt> option
104
+ # in +protect_from_forgery+ to add a custom salt to the hash.
105
+ def form_authenticity_token
106
+ session[:_csrf_token] ||= ActiveSupport::SecureRandom.base64(32)
107
+ end
108
+
109
+ def protect_against_forgery?
110
+ allow_forgery_protection && request_forgery_protection_token
111
+ end
112
+ end
113
+ end