actionpack-rack-upgrade-2 2.3.15

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 (441) hide show
  1. data/CHANGELOG +5250 -0
  2. data/MIT-LICENSE +21 -0
  3. data/README +409 -0
  4. data/RUNNING_UNIT_TESTS +24 -0
  5. data/Rakefile +158 -0
  6. data/install.rb +30 -0
  7. data/lib/action_controller.rb +113 -0
  8. data/lib/action_controller/assertions/dom_assertions.rb +55 -0
  9. data/lib/action_controller/assertions/model_assertions.rb +21 -0
  10. data/lib/action_controller/assertions/response_assertions.rb +169 -0
  11. data/lib/action_controller/assertions/routing_assertions.rb +146 -0
  12. data/lib/action_controller/assertions/selector_assertions.rb +638 -0
  13. data/lib/action_controller/assertions/tag_assertions.rb +127 -0
  14. data/lib/action_controller/base.rb +1425 -0
  15. data/lib/action_controller/benchmarking.rb +107 -0
  16. data/lib/action_controller/caching.rb +71 -0
  17. data/lib/action_controller/caching/actions.rb +177 -0
  18. data/lib/action_controller/caching/fragments.rb +120 -0
  19. data/lib/action_controller/caching/pages.rb +152 -0
  20. data/lib/action_controller/caching/sweeper.rb +45 -0
  21. data/lib/action_controller/caching/sweeping.rb +55 -0
  22. data/lib/action_controller/cgi_ext.rb +15 -0
  23. data/lib/action_controller/cgi_ext/cookie.rb +112 -0
  24. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  25. data/lib/action_controller/cgi_ext/stdinput.rb +24 -0
  26. data/lib/action_controller/cgi_process.rb +77 -0
  27. data/lib/action_controller/cookies.rb +197 -0
  28. data/lib/action_controller/dispatcher.rb +133 -0
  29. data/lib/action_controller/failsafe.rb +87 -0
  30. data/lib/action_controller/filters.rb +680 -0
  31. data/lib/action_controller/flash.rb +213 -0
  32. data/lib/action_controller/headers.rb +33 -0
  33. data/lib/action_controller/helpers.rb +225 -0
  34. data/lib/action_controller/http_authentication.rb +309 -0
  35. data/lib/action_controller/integration.rb +708 -0
  36. data/lib/action_controller/layout.rb +286 -0
  37. data/lib/action_controller/middleware_stack.rb +119 -0
  38. data/lib/action_controller/middlewares.rb +14 -0
  39. data/lib/action_controller/mime_responds.rb +193 -0
  40. data/lib/action_controller/mime_type.rb +212 -0
  41. data/lib/action_controller/mime_types.rb +21 -0
  42. data/lib/action_controller/params_parser.rb +77 -0
  43. data/lib/action_controller/performance_test.rb +15 -0
  44. data/lib/action_controller/polymorphic_routes.rb +189 -0
  45. data/lib/action_controller/rack_lint_patch.rb +36 -0
  46. data/lib/action_controller/record_identifier.rb +104 -0
  47. data/lib/action_controller/reloader.rb +54 -0
  48. data/lib/action_controller/request.rb +495 -0
  49. data/lib/action_controller/request_forgery_protection.rb +116 -0
  50. data/lib/action_controller/rescue.rb +183 -0
  51. data/lib/action_controller/resources.rb +682 -0
  52. data/lib/action_controller/response.rb +237 -0
  53. data/lib/action_controller/routing.rb +388 -0
  54. data/lib/action_controller/routing/builder.rb +197 -0
  55. data/lib/action_controller/routing/optimisations.rb +130 -0
  56. data/lib/action_controller/routing/recognition_optimisation.rb +167 -0
  57. data/lib/action_controller/routing/route.rb +265 -0
  58. data/lib/action_controller/routing/route_set.rb +503 -0
  59. data/lib/action_controller/routing/routing_ext.rb +49 -0
  60. data/lib/action_controller/routing/segments.rb +343 -0
  61. data/lib/action_controller/session/abstract_store.rb +276 -0
  62. data/lib/action_controller/session/cookie_store.rb +240 -0
  63. data/lib/action_controller/session/mem_cache_store.rb +60 -0
  64. data/lib/action_controller/session_management.rb +54 -0
  65. data/lib/action_controller/status_codes.rb +88 -0
  66. data/lib/action_controller/streaming.rb +181 -0
  67. data/lib/action_controller/string_coercion.rb +29 -0
  68. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  69. data/lib/action_controller/templates/rescues/_trace.erb +26 -0
  70. data/lib/action_controller/templates/rescues/diagnostics.erb +11 -0
  71. data/lib/action_controller/templates/rescues/layout.erb +29 -0
  72. data/lib/action_controller/templates/rescues/missing_template.erb +2 -0
  73. data/lib/action_controller/templates/rescues/routing_error.erb +10 -0
  74. data/lib/action_controller/templates/rescues/template_error.erb +21 -0
  75. data/lib/action_controller/templates/rescues/unknown_action.erb +2 -0
  76. data/lib/action_controller/test_case.rb +209 -0
  77. data/lib/action_controller/test_process.rb +580 -0
  78. data/lib/action_controller/translation.rb +13 -0
  79. data/lib/action_controller/uploaded_file.rb +44 -0
  80. data/lib/action_controller/url_rewriter.rb +229 -0
  81. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  82. data/lib/action_controller/vendor/html-scanner/html/document.rb +68 -0
  83. data/lib/action_controller/vendor/html-scanner/html/node.rb +537 -0
  84. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  85. data/lib/action_controller/vendor/html-scanner/html/selector.rb +828 -0
  86. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +105 -0
  87. data/lib/action_controller/vendor/html-scanner/html/version.rb +11 -0
  88. data/lib/action_controller/verification.rb +130 -0
  89. data/lib/action_pack.rb +24 -0
  90. data/lib/action_pack/version.rb +9 -0
  91. data/lib/action_view.rb +58 -0
  92. data/lib/action_view/base.rb +362 -0
  93. data/lib/action_view/helpers.rb +61 -0
  94. data/lib/action_view/helpers/active_record_helper.rb +305 -0
  95. data/lib/action_view/helpers/asset_tag_helper.rb +695 -0
  96. data/lib/action_view/helpers/atom_feed_helper.rb +198 -0
  97. data/lib/action_view/helpers/benchmark_helper.rb +54 -0
  98. data/lib/action_view/helpers/cache_helper.rb +39 -0
  99. data/lib/action_view/helpers/capture_helper.rb +136 -0
  100. data/lib/action_view/helpers/csrf_helper.rb +14 -0
  101. data/lib/action_view/helpers/date_helper.rb +989 -0
  102. data/lib/action_view/helpers/debug_helper.rb +38 -0
  103. data/lib/action_view/helpers/form_helper.rb +1118 -0
  104. data/lib/action_view/helpers/form_options_helper.rb +599 -0
  105. data/lib/action_view/helpers/form_tag_helper.rb +490 -0
  106. data/lib/action_view/helpers/javascript_helper.rb +208 -0
  107. data/lib/action_view/helpers/number_helper.rb +308 -0
  108. data/lib/action_view/helpers/prototype_helper.rb +1305 -0
  109. data/lib/action_view/helpers/raw_output_helper.rb +9 -0
  110. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  111. data/lib/action_view/helpers/record_tag_helper.rb +58 -0
  112. data/lib/action_view/helpers/sanitize_helper.rb +251 -0
  113. data/lib/action_view/helpers/scriptaculous_helper.rb +226 -0
  114. data/lib/action_view/helpers/tag_helper.rb +151 -0
  115. data/lib/action_view/helpers/text_helper.rb +597 -0
  116. data/lib/action_view/helpers/translation_helper.rb +67 -0
  117. data/lib/action_view/helpers/url_helper.rb +637 -0
  118. data/lib/action_view/inline_template.rb +19 -0
  119. data/lib/action_view/locale/en.yml +117 -0
  120. data/lib/action_view/partials.rb +241 -0
  121. data/lib/action_view/paths.rb +77 -0
  122. data/lib/action_view/reloadable_template.rb +117 -0
  123. data/lib/action_view/renderable.rb +109 -0
  124. data/lib/action_view/renderable_partial.rb +53 -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.rb +48 -0
  129. data/lib/action_view/template_handlers/builder.rb +17 -0
  130. data/lib/action_view/template_handlers/erb.rb +25 -0
  131. data/lib/action_view/template_handlers/rjs.rb +13 -0
  132. data/lib/action_view/test_case.rb +162 -0
  133. data/lib/actionpack.rb +2 -0
  134. data/test/abstract_unit.rb +78 -0
  135. data/test/active_record_unit.rb +104 -0
  136. data/test/activerecord/active_record_store_test.rb +221 -0
  137. data/test/activerecord/render_partial_with_record_identification_test.rb +188 -0
  138. data/test/adv_attr_test.rb +20 -0
  139. data/test/controller/action_pack_assertions_test.rb +545 -0
  140. data/test/controller/addresses_render_test.rb +37 -0
  141. data/test/controller/assert_select_test.rb +735 -0
  142. data/test/controller/base_test.rb +217 -0
  143. data/test/controller/benchmark_test.rb +32 -0
  144. data/test/controller/caching_test.rb +743 -0
  145. data/test/controller/capture_test.rb +66 -0
  146. data/test/controller/content_type_test.rb +178 -0
  147. data/test/controller/controller_fixtures/app/controllers/admin/user_controller.rb +0 -0
  148. data/test/controller/controller_fixtures/app/controllers/user_controller.rb +0 -0
  149. data/test/controller/controller_fixtures/vendor/plugins/bad_plugin/lib/plugin_controller.rb +0 -0
  150. data/test/controller/cookie_test.rb +208 -0
  151. data/test/controller/deprecation/deprecated_base_methods_test.rb +32 -0
  152. data/test/controller/dispatcher_test.rb +144 -0
  153. data/test/controller/dom_assertions_test.rb +53 -0
  154. data/test/controller/failsafe_test.rb +60 -0
  155. data/test/controller/fake_controllers.rb +33 -0
  156. data/test/controller/fake_models.rb +19 -0
  157. data/test/controller/filter_params_test.rb +52 -0
  158. data/test/controller/filters_test.rb +885 -0
  159. data/test/controller/flash_test.rb +174 -0
  160. data/test/controller/header_test.rb +14 -0
  161. data/test/controller/helper_test.rb +224 -0
  162. data/test/controller/html-scanner/cdata_node_test.rb +15 -0
  163. data/test/controller/html-scanner/document_test.rb +148 -0
  164. data/test/controller/html-scanner/node_test.rb +89 -0
  165. data/test/controller/html-scanner/sanitizer_test.rb +281 -0
  166. data/test/controller/html-scanner/tag_node_test.rb +238 -0
  167. data/test/controller/html-scanner/text_node_test.rb +50 -0
  168. data/test/controller/html-scanner/tokenizer_test.rb +131 -0
  169. data/test/controller/http_basic_authentication_test.rb +113 -0
  170. data/test/controller/http_digest_authentication_test.rb +254 -0
  171. data/test/controller/integration_test.rb +526 -0
  172. data/test/controller/layout_test.rb +215 -0
  173. data/test/controller/localized_templates_test.rb +24 -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/output_escaping_test.rb +19 -0
  179. data/test/controller/polymorphic_routes_test.rb +297 -0
  180. data/test/controller/rack_test.rb +308 -0
  181. data/test/controller/record_identifier_test.rb +139 -0
  182. data/test/controller/redirect_test.rb +285 -0
  183. data/test/controller/reloader_test.rb +125 -0
  184. data/test/controller/render_test.rb +1783 -0
  185. data/test/controller/request/json_params_parsing_test.rb +65 -0
  186. data/test/controller/request/multipart_params_parsing_test.rb +177 -0
  187. data/test/controller/request/query_string_parsing_test.rb +120 -0
  188. data/test/controller/request/test_request_test.rb +35 -0
  189. data/test/controller/request/url_encoded_params_parsing_test.rb +146 -0
  190. data/test/controller/request/xml_params_parsing_test.rb +103 -0
  191. data/test/controller/request_forgery_protection_test.rb +233 -0
  192. data/test/controller/request_test.rb +398 -0
  193. data/test/controller/rescue_test.rb +541 -0
  194. data/test/controller/resources_test.rb +1393 -0
  195. data/test/controller/routing_test.rb +2592 -0
  196. data/test/controller/selector_test.rb +628 -0
  197. data/test/controller/send_file_test.rb +171 -0
  198. data/test/controller/session/abstract_store_test.rb +64 -0
  199. data/test/controller/session/cookie_store_test.rb +354 -0
  200. data/test/controller/session/mem_cache_store_test.rb +187 -0
  201. data/test/controller/session/test_session_test.rb +58 -0
  202. data/test/controller/test_test.rb +700 -0
  203. data/test/controller/translation_test.rb +26 -0
  204. data/test/controller/url_rewriter_test.rb +395 -0
  205. data/test/controller/verification_test.rb +270 -0
  206. data/test/controller/view_paths_test.rb +141 -0
  207. data/test/controller/webservice_test.rb +273 -0
  208. data/test/fixtures/_top_level_partial.html.erb +1 -0
  209. data/test/fixtures/_top_level_partial_only.erb +1 -0
  210. data/test/fixtures/addresses/list.erb +1 -0
  211. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  212. data/test/fixtures/bad_customers/_bad_customer.html.erb +1 -0
  213. data/test/fixtures/companies.yml +24 -0
  214. data/test/fixtures/company.rb +10 -0
  215. data/test/fixtures/content_type/render_default_content_types_for_respond_to.rhtml +1 -0
  216. data/test/fixtures/content_type/render_default_for_rhtml.rhtml +1 -0
  217. data/test/fixtures/content_type/render_default_for_rjs.rjs +1 -0
  218. data/test/fixtures/content_type/render_default_for_rxml.rxml +1 -0
  219. data/test/fixtures/customers/_customer.html.erb +1 -0
  220. data/test/fixtures/db_definitions/sqlite.sql +49 -0
  221. data/test/fixtures/developer.rb +9 -0
  222. data/test/fixtures/developers.yml +21 -0
  223. data/test/fixtures/developers/_developer.erb +1 -0
  224. data/test/fixtures/developers_projects.yml +13 -0
  225. data/test/fixtures/failsafe/500.html +1 -0
  226. data/test/fixtures/fun/games/_game.erb +1 -0
  227. data/test/fixtures/fun/games/hello_world.erb +1 -0
  228. data/test/fixtures/fun/serious/games/_game.erb +1 -0
  229. data/test/fixtures/functional_caching/_partial.erb +3 -0
  230. data/test/fixtures/functional_caching/formatted_fragment_cached.html.erb +3 -0
  231. data/test/fixtures/functional_caching/formatted_fragment_cached.js.rjs +6 -0
  232. data/test/fixtures/functional_caching/formatted_fragment_cached.xml.builder +5 -0
  233. data/test/fixtures/functional_caching/fragment_cached.html.erb +2 -0
  234. data/test/fixtures/functional_caching/html_fragment_cached_with_partial.html.erb +1 -0
  235. data/test/fixtures/functional_caching/inline_fragment_cached.html.erb +2 -0
  236. data/test/fixtures/functional_caching/js_fragment_cached_with_partial.js.rjs +1 -0
  237. data/test/fixtures/good_customers/_good_customer.html.erb +1 -0
  238. data/test/fixtures/helpers/abc_helper.rb +5 -0
  239. data/test/fixtures/helpers/fun/games_helper.rb +3 -0
  240. data/test/fixtures/helpers/fun/pdf_helper.rb +3 -0
  241. data/test/fixtures/layout_tests/abs_path_layout.rhtml +1 -0
  242. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  243. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  244. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  245. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  246. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  247. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  248. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  249. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  250. data/test/fixtures/layouts/_column.html.erb +2 -0
  251. data/test/fixtures/layouts/block_with_layout.erb +3 -0
  252. data/test/fixtures/layouts/builder.builder +3 -0
  253. data/test/fixtures/layouts/default_html.html.erb +1 -0
  254. data/test/fixtures/layouts/partial_with_layout.erb +3 -0
  255. data/test/fixtures/layouts/standard.erb +1 -0
  256. data/test/fixtures/layouts/talk_from_action.erb +2 -0
  257. data/test/fixtures/layouts/xhr.html.erb +2 -0
  258. data/test/fixtures/layouts/yield.erb +2 -0
  259. data/test/fixtures/localized/hello_world.de.html +1 -0
  260. data/test/fixtures/localized/hello_world.en.html +1 -0
  261. data/test/fixtures/mascot.rb +3 -0
  262. data/test/fixtures/mascots.yml +4 -0
  263. data/test/fixtures/mascots/_mascot.html.erb +1 -0
  264. data/test/fixtures/multipart/binary_file +0 -0
  265. data/test/fixtures/multipart/boundary_problem_file +10 -0
  266. data/test/fixtures/multipart/bracketed_param +5 -0
  267. data/test/fixtures/multipart/empty +10 -0
  268. data/test/fixtures/multipart/hello.txt +1 -0
  269. data/test/fixtures/multipart/large_text_file +10 -0
  270. data/test/fixtures/multipart/mixed_files +0 -0
  271. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  272. data/test/fixtures/multipart/none +9 -0
  273. data/test/fixtures/multipart/single_parameter +5 -0
  274. data/test/fixtures/multipart/text_file +10 -0
  275. data/test/fixtures/override/test/hello_world.erb +1 -0
  276. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  277. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  278. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  279. data/test/fixtures/post_test/post/index.html.erb +1 -0
  280. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  281. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  282. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  283. data/test/fixtures/project.rb +3 -0
  284. data/test/fixtures/projects.yml +7 -0
  285. data/test/fixtures/projects/_project.erb +1 -0
  286. data/test/fixtures/public/404.html +1 -0
  287. data/test/fixtures/public/500.da.html +1 -0
  288. data/test/fixtures/public/500.html +1 -0
  289. data/test/fixtures/public/absolute/test.css +23 -0
  290. data/test/fixtures/public/absolute/test.js +63 -0
  291. data/test/fixtures/public/images/rails.png +0 -0
  292. data/test/fixtures/public/javascripts/application.js +1 -0
  293. data/test/fixtures/public/javascripts/bank.js +1 -0
  294. data/test/fixtures/public/javascripts/controls.js +1 -0
  295. data/test/fixtures/public/javascripts/dragdrop.js +1 -0
  296. data/test/fixtures/public/javascripts/effects.js +1 -0
  297. data/test/fixtures/public/javascripts/prototype.js +1 -0
  298. data/test/fixtures/public/javascripts/robber.js +1 -0
  299. data/test/fixtures/public/javascripts/subdir/subdir.js +1 -0
  300. data/test/fixtures/public/javascripts/version.1.0.js +1 -0
  301. data/test/fixtures/public/stylesheets/bank.css +1 -0
  302. data/test/fixtures/public/stylesheets/robber.css +1 -0
  303. data/test/fixtures/public/stylesheets/subdir/subdir.css +1 -0
  304. data/test/fixtures/public/stylesheets/version.1.0.css +1 -0
  305. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  306. data/test/fixtures/replies.yml +15 -0
  307. data/test/fixtures/replies/_reply.erb +1 -0
  308. data/test/fixtures/reply.rb +7 -0
  309. data/test/fixtures/respond_to/all_types_with_layout.html.erb +1 -0
  310. data/test/fixtures/respond_to/all_types_with_layout.js.rjs +1 -0
  311. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  312. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  313. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  314. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  315. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  316. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  317. data/test/fixtures/respond_to/using_defaults.html.erb +1 -0
  318. data/test/fixtures/respond_to/using_defaults.js.rjs +1 -0
  319. data/test/fixtures/respond_to/using_defaults.xml.builder +1 -0
  320. data/test/fixtures/respond_to/using_defaults_with_type_list.html.erb +1 -0
  321. data/test/fixtures/respond_to/using_defaults_with_type_list.js.rjs +1 -0
  322. data/test/fixtures/respond_to/using_defaults_with_type_list.xml.builder +1 -0
  323. data/test/fixtures/scope/test/modgreet.erb +1 -0
  324. data/test/fixtures/session_autoload_test/session_autoload_test/foo.rb +10 -0
  325. data/test/fixtures/shared.html.erb +1 -0
  326. data/test/fixtures/symlink_parent/symlinked_layout.erb +5 -0
  327. data/test/fixtures/test/_counter.html.erb +1 -0
  328. data/test/fixtures/test/_customer.erb +1 -0
  329. data/test/fixtures/test/_customer_counter.erb +1 -0
  330. data/test/fixtures/test/_customer_counter_with_as.erb +1 -0
  331. data/test/fixtures/test/_customer_greeting.erb +1 -0
  332. data/test/fixtures/test/_customer_with_var.erb +1 -0
  333. data/test/fixtures/test/_form.erb +1 -0
  334. data/test/fixtures/test/_from_helper.erb +1 -0
  335. data/test/fixtures/test/_hash_greeting.erb +1 -0
  336. data/test/fixtures/test/_hash_object.erb +2 -0
  337. data/test/fixtures/test/_hello.builder +1 -0
  338. data/test/fixtures/test/_labelling_form.erb +1 -0
  339. data/test/fixtures/test/_layout_for_block_with_args.html.erb +3 -0
  340. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  341. data/test/fixtures/test/_local_inspector.html.erb +1 -0
  342. data/test/fixtures/test/_one.html.erb +1 -0
  343. data/test/fixtures/test/_partial.erb +1 -0
  344. data/test/fixtures/test/_partial.html.erb +1 -0
  345. data/test/fixtures/test/_partial.js.erb +1 -0
  346. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  347. data/test/fixtures/test/_partial_only.erb +1 -0
  348. data/test/fixtures/test/_partial_with_only_html_version.html.erb +1 -0
  349. data/test/fixtures/test/_person.erb +2 -0
  350. data/test/fixtures/test/_raise.html.erb +1 -0
  351. data/test/fixtures/test/_two.html.erb +1 -0
  352. data/test/fixtures/test/_utf8_partial.html.erb +1 -0
  353. data/test/fixtures/test/_utf8_partial_magic.html.erb +2 -0
  354. data/test/fixtures/test/action_talk_to_layout.erb +2 -0
  355. data/test/fixtures/test/array_translation.erb +1 -0
  356. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  357. data/test/fixtures/test/capturing.erb +4 -0
  358. data/test/fixtures/test/content_for.erb +2 -0
  359. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  360. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  361. data/test/fixtures/test/delete_with_js.rjs +2 -0
  362. data/test/fixtures/test/dont_pick_me +1 -0
  363. data/test/fixtures/test/dot.directory/render_file_with_ivar.erb +1 -0
  364. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  365. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  366. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  367. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  368. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  369. data/test/fixtures/test/greeting.erb +1 -0
  370. data/test/fixtures/test/greeting.js.rjs +1 -0
  371. data/test/fixtures/test/hello.builder +4 -0
  372. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  373. data/test/fixtures/test/hello_world.erb +1 -0
  374. data/test/fixtures/test/hello_world.erb~ +1 -0
  375. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  376. data/test/fixtures/test/hello_world_container.builder +3 -0
  377. data/test/fixtures/test/hello_world_from_rxml.builder +4 -0
  378. data/test/fixtures/test/hello_world_with_layout_false.erb +1 -0
  379. data/test/fixtures/test/hello_xml_world.builder +11 -0
  380. data/test/fixtures/test/hyphen-ated.erb +1 -0
  381. data/test/fixtures/test/implicit_content_type.atom.builder +2 -0
  382. data/test/fixtures/test/list.erb +1 -0
  383. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  384. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  385. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  386. data/test/fixtures/test/nested_layout.erb +3 -0
  387. data/test/fixtures/test/non_erb_block_content_for.builder +4 -0
  388. data/test/fixtures/test/potential_conflicts.erb +4 -0
  389. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  390. data/test/fixtures/test/render_file_from_template.html.erb +1 -0
  391. data/test/fixtures/test/render_file_with_ivar.erb +1 -0
  392. data/test/fixtures/test/render_file_with_locals.erb +1 -0
  393. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  394. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  395. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  396. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  397. data/test/fixtures/test/render_to_string_test.erb +1 -0
  398. data/test/fixtures/test/scoped_array_translation.erb +1 -0
  399. data/test/fixtures/test/sub_template_raise.html.erb +1 -0
  400. data/test/fixtures/test/template.erb +1 -0
  401. data/test/fixtures/test/translation.erb +1 -0
  402. data/test/fixtures/test/update_element_with_capture.erb +9 -0
  403. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  404. data/test/fixtures/test/using_layout_around_block_with_args.html.erb +1 -0
  405. data/test/fixtures/test/utf8.html.erb +4 -0
  406. data/test/fixtures/test/utf8_magic.html.erb +5 -0
  407. data/test/fixtures/test/utf8_magic_with_bare_partial.html.erb +5 -0
  408. data/test/fixtures/topic.rb +3 -0
  409. data/test/fixtures/topics.yml +22 -0
  410. data/test/fixtures/topics/_topic.html.erb +1 -0
  411. data/test/template/active_record_helper_i18n_test.rb +51 -0
  412. data/test/template/active_record_helper_test.rb +302 -0
  413. data/test/template/asset_tag_helper_test.rb +770 -0
  414. data/test/template/atom_feed_helper_test.rb +315 -0
  415. data/test/template/benchmark_helper_test.rb +86 -0
  416. data/test/template/compiled_templates_test.rb +204 -0
  417. data/test/template/date_helper_i18n_test.rb +121 -0
  418. data/test/template/date_helper_test.rb +2603 -0
  419. data/test/template/erb_util_test.rb +36 -0
  420. data/test/template/form_helper_test.rb +1447 -0
  421. data/test/template/form_options_helper_i18n_test.rb +27 -0
  422. data/test/template/form_options_helper_test.rb +811 -0
  423. data/test/template/form_tag_helper_test.rb +356 -0
  424. data/test/template/javascript_helper_test.rb +106 -0
  425. data/test/template/number_helper_i18n_test.rb +69 -0
  426. data/test/template/number_helper_test.rb +132 -0
  427. data/test/template/prototype_helper_test.rb +639 -0
  428. data/test/template/raw_output_helper_test.rb +21 -0
  429. data/test/template/record_tag_helper_test.rb +58 -0
  430. data/test/template/render_test.rb +329 -0
  431. data/test/template/sanitize_helper_test.rb +57 -0
  432. data/test/template/scriptaculous_helper_test.rb +90 -0
  433. data/test/template/tag_helper_test.rb +98 -0
  434. data/test/template/template_test.rb +32 -0
  435. data/test/template/test_test.rb +54 -0
  436. data/test/template/text_helper_test.rb +597 -0
  437. data/test/template/translation_helper_test.rb +95 -0
  438. data/test/template/url_helper_test.rb +641 -0
  439. data/test/testing_sandbox.rb +15 -0
  440. data/test/view/test_case_test.rb +176 -0
  441. metadata +519 -0
@@ -0,0 +1,36 @@
1
+ # Rack 1.0 does not allow string subclass body. This does not play well with our ActiveSupport::SafeBuffer.
2
+ # The next release of Rack will be allowing string subclass body - http://github.com/rack/rack/commit/de668df02802a0335376a81ba709270e43ba9d55
3
+ # TODO : Remove this monkey patch after the next release of Rack
4
+
5
+ module RackLintPatch
6
+ module AllowStringSubclass
7
+ def self.included(base)
8
+ base.send :alias_method, :each, :each_with_hack
9
+ end
10
+
11
+ def each_with_hack
12
+ @closed = false
13
+
14
+ @body.each { |part|
15
+ assert("Body yielded non-string value #{part.inspect}") {
16
+ part.kind_of?(String)
17
+ }
18
+ yield part
19
+ }
20
+
21
+ if @body.respond_to?(:to_path)
22
+ assert("The file identified by body.to_path does not exist") {
23
+ ::File.exist? @body.to_path
24
+ }
25
+ end
26
+ end
27
+ end
28
+
29
+ begin
30
+ app = proc {|env| [200, {"Content-Type" => "text/plain", "Content-Length" => "12"}, [Class.new(String).new("Hello World!")]] }
31
+ response = Rack::MockRequest.new(Rack::Lint.new(app)).get('/')
32
+ rescue Rack::Lint::LintError => e
33
+ raise(e) unless e.message =~ /Body yielded non-string value/
34
+ Rack::Lint.send :include, AllowStringSubclass
35
+ end
36
+ end
@@ -0,0 +1,104 @@
1
+ module ActionController
2
+ # The record identifier encapsulates a number of naming conventions for dealing with records, like Active Records or
3
+ # Active Resources or pretty much any other model type that has an id. These patterns are then used to try elevate
4
+ # the view actions to a higher logical level. Example:
5
+ #
6
+ # # routes
7
+ # map.resources :posts
8
+ #
9
+ # # view
10
+ # <% div_for(post) do %> <div id="post_45" class="post">
11
+ # <%= post.body %> What a wonderful world!
12
+ # <% end %> </div>
13
+ #
14
+ # # controller
15
+ # def destroy
16
+ # post = Post.find(params[:id])
17
+ # post.destroy
18
+ #
19
+ # respond_to do |format|
20
+ # format.html { redirect_to(post) } # Calls polymorphic_url(post) which in turn calls post_url(post)
21
+ # format.js do
22
+ # # Calls: new Effect.fade('post_45');
23
+ # render(:update) { |page| page[post].visual_effect(:fade) }
24
+ # end
25
+ # end
26
+ # end
27
+ #
28
+ # As the example above shows, you can stop caring to a large extent what the actual id of the post is. You just know
29
+ # that one is being assigned and that the subsequent calls in redirect_to and the RJS expect that same naming
30
+ # convention and allows you to write less code if you follow it.
31
+ module RecordIdentifier
32
+ extend self
33
+
34
+ JOIN = '_'.freeze
35
+ NEW = 'new'.freeze
36
+
37
+ # Returns plural/singular for a record or class. Example:
38
+ #
39
+ # partial_path(post) # => "posts/post"
40
+ # partial_path(Person) # => "people/person"
41
+ # partial_path(Person, "admin/games") # => "admin/people/person"
42
+ def partial_path(record_or_class, controller_path = nil)
43
+ name = model_name_from_record_or_class(record_or_class)
44
+
45
+ if controller_path && controller_path.include?("/")
46
+ "#{File.dirname(controller_path)}/#{name.partial_path}"
47
+ else
48
+ name.partial_path
49
+ end
50
+ end
51
+
52
+ # The DOM class convention is to use the singular form of an object or class. Examples:
53
+ #
54
+ # dom_class(post) # => "post"
55
+ # dom_class(Person) # => "person"
56
+ #
57
+ # If you need to address multiple instances of the same class in the same view, you can prefix the dom_class:
58
+ #
59
+ # dom_class(post, :edit) # => "edit_post"
60
+ # dom_class(Person, :edit) # => "edit_person"
61
+ def dom_class(record_or_class, prefix = nil)
62
+ singular = singular_class_name(record_or_class)
63
+ prefix ? "#{prefix}#{JOIN}#{singular}" : singular
64
+ end
65
+
66
+ # The DOM id convention is to use the singular form of an object or class with the id following an underscore.
67
+ # If no id is found, prefix with "new_" instead. Examples:
68
+ #
69
+ # dom_id(Post.find(45)) # => "post_45"
70
+ # dom_id(Post.new) # => "new_post"
71
+ #
72
+ # If you need to address multiple instances of the same class in the same view, you can prefix the dom_id:
73
+ #
74
+ # dom_id(Post.find(45), :edit) # => "edit_post_45"
75
+ def dom_id(record, prefix = nil)
76
+ if record_id = record.id
77
+ "#{dom_class(record, prefix)}#{JOIN}#{record_id}"
78
+ else
79
+ dom_class(record, prefix || NEW)
80
+ end
81
+ end
82
+
83
+ # Returns the plural class name of a record or class. Examples:
84
+ #
85
+ # plural_class_name(post) # => "posts"
86
+ # plural_class_name(Highrise::Person) # => "highrise_people"
87
+ def plural_class_name(record_or_class)
88
+ model_name_from_record_or_class(record_or_class).plural
89
+ end
90
+
91
+ # Returns the singular class name of a record or class. Examples:
92
+ #
93
+ # singular_class_name(post) # => "post"
94
+ # singular_class_name(Highrise::Person) # => "highrise_person"
95
+ def singular_class_name(record_or_class)
96
+ model_name_from_record_or_class(record_or_class).singular
97
+ end
98
+
99
+ private
100
+ def model_name_from_record_or_class(record_or_class)
101
+ (record_or_class.is_a?(Class) ? record_or_class : record_or_class.class).model_name
102
+ end
103
+ end
104
+ end
@@ -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,495 @@
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'].present? && @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
+ # session may be a hash, if so, we do not want to call destroy
450
+ # fixes issue 6440
451
+ session.destroy if session and session.respond_to?(:destroy)
452
+ self.session = {}
453
+ end
454
+
455
+ def session_options
456
+ @env['rack.session.options'] ||= {}
457
+ end
458
+
459
+ def session_options=(options)
460
+ @env['rack.session.options'] = options
461
+ end
462
+
463
+ def server_port
464
+ @env['SERVER_PORT'].to_i
465
+ end
466
+
467
+ private
468
+ def named_host?(host)
469
+ !(host.nil? || /\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.match(host))
470
+ end
471
+
472
+ # Convert nested Hashs to HashWithIndifferentAccess and replace
473
+ # file upload hashs with UploadedFile objects
474
+ def normalize_parameters(value)
475
+ case value
476
+ when Hash
477
+ if value.has_key?(:tempfile)
478
+ upload = value[:tempfile]
479
+ upload.extend(UploadedFile)
480
+ upload.original_path = value[:filename]
481
+ upload.content_type = value[:type]
482
+ upload
483
+ else
484
+ h = {}
485
+ value.each { |k, v| h[k] = normalize_parameters(v) }
486
+ h.with_indifferent_access
487
+ end
488
+ when Array
489
+ value.map { |e| normalize_parameters(e) }
490
+ else
491
+ value
492
+ end
493
+ end
494
+ end
495
+ end