actionpack 1.11.2 → 1.12.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 (149) hide show
  1. data/CHANGELOG +392 -5
  2. data/lib/action_controller.rb +8 -4
  3. data/lib/action_controller/assertions.rb +9 -10
  4. data/lib/action_controller/base.rb +177 -88
  5. data/lib/action_controller/benchmarking.rb +5 -5
  6. data/lib/action_controller/caching.rb +44 -36
  7. data/lib/action_controller/cgi_ext/cgi_methods.rb +71 -6
  8. data/lib/action_controller/cgi_ext/cookie_performance_fix.rb +1 -1
  9. data/lib/action_controller/cgi_process.rb +36 -24
  10. data/lib/action_controller/components.rb +152 -52
  11. data/lib/action_controller/dependencies.rb +1 -1
  12. data/lib/action_controller/deprecated_redirects.rb +2 -2
  13. data/lib/action_controller/deprecated_request_methods.rb +34 -0
  14. data/lib/action_controller/filters.rb +59 -19
  15. data/lib/action_controller/flash.rb +53 -47
  16. data/lib/action_controller/helpers.rb +2 -2
  17. data/lib/action_controller/integration.rb +524 -0
  18. data/lib/action_controller/layout.rb +58 -23
  19. data/lib/action_controller/mime_responds.rb +163 -0
  20. data/lib/action_controller/mime_type.rb +142 -0
  21. data/lib/action_controller/pagination.rb +13 -7
  22. data/lib/action_controller/request.rb +59 -56
  23. data/lib/action_controller/rescue.rb +1 -1
  24. data/lib/action_controller/routing.rb +29 -10
  25. data/lib/action_controller/scaffolding.rb +8 -0
  26. data/lib/action_controller/session/active_record_store.rb +21 -10
  27. data/lib/action_controller/session/mem_cache_store.rb +18 -12
  28. data/lib/action_controller/session_management.rb +30 -11
  29. data/lib/action_controller/templates/rescues/_trace.rhtml +1 -1
  30. data/lib/action_controller/templates/scaffolds/layout.rhtml +4 -4
  31. data/lib/action_controller/templates/scaffolds/list.rhtml +1 -1
  32. data/lib/action_controller/test_process.rb +189 -118
  33. data/lib/action_controller/vendor/html-scanner/html/node.rb +20 -1
  34. data/lib/action_controller/vendor/html-scanner/html/tokenizer.rb +3 -0
  35. data/lib/action_controller/vendor/html-scanner/html/version.rb +1 -1
  36. data/lib/action_controller/vendor/xml_node.rb +97 -0
  37. data/lib/action_controller/verification.rb +2 -0
  38. data/lib/action_pack/version.rb +3 -3
  39. data/lib/action_view.rb +0 -2
  40. data/lib/action_view/base.rb +109 -36
  41. data/lib/action_view/compiled_templates.rb +1 -1
  42. data/lib/action_view/helpers/active_record_helper.rb +4 -2
  43. data/lib/action_view/helpers/asset_tag_helper.rb +6 -7
  44. data/lib/action_view/helpers/capture_helper.rb +49 -12
  45. data/lib/action_view/helpers/date_helper.rb +14 -4
  46. data/lib/action_view/helpers/form_helper.rb +136 -20
  47. data/lib/action_view/helpers/form_options_helper.rb +29 -7
  48. data/lib/action_view/helpers/form_tag_helper.rb +22 -20
  49. data/lib/action_view/helpers/java_script_macros_helper.rb +29 -9
  50. data/lib/action_view/helpers/javascript_helper.rb +50 -446
  51. data/lib/action_view/helpers/javascripts/controls.js +95 -30
  52. data/lib/action_view/helpers/javascripts/dragdrop.js +161 -21
  53. data/lib/action_view/helpers/javascripts/effects.js +310 -211
  54. data/lib/action_view/helpers/javascripts/prototype.js +228 -28
  55. data/lib/action_view/helpers/number_helper.rb +9 -9
  56. data/lib/action_view/helpers/pagination_helper.rb +1 -1
  57. data/lib/action_view/helpers/prototype_helper.rb +900 -0
  58. data/lib/action_view/helpers/scriptaculous_helper.rb +135 -0
  59. data/lib/action_view/helpers/text_helper.rb +7 -6
  60. data/lib/action_view/helpers/url_helper.rb +23 -14
  61. data/lib/action_view/partials.rb +12 -4
  62. data/rakefile +13 -5
  63. data/test/abstract_unit.rb +4 -3
  64. data/test/active_record_unit.rb +88 -0
  65. data/test/{controller → activerecord}/active_record_assertions_test.rb +7 -50
  66. data/test/{controller → activerecord}/active_record_store_test.rb +27 -4
  67. data/test/activerecord/pagination_test.rb +161 -0
  68. data/test/controller/action_pack_assertions_test.rb +18 -15
  69. data/test/controller/base_test.rb +31 -42
  70. data/test/controller/benchmark_test.rb +8 -11
  71. data/test/controller/capture_test.rb +33 -1
  72. data/test/controller/cgi_test.rb +33 -0
  73. data/test/controller/custom_handler_test.rb +8 -0
  74. data/test/controller/fake_controllers.rb +9 -17
  75. data/test/controller/filters_test.rb +32 -3
  76. data/test/controller/flash_test.rb +26 -41
  77. data/test/controller/fragment_store_setting_test.rb +1 -1
  78. data/test/controller/layout_test.rb +73 -0
  79. data/test/controller/mime_responds_test.rb +257 -0
  80. data/test/controller/mime_type_test.rb +24 -0
  81. data/test/controller/new_render_test.rb +157 -1
  82. data/test/controller/redirect_test.rb +23 -0
  83. data/test/controller/render_test.rb +54 -56
  84. data/test/controller/request_test.rb +25 -0
  85. data/test/controller/routing_test.rb +74 -66
  86. data/test/controller/test_test.rb +66 -1
  87. data/test/controller/verification_test.rb +3 -1
  88. data/test/controller/webservice_test.rb +255 -0
  89. data/test/fixtures/companies.yml +24 -0
  90. data/test/fixtures/company.rb +9 -0
  91. data/test/fixtures/db_definitions/sqlite.sql +42 -0
  92. data/test/fixtures/developer.rb +7 -0
  93. data/test/fixtures/developers.yml +21 -0
  94. data/test/fixtures/developers_projects.yml +13 -0
  95. data/test/fixtures/layout_tests/layouts/controller_name_space/nested.rhtml +1 -0
  96. data/test/fixtures/layout_tests/layouts/item.rhtml +1 -0
  97. data/test/fixtures/layout_tests/layouts/layout_test.rhtml +1 -0
  98. data/test/fixtures/layout_tests/layouts/third_party_template_library.mab +1 -0
  99. data/test/fixtures/layout_tests/views/hello.rhtml +1 -0
  100. data/test/fixtures/multipart/mona_lisa.jpg +0 -0
  101. data/test/fixtures/project.rb +3 -0
  102. data/test/fixtures/projects.yml +7 -0
  103. data/test/fixtures/replies.yml +13 -0
  104. data/test/fixtures/reply.rb +5 -0
  105. data/test/fixtures/respond_to/all_types_with_layout.rhtml +1 -0
  106. data/test/fixtures/respond_to/all_types_with_layout.rjs +1 -0
  107. data/test/fixtures/respond_to/layouts/standard.rhtml +1 -0
  108. data/test/fixtures/respond_to/using_defaults.rhtml +1 -0
  109. data/test/fixtures/respond_to/using_defaults.rjs +1 -0
  110. data/test/fixtures/respond_to/using_defaults.rxml +1 -0
  111. data/test/fixtures/respond_to/using_defaults_with_type_list.rhtml +1 -0
  112. data/test/fixtures/respond_to/using_defaults_with_type_list.rjs +1 -0
  113. data/test/fixtures/respond_to/using_defaults_with_type_list.rxml +1 -0
  114. data/test/fixtures/test/block_content_for.rhtml +2 -0
  115. data/test/fixtures/test/delete_with_js.rjs +2 -0
  116. data/test/fixtures/test/dot.directory/render_file_with_ivar.rhtml +1 -0
  117. data/test/fixtures/test/enum_rjs_test.rjs +6 -0
  118. data/test/fixtures/test/erb_content_for.rhtml +2 -0
  119. data/test/fixtures/test/hello_world.rxml +3 -0
  120. data/test/fixtures/test/hello_world_with_layout_false.rhtml +1 -0
  121. data/test/fixtures/test/non_erb_block_content_for.rxml +4 -0
  122. data/test/fixtures/topic.rb +3 -0
  123. data/test/fixtures/topics.yml +22 -0
  124. data/test/template/active_record_helper_test.rb +4 -0
  125. data/test/template/asset_tag_helper_test.rb +7 -2
  126. data/test/template/date_helper_test.rb +39 -2
  127. data/test/template/form_helper_test.rb +238 -5
  128. data/test/template/form_options_helper_test.rb +78 -0
  129. data/test/template/form_tag_helper_test.rb +11 -0
  130. data/test/template/java_script_macros_helper_test.rb +51 -6
  131. data/test/template/javascript_helper_test.rb +7 -153
  132. data/test/template/number_helper_test.rb +14 -13
  133. data/test/template/prototype_helper_test.rb +423 -0
  134. data/test/template/scriptaculous_helper_test.rb +90 -0
  135. data/test/template/text_helper_test.rb +12 -9
  136. data/test/template/url_helper_test.rb +31 -15
  137. metadata +291 -246
  138. data/lib/action_controller/cgi_ext/multipart_progress.rb +0 -169
  139. data/lib/action_controller/upload_progress.rb +0 -473
  140. data/lib/action_controller/vendor/html-scanner/html/node.rb.rej +0 -17
  141. data/lib/action_view/helpers/upload_progress_helper.rb +0 -433
  142. data/lib/action_view/vendor/builder.rb +0 -13
  143. data/lib/action_view/vendor/builder/blankslate.rb +0 -53
  144. data/lib/action_view/vendor/builder/xmlbase.rb +0 -143
  145. data/lib/action_view/vendor/builder/xmlevents.rb +0 -63
  146. data/lib/action_view/vendor/builder/xmlmarkup.rb +0 -308
  147. data/test/controller/multipart_progress_testx.rb +0 -365
  148. data/test/controller/upload_progress_testx.rb +0 -89
  149. data/test/template/upload_progress_helper_testx.rb +0 -136
@@ -4,9 +4,9 @@ module ActionController #:nodoc:
4
4
  # The benchmarking module times the performance of actions and reports to the logger. If the Active Record
5
5
  # package has been included, a separate timing section for database calls will be added as well.
6
6
  module Benchmarking #:nodoc:
7
- def self.append_features(base)
8
- super
7
+ def self.included(base)
9
8
  base.extend(ClassMethods)
9
+
10
10
  base.class_eval do
11
11
  alias_method :perform_action_without_benchmark, :perform_action
12
12
  alias_method :perform_action, :perform_action_with_benchmark
@@ -43,14 +43,14 @@ module ActionController #:nodoc:
43
43
  end
44
44
  end
45
45
 
46
- def render_with_benchmark(options = nil, deprecated_status = nil)
46
+ def render_with_benchmark(options = nil, deprecated_status = nil, &block)
47
47
  unless logger
48
- render_without_benchmark(options, deprecated_status)
48
+ render_without_benchmark(options, deprecated_status, &block)
49
49
  else
50
50
  db_runtime = ActiveRecord::Base.connection.reset_runtime if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
51
51
 
52
52
  render_output = nil
53
- @rendering_runtime = Benchmark::measure{ render_output = render_without_benchmark(options, deprecated_status) }.real
53
+ @rendering_runtime = Benchmark::measure{ render_output = render_without_benchmark(options, deprecated_status, &block) }.real
54
54
 
55
55
  if Object.const_defined?("ActiveRecord") && ActiveRecord::Base.connected?
56
56
  @db_rt_before_render = db_runtime
@@ -8,16 +8,16 @@ module ActionController #:nodoc:
8
8
  #
9
9
  # Note: To turn off all caching and sweeping, set Base.perform_caching = false.
10
10
  module Caching
11
- def self.append_features(base) #:nodoc:
12
- super
11
+ def self.included(base) #:nodoc:
13
12
  base.send(:include, Pages, Actions, Fragments, Sweeping)
13
+
14
14
  base.class_eval do
15
15
  @@perform_caching = true
16
16
  cattr_accessor :perform_caching
17
17
  end
18
18
  end
19
19
 
20
- # Page caching is an approach to caching where the entire action output of is stored as a HTML file that the web server
20
+ # Page caching is an approach to caching where the entire action output of is stored as a HTML file that the web server
21
21
  # can serve without going through the Action Pack. This can be as much as 100 times faster than going through the process of dynamically
22
22
  # generating the content. Unfortunately, this incredible speed-up is only available to stateless pages where all visitors
23
23
  # are treated the same. Content management systems -- including weblogs and wikis -- have many pages that are a great fit
@@ -78,7 +78,7 @@ module ActionController #:nodoc:
78
78
  File.delete(page_cache_path(path)) if File.exists?(page_cache_path(path))
79
79
  end
80
80
  end
81
-
81
+
82
82
  # Manually cache the +content+ in the key determined by +path+. Example:
83
83
  # cache_page "I'm the cached content", "/lists/show"
84
84
  def cache_page(content, path)
@@ -94,18 +94,18 @@ module ActionController #:nodoc:
94
94
  # matches the triggering url.
95
95
  def caches_page(*actions)
96
96
  return unless perform_caching
97
- actions.each do |action|
97
+ actions.each do |action|
98
98
  class_eval "after_filter { |c| c.cache_page if c.action_name == '#{action}' }"
99
99
  end
100
100
  end
101
-
101
+
102
102
  private
103
103
  def page_cache_file(path)
104
104
  name = ((path.empty? || path == "/") ? "/index" : URI.unescape(path))
105
105
  name << page_cache_extension unless (name.split('/').last || name).include? '.'
106
106
  return name
107
107
  end
108
-
108
+
109
109
  def page_cache_path(path)
110
110
  page_cache_directory + page_cache_file(path)
111
111
  end
@@ -134,11 +134,11 @@ module ActionController #:nodoc:
134
134
 
135
135
  private
136
136
  def caching_allowed
137
- !@request.post?
137
+ !@request.post? && @response.headers['Status'] && @response.headers['Status'].to_i < 400
138
138
  end
139
139
  end
140
140
 
141
- # Action caching is similar to page caching by the fact that the entire output of the response is cached, but unlike page caching,
141
+ # Action caching is similar to page caching by the fact that the entire output of the response is cached, but unlike page caching,
142
142
  # every request still goes through the Action Pack. The key benefit of this is that filters are run before the cache is served, which
143
143
  # allows for authentication and other restrictions on whether someone is allowed to see the cache. Example:
144
144
  #
@@ -184,7 +184,7 @@ module ActionController #:nodoc:
184
184
  def initialize(*actions)
185
185
  @actions = actions
186
186
  end
187
-
187
+
188
188
  def before(controller)
189
189
  return unless @actions.include?(controller.action_name.intern)
190
190
  if cache = controller.read_fragment(controller.url_for.split("://").last)
@@ -193,7 +193,7 @@ module ActionController #:nodoc:
193
193
  false
194
194
  end
195
195
  end
196
-
196
+
197
197
  def after(controller)
198
198
  return if !@actions.include?(controller.action_name.intern) || controller.rendered_action_cache
199
199
  controller.write_fragment(controller.url_for.split("://").last, controller.response.body)
@@ -211,7 +211,7 @@ module ActionController #:nodoc:
211
211
  # <%= render_collection_of_partials "topic", Topic.find_all %>
212
212
  # <% end %>
213
213
  #
214
- # This cache will bind to the name of action that called it. So you would be able to invalidate it using
214
+ # This cache will bind to the name of action that called it. So you would be able to invalidate it using
215
215
  # <tt>expire_fragment(:controller => "topics", :action => "list")</tt> -- if that was the controller/action used. This is not too helpful
216
216
  # if you need to cache multiple fragments per action or if the action itself is cached using <tt>caches_action</tt>. So instead we should
217
217
  # qualify the name of the action used with something like:
@@ -272,7 +272,7 @@ module ActionController #:nodoc:
272
272
  # Called by CacheHelper#cache
273
273
  def cache_erb_fragment(block, name = {}, options = nil)
274
274
  unless perform_caching then block.call; return end
275
-
275
+
276
276
  buffer = eval("_erbout", block.binding)
277
277
 
278
278
  if cache = read_fragment(name, options)
@@ -283,7 +283,7 @@ module ActionController #:nodoc:
283
283
  write_fragment(name, buffer[pos..-1], options)
284
284
  end
285
285
  end
286
-
286
+
287
287
  def write_fragment(name, content, options = nil)
288
288
  return unless perform_caching
289
289
 
@@ -293,7 +293,7 @@ module ActionController #:nodoc:
293
293
  end
294
294
  content
295
295
  end
296
-
296
+
297
297
  def read_fragment(name, options = nil)
298
298
  return unless perform_caching
299
299
 
@@ -302,11 +302,11 @@ module ActionController #:nodoc:
302
302
  fragment_cache_store.read(key, options)
303
303
  end
304
304
  end
305
-
305
+
306
306
  # Name can take one of three forms:
307
307
  # * String: This would normally take the form of a path like "pages/45/notes"
308
308
  # * Hash: Is treated as an implicit call to url_for, like { :controller => "pages", :action => "notes", :id => 45 }
309
- # * Regexp: Will destroy all the matched fragments, example: %r{pages/\d*/notes}
309
+ # * Regexp: Will destroy all the matched fragments, example: %r{pages/\d*/notes} Ensure you do not specify start and finish in the regex (^$) because the actual filename matched looks like ./cache/filename/path.cache
310
310
  def expire_fragment(name, options = nil)
311
311
  return unless perform_caching
312
312
 
@@ -355,15 +355,15 @@ module ActionController #:nodoc:
355
355
  def read(name, options=nil) #:nodoc:
356
356
  @mutex.synchronize { super }
357
357
  end
358
-
358
+
359
359
  def write(name, value, options=nil) #:nodoc:
360
360
  @mutex.synchronize { super }
361
361
  end
362
-
362
+
363
363
  def delete(name, options=nil) #:nodoc:
364
364
  @mutex.synchronize { super }
365
365
  end
366
-
366
+
367
367
  def delete_matched(matcher, options=nil) #:nodoc:
368
368
  @mutex.synchronize { super }
369
369
  end
@@ -386,26 +386,28 @@ module ActionController #:nodoc:
386
386
  super()
387
387
  @address = address
388
388
  @data = DRbObject.new(nil, address)
389
- end
389
+ end
390
390
  end
391
391
 
392
392
  class MemCacheStore < MemoryStore #:nodoc:
393
- attr_reader :address
393
+ attr_reader :addresses
394
394
 
395
- def initialize(address = 'localhost')
395
+ def initialize(*addresses)
396
396
  super()
397
- @address = address
398
- @data = MemCache.new(address)
399
- end
397
+ addresses = addresses.flatten
398
+ addresses = ["localhost"] if addresses.empty?
399
+ @addresses = addresses
400
+ @data = MemCache.new(*addresses)
401
+ end
400
402
  end
401
403
 
402
404
  class UnthreadedFileStore #:nodoc:
403
405
  attr_reader :cache_path
404
-
406
+
405
407
  def initialize(cache_path)
406
408
  @cache_path = cache_path
407
409
  end
408
-
410
+
409
411
  def write(name, value, options = nil) #:nodoc:
410
412
  ensure_cache_path(File.dirname(real_file_path(name)))
411
413
  File.open(real_file_path(name), "wb+") { |f| f.write(value) }
@@ -426,7 +428,7 @@ module ActionController #:nodoc:
426
428
  def delete_matched(matcher, options) #:nodoc:
427
429
  search_dir(@cache_path) do |f|
428
430
  if f =~ matcher
429
- begin
431
+ begin
430
432
  File.delete(f)
431
433
  rescue Object => e
432
434
  # If there's no cache, then there's nothing to complain about
@@ -434,12 +436,12 @@ module ActionController #:nodoc:
434
436
  end
435
437
  end
436
438
  end
437
-
439
+
438
440
  private
439
441
  def real_file_path(name)
440
442
  '%s/%s.cache' % [@cache_path, name.gsub('?', '.').gsub(':', '.')]
441
443
  end
442
-
444
+
443
445
  def ensure_cache_path(path)
444
446
  FileUtils.makedirs(path) unless File.exists?(path)
445
447
  end
@@ -470,10 +472,10 @@ module ActionController #:nodoc:
470
472
 
471
473
  # Sweepers are the terminators of the caching world and responsible for expiring caches when model objects change.
472
474
  # They do this by being half-observers, half-filters and implementing callbacks for both roles. A Sweeper example:
473
- #
475
+ #
474
476
  # class ListSweeper < ActionController::Caching::Sweeper
475
477
  # observe List, Item
476
- #
478
+ #
477
479
  # def after_save(record)
478
480
  # list = record.is_a?(List) ? record : record.list
479
481
  # expire_page(:controller => "lists", :action => %w( show public feed ), :id => list.id)
@@ -518,6 +520,10 @@ module ActionController #:nodoc:
518
520
  if defined?(ActiveRecord) and defined?(ActiveRecord::Observer)
519
521
  class Sweeper < ActiveRecord::Observer #:nodoc:
520
522
  attr_accessor :controller
523
+
524
+ # ActiveRecord::Observer will mark this class as reloadable even though it should not be.
525
+ # However, subclasses of ActionController::Caching::Sweeper should be Reloadable
526
+ include Reloadable::Subclasses
521
527
 
522
528
  def before(controller)
523
529
  self.controller = controller
@@ -526,17 +532,19 @@ module ActionController #:nodoc:
526
532
 
527
533
  def after(controller)
528
534
  callback(:after)
535
+ # Clean up, so that the controller can be collected after this request
536
+ self.controller = nil
529
537
  end
530
-
538
+
531
539
  private
532
540
  def callback(timing)
533
541
  controller_callback_method_name = "#{timing}_#{controller.controller_name.underscore}"
534
542
  action_callback_method_name = "#{controller_callback_method_name}_#{controller.action_name}"
535
-
543
+
536
544
  send(controller_callback_method_name) if respond_to?(controller_callback_method_name)
537
545
  send(action_callback_method_name) if respond_to?(action_callback_method_name)
538
546
  end
539
-
547
+
540
548
  def method_missing(method, *arguments)
541
549
  return if @controller.nil?
542
550
  @controller.send(method, *arguments)
@@ -1,5 +1,6 @@
1
1
  require 'cgi'
2
2
  require 'action_controller/vendor/xml_simple'
3
+ require 'action_controller/vendor/xml_node'
3
4
 
4
5
  # Static methods for parsing the query and request parameters that can be used in
5
6
  # a CGI extension class or testing in isolation.
@@ -57,20 +58,84 @@ class CGIMethods #:nodoc:
57
58
  parsed_params
58
59
  end
59
60
 
60
- def self.parse_formatted_request_parameters(format, raw_post_data)
61
- case format
62
- when :xml
63
- return XmlSimple.xml_in(raw_post_data, 'ForceArray' => false)
61
+ def self.parse_formatted_request_parameters(mime_type, raw_post_data)
62
+ params = case strategy = ActionController::Base.param_parsers[mime_type]
63
+ when Proc
64
+ strategy.call(raw_post_data)
65
+ when :xml_simple
66
+ raw_post_data.blank? ? nil :
67
+ typecast_xml_value(XmlSimple.xml_in(raw_post_data,
68
+ 'forcearray' => false,
69
+ 'forcecontent' => true,
70
+ 'keeproot' => true,
71
+ 'contentkey' => '__content__'))
64
72
  when :yaml
65
- return YAML.load(raw_post_data)
73
+ YAML.load(raw_post_data)
74
+ when :xml_node
75
+ node = XmlNode.from_xml(raw_post_data)
76
+ { node.node_name => node }
66
77
  end
78
+
79
+ dasherize_keys(params || {})
67
80
  rescue Object => e
68
81
  { "exception" => "#{e.message} (#{e.class})", "backtrace" => e.backtrace,
69
- "raw_post_data" => raw_post_data, "format" => format }
82
+ "raw_post_data" => raw_post_data, "format" => mime_type }
83
+ end
84
+
85
+ def self.typecast_xml_value(value)
86
+ case value
87
+ when Hash
88
+ if value.has_key?("__content__")
89
+ content = translate_xml_entities(value["__content__"])
90
+ case value["type"]
91
+ when "integer" then content.to_i
92
+ when "boolean" then content == "true"
93
+ when "datetime" then Time.parse(content)
94
+ when "date" then Date.parse(content)
95
+ else content
96
+ end
97
+ else
98
+ value.empty? ? nil : value.inject({}) do |h,(k,v)|
99
+ h[k] = typecast_xml_value(v)
100
+ h
101
+ end
102
+ end
103
+ when Array
104
+ value.map! { |i| typecast_xml_value(i) }
105
+ case value.length
106
+ when 0 then nil
107
+ when 1 then value.first
108
+ else value
109
+ end
110
+ else
111
+ raise "can't typecast #{value.inspect}"
112
+ end
70
113
  end
71
114
 
72
115
  private
73
116
 
117
+ def self.translate_xml_entities(value)
118
+ value.gsub(/&lt;/, "<").
119
+ gsub(/&gt;/, ">").
120
+ gsub(/&quot;/, '"').
121
+ gsub(/&apos;/, "'").
122
+ gsub(/&amp;/, "&")
123
+ end
124
+
125
+ def self.dasherize_keys(params)
126
+ case params.class.to_s
127
+ when "Hash"
128
+ params.inject({}) do |h,(k,v)|
129
+ h[k.to_s.tr("-", "_")] = dasherize_keys(v)
130
+ h
131
+ end
132
+ when "Array"
133
+ params.map { |v| dasherize_keys(v) }
134
+ else
135
+ params
136
+ end
137
+ end
138
+
74
139
  # Splits the given key into several pieces. Example keys are 'name', 'person[name]',
75
140
  # 'person[name][first]', and 'people[]'. In each instance, an Array instance is returned.
76
141
  # 'person[name][first]' produces ['person', 'name', 'first']; 'people[]' produces ['people', '']
@@ -108,7 +108,7 @@ class CGI #:nodoc:
108
108
  cookies = Hash.new([])
109
109
 
110
110
  if raw_cookie
111
- raw_cookie.split(/; /).each do |pairs|
111
+ raw_cookie.split(/; ?/).each do |pairs|
112
112
  name, values = pairs.split('=',2)
113
113
  next unless name and values
114
114
  name = CGI::unescape(name)
@@ -36,25 +36,26 @@ module ActionController #:nodoc:
36
36
 
37
37
  DEFAULT_SESSION_OPTIONS = {
38
38
  :database_manager => CGI::Session::PStore,
39
- :prefix => "ruby_sess.",
40
- :session_path => "/"
39
+ :prefix => "ruby_sess.",
40
+ :session_path => "/"
41
41
  } unless const_defined?(:DEFAULT_SESSION_OPTIONS)
42
42
 
43
43
  def initialize(cgi, session_options = {})
44
44
  @cgi = cgi
45
45
  @session_options = session_options
46
+ @env = @cgi.send(:env_table)
46
47
  super()
47
48
  end
48
49
 
49
50
  def query_string
50
51
  if (qs = @cgi.query_string) && !qs.empty?
51
52
  qs
52
- elsif uri = env['REQUEST_URI']
53
+ elsif uri = @env['REQUEST_URI']
53
54
  parts = uri.split('?')
54
55
  parts.shift
55
56
  parts.join('?')
56
57
  else
57
- env['QUERY_STRING'] || ''
58
+ @env['QUERY_STRING'] || ''
58
59
  end
59
60
  end
60
61
 
@@ -63,31 +64,39 @@ module ActionController #:nodoc:
63
64
  end
64
65
 
65
66
  def request_parameters
66
- if formatted_post?
67
- CGIMethods.parse_formatted_request_parameters(post_format, env['RAW_POST_DATA'])
67
+ if ActionController::Base.param_parsers.has_key?(content_type)
68
+ CGIMethods.parse_formatted_request_parameters(content_type, @env['RAW_POST_DATA'])
68
69
  else
69
70
  CGIMethods.parse_request_parameters(@cgi.params)
70
71
  end
71
72
  end
72
-
73
- def env
74
- @cgi.send(:env_table)
75
- end
76
-
73
+
77
74
  def cookies
78
75
  @cgi.cookies.freeze
79
76
  end
80
77
 
78
+ def host_with_port
79
+ if forwarded = env["HTTP_X_FORWARDED_HOST"]
80
+ forwarded.split(/,\s?/).last
81
+ elsif http_host = env['HTTP_HOST']
82
+ http_host
83
+ elsif server_name = env['SERVER_NAME']
84
+ server_name
85
+ else
86
+ "#{env['SERVER_ADDR']}:#{env['SERVER_PORT']}"
87
+ end
88
+ end
89
+
81
90
  def host
82
- env["HTTP_X_FORWARDED_HOST"] || ($1 if env['HTTP_HOST'] && /^(.*):\d+$/ =~ env['HTTP_HOST']) || @cgi.host.to_s.split(":").first || ''
91
+ host_with_port[/^[^:]+/]
83
92
  end
84
-
93
+
85
94
  def port
86
- env["HTTP_X_FORWARDED_HOST"] ? standard_port : (port_from_http_host || super)
87
- end
88
-
89
- def port_from_http_host
90
- $1.to_i if env['HTTP_HOST'] && /:(\d+)$/ =~ env['HTTP_HOST']
95
+ if host_with_port =~ /:(\d+)$/
96
+ $1.to_i
97
+ else
98
+ standard_port
99
+ end
91
100
  end
92
101
 
93
102
  def session
@@ -136,7 +145,7 @@ module ActionController #:nodoc:
136
145
  Module.const_missing($1)
137
146
  rescue LoadError, NameError => const_error
138
147
  raise ActionController::SessionRestoreError, <<end_msg
139
- Session contains objects whose class definition isn't available.
148
+ Session contains objects whose class definition isn\'t available.
140
149
  Remember to require the classes for all objects kept in the session.
141
150
  (Original exception: #{const_error.message} [#{const_error.class}])
142
151
  end_msg
@@ -183,11 +192,14 @@ end_msg
183
192
 
184
193
  private
185
194
  def convert_content_type!(headers)
186
- %w( Content-Type Content-type content-type ).each do |ct|
187
- if headers[ct]
188
- headers["type"] = headers[ct]
189
- headers.delete(ct)
190
- end
195
+ if header = headers.delete("Content-Type")
196
+ headers["type"] = header
197
+ end
198
+ if header = headers.delete("Content-type")
199
+ headers["type"] = header
200
+ end
201
+ if header = headers.delete("content-type")
202
+ headers["type"] = header
191
203
  end
192
204
  end
193
205
  end