actionpack 1.13.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of actionpack might be problematic. Click here for more details.

Files changed (317) hide show
  1. data/CHANGELOG +1400 -20
  2. data/MIT-LICENSE +1 -1
  3. data/README +5 -5
  4. data/RUNNING_UNIT_TESTS +4 -5
  5. data/Rakefile +5 -6
  6. data/install.rb +2 -2
  7. data/lib/action_controller.rb +11 -15
  8. data/lib/action_controller/assertions.rb +12 -25
  9. data/lib/action_controller/assertions/dom_assertions.rb +18 -4
  10. data/lib/action_controller/assertions/model_assertions.rb +8 -1
  11. data/lib/action_controller/assertions/response_assertions.rb +35 -12
  12. data/lib/action_controller/assertions/routing_assertions.rb +56 -12
  13. data/lib/action_controller/assertions/selector_assertions.rb +105 -38
  14. data/lib/action_controller/assertions/tag_assertions.rb +28 -15
  15. data/lib/action_controller/base.rb +318 -250
  16. data/lib/action_controller/benchmarking.rb +33 -29
  17. data/lib/action_controller/caching.rb +130 -64
  18. data/lib/action_controller/cgi_ext.rb +16 -0
  19. data/lib/action_controller/cgi_ext/{cookie_performance_fix.rb → cookie.rb} +25 -40
  20. data/lib/action_controller/cgi_ext/query_extension.rb +22 -0
  21. data/lib/action_controller/cgi_ext/session.rb +73 -0
  22. data/lib/action_controller/cgi_ext/stdinput.rb +23 -0
  23. data/lib/action_controller/cgi_process.rb +34 -57
  24. data/lib/action_controller/components.rb +19 -36
  25. data/lib/action_controller/cookies.rb +10 -9
  26. data/lib/action_controller/dispatcher.rb +195 -0
  27. data/lib/action_controller/filters.rb +35 -34
  28. data/lib/action_controller/flash.rb +30 -35
  29. data/lib/action_controller/helpers.rb +121 -47
  30. data/lib/action_controller/http_authentication.rb +126 -0
  31. data/lib/action_controller/integration.rb +105 -101
  32. data/lib/action_controller/layout.rb +59 -47
  33. data/lib/action_controller/mime_responds.rb +57 -68
  34. data/lib/action_controller/mime_type.rb +43 -80
  35. data/lib/action_controller/mime_types.rb +20 -0
  36. data/lib/action_controller/polymorphic_routes.rb +88 -0
  37. data/lib/action_controller/record_identifier.rb +91 -0
  38. data/lib/action_controller/request.rb +553 -88
  39. data/lib/action_controller/request_forgery_protection.rb +126 -0
  40. data/lib/action_controller/request_profiler.rb +138 -0
  41. data/lib/action_controller/rescue.rb +185 -69
  42. data/lib/action_controller/resources.rb +211 -172
  43. data/lib/action_controller/response.rb +49 -8
  44. data/lib/action_controller/routing.rb +359 -236
  45. data/lib/action_controller/routing_optimisation.rb +119 -0
  46. data/lib/action_controller/session/active_record_store.rb +3 -2
  47. data/lib/action_controller/session/cookie_store.rb +161 -0
  48. data/lib/action_controller/session/mem_cache_store.rb +9 -16
  49. data/lib/action_controller/session_management.rb +17 -8
  50. data/lib/action_controller/streaming.rb +6 -3
  51. data/lib/action_controller/templates/rescues/_request_and_response.erb +24 -0
  52. data/lib/action_controller/templates/rescues/{_trace.rhtml → _trace.erb} +0 -0
  53. data/lib/action_controller/templates/rescues/{diagnostics.rhtml → diagnostics.erb} +2 -2
  54. data/lib/action_controller/templates/rescues/{layout.rhtml → layout.erb} +0 -0
  55. data/lib/action_controller/templates/rescues/{missing_template.rhtml → missing_template.erb} +0 -0
  56. data/lib/action_controller/templates/rescues/{routing_error.rhtml → routing_error.erb} +0 -0
  57. data/lib/action_controller/templates/rescues/{template_error.rhtml → template_error.erb} +2 -2
  58. data/lib/action_controller/templates/rescues/{unknown_action.rhtml → unknown_action.erb} +0 -0
  59. data/lib/action_controller/test_case.rb +53 -0
  60. data/lib/action_controller/test_process.rb +59 -46
  61. data/lib/action_controller/url_rewriter.rb +48 -24
  62. data/lib/action_controller/vendor/html-scanner/html/document.rb +7 -4
  63. data/lib/action_controller/vendor/html-scanner/html/sanitizer.rb +173 -0
  64. data/lib/action_controller/vendor/html-scanner/html/selector.rb +11 -6
  65. data/lib/action_controller/verification.rb +27 -21
  66. data/lib/action_pack.rb +1 -1
  67. data/lib/action_pack/version.rb +4 -4
  68. data/lib/action_view.rb +2 -3
  69. data/lib/action_view/base.rb +218 -63
  70. data/lib/action_view/compiled_templates.rb +1 -2
  71. data/lib/action_view/helpers/active_record_helper.rb +35 -17
  72. data/lib/action_view/helpers/asset_tag_helper.rb +395 -87
  73. data/lib/action_view/helpers/atom_feed_helper.rb +111 -0
  74. data/lib/action_view/helpers/benchmark_helper.rb +12 -5
  75. data/lib/action_view/helpers/cache_helper.rb +29 -0
  76. data/lib/action_view/helpers/capture_helper.rb +97 -63
  77. data/lib/action_view/helpers/date_helper.rb +295 -35
  78. data/lib/action_view/helpers/debug_helper.rb +6 -2
  79. data/lib/action_view/helpers/form_helper.rb +354 -111
  80. data/lib/action_view/helpers/form_options_helper.rb +171 -109
  81. data/lib/action_view/helpers/form_tag_helper.rb +332 -76
  82. data/lib/action_view/helpers/javascript_helper.rb +35 -11
  83. data/lib/action_view/helpers/javascripts/controls.js +484 -354
  84. data/lib/action_view/helpers/javascripts/dragdrop.js +88 -58
  85. data/lib/action_view/helpers/javascripts/effects.js +396 -364
  86. data/lib/action_view/helpers/javascripts/prototype.js +2817 -1107
  87. data/lib/action_view/helpers/number_helper.rb +84 -60
  88. data/lib/action_view/helpers/prototype_helper.rb +419 -43
  89. data/lib/action_view/helpers/record_identification_helper.rb +20 -0
  90. data/lib/action_view/helpers/record_tag_helper.rb +59 -0
  91. data/lib/action_view/helpers/sanitize_helper.rb +223 -0
  92. data/lib/action_view/helpers/scriptaculous_helper.rb +63 -4
  93. data/lib/action_view/helpers/tag_helper.rb +69 -39
  94. data/lib/action_view/helpers/text_helper.rb +221 -148
  95. data/lib/action_view/helpers/url_helper.rb +283 -165
  96. data/lib/action_view/partials.rb +134 -62
  97. data/lib/action_view/template_error.rb +4 -12
  98. data/lib/actionpack.rb +1 -0
  99. data/test/abstract_unit.rb +21 -1
  100. data/test/action_view_test.rb +26 -0
  101. data/test/active_record_unit.rb +12 -20
  102. data/test/activerecord/active_record_store_test.rb +2 -2
  103. data/test/activerecord/render_partial_with_record_identification_test.rb +74 -0
  104. data/test/controller/action_pack_assertions_test.rb +21 -152
  105. data/test/controller/addresses_render_test.rb +2 -7
  106. data/test/controller/assert_select_test.rb +120 -14
  107. data/test/controller/base_test.rb +11 -13
  108. data/test/controller/caching_test.rb +125 -5
  109. data/test/controller/capture_test.rb +23 -16
  110. data/test/controller/cgi_test.rb +66 -391
  111. data/test/controller/components_test.rb +31 -42
  112. data/test/controller/content_type_test.rb +1 -1
  113. data/test/controller/cookie_test.rb +42 -14
  114. data/test/controller/deprecation/deprecated_base_methods_test.rb +1 -42
  115. data/test/controller/dispatcher_test.rb +123 -0
  116. data/test/controller/fake_models.rb +5 -0
  117. data/test/controller/filters_test.rb +44 -7
  118. data/test/controller/flash_test.rb +46 -2
  119. data/test/controller/fragment_store_setting_test.rb +10 -8
  120. data/test/controller/helper_test.rb +19 -2
  121. data/test/controller/html-scanner/document_test.rb +124 -0
  122. data/test/controller/html-scanner/node_test.rb +69 -0
  123. data/test/controller/html-scanner/sanitizer_test.rb +250 -0
  124. data/test/controller/html-scanner/tag_node_test.rb +239 -0
  125. data/test/controller/html-scanner/text_node_test.rb +51 -0
  126. data/test/controller/html-scanner/tokenizer_test.rb +125 -0
  127. data/test/controller/http_authentication_test.rb +54 -0
  128. data/test/controller/integration_test.rb +12 -26
  129. data/test/controller/layout_test.rb +64 -12
  130. data/test/controller/mime_responds_test.rb +193 -38
  131. data/test/controller/mime_type_test.rb +30 -8
  132. data/test/controller/new_render_test.rb +104 -22
  133. data/test/controller/polymorphic_routes_test.rb +98 -0
  134. data/test/controller/record_identifier_test.rb +103 -0
  135. data/test/controller/redirect_test.rb +120 -18
  136. data/test/controller/render_test.rb +195 -45
  137. data/test/controller/request_forgery_protection_test.rb +217 -0
  138. data/test/controller/request_test.rb +545 -27
  139. data/test/controller/rescue_test.rb +501 -0
  140. data/test/controller/resources_test.rb +258 -132
  141. data/test/controller/routing_test.rb +502 -106
  142. data/test/controller/selector_test.rb +5 -5
  143. data/test/controller/send_file_test.rb +17 -7
  144. data/test/controller/session/cookie_store_test.rb +246 -0
  145. data/test/controller/session/mem_cache_store_test.rb +182 -0
  146. data/test/controller/session_fixation_test.rb +8 -11
  147. data/test/controller/session_management_test.rb +7 -7
  148. data/test/controller/test_test.rb +150 -38
  149. data/test/controller/url_rewriter_test.rb +87 -12
  150. data/test/controller/verification_test.rb +11 -0
  151. data/test/controller/view_paths_test.rb +137 -0
  152. data/test/controller/webservice_test.rb +11 -75
  153. data/test/fixtures/addresses/{list.rhtml → list.erb} +0 -0
  154. data/test/fixtures/db_definitions/sqlite.sql +2 -1
  155. data/test/fixtures/developer.rb +2 -0
  156. data/test/fixtures/fun/games/{hello_world.rhtml → hello_world.erb} +0 -0
  157. data/test/fixtures/helpers/fun/pdf_helper.rb +1 -1
  158. data/test/fixtures/layout_tests/alt/hello.rhtml +1 -0
  159. data/test/fixtures/layout_tests/layouts/multiple_extensions.html.erb +1 -0
  160. data/test/fixtures/layouts/{builder.rxml → builder.builder} +0 -0
  161. data/test/fixtures/layouts/{standard.rhtml → standard.erb} +0 -0
  162. data/test/fixtures/layouts/{talk_from_action.rhtml → talk_from_action.erb} +0 -0
  163. data/test/fixtures/layouts/{yield.rhtml → yield.erb} +0 -0
  164. data/test/fixtures/multipart/binary_file +0 -0
  165. data/test/fixtures/multipart/bracketed_param +5 -0
  166. data/test/fixtures/override/test/hello_world.erb +1 -0
  167. data/test/fixtures/override2/layouts/test/sub.erb +1 -0
  168. data/test/fixtures/post_test/layouts/post.html.erb +1 -0
  169. data/test/fixtures/post_test/layouts/super_post.iphone.erb +1 -0
  170. data/test/fixtures/post_test/post/index.html.erb +1 -0
  171. data/test/fixtures/post_test/post/index.iphone.erb +1 -0
  172. data/test/fixtures/post_test/super_post/index.html.erb +1 -0
  173. data/test/fixtures/post_test/super_post/index.iphone.erb +1 -0
  174. data/test/fixtures/public/404.html +1 -0
  175. data/test/fixtures/public/500.html +1 -0
  176. data/test/fixtures/public/javascripts/application.js +0 -1
  177. data/test/fixtures/public/javascripts/bank.js +1 -0
  178. data/test/fixtures/public/javascripts/robber.js +1 -0
  179. data/test/fixtures/public/stylesheets/bank.css +1 -0
  180. data/test/fixtures/public/stylesheets/robber.css +1 -0
  181. data/test/fixtures/replies.yml +2 -0
  182. data/test/fixtures/reply.rb +2 -1
  183. data/test/fixtures/respond_to/{all_types_with_layout.rhtml → all_types_with_layout.html.erb} +0 -0
  184. data/test/fixtures/respond_to/{all_types_with_layout.rjs → all_types_with_layout.js.rjs} +0 -0
  185. data/test/fixtures/respond_to/custom_constant_handling_without_block.mobile.erb +1 -0
  186. data/test/fixtures/respond_to/iphone_with_html_response_type.html.erb +1 -0
  187. data/test/fixtures/respond_to/iphone_with_html_response_type.iphone.erb +1 -0
  188. data/test/fixtures/respond_to/layouts/missing.html.erb +1 -0
  189. data/test/fixtures/respond_to/layouts/standard.html.erb +1 -0
  190. data/test/fixtures/respond_to/layouts/standard.iphone.erb +1 -0
  191. data/test/fixtures/respond_to/{using_defaults.rhtml → using_defaults.html.erb} +0 -0
  192. data/test/fixtures/respond_to/{using_defaults.rjs → using_defaults.js.rjs} +0 -0
  193. data/test/fixtures/respond_to/{using_defaults.rxml → using_defaults.xml.builder} +0 -0
  194. data/test/fixtures/respond_to/{using_defaults_with_type_list.rhtml → using_defaults_with_type_list.html.erb} +0 -0
  195. data/test/fixtures/respond_to/{using_defaults_with_type_list.rjs → using_defaults_with_type_list.js.rjs} +0 -0
  196. data/test/fixtures/respond_to/{using_defaults_with_type_list.rxml → using_defaults_with_type_list.xml.builder} +0 -0
  197. data/test/fixtures/scope/test/{modgreet.rhtml → modgreet.erb} +0 -0
  198. data/test/fixtures/test/{_customer.rhtml → _customer.erb} +0 -0
  199. data/test/fixtures/test/{_customer_greeting.rhtml → _customer_greeting.erb} +0 -0
  200. data/test/fixtures/test/_hash_greeting.erb +1 -0
  201. data/test/fixtures/test/_hash_object.erb +2 -0
  202. data/test/fixtures/test/{_hello.rxml → _hello.builder} +0 -0
  203. data/test/fixtures/test/_layout_for_partial.html.erb +3 -0
  204. data/test/fixtures/test/_partial.erb +1 -0
  205. data/test/fixtures/test/_partial.html.erb +1 -0
  206. data/test/fixtures/test/_partial.js.erb +1 -0
  207. data/test/fixtures/test/_partial_for_use_in_layout.html.erb +1 -0
  208. data/test/fixtures/test/{_partial_only.rhtml → _partial_only.erb} +0 -0
  209. data/test/fixtures/test/{_person.rhtml → _person.erb} +0 -0
  210. data/test/fixtures/test/{action_talk_to_layout.rhtml → action_talk_to_layout.erb} +0 -0
  211. data/test/fixtures/test/{block_content_for.rhtml → block_content_for.erb} +0 -0
  212. data/test/fixtures/test/calling_partial_with_layout.html.erb +1 -0
  213. data/test/fixtures/test/{capturing.rhtml → capturing.erb} +0 -0
  214. data/test/fixtures/test/{content_for.rhtml → content_for.erb} +0 -0
  215. data/test/fixtures/test/content_for_concatenated.erb +3 -0
  216. data/test/fixtures/test/content_for_with_parameter.erb +2 -0
  217. data/test/fixtures/test/dot.directory/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
  218. data/test/fixtures/test/{erb_content_for.rhtml → erb_content_for.erb} +0 -0
  219. data/test/fixtures/test/formatted_html_erb.html.erb +1 -0
  220. data/test/fixtures/test/formatted_xml_erb.builder +1 -0
  221. data/test/fixtures/test/formatted_xml_erb.html.erb +1 -0
  222. data/test/fixtures/test/formatted_xml_erb.xml.erb +1 -0
  223. data/test/fixtures/test/{greeting.rhtml → greeting.erb} +0 -0
  224. data/test/fixtures/test/{hello.rxml → hello.builder} +0 -0
  225. data/test/fixtures/test/{hello_world.rxml → hello_world.builder} +0 -0
  226. data/test/fixtures/test/{hello_world.rhtml → hello_world.erb} +0 -0
  227. data/test/fixtures/test/{hello_world_container.rxml → hello_world_container.builder} +0 -0
  228. data/test/fixtures/test/{hello_world_with_layout_false.rhtml → hello_world_with_layout_false.erb} +0 -0
  229. data/test/fixtures/test/{hello_xml_world.rxml → hello_xml_world.builder} +0 -0
  230. data/test/fixtures/test/list.erb +1 -0
  231. data/test/fixtures/test/{non_erb_block_content_for.rxml → non_erb_block_content_for.builder} +0 -0
  232. data/test/fixtures/test/{potential_conflicts.rhtml → potential_conflicts.erb} +0 -0
  233. data/test/fixtures/test/{render_file_with_ivar.rhtml → render_file_with_ivar.erb} +0 -0
  234. data/test/fixtures/test/{render_file_with_locals.rhtml → render_file_with_locals.erb} +0 -0
  235. data/test/fixtures/test/{render_to_string_test.rhtml → render_to_string_test.erb} +0 -0
  236. data/test/fixtures/test/{update_element_with_capture.rhtml → update_element_with_capture.erb} +0 -0
  237. data/test/fixtures/test/using_layout_around_block.html.erb +1 -0
  238. data/test/fixtures/topic.rb +1 -1
  239. data/test/template/active_record_helper_test.rb +67 -20
  240. data/test/template/asset_tag_helper_test.rb +222 -54
  241. data/test/template/atom_feed_helper_test.rb +101 -0
  242. data/test/template/benchmark_helper_test.rb +2 -2
  243. data/test/template/compiled_templates_test.rb +76 -32
  244. data/test/template/date_helper_test.rb +125 -9
  245. data/test/template/form_helper_test.rb +326 -33
  246. data/test/template/form_options_helper_test.rb +822 -15
  247. data/test/template/form_tag_helper_test.rb +96 -30
  248. data/test/template/javascript_helper_test.rb +61 -13
  249. data/test/template/number_helper_test.rb +12 -11
  250. data/test/template/prototype_helper_test.rb +185 -24
  251. data/test/template/sanitize_helper_test.rb +49 -0
  252. data/test/template/scriptaculous_helper_test.rb +9 -3
  253. data/test/template/tag_helper_test.rb +13 -2
  254. data/test/template/text_helper_test.rb +38 -52
  255. data/test/template/url_helper_test.rb +216 -46
  256. metadata +144 -116
  257. data/examples/.htaccess +0 -24
  258. data/examples/address_book/index.rhtml +0 -33
  259. data/examples/address_book/layout.rhtml +0 -8
  260. data/examples/address_book_controller.cgi +0 -9
  261. data/examples/address_book_controller.fcgi +0 -6
  262. data/examples/address_book_controller.rb +0 -52
  263. data/examples/address_book_controller.rbx +0 -4
  264. data/examples/benchmark.rb +0 -52
  265. data/examples/benchmark_with_ar.fcgi +0 -89
  266. data/examples/blog_controller.cgi +0 -53
  267. data/examples/debate/index.rhtml +0 -14
  268. data/examples/debate/new_topic.rhtml +0 -22
  269. data/examples/debate/topic.rhtml +0 -32
  270. data/examples/debate_controller.cgi +0 -57
  271. data/lib/action_controller/assertions/deprecated_assertions.rb +0 -228
  272. data/lib/action_controller/cgi_ext/cgi_ext.rb +0 -36
  273. data/lib/action_controller/cgi_ext/cgi_methods.rb +0 -211
  274. data/lib/action_controller/cgi_ext/pstore_performance_fix.rb +0 -30
  275. data/lib/action_controller/cgi_ext/raw_post_data_fix.rb +0 -95
  276. data/lib/action_controller/cgi_ext/session_performance_fix.rb +0 -30
  277. data/lib/action_controller/deprecated_dependencies.rb +0 -65
  278. data/lib/action_controller/deprecated_redirects.rb +0 -17
  279. data/lib/action_controller/deprecated_request_methods.rb +0 -34
  280. data/lib/action_controller/macros/auto_complete.rb +0 -53
  281. data/lib/action_controller/macros/in_place_editing.rb +0 -33
  282. data/lib/action_controller/pagination.rb +0 -408
  283. data/lib/action_controller/scaffolding.rb +0 -189
  284. data/lib/action_controller/templates/rescues/_request_and_response.rhtml +0 -44
  285. data/lib/action_controller/templates/scaffolds/edit.rhtml +0 -7
  286. data/lib/action_controller/templates/scaffolds/layout.rhtml +0 -69
  287. data/lib/action_controller/templates/scaffolds/list.rhtml +0 -27
  288. data/lib/action_controller/templates/scaffolds/new.rhtml +0 -6
  289. data/lib/action_controller/templates/scaffolds/show.rhtml +0 -9
  290. data/lib/action_controller/vendor/xml_node.rb +0 -97
  291. data/lib/action_view/helpers/deprecated_helper.rb +0 -37
  292. data/lib/action_view/helpers/java_script_macros_helper.rb +0 -233
  293. data/lib/action_view/helpers/pagination_helper.rb +0 -86
  294. data/test/activerecord/active_record_assertions_test.rb +0 -92
  295. data/test/activerecord/pagination_test.rb +0 -165
  296. data/test/controller/deprecated_instance_variables_test.rb +0 -48
  297. data/test/controller/raw_post_test.rb +0 -68
  298. data/test/fixtures/deprecated_instance_variables/_cookies_ivar.rhtml +0 -1
  299. data/test/fixtures/deprecated_instance_variables/_cookies_method.rhtml +0 -1
  300. data/test/fixtures/deprecated_instance_variables/_flash_ivar.rhtml +0 -1
  301. data/test/fixtures/deprecated_instance_variables/_flash_method.rhtml +0 -1
  302. data/test/fixtures/deprecated_instance_variables/_headers_ivar.rhtml +0 -1
  303. data/test/fixtures/deprecated_instance_variables/_headers_method.rhtml +0 -1
  304. data/test/fixtures/deprecated_instance_variables/_params_ivar.rhtml +0 -1
  305. data/test/fixtures/deprecated_instance_variables/_params_method.rhtml +0 -1
  306. data/test/fixtures/deprecated_instance_variables/_request_ivar.rhtml +0 -1
  307. data/test/fixtures/deprecated_instance_variables/_request_method.rhtml +0 -1
  308. data/test/fixtures/deprecated_instance_variables/_response_ivar.rhtml +0 -1
  309. data/test/fixtures/deprecated_instance_variables/_response_method.rhtml +0 -1
  310. data/test/fixtures/deprecated_instance_variables/_session_ivar.rhtml +0 -1
  311. data/test/fixtures/deprecated_instance_variables/_session_method.rhtml +0 -1
  312. data/test/fixtures/respond_to/layouts/standard.rhtml +0 -1
  313. data/test/fixtures/test/_hash_object.rhtml +0 -1
  314. data/test/fixtures/test/list.rhtml +0 -1
  315. data/test/template/deprecated_helper_test.rb +0 -36
  316. data/test/template/deprecated_instance_variables_test.rb +0 -43
  317. data/test/template/java_script_macros_helper_test.rb +0 -109
@@ -0,0 +1,119 @@
1
+ module ActionController
2
+ module Routing
3
+ # Much of the slow performance from routes comes from the
4
+ # complexity of expiry, :requirements matching, defaults providing
5
+ # and figuring out which url pattern to use. With named routes
6
+ # we can avoid the expense of finding the right route. So if
7
+ # they've provided the right number of arguments, and have no
8
+ # :requirements, we can just build up a string and return it.
9
+ #
10
+ # To support building optimisations for other common cases, the
11
+ # generation code is separated into several classes
12
+ module Optimisation
13
+ def generate_optimisation_block(route, kind)
14
+ return "" unless route.optimise?
15
+ OPTIMISERS.inject("") do |memo, klazz|
16
+ memo << klazz.new(route, kind).source_code
17
+ memo
18
+ end
19
+ end
20
+
21
+ class Optimiser
22
+ attr_reader :route, :kind
23
+ def initialize(route, kind)
24
+ @route = route
25
+ @kind = kind
26
+ end
27
+
28
+ def guard_condition
29
+ 'false'
30
+ end
31
+
32
+ def generation_code
33
+ 'nil'
34
+ end
35
+
36
+ def source_code
37
+ if applicable?
38
+ "return #{generation_code} if #{guard_condition}\n"
39
+ else
40
+ "\n"
41
+ end
42
+ end
43
+
44
+ # Temporarily disabled :url optimisation pending proper solution to
45
+ # Issues around request.host etc.
46
+ def applicable?
47
+ true
48
+ end
49
+ end
50
+
51
+ # Given a route:
52
+ # map.person '/people/:id'
53
+ #
54
+ # If the user calls person_url(@person), we can simply
55
+ # return a string like "/people/#{@person.to_param}"
56
+ # rather than triggering the expensive logic in url_for
57
+ class PositionalArguments < Optimiser
58
+ def guard_condition
59
+ number_of_arguments = route.segment_keys.size
60
+ # if they're using foo_url(:id=>2) it's one
61
+ # argument, but we don't want to generate /foos/id2
62
+ if number_of_arguments == 1
63
+ "defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)"
64
+ else
65
+ "defined?(request) && request && args.size == #{number_of_arguments}"
66
+ end
67
+ end
68
+
69
+ def generation_code
70
+ elements = []
71
+ idx = 0
72
+
73
+ if kind == :url
74
+ elements << '#{request.protocol}'
75
+ elements << '#{request.host_with_port}'
76
+ end
77
+
78
+ elements << '#{request.relative_url_root if request.relative_url_root}'
79
+
80
+ # The last entry in route.segments appears to # *always* be a
81
+ # 'divider segment' for '/' but we have assertions to ensure that
82
+ # we don't include the trailing slashes, so skip them.
83
+ (route.segments.size == 1 ? route.segments : route.segments[0..-2]).each do |segment|
84
+ if segment.is_a?(DynamicSegment)
85
+ elements << segment.interpolation_chunk("args[#{idx}].to_param")
86
+ idx += 1
87
+ else
88
+ elements << segment.interpolation_chunk
89
+ end
90
+ end
91
+ %("#{elements * ''}")
92
+ end
93
+ end
94
+
95
+ # This case is mostly the same as the positional arguments case
96
+ # above, but it supports additional query parameters as the last
97
+ # argument
98
+ class PositionalArgumentsWithAdditionalParams < PositionalArguments
99
+ def guard_condition
100
+ "defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)"
101
+ end
102
+
103
+ # This case uses almost the same code as positional arguments,
104
+ # but add an args.last.to_query on the end
105
+ def generation_code
106
+ super.insert(-2, '?#{args.last.to_query}')
107
+ end
108
+
109
+ # To avoid generating http://localhost/?host=foo.example.com we
110
+ # can't use this optimisation on routes without any segments
111
+ def applicable?
112
+ super && route.segment_keys.size > 0
113
+ end
114
+ end
115
+
116
+ OPTIMISERS = [PositionalArguments, PositionalArgumentsWithAdditionalParams]
117
+ end
118
+ end
119
+ end
@@ -122,13 +122,14 @@ class CGI
122
122
  @data ||= self.class.unmarshal(read_attribute(@@data_column_name)) || {}
123
123
  end
124
124
 
125
+ attr_writer :data
126
+
125
127
  # Has the session been loaded yet?
126
128
  def loaded?
127
129
  !! @data
128
130
  end
129
131
 
130
132
  private
131
- attr_writer :data
132
133
 
133
134
  def marshal_data!
134
135
  return false if !loaded?
@@ -332,4 +333,4 @@ class CGI
332
333
  end
333
334
  end
334
335
  end
335
- end
336
+ end
@@ -0,0 +1,161 @@
1
+ require 'cgi'
2
+ require 'cgi/session'
3
+ require 'base64' # to convert Marshal.dump to ASCII
4
+ require 'openssl' # to generate the HMAC message digest
5
+
6
+ # This cookie-based session store is the Rails default. Sessions typically
7
+ # contain at most a user_id and flash message; both fit within the 4K cookie
8
+ # size limit. Cookie-based sessions are dramatically faster than the
9
+ # alternatives.
10
+ #
11
+ # If you have more than 4K of session data or don't want your data to be
12
+ # visible to the user, pick another session store.
13
+ #
14
+ # CookieOverflow is raised if you attempt to store more than 4K of data.
15
+ # TamperedWithCookie is raised if the data integrity check fails.
16
+ #
17
+ # A message digest is included with the cookie to ensure data integrity:
18
+ # a user cannot alter his user_id without knowing the secret key included in
19
+ # the hash. New apps are generated with a pregenerated secret in
20
+ # config/environment.rb. Set your own for old apps you're upgrading.
21
+ #
22
+ # Session options:
23
+ # :secret An application-wide key string or block returning a string
24
+ # called per generated digest. The block is called with the
25
+ # CGI::Session instance as an argument. It's important that the
26
+ # secret is not vulnerable to a dictionary attack. Therefore,
27
+ # you should choose a secret consisting of random numbers and
28
+ # letters and more than 30 characters.
29
+ #
30
+ # Example: :secret => '449fe2e7daee471bffae2fd8dc02313d'
31
+ # :secret => Proc.new { User.current_user.secret_key }
32
+ #
33
+ # :digest The message digest algorithm used to verify session integrity
34
+ # defaults to 'SHA1' but may be any digest provided by OpenSSL,
35
+ # such as 'MD5', 'RIPEMD160', 'SHA256', etc.
36
+ #
37
+ # Note that changing digest or secret invalidates all existing sessions!
38
+ class CGI::Session::CookieStore
39
+ # Cookies can typically store 4096 bytes.
40
+ MAX = 4096
41
+ SECRET_MIN_LENGTH = 30 # characters
42
+
43
+ # Raised when storing more than 4K of session data.
44
+ class CookieOverflow < StandardError; end
45
+
46
+ # Raised when the cookie fails its integrity check.
47
+ class TamperedWithCookie < StandardError; end
48
+
49
+ # Called from CGI::Session only.
50
+ def initialize(session, options = {})
51
+ # The session_key option is required.
52
+ if options['session_key'].blank?
53
+ raise ArgumentError, 'A session_key is required to write a cookie containing the session data. Use config.action_controller.session = { :session_key => "_myapp_session", :secret => "some secret phrase" } in config/environment.rb'
54
+ end
55
+
56
+ # The secret option is required.
57
+ ensure_secret_secure(options['secret'])
58
+
59
+ # Keep the session and its secret on hand so we can read and write cookies.
60
+ @session, @secret = session, options['secret']
61
+
62
+ # Message digest defaults to SHA1.
63
+ @digest = options['digest'] || 'SHA1'
64
+
65
+ # Default cookie options derived from session settings.
66
+ @cookie_options = {
67
+ 'name' => options['session_key'],
68
+ 'path' => options['session_path'],
69
+ 'domain' => options['session_domain'],
70
+ 'expires' => options['session_expires'],
71
+ 'secure' => options['session_secure']
72
+ }
73
+
74
+ # Set no_hidden and no_cookies since the session id is unused and we
75
+ # set our own data cookie.
76
+ options['no_hidden'] = true
77
+ options['no_cookies'] = true
78
+ end
79
+
80
+ # To prevent users from using something insecure like "Password" we make sure that the
81
+ # secret they've provided is at least 30 characters in length.
82
+ def ensure_secret_secure(secret)
83
+ # There's no way we can do this check if they've provided a proc for the
84
+ # secret.
85
+ return true if secret.is_a?(Proc)
86
+
87
+ if secret.blank?
88
+ raise ArgumentError, %Q{A secret is required to generate an integrity hash for cookie session data. Use config.action_controller.session = { :session_key => "_myapp_session", :secret => "some secret phrase of at least #{SECRET_MIN_LENGTH} characters" } in config/environment.rb}
89
+ end
90
+
91
+ if secret.length < SECRET_MIN_LENGTH
92
+ raise ArgumentError, %Q{Secret should be something secure, like "#{CGI::Session.generate_unique_id}". The value you provided, "#{secret}", is shorter than the minimum length of #{SECRET_MIN_LENGTH} characters}
93
+ end
94
+ end
95
+
96
+ # Restore session data from the cookie.
97
+ def restore
98
+ @original = read_cookie
99
+ @data = unmarshal(@original) || {}
100
+ end
101
+
102
+ # Wait until close to write the session data cookie.
103
+ def update; end
104
+
105
+ # Write the session data cookie if it was loaded and has changed.
106
+ def close
107
+ if defined?(@data) && !@data.blank?
108
+ updated = marshal(@data)
109
+ raise CookieOverflow if updated.size > MAX
110
+ write_cookie('value' => updated) unless updated == @original
111
+ end
112
+ end
113
+
114
+ # Delete the session data by setting an expired cookie with no data.
115
+ def delete
116
+ @data = nil
117
+ clear_old_cookie_value
118
+ write_cookie('value' => '', 'expires' => 1.year.ago)
119
+ end
120
+
121
+ # Generate the HMAC keyed message digest. Uses SHA1 by default.
122
+ def generate_digest(data)
123
+ key = @secret.respond_to?(:call) ? @secret.call(@session) : @secret
124
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(@digest), key, data)
125
+ end
126
+
127
+ private
128
+ # Marshal a session hash into safe cookie data. Include an integrity hash.
129
+ def marshal(session)
130
+ data = Base64.encode64(Marshal.dump(session)).chop
131
+ CGI.escape "#{data}--#{generate_digest(data)}"
132
+ end
133
+
134
+ # Unmarshal cookie data to a hash and verify its integrity.
135
+ def unmarshal(cookie)
136
+ if cookie
137
+ data, digest = CGI.unescape(cookie).split('--')
138
+ unless digest == generate_digest(data)
139
+ delete
140
+ raise TamperedWithCookie
141
+ end
142
+ Marshal.load(Base64.decode64(data))
143
+ end
144
+ end
145
+
146
+ # Read the session data cookie.
147
+ def read_cookie
148
+ @session.cgi.cookies[@cookie_options['name']].first
149
+ end
150
+
151
+ # CGI likes to make you hack.
152
+ def write_cookie(options)
153
+ cookie = CGI::Cookie.new(@cookie_options.merge(options))
154
+ @session.cgi.send :instance_variable_set, '@output_cookies', [cookie]
155
+ end
156
+
157
+ # Clear cookie value so subsequent new_session doesn't reload old data.
158
+ def clear_old_cookie_value
159
+ @session.cgi.cookies[@cookie_options['name']].clear
160
+ end
161
+ end
@@ -9,7 +9,7 @@
9
9
 
10
10
  begin
11
11
  require 'cgi/session'
12
- require 'memcache'
12
+ require_library_or_gem 'memcache'
13
13
 
14
14
  class CGI
15
15
  class Session
@@ -57,26 +57,22 @@ begin
57
57
  @expires = options['expires'] || 0
58
58
  @session_key = "session:#{id}"
59
59
  @session_data = {}
60
+ # Add this key to the store if haven't done so yet
61
+ unless @cache.get(@session_key)
62
+ @cache.add(@session_key, @session_data, @expires)
63
+ end
60
64
  end
61
65
 
62
66
  # Restore session state from the session's memcache entry.
63
67
  #
64
68
  # Returns the session state as a hash.
65
69
  def restore
66
- begin
67
- @session_data = @cache[@session_key] || {}
68
- rescue
69
- @session_data = {}
70
- end
70
+ @session_data = @cache[@session_key] || {}
71
71
  end
72
72
 
73
73
  # Save session state to the session's memcache entry.
74
74
  def update
75
- begin
76
- @cache.set(@session_key, @session_data, @expires)
77
- rescue
78
- # Ignore session update failures.
79
- end
75
+ @cache.set(@session_key, @session_data, @expires)
80
76
  end
81
77
 
82
78
  # Update and close the session's memcache entry.
@@ -86,17 +82,14 @@ begin
86
82
 
87
83
  # Delete the session's memcache entry.
88
84
  def delete
89
- begin
90
- @cache.delete(@session_key)
91
- rescue
92
- # Ignore session delete failures.
93
- end
85
+ @cache.delete(@session_key)
94
86
  @session_data = {}
95
87
  end
96
88
 
97
89
  def data
98
90
  @session_data
99
91
  end
92
+
100
93
  end
101
94
  end
102
95
  end
@@ -1,3 +1,4 @@
1
+ require 'action_controller/session/cookie_store'
1
2
  require 'action_controller/session/drb_store'
2
3
  require 'action_controller/session/mem_cache_store'
3
4
  if Object.const_defined?(:ActiveRecord)
@@ -7,16 +8,17 @@ end
7
8
  module ActionController #:nodoc:
8
9
  module SessionManagement #:nodoc:
9
10
  def self.included(base)
10
- base.extend(ClassMethods)
11
-
12
- base.send :alias_method_chain, :process, :session_management_support
13
- base.send :alias_method_chain, :process_cleanup, :session_management_support
11
+ base.class_eval do
12
+ extend ClassMethods
13
+ alias_method_chain :process, :session_management_support
14
+ alias_method_chain :process_cleanup, :session_management_support
15
+ end
14
16
  end
15
17
 
16
18
  module ClassMethods
17
- # Set the session store to be used for keeping the session data between requests. The default is using the
18
- # file system, but you can also specify one of the other included stores (:active_record_store, :drb_store,
19
- # :mem_cache_store, or :memory_store) or use your own class.
19
+ # Set the session store to be used for keeping the session data between requests. By default, sessions are stored
20
+ # in browser cookies (:cookie_store), but you can also specify one of the other included stores
21
+ # (:active_record_store, :p_store, drb_store, :mem_cache_store, or :memory_store) or your own custom class.
20
22
  def session_store=(store)
21
23
  ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS[:database_manager] =
22
24
  store.is_a?(Symbol) ? CGI::Session.const_get(store == :drb_store ? "DRbStore" : store.to_s.camelize) : store
@@ -61,10 +63,14 @@ module ActionController #:nodoc:
61
63
  # session :off, :only => :foo,
62
64
  # :if => Proc.new { |req| req.parameters[:ws] }
63
65
  #
66
+ # # the session will be disabled for non html/ajax requests
67
+ # session :off,
68
+ # :if => Proc.new { |req| !(req.format.html? || req.format.js?) }
69
+ #
64
70
  # All session options described for ActionController::Base.process_cgi
65
71
  # are valid arguments.
66
72
  def session(*args)
67
- options = Hash === args.last ? args.pop : {}
73
+ options = args.extract_options!
68
74
 
69
75
  options[:disabled] = true if !args.empty?
70
76
  options[:only] = [*options[:only]].map { |o| o.to_s } if options[:only]
@@ -76,6 +82,9 @@ module ActionController #:nodoc:
76
82
  write_inheritable_array("session_options", [options])
77
83
  end
78
84
 
85
+ # So we can declare session options in the Rails initializer.
86
+ alias_method :session=, :session
87
+
79
88
  def cached_session_options #:nodoc:
80
89
  @session_options ||= read_inheritable_attribute("session_options") || []
81
90
  end
@@ -29,6 +29,9 @@ module ActionController #:nodoc:
29
29
  # * <tt>:buffer_size</tt> - specifies size (in bytes) of the buffer used to stream the file.
30
30
  # Defaults to 4096.
31
31
  # * <tt>:status</tt> - specifies the status code to send with the response. Defaults to '200 OK'.
32
+ # * <tt>:url_based_filename</tt> - set to true if you want the browser guess the filename from
33
+ # the URL, which is necessary for i18n filenames on certain browsers
34
+ # (setting :filename overrides this option).
32
35
  #
33
36
  # The default Content-Type and Content-Disposition headers are
34
37
  # set to download arbitrary binary files in as many browsers as
@@ -42,7 +45,7 @@ module ActionController #:nodoc:
42
45
  # send_file '/path/to.jpeg', :type => 'image/jpeg', :disposition => 'inline'
43
46
  #
44
47
  # Show a 404 page in the browser:
45
- # send_file '/path/to/404.html, :type => 'text/html; charset=utf-8', :status => 404
48
+ # send_file '/path/to/404.html', :type => 'text/html; charset=utf-8', :status => 404
46
49
  #
47
50
  # Read about the other Content-* HTTP headers if you'd like to
48
51
  # provide the user with more information (such as Content-Description).
@@ -59,7 +62,7 @@ module ActionController #:nodoc:
59
62
  raise MissingFile, "Cannot read file #{path}" unless File.file?(path) and File.readable?(path)
60
63
 
61
64
  options[:length] ||= File.size(path)
62
- options[:filename] ||= File.basename(path)
65
+ options[:filename] ||= File.basename(path) unless options[:url_based_filename]
63
66
  send_file_headers! options
64
67
 
65
68
  @performed_render = false
@@ -121,7 +124,7 @@ module ActionController #:nodoc:
121
124
 
122
125
  headers.update(
123
126
  'Content-Length' => options[:length],
124
- 'Content-Type' => options[:type].strip, # fixes a problem with extra '\r' with some browsers
127
+ 'Content-Type' => options[:type].to_s.strip, # fixes a problem with extra '\r' with some browsers
125
128
  'Content-Disposition' => disposition,
126
129
  'Content-Transfer-Encoding' => 'binary'
127
130
  )