actionpack 2.3.3 → 2.3.4

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 (50) hide show
  1. data/CHANGELOG +12 -1
  2. data/Rakefile +9 -8
  3. data/lib/action_controller/assertions/response_assertions.rb +3 -1
  4. data/lib/action_controller/base.rb +6 -2
  5. data/lib/action_controller/cookies.rb +1 -1
  6. data/lib/action_controller/dispatcher.rb +21 -6
  7. data/lib/action_controller/http_authentication.rb +3 -2
  8. data/lib/action_controller/params_parser.rb +6 -0
  9. data/lib/action_controller/reloader.rb +30 -21
  10. data/lib/action_controller/request_forgery_protection.rb +2 -1
  11. data/lib/action_controller/resources.rb +17 -13
  12. data/lib/action_controller/response.rb +6 -0
  13. data/lib/action_controller/routing.rb +3 -0
  14. data/lib/action_controller/routing/route_set.rb +18 -5
  15. data/lib/action_controller/streaming.rb +3 -1
  16. data/lib/action_controller/url_rewriter.rb +1 -1
  17. data/lib/action_pack/version.rb +1 -1
  18. data/lib/action_view/helpers/atom_feed_helper.rb +1 -1
  19. data/lib/action_view/helpers/form_helper.rb +3 -2
  20. data/lib/action_view/helpers/form_options_helper.rb +69 -1
  21. data/lib/action_view/helpers/tag_helper.rb +1 -1
  22. data/lib/action_view/helpers/text_helper.rb +20 -11
  23. data/lib/action_view/helpers/url_helper.rb +1 -1
  24. data/lib/action_view/locale/en.yml +4 -0
  25. data/test/abstract_unit.rb +16 -0
  26. data/test/controller/caching_test.rb +1 -1
  27. data/test/controller/cookie_test.rb +6 -0
  28. data/test/controller/dispatcher_test.rb +50 -11
  29. data/test/controller/filter_params_test.rb +2 -1
  30. data/test/controller/http_basic_authentication_test.rb +25 -0
  31. data/test/controller/http_digest_authentication_test.rb +29 -6
  32. data/test/controller/rack_test.rb +18 -1
  33. data/test/controller/redirect_test.rb +1 -1
  34. data/test/controller/reloader_test.rb +47 -20
  35. data/test/controller/request/json_params_parsing_test.rb +24 -4
  36. data/test/controller/request/xml_params_parsing_test.rb +15 -0
  37. data/test/controller/request_forgery_protection_test.rb +6 -5
  38. data/test/controller/resources_test.rb +44 -0
  39. data/test/controller/routing_test.rb +7 -2
  40. data/test/controller/send_file_test.rb +11 -1
  41. data/test/controller/url_rewriter_test.rb +29 -3
  42. data/test/fixtures/public/absolute/test.css +23 -0
  43. data/test/fixtures/public/absolute/test.js +63 -0
  44. data/test/template/atom_feed_helper_test.rb +29 -0
  45. data/test/template/form_helper_test.rb +26 -0
  46. data/test/template/form_options_helper_i18n_test.rb +27 -0
  47. data/test/template/form_options_helper_test.rb +34 -0
  48. data/test/template/text_helper_test.rb +23 -0
  49. data/test/template/url_helper_test.rb +8 -0
  50. metadata +10 -94
@@ -184,7 +184,7 @@ module ActionController
184
184
  path = rewrite_path(options)
185
185
  rewritten_url << ActionController::Base.relative_url_root.to_s unless options[:skip_relative_url_root]
186
186
  rewritten_url << (options[:trailing_slash] ? path.sub(/\?|\z/) { "/" + $& } : path)
187
- rewritten_url << "##{options[:anchor]}" if options[:anchor]
187
+ rewritten_url << "##{CGI.escape(options[:anchor].to_param.to_s)}" if options[:anchor]
188
188
 
189
189
  rewritten_url
190
190
  end
@@ -2,7 +2,7 @@ module ActionPack #:nodoc:
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 2
4
4
  MINOR = 3
5
- TINY = 3
5
+ TINY = 4
6
6
 
7
7
  STRING = [MAJOR, MINOR, TINY].join('.')
8
8
  end
@@ -98,7 +98,7 @@ module ActionView
98
98
  options[:schema_date] = "2005" # The Atom spec copyright date
99
99
  end
100
100
 
101
- xml = options[:xml] || eval("xml", block.binding)
101
+ xml = options.delete(:xml) || eval("xml", block.binding)
102
102
  xml.instruct!
103
103
  if options[:instruct]
104
104
  options[:instruct].each do |target,attrs|
@@ -726,6 +726,7 @@ module ActionView
726
726
  options = options.stringify_keys
727
727
  tag_value = options.delete("value")
728
728
  name_and_id = options.dup
729
+ name_and_id["id"] = name_and_id["for"]
729
730
  add_default_name_and_id_for_value(tag_value, name_and_id)
730
731
  options.delete("index")
731
732
  options["for"] ||= name_and_id["id"]
@@ -860,8 +861,8 @@ module ActionView
860
861
 
861
862
  private
862
863
  def add_default_name_and_id_for_value(tag_value, options)
863
- if tag_value
864
- pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
864
+ unless tag_value.nil?
865
+ pretty_tag_value = tag_value.to_s.gsub(/\s/, "_").gsub(/\W/, "").downcase
865
866
  specified_id = options["id"]
866
867
  add_default_name_and_id(options)
867
868
  options["id"] += "_#{pretty_tag_value}" unless specified_id
@@ -162,6 +162,60 @@ module ActionView
162
162
  InstanceTag.new(object, method, self, options.delete(:object)).to_collection_select_tag(collection, value_method, text_method, options, html_options)
163
163
  end
164
164
 
165
+
166
+ # Returns <tt><select></tt>, <tt><optgroup></tt> and <tt><option></tt> tags for the collection of existing return values of
167
+ # +method+ for +object+'s class. The value returned from calling +method+ on the instance +object+ will
168
+ # be selected. If calling +method+ returns +nil+, no selection is made without including <tt>:prompt</tt>
169
+ # or <tt>:include_blank</tt> in the +options+ hash.
170
+ #
171
+ # Parameters:
172
+ # * +object+ - The instance of the class to be used for the select tag
173
+ # * +method+ - The attribute of +object+ corresponding to the select tag
174
+ # * +collection+ - An array of objects representing the <tt><optgroup></tt> tags.
175
+ # * +group_method+ - The name of a method which, when called on a member of +collection+, returns an
176
+ # array of child objects representing the <tt><option></tt> tags.
177
+ # * +group_label_method+ - The name of a method which, when called on a member of +collection+, returns a
178
+ # string to be used as the +label+ attribute for its <tt><optgroup></tt> tag.
179
+ # * +option_key_method+ - The name of a method which, when called on a child object of a member of
180
+ # +collection+, returns a value to be used as the +value+ attribute for its <tt><option></tt> tag.
181
+ # * +option_value_method+ - The name of a method which, when called on a child object of a member of
182
+ # +collection+, returns a value to be used as the contents of its <tt><option></tt> tag.
183
+ #
184
+ # Example object structure for use with this method:
185
+ # class Continent < ActiveRecord::Base
186
+ # has_many :countries
187
+ # # attribs: id, name
188
+ # end
189
+ # class Country < ActiveRecord::Base
190
+ # belongs_to :continent
191
+ # # attribs: id, name, continent_id
192
+ # end
193
+ # class City < ActiveRecord::Base
194
+ # belongs_to :country
195
+ # # attribs: id, name, country_id
196
+ # end
197
+ #
198
+ # Sample usage:
199
+ # grouped_collection_select(:city, :country_id, @continents, :countries, :name, :id, :name)
200
+ #
201
+ # Possible output:
202
+ # <select name="city[country_id]">
203
+ # <optgroup label="Africa">
204
+ # <option value="1">South Africa</option>
205
+ # <option value="3">Somalia</option>
206
+ # </optgroup>
207
+ # <optgroup label="Europe">
208
+ # <option value="7" selected="selected">Denmark</option>
209
+ # <option value="2">Ireland</option>
210
+ # </optgroup>
211
+ # </select>
212
+ #
213
+ def grouped_collection_select(object, method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
214
+ InstanceTag.new(object, method, self, options.delete(:object)).to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
215
+ end
216
+
217
+
218
+
165
219
  # Return select and option tags for the given object and method, using
166
220
  # #time_zone_options_for_select to generate the list of option tags.
167
221
  #
@@ -490,6 +544,15 @@ module ActionView
490
544
  )
491
545
  end
492
546
 
547
+ def to_grouped_collection_select_tag(collection, group_method, group_label_method, option_key_method, option_value_method, options, html_options)
548
+ html_options = html_options.stringify_keys
549
+ add_default_name_and_id(html_options)
550
+ value = value(object)
551
+ content_tag(
552
+ "select", add_options(option_groups_from_collection_for_select(collection, group_method, group_label_method, option_key_method, option_value_method, value), options, value), html_options
553
+ )
554
+ end
555
+
493
556
  def to_time_zone_select_tag(priority_zones, options, html_options)
494
557
  html_options = html_options.stringify_keys
495
558
  add_default_name_and_id(html_options)
@@ -508,7 +571,8 @@ module ActionView
508
571
  option_tags = "<option value=\"\">#{options[:include_blank] if options[:include_blank].kind_of?(String)}</option>\n" + option_tags
509
572
  end
510
573
  if value.blank? && options[:prompt]
511
- ("<option value=\"\">#{options[:prompt].kind_of?(String) ? options[:prompt] : 'Please select'}</option>\n") + option_tags
574
+ prompt = options[:prompt].kind_of?(String) ? options[:prompt] : I18n.translate('support.select.prompt', :default => 'Please select')
575
+ "<option value=\"\">#{prompt}</option>\n" + option_tags
512
576
  else
513
577
  option_tags
514
578
  end
@@ -524,6 +588,10 @@ module ActionView
524
588
  @template.collection_select(@object_name, method, collection, value_method, text_method, objectify_options(options), @default_options.merge(html_options))
525
589
  end
526
590
 
591
+ def grouped_collection_select(method, collection, group_method, group_label_method, option_key_method, option_value_method, options = {}, html_options = {})
592
+ @template.grouped_collection_select(@object_name, method, collection, group_method, group_label_method, option_key_method, option_value_method, objectify_options(options), @default_options.merge(html_options))
593
+ end
594
+
527
595
  def time_zone_select(method, priority_zones = nil, options = {}, html_options = {})
528
596
  @template.time_zone_select(@object_name, method, priority_zones, objectify_options(options), @default_options.merge(html_options))
529
597
  end
@@ -103,7 +103,7 @@ module ActionView
103
103
  # escape_once("&lt;&lt; Accept & Checkout")
104
104
  # # => "&lt;&lt; Accept &amp; Checkout"
105
105
  def escape_once(html)
106
- html.to_s.gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
106
+ ActiveSupport::Multibyte.clean(html.to_s).gsub(/[\"><]|&(?!([a-zA-Z]+|(#\d+));)/) { |special| ERB::Util::HTML_ESCAPE[special] }
107
107
  end
108
108
 
109
109
  private
@@ -33,30 +33,31 @@ module ActionView
33
33
  end
34
34
 
35
35
  # Truncates a given +text+ after a given <tt>:length</tt> if +text+ is longer than <tt>:length</tt>
36
- # (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...").
36
+ # (defaults to 30). The last characters will be replaced with the <tt>:omission</tt> (defaults to "...")
37
+ # for a total length not exceeding <tt>:length</tt>.
37
38
  #
38
39
  # ==== Examples
39
40
  #
40
41
  # truncate("Once upon a time in a world far far away")
41
- # # => Once upon a time in a world f...
42
+ # # => Once upon a time in a world...
42
43
  #
43
44
  # truncate("Once upon a time in a world far far away", :length => 14)
44
45
  # # => Once upon a...
45
46
  #
46
47
  # truncate("And they found that many people were sleeping better.", :length => 25, "(clipped)")
47
- # # => And they found that many (clipped)
48
+ # # => And they found t(clipped)
48
49
  #
49
- # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 15)
50
- # # => And they found... (continued)
50
+ # truncate("And they found that many people were sleeping better.", :omission => "... (continued)", :length => 25)
51
+ # # => And they f... (continued)
51
52
  #
52
53
  # You can still use <tt>truncate</tt> with the old API that accepts the
53
54
  # +length+ as its optional second and the +ellipsis+ as its
54
55
  # optional third parameter:
55
56
  # truncate("Once upon a time in a world far far away", 14)
56
- # # => Once upon a time in a world f...
57
+ # # => Once upon a...
57
58
  #
58
- # truncate("And they found that many people were sleeping better.", 15, "... (continued)")
59
- # # => And they found... (continued)
59
+ # truncate("And they found that many people were sleeping better.", 25, "... (continued)")
60
+ # # => And they f... (continued)
60
61
  def truncate(text, *args)
61
62
  options = args.extract_options!
62
63
  unless args.empty?
@@ -234,12 +235,20 @@ module ActionView
234
235
  #
235
236
  # textilize("Visit the Rails website "here":http://www.rubyonrails.org/.)
236
237
  # # => "<p>Visit the Rails website <a href="http://www.rubyonrails.org/">here</a>.</p>"
237
- def textilize(text)
238
+ #
239
+ # textilize("This is worded <strong>strongly</strong>")
240
+ # # => "<p>This is worded <strong>strongly</strong></p>"
241
+ #
242
+ # textilize("This is worded <strong>strongly</strong>", :filter_html)
243
+ # # => "<p>This is worded &lt;strong&gt;strongly&lt;/strong&gt;</p>"
244
+ #
245
+ def textilize(text, *options)
246
+ options ||= [:hard_breaks]
247
+
238
248
  if text.blank?
239
249
  ""
240
250
  else
241
- textilized = RedCloth.new(text, [ :hard_breaks ])
242
- textilized.hard_breaks = true if textilized.respond_to?(:hard_breaks=)
251
+ textilized = RedCloth.new(text, options)
243
252
  textilized.to_html
244
253
  end
245
254
  end
@@ -568,7 +568,7 @@ module ActionView
568
568
  when confirm && popup
569
569
  "if (#{confirm_javascript_function(confirm)}) { #{popup_javascript_function(popup)} };return false;"
570
570
  when confirm && method
571
- "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method)} };return false;"
571
+ "if (#{confirm_javascript_function(confirm)}) { #{method_javascript_function(method, url, href)} };return false;"
572
572
  when confirm
573
573
  "return #{confirm_javascript_function(confirm)};"
574
574
  when method
@@ -108,3 +108,7 @@
108
108
  # The variable :count is also available
109
109
  body: "There were problems with the following fields:"
110
110
 
111
+ support:
112
+ select:
113
+ # default value for :prompt => true in FormOptionsHelper
114
+ prompt: "Please select"
@@ -43,3 +43,19 @@ ActionController::Base.view_paths = FIXTURE_LOAD_PATH
43
43
  CACHED_VIEW_PATHS = ActionView::Base.cache_template_loading? ?
44
44
  ActionController::Base.view_paths :
45
45
  ActionController::Base.view_paths.map {|path| ActionView::Template::EagerPath.new(path.to_s)}
46
+
47
+ class DummyMutex
48
+ def lock
49
+ @locked = true
50
+ end
51
+
52
+ def unlock
53
+ @locked = false
54
+ end
55
+
56
+ def locked?
57
+ @locked
58
+ end
59
+ end
60
+
61
+ ActionController::Reloader.default_lock = DummyMutex.new
@@ -52,7 +52,7 @@ class PageCachingTest < ActionController::TestCase
52
52
  ActionController::Base.perform_caching = true
53
53
 
54
54
  ActionController::Routing::Routes.draw do |map|
55
- map.main '', :controller => 'posts'
55
+ map.main '', :controller => 'posts', :format => nil
56
56
  map.formatted_posts 'posts.:format', :controller => 'posts'
57
57
  map.resources :posts
58
58
  map.connect ':controller/:action/:id'
@@ -118,4 +118,10 @@ class CookieTest < ActionController::TestCase
118
118
  get :delete_cookie_with_path
119
119
  assert_equal ["user_name=; path=/beaten; expires=Thu, 01-Jan-1970 00:00:00 GMT"], @response.headers["Set-Cookie"]
120
120
  end
121
+
122
+ def test_cookies_persist_throughout_request
123
+ get :authenticate
124
+ cookies = @controller.send(:cookies)
125
+ assert_equal 'david', cookies['user_name']
126
+ end
121
127
  end
@@ -2,25 +2,17 @@ require 'abstract_unit'
2
2
 
3
3
  class DispatcherTest < Test::Unit::TestCase
4
4
  Dispatcher = ActionController::Dispatcher
5
+ Reloader = ActionController::Reloader
5
6
 
6
7
  def setup
7
8
  ENV['REQUEST_METHOD'] = 'GET'
8
-
9
- Dispatcher.middleware = ActionController::MiddlewareStack.new do |middleware|
10
- middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/middlewares.rb"))
11
- middleware.instance_eval(File.read(middlewares))
12
- end
13
-
14
- # Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks
15
- Dispatcher.instance_variable_set("@prepare_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
16
- Dispatcher.instance_variable_set("@before_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
17
- Dispatcher.instance_variable_set("@after_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
18
-
9
+ reset_dispatcher
19
10
  Dispatcher.stubs(:require_dependency)
20
11
  end
21
12
 
22
13
  def teardown
23
14
  ENV.delete 'REQUEST_METHOD'
15
+ reset_dispatcher
24
16
  end
25
17
 
26
18
  def test_clears_dependencies_after_dispatch_if_in_loading_mode
@@ -41,6 +33,34 @@ class DispatcherTest < Test::Unit::TestCase
41
33
  dispatch
42
34
  end
43
35
 
36
+ def test_builds_middleware_stack_only_during_initialization_if_not_in_loading_mode
37
+ dispatcher = create_dispatcher
38
+ assert_not_nil dispatcher.instance_variable_get(:"@app")
39
+ dispatcher.instance_variable_set(:"@app", lambda { |env| })
40
+ dispatcher.expects(:build_middleware_stack).never
41
+ dispatcher.call(nil)
42
+ dispatcher.call(nil)
43
+ end
44
+
45
+ def test_rebuilds_middleware_stack_on_every_request_if_in_loading_mode
46
+ dispatcher = create_dispatcher(false)
47
+ dispatcher.instance_variable_set(:"@app", lambda { |env| })
48
+ dispatcher.expects(:build_middleware_stack).twice
49
+ dispatcher.call(nil)
50
+ Reloader.default_lock.unlock
51
+ dispatcher.call(nil)
52
+ end
53
+
54
+ def test_doesnt_wrap_call_in_reloader_if_not_in_loading_mode
55
+ Reloader.expects(:run).never
56
+ dispatch
57
+ end
58
+
59
+ def test_wraps_call_in_reloader_if_in_loading_mode
60
+ Reloader.expects(:run).once
61
+ dispatch(false)
62
+ end
63
+
44
64
  # Stub out dispatch error logger
45
65
  class << Dispatcher
46
66
  def log_failsafe_exception(status, exception); end
@@ -99,6 +119,25 @@ class DispatcherTest < Test::Unit::TestCase
99
119
  Dispatcher.new.call({'rack.input' => StringIO.new('')})
100
120
  end
101
121
 
122
+ def create_dispatcher(cache_classes = true)
123
+ Dispatcher.define_dispatcher_callbacks(cache_classes)
124
+ Dispatcher.new
125
+ end
126
+
127
+ def reset_dispatcher
128
+ Dispatcher.middleware = ActionController::MiddlewareStack.new do |middleware|
129
+ middlewares = File.expand_path(File.join(File.dirname(__FILE__), "../../lib/action_controller/middlewares.rb"))
130
+ middleware.instance_eval(File.read(middlewares))
131
+ end
132
+
133
+ # Clear callbacks as they are redefined by Dispatcher#define_dispatcher_callbacks
134
+ Dispatcher.instance_variable_set("@prepare_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
135
+ Dispatcher.instance_variable_set("@before_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
136
+ Dispatcher.instance_variable_set("@after_dispatch_callbacks", ActiveSupport::Callbacks::CallbackChain.new)
137
+
138
+ Dispatcher.define_dispatcher_callbacks(true)
139
+ end
140
+
102
141
  def assert_subclasses(howmany, klass, message = klass.subclasses.inspect)
103
142
  assert_equal howmany, klass.subclasses.size, message
104
143
  end
@@ -24,7 +24,8 @@ class FilterParamTest < Test::Unit::TestCase
24
24
  [{'foo'=>'bar', 'baz'=>'foo'},{'foo'=>'[FILTERED]', 'baz'=>'[FILTERED]'},%w'foo baz'],
25
25
  [{'bar'=>{'foo'=>'bar','bar'=>'foo'}},{'bar'=>{'foo'=>'[FILTERED]','bar'=>'foo'}},%w'fo'],
26
26
  [{'foo'=>{'foo'=>'bar','bar'=>'foo'}},{'foo'=>'[FILTERED]'},%w'f banana'],
27
- [{'baz'=>[{'foo'=>'baz'}]}, {'baz'=>[{'foo'=>'[FILTERED]'}]}, %w(foo)]]
27
+ [{'baz'=>[{'foo'=>'baz'}]}, {'baz'=>[{'foo'=>'[FILTERED]'}]}, %w(foo)],
28
+ [{'baz'=>[{'foo'=>'baz'}, 1, 2, 3]}, {'baz'=>[{'foo'=>'[FILTERED]'}, 1, 2, 3]}, %w(foo)]]
28
29
 
29
30
  test_hashes.each do |before_filter, after_filter, filter_words|
30
31
  FilterParamController.filter_parameter_logging(*filter_words)
@@ -4,6 +4,7 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
4
4
  class DummyController < ActionController::Base
5
5
  before_filter :authenticate, :only => :index
6
6
  before_filter :authenticate_with_request, :only => :display
7
+ before_filter :authenticate_long_credentials, :only => :show
7
8
 
8
9
  def index
9
10
  render :text => "Hello Secret"
@@ -12,6 +13,10 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
12
13
  def display
13
14
  render :text => 'Definitely Maybe'
14
15
  end
16
+
17
+ def show
18
+ render :text => 'Only for loooooong credentials'
19
+ end
15
20
 
16
21
  private
17
22
 
@@ -28,6 +33,12 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
28
33
  request_http_basic_authentication("SuperSecret")
29
34
  end
30
35
  end
36
+
37
+ def authenticate_long_credentials
38
+ authenticate_or_request_with_http_basic do |username, password|
39
+ username == '1234567890123456789012345678901234567890' && password == '1234567890123456789012345678901234567890'
40
+ end
41
+ end
31
42
  end
32
43
 
33
44
  AUTH_HEADERS = ['HTTP_AUTHORIZATION', 'X-HTTP_AUTHORIZATION', 'X_HTTP_AUTHORIZATION', 'REDIRECT_X_HTTP_AUTHORIZATION']
@@ -42,6 +53,13 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
42
53
  assert_response :success
43
54
  assert_equal 'Hello Secret', @response.body, "Authentication failed for request header #{header}"
44
55
  end
56
+ test "successful authentication with #{header.downcase} and long credentials" do
57
+ @request.env[header] = encode_credentials('1234567890123456789012345678901234567890', '1234567890123456789012345678901234567890')
58
+ get :show
59
+
60
+ assert_response :success
61
+ assert_equal 'Only for loooooong credentials', @response.body, "Authentication failed for request header #{header} and long credentials"
62
+ end
45
63
  end
46
64
 
47
65
  AUTH_HEADERS.each do |header|
@@ -52,6 +70,13 @@ class HttpBasicAuthenticationTest < ActionController::TestCase
52
70
  assert_response :unauthorized
53
71
  assert_equal "HTTP Basic: Access denied.\n", @response.body, "Authentication didn't fail for request header #{header}"
54
72
  end
73
+ test "unsuccessful authentication with #{header.downcase} and long credentials" do
74
+ @request.env[header] = encode_credentials('h4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0rh4x0r', 'worldworldworldworldworldworldworldworld')
75
+ get :show
76
+
77
+ assert_response :unauthorized
78
+ assert_equal "HTTP Basic: Access denied.\n", @response.body, "Authentication didn't fail for request header #{header} and long credentials"
79
+ end
55
80
  end
56
81
 
57
82
  test "authentication request without credential" do
@@ -129,7 +129,7 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
129
129
  assert_equal 'Definitely Maybe', @response.body
130
130
  end
131
131
 
132
- test "authentication request with request-uri that doesn't match credentials digest-uri" do
132
+ test "authentication request with request-uri that doesn't match credentials digest-uri" do
133
133
  @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
134
134
  @request.env['REQUEST_URI'] = "/http_digest_authentication_test/dummy_digest/altered/uri"
135
135
  get :display
@@ -138,10 +138,33 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
138
138
  assert_equal "Authentication Failed", @response.body
139
139
  end
140
140
 
141
- test "authentication request with absolute uri" do
142
- @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:uri => "http://test.host/http_digest_authentication_test/dummy_digest/display",
141
+ test "authentication request with absolute request uri (as in webrick)" do
142
+ @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:username => 'pretty', :password => 'please')
143
+ @request.env['REQUEST_URI'] = "http://test.host/http_digest_authentication_test/dummy_digest"
144
+
145
+ get :display
146
+
147
+ assert_response :success
148
+ assert assigns(:logged_in)
149
+ assert_equal 'Definitely Maybe', @response.body
150
+ end
151
+
152
+ test "authentication request with absolute uri in credentials (as in IE)" do
153
+ @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:url => "http://test.host/http_digest_authentication_test/dummy_digest",
143
154
  :username => 'pretty', :password => 'please')
144
- @request.env['REQUEST_URI'] = "http://test.host/http_digest_authentication_test/dummy_digest/display"
155
+
156
+ get :display
157
+
158
+ assert_response :success
159
+ assert assigns(:logged_in)
160
+ assert_equal 'Definitely Maybe', @response.body
161
+ end
162
+
163
+ test "authentication request with absolute uri in both request and credentials (as in Webrick with IE)" do
164
+ @request.env['HTTP_AUTHORIZATION'] = encode_credentials(:url => "http://test.host/http_digest_authentication_test/dummy_digest",
165
+ :username => 'pretty', :password => 'please')
166
+ @request.env['REQUEST_URI'] = "http://test.host/http_digest_authentication_test/dummy_digest"
167
+
145
168
  get :display
146
169
 
147
170
  assert_response :success
@@ -199,11 +222,11 @@ class HttpDigestAuthenticationTest < ActionController::TestCase
199
222
 
200
223
  credentials = decode_credentials(@response.headers['WWW-Authenticate'])
201
224
  credentials.merge!(options)
202
- credentials.reverse_merge!(:uri => "#{@request.env['REQUEST_URI']}")
225
+ credentials.merge!(:uri => @request.env['REQUEST_URI'].to_s)
203
226
  ActionController::HttpAuthentication::Digest.encode_credentials(method, credentials, password, options[:password_is_ha1])
204
227
  end
205
228
 
206
229
  def decode_credentials(header)
207
230
  ActionController::HttpAuthentication::Digest.decode_credentials(@response.headers['WWW-Authenticate'])
208
231
  end
209
- end
232
+ end