actionpack 2.2.3 → 2.3.2

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 (264) hide show
  1. data/CHANGELOG +433 -375
  2. data/MIT-LICENSE +1 -1
  3. data/README +21 -75
  4. data/Rakefile +1 -1
  5. data/lib/action_controller.rb +80 -43
  6. data/lib/action_controller/assertions/model_assertions.rb +1 -0
  7. data/lib/action_controller/assertions/response_assertions.rb +43 -16
  8. data/lib/action_controller/assertions/routing_assertions.rb +1 -1
  9. data/lib/action_controller/assertions/selector_assertions.rb +17 -12
  10. data/lib/action_controller/assertions/tag_assertions.rb +1 -4
  11. data/lib/action_controller/base.rb +153 -82
  12. data/lib/action_controller/benchmarking.rb +9 -9
  13. data/lib/action_controller/caching.rb +9 -11
  14. data/lib/action_controller/caching/actions.rb +11 -18
  15. data/lib/action_controller/caching/fragments.rb +28 -20
  16. data/lib/action_controller/caching/pages.rb +13 -15
  17. data/lib/action_controller/caching/sweeping.rb +2 -2
  18. data/lib/action_controller/cgi_ext.rb +0 -1
  19. data/lib/action_controller/cgi_ext/cookie.rb +2 -0
  20. data/lib/action_controller/cgi_process.rb +54 -162
  21. data/lib/action_controller/cookies.rb +13 -25
  22. data/lib/action_controller/dispatcher.rb +43 -122
  23. data/lib/action_controller/failsafe.rb +52 -0
  24. data/lib/action_controller/flash.rb +38 -47
  25. data/lib/action_controller/helpers.rb +13 -9
  26. data/lib/action_controller/http_authentication.rb +203 -23
  27. data/lib/action_controller/integration.rb +126 -70
  28. data/lib/action_controller/layout.rb +36 -39
  29. data/lib/action_controller/middleware_stack.rb +119 -0
  30. data/lib/action_controller/middlewares.rb +13 -0
  31. data/lib/action_controller/mime_responds.rb +19 -4
  32. data/lib/action_controller/mime_type.rb +8 -0
  33. data/lib/action_controller/params_parser.rb +71 -0
  34. data/lib/action_controller/performance_test.rb +0 -1
  35. data/lib/action_controller/polymorphic_routes.rb +36 -30
  36. data/lib/action_controller/reloader.rb +14 -0
  37. data/lib/action_controller/request.rb +107 -499
  38. data/lib/action_controller/request_forgery_protection.rb +7 -39
  39. data/lib/action_controller/rescue.rb +55 -35
  40. data/lib/action_controller/resources.rb +34 -31
  41. data/lib/action_controller/response.rb +99 -57
  42. data/lib/action_controller/rewindable_input.rb +28 -0
  43. data/lib/action_controller/routing.rb +7 -7
  44. data/lib/action_controller/routing/builder.rb +4 -1
  45. data/lib/action_controller/routing/optimisations.rb +1 -1
  46. data/lib/action_controller/routing/recognition_optimisation.rb +1 -2
  47. data/lib/action_controller/routing/route.rb +15 -5
  48. data/lib/action_controller/routing/route_set.rb +82 -35
  49. data/lib/action_controller/routing/segments.rb +35 -0
  50. data/lib/action_controller/session/abstract_store.rb +181 -0
  51. data/lib/action_controller/session/cookie_store.rb +197 -175
  52. data/lib/action_controller/session/mem_cache_store.rb +36 -83
  53. data/lib/action_controller/session_management.rb +26 -134
  54. data/lib/action_controller/streaming.rb +24 -7
  55. data/lib/action_controller/templates/rescues/diagnostics.erb +2 -2
  56. data/lib/action_controller/templates/rescues/template_error.erb +2 -2
  57. data/lib/action_controller/test_case.rb +87 -30
  58. data/lib/action_controller/test_process.rb +145 -104
  59. data/lib/action_controller/uploaded_file.rb +44 -0
  60. data/lib/action_controller/url_rewriter.rb +3 -6
  61. data/lib/action_controller/vendor/html-scanner.rb +16 -0
  62. data/lib/action_controller/vendor/html-scanner/html/selector.rb +1 -1
  63. data/lib/action_controller/vendor/rack-1.0/rack.rb +89 -0
  64. data/lib/action_controller/vendor/rack-1.0/rack/adapter/camping.rb +22 -0
  65. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/handler.rb +37 -0
  66. data/lib/action_controller/vendor/rack-1.0/rack/auth/abstract/request.rb +37 -0
  67. data/lib/action_controller/vendor/rack-1.0/rack/auth/basic.rb +58 -0
  68. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/md5.rb +124 -0
  69. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/nonce.rb +51 -0
  70. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/params.rb +55 -0
  71. data/lib/action_controller/vendor/rack-1.0/rack/auth/digest/request.rb +40 -0
  72. data/lib/action_controller/vendor/rack-1.0/rack/auth/openid.rb +480 -0
  73. data/lib/action_controller/vendor/rack-1.0/rack/builder.rb +63 -0
  74. data/lib/action_controller/vendor/rack-1.0/rack/cascade.rb +36 -0
  75. data/lib/action_controller/vendor/rack-1.0/rack/chunked.rb +49 -0
  76. data/lib/action_controller/vendor/rack-1.0/rack/commonlogger.rb +61 -0
  77. data/lib/action_controller/vendor/rack-1.0/rack/conditionalget.rb +45 -0
  78. data/lib/action_controller/vendor/rack-1.0/rack/content_length.rb +29 -0
  79. data/lib/action_controller/vendor/rack-1.0/rack/content_type.rb +23 -0
  80. data/lib/action_controller/vendor/rack-1.0/rack/deflater.rb +85 -0
  81. data/lib/action_controller/vendor/rack-1.0/rack/directory.rb +153 -0
  82. data/lib/action_controller/vendor/rack-1.0/rack/file.rb +88 -0
  83. data/lib/action_controller/vendor/rack-1.0/rack/handler.rb +48 -0
  84. data/lib/action_controller/vendor/rack-1.0/rack/handler/cgi.rb +61 -0
  85. data/lib/action_controller/vendor/rack-1.0/rack/handler/evented_mongrel.rb +8 -0
  86. data/lib/action_controller/vendor/rack-1.0/rack/handler/fastcgi.rb +89 -0
  87. data/lib/action_controller/vendor/rack-1.0/rack/handler/lsws.rb +55 -0
  88. data/lib/action_controller/vendor/rack-1.0/rack/handler/mongrel.rb +84 -0
  89. data/lib/action_controller/vendor/rack-1.0/rack/handler/scgi.rb +59 -0
  90. data/lib/action_controller/vendor/rack-1.0/rack/handler/swiftiplied_mongrel.rb +8 -0
  91. data/lib/action_controller/vendor/rack-1.0/rack/handler/thin.rb +18 -0
  92. data/lib/action_controller/vendor/rack-1.0/rack/handler/webrick.rb +67 -0
  93. data/lib/action_controller/vendor/rack-1.0/rack/head.rb +19 -0
  94. data/lib/action_controller/vendor/rack-1.0/rack/lint.rb +462 -0
  95. data/lib/action_controller/vendor/rack-1.0/rack/lobster.rb +65 -0
  96. data/lib/action_controller/vendor/rack-1.0/rack/lock.rb +16 -0
  97. data/lib/action_controller/vendor/rack-1.0/rack/methodoverride.rb +27 -0
  98. data/lib/action_controller/vendor/rack-1.0/rack/mime.rb +204 -0
  99. data/lib/action_controller/vendor/rack-1.0/rack/mock.rb +160 -0
  100. data/lib/action_controller/vendor/rack-1.0/rack/recursive.rb +57 -0
  101. data/lib/action_controller/vendor/rack-1.0/rack/reloader.rb +64 -0
  102. data/lib/action_controller/vendor/rack-1.0/rack/request.rb +241 -0
  103. data/lib/action_controller/vendor/rack-1.0/rack/response.rb +179 -0
  104. data/lib/action_controller/vendor/rack-1.0/rack/session/abstract/id.rb +142 -0
  105. data/lib/action_controller/vendor/rack-1.0/rack/session/cookie.rb +91 -0
  106. data/lib/action_controller/vendor/rack-1.0/rack/session/memcache.rb +109 -0
  107. data/lib/action_controller/vendor/rack-1.0/rack/session/pool.rb +100 -0
  108. data/lib/action_controller/vendor/rack-1.0/rack/showexceptions.rb +349 -0
  109. data/lib/action_controller/vendor/rack-1.0/rack/showstatus.rb +106 -0
  110. data/lib/action_controller/vendor/rack-1.0/rack/static.rb +38 -0
  111. data/lib/action_controller/vendor/rack-1.0/rack/urlmap.rb +55 -0
  112. data/lib/action_controller/vendor/rack-1.0/rack/utils.rb +392 -0
  113. data/lib/action_controller/verification.rb +1 -1
  114. data/lib/action_pack.rb +1 -1
  115. data/lib/action_pack/version.rb +2 -2
  116. data/lib/action_view.rb +22 -17
  117. data/lib/action_view/base.rb +53 -79
  118. data/lib/action_view/erb/util.rb +38 -0
  119. data/lib/action_view/helpers.rb +24 -5
  120. data/lib/action_view/helpers/active_record_helper.rb +2 -2
  121. data/lib/action_view/helpers/asset_tag_helper.rb +81 -50
  122. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  123. data/lib/action_view/helpers/benchmark_helper.rb +26 -5
  124. data/lib/action_view/helpers/date_helper.rb +82 -7
  125. data/lib/action_view/helpers/form_helper.rb +295 -64
  126. data/lib/action_view/helpers/form_options_helper.rb +160 -18
  127. data/lib/action_view/helpers/form_tag_helper.rb +2 -2
  128. data/lib/action_view/helpers/number_helper.rb +31 -18
  129. data/lib/action_view/helpers/prototype_helper.rb +2 -12
  130. data/lib/action_view/helpers/sanitize_helper.rb +0 -10
  131. data/lib/action_view/helpers/scriptaculous_helper.rb +1 -0
  132. data/lib/action_view/helpers/tag_helper.rb +3 -4
  133. data/lib/action_view/helpers/text_helper.rb +99 -122
  134. data/lib/action_view/helpers/translation_helper.rb +19 -1
  135. data/lib/action_view/helpers/url_helper.rb +25 -2
  136. data/lib/action_view/inline_template.rb +1 -1
  137. data/lib/action_view/locale/en.yml +19 -1
  138. data/lib/action_view/partials.rb +46 -9
  139. data/lib/action_view/paths.rb +28 -84
  140. data/lib/action_view/reloadable_template.rb +117 -0
  141. data/lib/action_view/renderable.rb +28 -35
  142. data/lib/action_view/renderable_partial.rb +3 -4
  143. data/lib/action_view/template.rb +172 -31
  144. data/lib/action_view/template_error.rb +8 -9
  145. data/lib/action_view/template_handler.rb +1 -1
  146. data/lib/action_view/template_handlers.rb +9 -6
  147. data/lib/action_view/template_handlers/erb.rb +2 -39
  148. data/lib/action_view/template_handlers/rjs.rb +1 -0
  149. data/lib/action_view/test_case.rb +27 -1
  150. data/test/abstract_unit.rb +23 -17
  151. data/test/active_record_unit.rb +5 -4
  152. data/test/activerecord/active_record_store_test.rb +139 -106
  153. data/test/activerecord/render_partial_with_record_identification_test.rb +5 -21
  154. data/test/controller/action_pack_assertions_test.rb +25 -23
  155. data/test/controller/addresses_render_test.rb +3 -6
  156. data/test/controller/assert_select_test.rb +83 -70
  157. data/test/controller/base_test.rb +11 -13
  158. data/test/controller/benchmark_test.rb +3 -3
  159. data/test/controller/caching_test.rb +34 -24
  160. data/test/controller/capture_test.rb +3 -6
  161. data/test/controller/content_type_test.rb +3 -6
  162. data/test/controller/cookie_test.rb +31 -66
  163. data/test/controller/deprecation/deprecated_base_methods_test.rb +9 -11
  164. data/test/controller/dispatcher_test.rb +23 -28
  165. data/test/controller/fake_models.rb +8 -0
  166. data/test/controller/filters_test.rb +6 -2
  167. data/test/controller/flash_test.rb +2 -6
  168. data/test/controller/helper_test.rb +15 -1
  169. data/test/controller/html-scanner/document_test.rb +1 -1
  170. data/test/controller/html-scanner/sanitizer_test.rb +1 -1
  171. data/test/controller/http_basic_authentication_test.rb +88 -0
  172. data/test/controller/http_digest_authentication_test.rb +178 -0
  173. data/test/controller/integration_test.rb +56 -52
  174. data/test/controller/layout_test.rb +46 -44
  175. data/test/controller/middleware_stack_test.rb +90 -0
  176. data/test/controller/mime_responds_test.rb +7 -11
  177. data/test/controller/mime_type_test.rb +9 -0
  178. data/test/controller/polymorphic_routes_test.rb +235 -151
  179. data/test/controller/rack_test.rb +52 -81
  180. data/test/controller/redirect_test.rb +6 -14
  181. data/test/controller/render_test.rb +273 -60
  182. data/test/controller/request/json_params_parsing_test.rb +45 -0
  183. data/test/controller/request/multipart_params_parsing_test.rb +223 -0
  184. data/test/controller/request/query_string_parsing_test.rb +120 -0
  185. data/test/controller/request/url_encoded_params_parsing_test.rb +184 -0
  186. data/test/controller/request/xml_params_parsing_test.rb +88 -0
  187. data/test/controller/request_forgery_protection_test.rb +17 -98
  188. data/test/controller/request_test.rb +45 -530
  189. data/test/controller/rescue_test.rb +45 -22
  190. data/test/controller/resources_test.rb +112 -37
  191. data/test/controller/routing_test.rb +1442 -1384
  192. data/test/controller/selector_test.rb +3 -3
  193. data/test/controller/send_file_test.rb +30 -3
  194. data/test/controller/session/cookie_store_test.rb +169 -240
  195. data/test/controller/session/mem_cache_store_test.rb +94 -148
  196. data/test/controller/session/test_session_test.rb +58 -0
  197. data/test/controller/test_test.rb +32 -13
  198. data/test/controller/url_rewriter_test.rb +54 -4
  199. data/test/controller/verification_test.rb +1 -1
  200. data/test/controller/view_paths_test.rb +15 -15
  201. data/test/controller/webservice_test.rb +178 -147
  202. data/test/fixtures/alternate_helpers/foo_helper.rb +3 -0
  203. data/test/fixtures/layout_tests/alt/layouts/alt.rhtml +0 -0
  204. data/test/fixtures/layouts/default_html.html.erb +1 -0
  205. data/test/fixtures/layouts/xhr.html.erb +2 -0
  206. data/test/fixtures/multipart/empty +10 -0
  207. data/test/fixtures/multipart/hello.txt +1 -0
  208. data/test/fixtures/multipart/none +9 -0
  209. data/test/fixtures/public/500.da.html +1 -0
  210. data/test/fixtures/quiz/questions/_question.html.erb +1 -0
  211. data/test/fixtures/replies.yml +1 -1
  212. data/test/fixtures/test/_one.html.erb +1 -0
  213. data/test/fixtures/test/_two.html.erb +1 -0
  214. data/test/fixtures/test/dont_pick_me +1 -0
  215. data/test/fixtures/test/hello.builder +1 -1
  216. data/test/fixtures/test/hello_world.da.html.erb +1 -0
  217. data/test/fixtures/test/hello_world.erb~ +1 -0
  218. data/test/fixtures/test/hello_world.pt-BR.html.erb +1 -0
  219. data/test/fixtures/test/malformed/malformed.en.html.erb~ +1 -0
  220. data/test/fixtures/test/malformed/malformed.erb~ +1 -0
  221. data/test/fixtures/test/malformed/malformed.html.erb~ +1 -0
  222. data/test/fixtures/test/render_explicit_html_template.js.rjs +1 -0
  223. data/test/fixtures/test/render_implicit_html_template.js.rjs +1 -0
  224. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.da.html.erb +1 -0
  225. data/test/fixtures/test/render_implicit_html_template_from_xhr_request.html.erb +1 -0
  226. data/test/fixtures/test/render_implicit_js_template_without_layout.js.erb +1 -0
  227. data/test/fixtures/test/utf8.html.erb +2 -0
  228. data/test/template/active_record_helper_i18n_test.rb +31 -33
  229. data/test/template/active_record_helper_test.rb +34 -0
  230. data/test/template/asset_tag_helper_test.rb +52 -14
  231. data/test/template/atom_feed_helper_test.rb +3 -5
  232. data/test/template/benchmark_helper_test.rb +50 -24
  233. data/test/template/compiled_templates_test.rb +177 -33
  234. data/test/template/date_helper_i18n_test.rb +88 -81
  235. data/test/template/date_helper_test.rb +427 -43
  236. data/test/template/form_helper_test.rb +243 -44
  237. data/test/template/form_options_helper_test.rb +631 -565
  238. data/test/template/form_tag_helper_test.rb +9 -2
  239. data/test/template/javascript_helper_test.rb +0 -5
  240. data/test/template/number_helper_i18n_test.rb +60 -48
  241. data/test/template/number_helper_test.rb +1 -0
  242. data/test/template/render_test.rb +117 -35
  243. data/test/template/test_test.rb +4 -6
  244. data/test/template/text_helper_test.rb +129 -50
  245. data/test/template/translation_helper_test.rb +23 -19
  246. data/test/template/url_helper_test.rb +35 -2
  247. data/test/view/test_case_test.rb +8 -0
  248. metadata +197 -23
  249. data/lib/action_controller/assertions.rb +0 -69
  250. data/lib/action_controller/caching/sql_cache.rb +0 -18
  251. data/lib/action_controller/cgi_ext/session.rb +0 -53
  252. data/lib/action_controller/components.rb +0 -169
  253. data/lib/action_controller/rack_process.rb +0 -297
  254. data/lib/action_controller/request_profiler.rb +0 -169
  255. data/lib/action_controller/session/active_record_store.rb +0 -340
  256. data/lib/action_controller/session/drb_server.rb +0 -32
  257. data/lib/action_controller/session/drb_store.rb +0 -35
  258. data/test/controller/cgi_test.rb +0 -269
  259. data/test/controller/components_test.rb +0 -156
  260. data/test/controller/http_authentication_test.rb +0 -54
  261. data/test/controller/integration_upload_test.rb +0 -43
  262. data/test/controller/session_fixation_test.rb +0 -89
  263. data/test/controller/session_management_test.rb +0 -178
  264. data/test/fixtures/test/hello_world.js +0 -1
@@ -23,8 +23,8 @@ module ActionController #:nodoc:
23
23
  def benchmark(title, log_level = Logger::DEBUG, use_silence = true)
24
24
  if logger && logger.level == log_level
25
25
  result = nil
26
- seconds = Benchmark.realtime { result = use_silence ? silence { yield } : yield }
27
- logger.add(log_level, "#{title} (#{('%.1f' % (seconds * 1000))}ms)")
26
+ ms = Benchmark.ms { result = use_silence ? silence { yield } : yield }
27
+ logger.add(log_level, "#{title} (#{('%.1f' % ms)}ms)")
28
28
  result
29
29
  else
30
30
  yield
@@ -48,7 +48,7 @@ module ActionController #:nodoc:
48
48
  end
49
49
 
50
50
  render_output = nil
51
- @view_runtime = Benchmark::realtime { render_output = render_without_benchmark(options, extra_options, &block) }
51
+ @view_runtime = Benchmark.ms { render_output = render_without_benchmark(options, extra_options, &block) }
52
52
 
53
53
  if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
54
54
  @db_rt_before_render = db_runtime
@@ -65,11 +65,11 @@ module ActionController #:nodoc:
65
65
  private
66
66
  def perform_action_with_benchmark
67
67
  if logger
68
- seconds = [ Benchmark::measure{ perform_action_without_benchmark }.real, 0.0001 ].max
68
+ ms = [Benchmark.ms { perform_action_without_benchmark }, 0.01].max
69
69
  logging_view = defined?(@view_runtime)
70
70
  logging_active_record = Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
71
71
 
72
- log_message = "Completed in #{sprintf("%.0f", seconds * 1000)}ms"
72
+ log_message = 'Completed in %.0fms' % ms
73
73
 
74
74
  if logging_view || logging_active_record
75
75
  log_message << " ("
@@ -83,25 +83,25 @@ module ActionController #:nodoc:
83
83
  end
84
84
  end
85
85
 
86
- log_message << " | #{headers["Status"]}"
86
+ log_message << " | #{response.status}"
87
87
  log_message << " [#{complete_request_uri rescue "unknown"}]"
88
88
 
89
89
  logger.info(log_message)
90
- response.headers["X-Runtime"] = "#{sprintf("%.0f", seconds * 1000)}ms"
90
+ response.headers["X-Runtime"] = "%.0f" % ms
91
91
  else
92
92
  perform_action_without_benchmark
93
93
  end
94
94
  end
95
95
 
96
96
  def view_runtime
97
- "View: %.0f" % (@view_runtime * 1000)
97
+ "View: %.0f" % @view_runtime
98
98
  end
99
99
 
100
100
  def active_record_runtime
101
101
  db_runtime = ActiveRecord::Base.connection.reset_runtime
102
102
  db_runtime += @db_rt_before_render if @db_rt_before_render
103
103
  db_runtime += @db_rt_after_render if @db_rt_after_render
104
- "DB: %.0f" % (db_runtime * 1000)
104
+ "DB: %.0f" % db_runtime
105
105
  end
106
106
  end
107
107
  end
@@ -2,13 +2,6 @@ require 'fileutils'
2
2
  require 'uri'
3
3
  require 'set'
4
4
 
5
- require 'action_controller/caching/pages'
6
- require 'action_controller/caching/actions'
7
- require 'action_controller/caching/sql_cache'
8
- require 'action_controller/caching/sweeping'
9
- require 'action_controller/caching/fragments'
10
-
11
-
12
5
  module ActionController #:nodoc:
13
6
  # Caching is a cheap way of speeding up slow applications by keeping the result of calculations, renderings, and database calls
14
7
  # around for subsequent requests. Action Controller affords you three approaches in varying levels of granularity: Page, Action, Fragment.
@@ -31,6 +24,12 @@ module ActionController #:nodoc:
31
24
  # ActionController::Base.cache_store = :mem_cache_store, "localhost"
32
25
  # ActionController::Base.cache_store = MyOwnStore.new("parameter")
33
26
  module Caching
27
+ autoload :Actions, 'action_controller/caching/actions'
28
+ autoload :Fragments, 'action_controller/caching/fragments'
29
+ autoload :Pages, 'action_controller/caching/pages'
30
+ autoload :Sweeper, 'action_controller/caching/sweeping'
31
+ autoload :Sweeping, 'action_controller/caching/sweeping'
32
+
34
33
  def self.included(base) #:nodoc:
35
34
  base.class_eval do
36
35
  @@cache_store = nil
@@ -42,7 +41,7 @@ module ActionController #:nodoc:
42
41
  end
43
42
 
44
43
  include Pages, Actions, Fragments
45
- include Sweeping, SqlCache if defined?(ActiveRecord)
44
+ include Sweeping if defined?(ActiveRecord)
46
45
 
47
46
  @@perform_caching = true
48
47
  cattr_accessor :perform_caching
@@ -63,10 +62,9 @@ module ActionController #:nodoc:
63
62
  end
64
63
  end
65
64
 
66
-
67
- private
65
+ private
68
66
  def cache_configured?
69
67
  self.class.cache_configured?
70
68
  end
71
69
  end
72
- end
70
+ end
@@ -113,7 +113,7 @@ module ActionController #:nodoc:
113
113
  end
114
114
 
115
115
  def caching_allowed(controller)
116
- controller.request.get? && controller.response.headers['Status'].to_i == 200
116
+ controller.request.get? && controller.response.status.to_i == 200
117
117
  end
118
118
 
119
119
  def cache_layout?
@@ -129,24 +129,23 @@ module ActionController #:nodoc:
129
129
  attr_reader :path, :extension
130
130
 
131
131
  class << self
132
- def path_for(controller, options, infer_extension=true)
132
+ def path_for(controller, options, infer_extension = true)
133
133
  new(controller, options, infer_extension).path
134
134
  end
135
135
  end
136
136
 
137
137
  # When true, infer_extension will look up the cache path extension from the request's path & format.
138
- # This is desirable when reading and writing the cache, but not when expiring the cache - expire_action should expire the same files regardless of the request format.
139
- def initialize(controller, options = {}, infer_extension=true)
140
- if infer_extension and options.is_a? Hash
141
- request_extension = extract_extension(controller.request)
142
- options = options.reverse_merge(:format => request_extension)
138
+ # This is desirable when reading and writing the cache, but not when expiring the cache -
139
+ # expire_action should expire the same files regardless of the request format.
140
+ def initialize(controller, options = {}, infer_extension = true)
141
+ if infer_extension
142
+ extract_extension(controller.request)
143
+ options = options.reverse_merge(:format => @extension) if options.is_a?(Hash)
143
144
  end
145
+
144
146
  path = controller.url_for(options).split('://').last
145
147
  normalize!(path)
146
- if infer_extension
147
- @extension = request_extension
148
- add_extension!(path, @extension)
149
- end
148
+ add_extension!(path, @extension)
150
149
  @path = URI.unescape(path)
151
150
  end
152
151
 
@@ -162,13 +161,7 @@ module ActionController #:nodoc:
162
161
  def extract_extension(request)
163
162
  # Don't want just what comes after the last '.' to accommodate multi part extensions
164
163
  # such as tar.gz.
165
- extension = request.path[/^[^.]+\.(.+)$/, 1]
166
-
167
- # If there's no extension in the path, check request.format
168
- if extension.nil?
169
- extension = request.cache_format
170
- end
171
- extension
164
+ @extension = request.path[/^[^.]+\.(.+)$/, 1] || request.cache_format
172
165
  end
173
166
  end
174
167
  end
@@ -10,23 +10,23 @@ module ActionController #:nodoc:
10
10
  # <%= render :partial => "topic", :collection => Topic.find(:all) %>
11
11
  # <% end %>
12
12
  #
13
- # This cache will bind to the name of the action that called it, so if this code was part of the view for the topics/list action, you would
14
- # be able to invalidate it using <tt>expire_fragment(:controller => "topics", :action => "list")</tt>.
15
- #
16
- # This default behavior is of limited use if you need to cache multiple fragments per action or if the action itself is cached using
13
+ # This cache will bind to the name of the action that called it, so if this code was part of the view for the topics/list action, you would
14
+ # be able to invalidate it using <tt>expire_fragment(:controller => "topics", :action => "list")</tt>.
15
+ #
16
+ # This default behavior is of limited use if you need to cache multiple fragments per action or if the action itself is cached using
17
17
  # <tt>caches_action</tt>, so we also have the option to qualify the name of the cached fragment with something like:
18
18
  #
19
19
  # <% cache(:action => "list", :action_suffix => "all_topics") do %>
20
20
  #
21
- # That would result in a name such as "/topics/list/all_topics", avoiding conflicts with the action cache and with any fragments that use a
22
- # different suffix. Note that the URL doesn't have to really exist or be callable - the url_for system is just used to generate unique
23
- # cache names that we can refer to when we need to expire the cache.
24
- #
21
+ # That would result in a name such as "/topics/list/all_topics", avoiding conflicts with the action cache and with any fragments that use a
22
+ # different suffix. Note that the URL doesn't have to really exist or be callable - the url_for system is just used to generate unique
23
+ # cache names that we can refer to when we need to expire the cache.
24
+ #
25
25
  # The expiration call for this example is:
26
- #
26
+ #
27
27
  # expire_fragment(:controller => "topics", :action => "list", :action_suffix => "all_topics")
28
28
  module Fragments
29
- # Given a key (as described in <tt>expire_fragment</tt>), returns a key suitable for use in reading,
29
+ # Given a key (as described in <tt>expire_fragment</tt>), returns a key suitable for use in reading,
30
30
  # writing, or expiring a cached fragment. If the key is a hash, the generated key is the return
31
31
  # value of url_for on that hash (without the protocol). All keys are prefixed with "views/" and uses
32
32
  # ActiveSupport::Cache.expand_cache_key for the expansion.
@@ -50,7 +50,7 @@ module ActionController #:nodoc:
50
50
 
51
51
  # Writes <tt>content</tt> to the location signified by <tt>key</tt> (see <tt>expire_fragment</tt> for acceptable formats)
52
52
  def write_fragment(key, content, options = nil)
53
- return unless cache_configured?
53
+ return content unless cache_configured?
54
54
 
55
55
  key = fragment_cache_key(key)
56
56
 
@@ -83,15 +83,23 @@ module ActionController #:nodoc:
83
83
  end
84
84
  end
85
85
 
86
- # Name can take one of three forms:
87
- # * String: This would normally take the form of a path like "pages/45/notes"
88
- # * Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 }
89
- # * Regexp: Will destroy all the matched fragments, example:
90
- # %r{pages/\d*/notes}
91
- # Ensure you do not specify start and finish in the regex (^$) because
92
- # the actual filename matched looks like ./cache/filename/path.cache
93
- # Regexp expiration is only supported on caches that can iterate over
94
- # all keys (unlike memcached).
86
+ # Removes fragments from the cache.
87
+ #
88
+ # +key+ can take one of three forms:
89
+ # * String - This would normally take the form of a path, like
90
+ # <tt>"pages/45/notes"</tt>.
91
+ # * Hash - Treated as an implicit call to +url_for+, like
92
+ # <tt>{:controller => "pages", :action => "notes", :id => 45}</tt>
93
+ # * Regexp - Will remove any fragment that matches, so
94
+ # <tt>%r{pages/\d*/notes}</tt> might remove all notes. Make sure you
95
+ # don't use anchors in the regex (<tt>^</tt> or <tt>$</tt>) because
96
+ # the actual filename matched looks like
97
+ # <tt>./cache/filename/path.cache</tt>. Note: Regexp expiration is
98
+ # only supported on caches that can iterate over all keys (unlike
99
+ # memcached).
100
+ #
101
+ # +options+ is passed through to the cache store's <tt>delete</tt>
102
+ # method (or <tt>delete_matched</tt>, for Regexp keys.)
95
103
  def expire_fragment(key, options = nil)
96
104
  return unless cache_configured?
97
105
 
@@ -33,28 +33,26 @@ module ActionController #:nodoc:
33
33
  #
34
34
  # Additionally, you can expire caches using Sweepers that act on changes in the model to determine when a cache is supposed to be
35
35
  # expired.
36
- #
37
- # == Setting the cache directory
38
- #
39
- # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>.
40
- # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing
41
- # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
42
- # web server to look in the new location for cached files.
43
- #
44
- # == Setting the cache extension
45
- #
46
- # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in
47
- # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
48
- # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
49
- # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
50
36
  module Pages
51
37
  def self.included(base) #:nodoc:
52
38
  base.extend(ClassMethods)
53
39
  base.class_eval do
54
40
  @@page_cache_directory = defined?(Rails.public_path) ? Rails.public_path : ""
41
+ ##
42
+ # :singleton-method:
43
+ # The cache directory should be the document root for the web server and is set using <tt>Base.page_cache_directory = "/document/root"</tt>.
44
+ # For Rails, this directory has already been set to Rails.public_path (which is usually set to <tt>RAILS_ROOT + "/public"</tt>). Changing
45
+ # this setting can be useful to avoid naming conflicts with files in <tt>public/</tt>, but doing so will likely require configuring your
46
+ # web server to look in the new location for cached files.
55
47
  cattr_accessor :page_cache_directory
56
48
 
57
49
  @@page_cache_extension = '.html'
50
+ ##
51
+ # :singleton-method:
52
+ # Most Rails requests do not have an extension, such as <tt>/weblog/new</tt>. In these cases, the page caching mechanism will add one in
53
+ # order to make it easy for the cached files to be picked up properly by the web server. By default, this cache extension is <tt>.html</tt>.
54
+ # If you want something else, like <tt>.php</tt> or <tt>.shtml</tt>, just set Base.page_cache_extension. In cases where a request already has an
55
+ # extension, such as <tt>.xml</tt> or <tt>.rss</tt>, page caching will not add an extension. This allows it to work well with RESTful apps.
58
56
  cattr_accessor :page_cache_extension
59
57
  end
60
58
  end
@@ -147,7 +145,7 @@ module ActionController #:nodoc:
147
145
 
148
146
  private
149
147
  def caching_allowed
150
- request.get? && response.headers['Status'].to_i == 200
148
+ request.get? && response.status.to_i == 200
151
149
  end
152
150
  end
153
151
  end
@@ -87,9 +87,9 @@ module ActionController #:nodoc:
87
87
  __send__(action_callback_method_name) if respond_to?(action_callback_method_name, true)
88
88
  end
89
89
 
90
- def method_missing(method, *arguments)
90
+ def method_missing(method, *arguments, &block)
91
91
  return if @controller.nil?
92
- @controller.__send__(method, *arguments)
92
+ @controller.__send__(method, *arguments, &block)
93
93
  end
94
94
  end
95
95
  end
@@ -1,7 +1,6 @@
1
1
  require 'action_controller/cgi_ext/stdinput'
2
2
  require 'action_controller/cgi_ext/query_extension'
3
3
  require 'action_controller/cgi_ext/cookie'
4
- require 'action_controller/cgi_ext/session'
5
4
 
6
5
  class CGI #:nodoc:
7
6
  include ActionController::CgiExt::Stdinput
@@ -1,3 +1,5 @@
1
+ require 'delegate'
2
+
1
3
  CGI.module_eval { remove_const "Cookie" }
2
4
 
3
5
  # TODO: document how this differs from stdlib CGI::Cookie
@@ -1,185 +1,77 @@
1
1
  require 'action_controller/cgi_ext'
2
- require 'action_controller/session/cookie_store'
3
2
 
4
3
  module ActionController #:nodoc:
5
- class Base
6
- # Process a request extracted from a CGI object and return a response. Pass false as <tt>session_options</tt> to disable
7
- # sessions (large performance increase if sessions are not needed). The <tt>session_options</tt> are the same as for CGI::Session:
8
- #
9
- # * <tt>:database_manager</tt> - standard options are CGI::Session::FileStore, CGI::Session::MemoryStore, and CGI::Session::PStore
10
- # (default). Additionally, there is CGI::Session::DRbStore and CGI::Session::ActiveRecordStore. Read more about these in
11
- # lib/action_controller/session.
12
- # * <tt>:session_key</tt> - the parameter name used for the session id. Defaults to '_session_id'.
13
- # * <tt>:session_id</tt> - the session id to use. If not provided, then it is retrieved from the +session_key+ cookie, or
14
- # automatically generated for a new session.
15
- # * <tt>:new_session</tt> - if true, force creation of a new session. If not set, a new session is only created if none currently
16
- # exists. If false, a new session is never created, and if none currently exists and the +session_id+ option is not set,
17
- # an ArgumentError is raised.
18
- # * <tt>:session_expires</tt> - the time the current session expires, as a Time object. If not set, the session will continue
19
- # indefinitely.
20
- # * <tt>:session_domain</tt> - the hostname domain for which this session is valid. If not set, defaults to the hostname of the
21
- # server.
22
- # * <tt>:session_secure</tt> - if +true+, this session will only work over HTTPS.
23
- # * <tt>:session_path</tt> - the path for which this session applies. Defaults to the directory of the CGI script.
24
- # * <tt>:cookie_only</tt> - if +true+ (the default), session IDs will only be accepted from cookies and not from
25
- # the query string or POST parameters. This protects against session fixation attacks.
26
- def self.process_cgi(cgi = CGI.new, session_options = {})
27
- new.process_cgi(cgi, session_options)
28
- end
29
-
30
- def process_cgi(cgi, session_options = {}) #:nodoc:
31
- process(CgiRequest.new(cgi, session_options), CgiResponse.new(cgi)).out
32
- end
33
- end
34
-
35
- class CgiRequest < AbstractRequest #:nodoc:
36
- attr_accessor :cgi, :session_options
37
- class SessionFixationAttempt < StandardError #:nodoc:
38
- end
39
-
40
- DEFAULT_SESSION_OPTIONS = {
41
- :database_manager => CGI::Session::CookieStore, # store data in cookie
42
- :prefix => "ruby_sess.", # prefix session file names
43
- :session_path => "/", # available to all paths in app
44
- :session_key => "_session_id",
45
- :cookie_only => true,
46
- :session_http_only=> true
47
- }
48
-
49
- def initialize(cgi, session_options = {})
50
- @cgi = cgi
51
- @session_options = session_options
52
- @env = @cgi.__send__(:env_table)
53
- super()
54
- end
55
-
56
- def query_string
57
- qs = @cgi.query_string if @cgi.respond_to?(:query_string)
58
- if !qs.blank?
59
- qs
60
- else
61
- super
62
- end
63
- end
64
-
65
- def body_stream #:nodoc:
66
- @cgi.stdinput
67
- end
68
-
69
- def cookies
70
- @cgi.cookies.freeze
71
- end
72
-
73
- def session
74
- unless defined?(@session)
75
- if @session_options == false
76
- @session = Hash.new
77
- else
78
- stale_session_check! do
79
- if cookie_only? && query_parameters[session_options_with_string_keys['session_key']]
80
- raise SessionFixationAttempt
81
- end
82
- case value = session_options_with_string_keys['new_session']
83
- when true
84
- @session = new_session
85
- when false
86
- begin
87
- @session = CGI::Session.new(@cgi, session_options_with_string_keys)
88
- # CGI::Session raises ArgumentError if 'new_session' == false
89
- # and no session cookie or query param is present.
90
- rescue ArgumentError
91
- @session = Hash.new
92
- end
93
- when nil
94
- @session = CGI::Session.new(@cgi, session_options_with_string_keys)
95
- else
96
- raise ArgumentError, "Invalid new_session option: #{value}"
97
- end
98
- @session['__valid_session']
99
- end
4
+ class CGIHandler
5
+ module ProperStream
6
+ def each
7
+ while line = gets
8
+ yield line
100
9
  end
101
10
  end
102
- @session
103
- end
104
11
 
105
- def reset_session
106
- @session.delete if defined?(@session) && @session.is_a?(CGI::Session)
107
- @session = new_session
108
- end
109
-
110
- def method_missing(method_id, *arguments)
111
- @cgi.__send__(method_id, *arguments) rescue super
112
- end
113
-
114
- private
115
- # Delete an old session if it exists then create a new one.
116
- def new_session
117
- if @session_options == false
118
- Hash.new
12
+ def read(*args)
13
+ if args.empty?
14
+ super || ""
119
15
  else
120
- CGI::Session.new(@cgi, session_options_with_string_keys.merge("new_session" => false)).delete rescue nil
121
- CGI::Session.new(@cgi, session_options_with_string_keys.merge("new_session" => true))
16
+ super
122
17
  end
123
18
  end
19
+ end
124
20
 
125
- def cookie_only?
126
- session_options_with_string_keys['cookie_only']
127
- end
128
-
129
- def stale_session_check!
130
- yield
131
- rescue ArgumentError => argument_error
132
- if argument_error.message =~ %r{undefined class/module ([\w:]*\w)}
133
- begin
134
- # Note that the regexp does not allow $1 to end with a ':'
135
- $1.constantize
136
- rescue LoadError, NameError => const_error
137
- raise ActionController::SessionRestoreError, <<-end_msg
138
- Session contains objects whose class definition isn\'t available.
139
- Remember to require the classes for all objects kept in the session.
140
- (Original exception: #{const_error.message} [#{const_error.class}])
141
- end_msg
142
- end
21
+ def self.dispatch_cgi(app, cgi, out = $stdout)
22
+ env = cgi.__send__(:env_table)
23
+ env.delete "HTTP_CONTENT_LENGTH"
143
24
 
144
- retry
145
- else
146
- raise
147
- end
148
- end
25
+ cgi.stdinput.extend ProperStream
149
26
 
150
- def session_options_with_string_keys
151
- @session_options_with_string_keys ||= DEFAULT_SESSION_OPTIONS.merge(@session_options).stringify_keys
152
- end
153
- end
27
+ env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
154
28
 
155
- class CgiResponse < AbstractResponse #:nodoc:
156
- def initialize(cgi)
157
- @cgi = cgi
158
- super()
159
- end
29
+ env.update({
30
+ "rack.version" => [0,1],
31
+ "rack.input" => cgi.stdinput,
32
+ "rack.errors" => $stderr,
33
+ "rack.multithread" => false,
34
+ "rack.multiprocess" => true,
35
+ "rack.run_once" => false,
36
+ "rack.url_scheme" => ["yes", "on", "1"].include?(env["HTTPS"]) ? "https" : "http"
37
+ })
160
38
 
161
- def out(output = $stdout)
162
- output.binmode if output.respond_to?(:binmode)
163
- output.sync = false if output.respond_to?(:sync=)
39
+ env["QUERY_STRING"] ||= ""
40
+ env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
41
+ env["REQUEST_PATH"] ||= "/"
42
+ env.delete "PATH_INFO" if env["PATH_INFO"] == ""
164
43
 
44
+ status, headers, body = app.call(env)
165
45
  begin
166
- output.write(@cgi.header(@headers))
46
+ out.binmode if out.respond_to?(:binmode)
47
+ out.sync = false if out.respond_to?(:sync=)
167
48
 
168
- if @cgi.__send__(:env_table)['REQUEST_METHOD'] == 'HEAD'
169
- return
170
- elsif @body.respond_to?(:call)
171
- # Flush the output now in case the @body Proc uses
172
- # #syswrite.
173
- output.flush if output.respond_to?(:flush)
174
- @body.call(self, output)
175
- else
176
- output.write(@body)
49
+ headers['Status'] = status.to_s
50
+
51
+ if headers.include?('Set-Cookie')
52
+ headers['cookie'] = headers.delete('Set-Cookie').split("\n")
177
53
  end
178
54
 
179
- output.flush if output.respond_to?(:flush)
180
- rescue Errno::EPIPE, Errno::ECONNRESET
181
- # lost connection to parent process, ignore output
55
+ out.write(cgi.header(headers))
56
+
57
+ body.each { |part|
58
+ out.write part
59
+ out.flush if out.respond_to?(:flush)
60
+ }
61
+ ensure
62
+ body.close if body.respond_to?(:close)
182
63
  end
183
64
  end
184
65
  end
66
+
67
+ class CgiRequest #:nodoc:
68
+ DEFAULT_SESSION_OPTIONS = {
69
+ :database_manager => nil,
70
+ :prefix => "ruby_sess.",
71
+ :session_path => "/",
72
+ :session_key => "_session_id",
73
+ :cookie_only => true,
74
+ :session_http_only => true
75
+ }
76
+ end
185
77
  end