rack 1.6.13 → 2.0.1

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

Potentially problematic release.


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

Files changed (144) hide show
  1. checksums.yaml +5 -5
  2. data/COPYING +1 -1
  3. data/HISTORY.md +138 -8
  4. data/README.rdoc +17 -25
  5. data/Rakefile +6 -14
  6. data/SPEC +8 -9
  7. data/contrib/rack_logo.svg +164 -111
  8. data/example/protectedlobster.rb +1 -1
  9. data/example/protectedlobster.ru +1 -1
  10. data/lib/rack/auth/abstract/request.rb +5 -1
  11. data/lib/rack/auth/digest/params.rb +2 -3
  12. data/lib/rack/auth/digest/request.rb +1 -1
  13. data/lib/rack/body_proxy.rb +14 -9
  14. data/lib/rack/builder.rb +3 -3
  15. data/lib/rack/chunked.rb +5 -5
  16. data/lib/rack/{commonlogger.rb → common_logger.rb} +3 -3
  17. data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
  18. data/lib/rack/content_length.rb +2 -2
  19. data/lib/rack/deflater.rb +4 -4
  20. data/lib/rack/directory.rb +66 -54
  21. data/lib/rack/etag.rb +4 -3
  22. data/lib/rack/events.rb +154 -0
  23. data/lib/rack/file.rb +63 -39
  24. data/lib/rack/handler/cgi.rb +15 -16
  25. data/lib/rack/handler/fastcgi.rb +13 -14
  26. data/lib/rack/handler/lsws.rb +11 -11
  27. data/lib/rack/handler/scgi.rb +15 -15
  28. data/lib/rack/handler/thin.rb +3 -0
  29. data/lib/rack/handler/webrick.rb +22 -24
  30. data/lib/rack/handler.rb +3 -25
  31. data/lib/rack/head.rb +15 -17
  32. data/lib/rack/lint.rb +38 -38
  33. data/lib/rack/lobster.rb +1 -1
  34. data/lib/rack/lock.rb +6 -10
  35. data/lib/rack/logger.rb +2 -2
  36. data/lib/rack/media_type.rb +38 -0
  37. data/lib/rack/{methodoverride.rb → method_override.rb} +4 -11
  38. data/lib/rack/mime.rb +18 -5
  39. data/lib/rack/mock.rb +35 -53
  40. data/lib/rack/multipart/generator.rb +5 -5
  41. data/lib/rack/multipart/parser.rb +272 -158
  42. data/lib/rack/multipart/uploaded_file.rb +1 -2
  43. data/lib/rack/multipart.rb +35 -6
  44. data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
  45. data/lib/rack/query_parser.rb +192 -0
  46. data/lib/rack/recursive.rb +8 -8
  47. data/lib/rack/request.rb +383 -307
  48. data/lib/rack/response.rb +129 -56
  49. data/lib/rack/rewindable_input.rb +1 -12
  50. data/lib/rack/runtime.rb +10 -18
  51. data/lib/rack/sendfile.rb +5 -7
  52. data/lib/rack/server.rb +31 -25
  53. data/lib/rack/session/abstract/id.rb +95 -135
  54. data/lib/rack/session/cookie.rb +26 -28
  55. data/lib/rack/session/memcache.rb +8 -14
  56. data/lib/rack/session/pool.rb +14 -21
  57. data/lib/rack/show_exceptions.rb +386 -0
  58. data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
  59. data/lib/rack/static.rb +30 -5
  60. data/lib/rack/tempfile_reaper.rb +2 -2
  61. data/lib/rack/urlmap.rb +15 -14
  62. data/lib/rack/utils.rb +135 -210
  63. data/lib/rack.rb +70 -21
  64. data/rack.gemspec +7 -5
  65. data/test/builder/an_underscore_app.rb +5 -0
  66. data/test/builder/options.ru +1 -1
  67. data/test/cgi/test.fcgi +1 -0
  68. data/test/cgi/test.gz +0 -0
  69. data/test/helper.rb +34 -0
  70. data/test/multipart/filename_with_encoded_words +7 -0
  71. data/test/multipart/{filename_with_null_byte → filename_with_single_quote} +1 -1
  72. data/test/multipart/quoted +15 -0
  73. data/test/multipart/rack-logo.png +0 -0
  74. data/test/multipart/unity3d_wwwform +11 -0
  75. data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
  76. data/test/spec_auth_basic.rb +27 -19
  77. data/test/spec_auth_digest.rb +47 -46
  78. data/test/spec_body_proxy.rb +27 -27
  79. data/test/spec_builder.rb +51 -41
  80. data/test/spec_cascade.rb +24 -22
  81. data/test/spec_cgi.rb +49 -67
  82. data/test/spec_chunked.rb +36 -34
  83. data/test/{spec_commonlogger.rb → spec_common_logger.rb} +23 -21
  84. data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
  85. data/test/spec_config.rb +3 -2
  86. data/test/spec_content_length.rb +18 -17
  87. data/test/spec_content_type.rb +13 -12
  88. data/test/spec_deflater.rb +66 -40
  89. data/test/spec_directory.rb +87 -27
  90. data/test/spec_etag.rb +32 -31
  91. data/test/spec_events.rb +133 -0
  92. data/test/spec_fastcgi.rb +50 -72
  93. data/test/spec_file.rb +107 -77
  94. data/test/spec_handler.rb +19 -34
  95. data/test/spec_head.rb +15 -14
  96. data/test/spec_lint.rb +162 -197
  97. data/test/spec_lobster.rb +24 -23
  98. data/test/spec_lock.rb +69 -39
  99. data/test/spec_logger.rb +4 -3
  100. data/test/spec_media_type.rb +42 -0
  101. data/test/spec_method_override.rb +83 -0
  102. data/test/spec_mime.rb +19 -19
  103. data/test/spec_mock.rb +196 -151
  104. data/test/spec_multipart.rb +317 -201
  105. data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
  106. data/test/spec_recursive.rb +17 -14
  107. data/test/spec_request.rb +768 -607
  108. data/test/spec_response.rb +214 -111
  109. data/test/spec_rewindable_input.rb +50 -40
  110. data/test/spec_runtime.rb +11 -10
  111. data/test/spec_sendfile.rb +30 -35
  112. data/test/spec_server.rb +78 -52
  113. data/test/spec_session_abstract_id.rb +11 -33
  114. data/test/spec_session_abstract_session_hash.rb +28 -0
  115. data/test/spec_session_cookie.rb +97 -65
  116. data/test/spec_session_memcache.rb +63 -101
  117. data/test/spec_session_pool.rb +48 -84
  118. data/test/spec_show_exceptions.rb +80 -0
  119. data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
  120. data/test/spec_static.rb +71 -32
  121. data/test/spec_tempfile_reaper.rb +11 -10
  122. data/test/spec_thin.rb +55 -50
  123. data/test/spec_urlmap.rb +79 -78
  124. data/test/spec_utils.rb +441 -346
  125. data/test/spec_version.rb +2 -8
  126. data/test/spec_webrick.rb +91 -67
  127. data/test/static/foo.html +1 -0
  128. data/test/testrequest.rb +1 -1
  129. data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
  130. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
  131. metadata +103 -69
  132. data/KNOWN-ISSUES +0 -44
  133. data/lib/rack/backports/uri/common_18.rb +0 -56
  134. data/lib/rack/backports/uri/common_192.rb +0 -52
  135. data/lib/rack/backports/uri/common_193.rb +0 -29
  136. data/lib/rack/handler/evented_mongrel.rb +0 -8
  137. data/lib/rack/handler/mongrel.rb +0 -106
  138. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  139. data/lib/rack/showexceptions.rb +0 -387
  140. data/lib/rack/utils/okjson.rb +0 -600
  141. data/test/spec_methodoverride.rb +0 -111
  142. data/test/spec_mongrel.rb +0 -182
  143. data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
  144. data/test/spec_showexceptions.rb +0 -98
data/test/spec_utils.rb CHANGED
@@ -1,288 +1,334 @@
1
1
  # -*- encoding: utf-8 -*-
2
+ require 'minitest/autorun'
2
3
  require 'rack/utils'
3
4
  require 'rack/mock'
4
5
  require 'timeout'
5
6
 
6
7
  describe Rack::Utils do
7
8
 
8
- # A helper method which checks
9
- # if certain query parameters
10
- # are equal.
11
- def equal_query_to(query)
12
- parts = query.split('&')
13
- lambda{|other| (parts & other.split('&')) == parts }
9
+ def assert_sets exp, act
10
+ exp = Set.new exp.split '&'
11
+ act = Set.new act.split '&'
12
+
13
+ assert_equal exp, act
14
+ end
15
+
16
+ def assert_query exp, act
17
+ assert_sets exp, Rack::Utils.build_query(act)
14
18
  end
15
19
 
16
- def kcodeu
17
- one8 = RUBY_VERSION.to_f < 1.9
18
- default_kcode, $KCODE = $KCODE, 'U' if one8
19
- yield
20
- ensure
21
- $KCODE = default_kcode if one8
20
+ def assert_nested_query exp, act
21
+ assert_sets exp, Rack::Utils.build_nested_query(act)
22
+ end
23
+
24
+ it 'can be mixed in and used' do
25
+ instance = Class.new {
26
+ include Rack::Utils
27
+
28
+ public :parse_nested_query
29
+ public :parse_query
30
+ }.new
31
+
32
+ assert_equal({ "foo" => "bar" }, instance.parse_nested_query("foo=bar"))
33
+ assert_equal({ "foo" => "bar" }, instance.parse_query("foo=bar"))
22
34
  end
23
35
 
24
- should "round trip binary data" do
36
+ it "round trip binary data" do
25
37
  r = [218, 0].pack 'CC'
26
- if defined?(::Encoding)
27
38
  z = Rack::Utils.unescape(Rack::Utils.escape(r), Encoding::BINARY)
28
- else
29
- z = Rack::Utils.unescape(Rack::Utils.escape(r))
30
- end
31
- r.should.equal z
39
+ r.must_equal z
32
40
  end
33
41
 
34
- should "escape correctly" do
35
- Rack::Utils.escape("fo<o>bar").should.equal "fo%3Co%3Ebar"
36
- Rack::Utils.escape("a space").should.equal "a+space"
42
+ it "escape correctly" do
43
+ Rack::Utils.escape("fo<o>bar").must_equal "fo%3Co%3Ebar"
44
+ Rack::Utils.escape("a space").must_equal "a+space"
37
45
  Rack::Utils.escape("q1!2\"'w$5&7/z8)?\\").
38
- should.equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
46
+ must_equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
39
47
  end
40
48
 
41
- should "escape correctly for multibyte characters" do
49
+ it "escape correctly for multibyte characters" do
42
50
  matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
43
- matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
44
- Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
51
+ matz_name.force_encoding(Encoding::UTF_8)
52
+ Rack::Utils.escape(matz_name).must_equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
45
53
  matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
46
54
  matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
47
- Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
48
- end
49
-
50
- if RUBY_VERSION[/^\d+\.\d+/] == '1.8'
51
- should "escape correctly for multibyte characters if $KCODE is set to 'U'" do
52
- kcodeu do
53
- matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
54
- matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
55
- Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
56
- matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
57
- matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
58
- Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
59
- end
60
- end
55
+ Rack::Utils.escape(matz_name_sep).must_equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
56
+ end
61
57
 
62
- should "unescape multibyte characters correctly if $KCODE is set to 'U'" do
63
- kcodeu do
64
- Rack::Utils.unescape('%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8').should.equal(
65
- "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0])
66
- end
67
- end
58
+ it "escape objects that responds to to_s" do
59
+ Rack::Utils.escape(:id).must_equal "id"
68
60
  end
69
61
 
70
- should "escape objects that responds to to_s" do
71
- kcodeu do
72
- Rack::Utils.escape(:id).should.equal "id"
73
- end
62
+ it "escape non-UTF8 strings" do
63
+ Rack::Utils.escape("ø".encode("ISO-8859-1")).must_equal "%F8"
74
64
  end
75
65
 
76
- if "".respond_to?(:encode)
77
- should "escape non-UTF8 strings" do
78
- Rack::Utils.escape("ø".encode("ISO-8859-1")).should.equal "%F8"
66
+ it "not hang on escaping long strings that end in % (http://redmine.ruby-lang.org/issues/5149)" do
67
+ Timeout.timeout(1) do
68
+ lambda {
69
+ URI.decode_www_form_component "A string that causes catastrophic backtracking as it gets longer %"
70
+ }.must_raise ArgumentError
79
71
  end
80
72
  end
81
-
82
- should "not hang on escaping long strings that end in % (http://redmine.ruby-lang.org/issues/5149)" do
83
- lambda {
84
- timeout(1) do
85
- lambda {
86
- URI.decode_www_form_component "A string that causes catastrophic backtracking as it gets longer %"
87
- }.should.raise(ArgumentError)
88
- end
89
- }.should.not.raise(Timeout::Error)
90
- end
91
73
 
92
- should "escape path spaces with %20" do
93
- Rack::Utils.escape_path("foo bar").should.equal "foo%20bar"
74
+ it "escape path spaces with %20" do
75
+ Rack::Utils.escape_path("foo bar").must_equal "foo%20bar"
94
76
  end
95
77
 
96
- should "unescape correctly" do
97
- Rack::Utils.unescape("fo%3Co%3Ebar").should.equal "fo<o>bar"
98
- Rack::Utils.unescape("a+space").should.equal "a space"
99
- Rack::Utils.unescape("a%20space").should.equal "a space"
78
+ it "unescape correctly" do
79
+ Rack::Utils.unescape("fo%3Co%3Ebar").must_equal "fo<o>bar"
80
+ Rack::Utils.unescape("a+space").must_equal "a space"
81
+ Rack::Utils.unescape("a%20space").must_equal "a space"
100
82
  Rack::Utils.unescape("q1%212%22%27w%245%267%2Fz8%29%3F%5C").
101
- should.equal "q1!2\"'w$5&7/z8)?\\"
83
+ must_equal "q1!2\"'w$5&7/z8)?\\"
102
84
  end
103
85
 
104
- should "parse query strings correctly" do
86
+ it "parse query strings correctly" do
105
87
  Rack::Utils.parse_query("foo=bar").
106
- should.equal "foo" => "bar"
88
+ must_equal "foo" => "bar"
107
89
  Rack::Utils.parse_query("foo=\"bar\"").
108
- should.equal "foo" => "\"bar\""
90
+ must_equal "foo" => "\"bar\""
109
91
  Rack::Utils.parse_query("foo=bar&foo=quux").
110
- should.equal "foo" => ["bar", "quux"]
92
+ must_equal "foo" => ["bar", "quux"]
111
93
  Rack::Utils.parse_query("foo=1&bar=2").
112
- should.equal "foo" => "1", "bar" => "2"
94
+ must_equal "foo" => "1", "bar" => "2"
113
95
  Rack::Utils.parse_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
114
- should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
115
- Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar"
116
- Rack::Utils.parse_query("=").should.equal "" => ""
117
- Rack::Utils.parse_query("=value").should.equal "" => "value"
118
- Rack::Utils.parse_query("key=").should.equal "key" => ""
119
- Rack::Utils.parse_query("&key&").should.equal "key" => nil
120
- Rack::Utils.parse_query(";key;", ";,").should.equal "key" => nil
121
- Rack::Utils.parse_query(",key,", ";,").should.equal "key" => nil
122
- Rack::Utils.parse_query(";foo=bar,;", ";,").should.equal "foo" => "bar"
123
- Rack::Utils.parse_query(",foo=bar;,", ";,").should.equal "foo" => "bar"
124
- end
125
-
126
- should "not create infinite loops with cycle structures" do
96
+ must_equal "my weird field" => "q1!2\"'w$5&7/z8)?"
97
+ Rack::Utils.parse_query("foo%3Dbaz=bar").must_equal "foo=baz" => "bar"
98
+ Rack::Utils.parse_query("=").must_equal "" => ""
99
+ Rack::Utils.parse_query("=value").must_equal "" => "value"
100
+ Rack::Utils.parse_query("key=").must_equal "key" => ""
101
+ Rack::Utils.parse_query("&key&").must_equal "key" => nil
102
+ Rack::Utils.parse_query(";key;", ";,").must_equal "key" => nil
103
+ Rack::Utils.parse_query(",key,", ";,").must_equal "key" => nil
104
+ Rack::Utils.parse_query(";foo=bar,;", ";,").must_equal "foo" => "bar"
105
+ Rack::Utils.parse_query(",foo=bar;,", ";,").must_equal "foo" => "bar"
106
+ end
107
+
108
+ it "not create infinite loops with cycle structures" do
127
109
  ex = { "foo" => nil }
128
110
  ex["foo"] = ex
129
111
 
130
- params = Rack::Utils::KeySpaceConstrainedParams.new
112
+ params = Rack::Utils::KeySpaceConstrainedParams.new(65536)
131
113
  params['foo'] = params
132
- lambda {
133
- params.to_params_hash.to_s.should.equal ex.to_s
134
- }.should.not.raise
114
+ params.to_params_hash.to_s.must_equal ex.to_s
135
115
  end
136
116
 
137
- should "raise an exception if the params are too deep" do
117
+ it "parse nil as an empty query string" do
118
+ Rack::Utils.parse_nested_query(nil).must_equal({})
119
+ end
120
+
121
+ it "raise an exception if the params are too deep" do
138
122
  len = Rack::Utils.param_depth_limit
139
123
 
140
124
  lambda {
141
125
  Rack::Utils.parse_nested_query("foo#{"[a]" * len}=bar")
142
- }.should.raise(RangeError)
126
+ }.must_raise(RangeError)
143
127
 
144
- lambda {
145
- Rack::Utils.parse_nested_query("foo#{"[a]" * (len - 1)}=bar")
146
- }.should.not.raise
128
+ Rack::Utils.parse_nested_query("foo#{"[a]" * (len - 1)}=bar")
147
129
  end
148
130
 
149
- should "parse nested query strings correctly" do
131
+ it "parse nested query strings correctly" do
150
132
  Rack::Utils.parse_nested_query("foo").
151
- should.equal "foo" => nil
133
+ must_equal "foo" => nil
152
134
  Rack::Utils.parse_nested_query("foo=").
153
- should.equal "foo" => ""
135
+ must_equal "foo" => ""
154
136
  Rack::Utils.parse_nested_query("foo=bar").
155
- should.equal "foo" => "bar"
137
+ must_equal "foo" => "bar"
156
138
  Rack::Utils.parse_nested_query("foo=\"bar\"").
157
- should.equal "foo" => "\"bar\""
139
+ must_equal "foo" => "\"bar\""
158
140
 
159
141
  Rack::Utils.parse_nested_query("foo=bar&foo=quux").
160
- should.equal "foo" => "quux"
142
+ must_equal "foo" => "quux"
161
143
  Rack::Utils.parse_nested_query("foo&foo=").
162
- should.equal "foo" => ""
144
+ must_equal "foo" => ""
163
145
  Rack::Utils.parse_nested_query("foo=1&bar=2").
164
- should.equal "foo" => "1", "bar" => "2"
146
+ must_equal "foo" => "1", "bar" => "2"
165
147
  Rack::Utils.parse_nested_query("&foo=1&&bar=2").
166
- should.equal "foo" => "1", "bar" => "2"
148
+ must_equal "foo" => "1", "bar" => "2"
167
149
  Rack::Utils.parse_nested_query("foo&bar=").
168
- should.equal "foo" => nil, "bar" => ""
150
+ must_equal "foo" => nil, "bar" => ""
169
151
  Rack::Utils.parse_nested_query("foo=bar&baz=").
170
- should.equal "foo" => "bar", "baz" => ""
152
+ must_equal "foo" => "bar", "baz" => ""
171
153
  Rack::Utils.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
172
- should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
154
+ must_equal "my weird field" => "q1!2\"'w$5&7/z8)?"
173
155
 
174
156
  Rack::Utils.parse_nested_query("a=b&pid%3D1234=1023").
175
- should.equal "pid=1234" => "1023", "a" => "b"
157
+ must_equal "pid=1234" => "1023", "a" => "b"
176
158
 
177
159
  Rack::Utils.parse_nested_query("foo[]").
178
- should.equal "foo" => [nil]
160
+ must_equal "foo" => [nil]
179
161
  Rack::Utils.parse_nested_query("foo[]=").
180
- should.equal "foo" => [""]
162
+ must_equal "foo" => [""]
181
163
  Rack::Utils.parse_nested_query("foo[]=bar").
182
- should.equal "foo" => ["bar"]
164
+ must_equal "foo" => ["bar"]
183
165
  Rack::Utils.parse_nested_query("foo[]=bar&foo").
184
- should.equal "foo" => nil
166
+ must_equal "foo" => nil
185
167
  Rack::Utils.parse_nested_query("foo[]=bar&foo[").
186
- should.equal "foo" => ["bar"], "foo[" => nil
168
+ must_equal "foo" => ["bar"], "foo[" => nil
187
169
  Rack::Utils.parse_nested_query("foo[]=bar&foo[=baz").
188
- should.equal "foo" => ["bar"], "foo[" => "baz"
170
+ must_equal "foo" => ["bar"], "foo[" => "baz"
189
171
  Rack::Utils.parse_nested_query("foo[]=bar&foo[]").
190
- should.equal "foo" => ["bar", nil]
172
+ must_equal "foo" => ["bar", nil]
191
173
  Rack::Utils.parse_nested_query("foo[]=bar&foo[]=").
192
- should.equal "foo" => ["bar", ""]
174
+ must_equal "foo" => ["bar", ""]
193
175
 
194
176
  Rack::Utils.parse_nested_query("foo[]=1&foo[]=2").
195
- should.equal "foo" => ["1", "2"]
177
+ must_equal "foo" => ["1", "2"]
196
178
  Rack::Utils.parse_nested_query("foo=bar&baz[]=1&baz[]=2&baz[]=3").
197
- should.equal "foo" => "bar", "baz" => ["1", "2", "3"]
179
+ must_equal "foo" => "bar", "baz" => ["1", "2", "3"]
198
180
  Rack::Utils.parse_nested_query("foo[]=bar&baz[]=1&baz[]=2&baz[]=3").
199
- should.equal "foo" => ["bar"], "baz" => ["1", "2", "3"]
181
+ must_equal "foo" => ["bar"], "baz" => ["1", "2", "3"]
200
182
 
201
183
  Rack::Utils.parse_nested_query("x[y][z]=1").
202
- should.equal "x" => {"y" => {"z" => "1"}}
184
+ must_equal "x" => {"y" => {"z" => "1"}}
203
185
  Rack::Utils.parse_nested_query("x[y][z][]=1").
204
- should.equal "x" => {"y" => {"z" => ["1"]}}
186
+ must_equal "x" => {"y" => {"z" => ["1"]}}
205
187
  Rack::Utils.parse_nested_query("x[y][z]=1&x[y][z]=2").
206
- should.equal "x" => {"y" => {"z" => "2"}}
188
+ must_equal "x" => {"y" => {"z" => "2"}}
207
189
  Rack::Utils.parse_nested_query("x[y][z][]=1&x[y][z][]=2").
208
- should.equal "x" => {"y" => {"z" => ["1", "2"]}}
190
+ must_equal "x" => {"y" => {"z" => ["1", "2"]}}
209
191
 
210
192
  Rack::Utils.parse_nested_query("x[y][][z]=1").
211
- should.equal "x" => {"y" => [{"z" => "1"}]}
193
+ must_equal "x" => {"y" => [{"z" => "1"}]}
212
194
  Rack::Utils.parse_nested_query("x[y][][z][]=1").
213
- should.equal "x" => {"y" => [{"z" => ["1"]}]}
195
+ must_equal "x" => {"y" => [{"z" => ["1"]}]}
214
196
  Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2").
215
- should.equal "x" => {"y" => [{"z" => "1", "w" => "2"}]}
197
+ must_equal "x" => {"y" => [{"z" => "1", "w" => "2"}]}
216
198
 
217
199
  Rack::Utils.parse_nested_query("x[y][][v][w]=1").
218
- should.equal "x" => {"y" => [{"v" => {"w" => "1"}}]}
200
+ must_equal "x" => {"y" => [{"v" => {"w" => "1"}}]}
219
201
  Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][v][w]=2").
220
- should.equal "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}
202
+ must_equal "x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}
221
203
 
222
204
  Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][z]=2").
223
- should.equal "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}
205
+ must_equal "x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}
224
206
  Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3").
225
- should.equal "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}
207
+ must_equal "x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}
208
+
209
+ Rack::Utils.parse_nested_query("x[][y]=1&x[][z][w]=a&x[][y]=2&x[][z][w]=b").
210
+ must_equal "x" => [{"y" => "1", "z" => {"w" => "a"}}, {"y" => "2", "z" => {"w" => "b"}}]
211
+ Rack::Utils.parse_nested_query("x[][z][w]=a&x[][y]=1&x[][z][w]=b&x[][y]=2").
212
+ must_equal "x" => [{"y" => "1", "z" => {"w" => "a"}}, {"y" => "2", "z" => {"w" => "b"}}]
213
+
214
+ Rack::Utils.parse_nested_query("data[books][][data][page]=1&data[books][][data][page]=2").
215
+ must_equal "data" => { "books" => [{ "data" => { "page" => "1"}}, { "data" => { "page" => "2"}}] }
226
216
 
227
217
  lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y]z=2") }.
228
- should.raise(Rack::Utils::ParameterTypeError).
229
- message.should.equal "expected Hash (got String) for param `y'"
218
+ must_raise(Rack::Utils::ParameterTypeError).
219
+ message.must_equal "expected Hash (got String) for param `y'"
230
220
 
231
221
  lambda { Rack::Utils.parse_nested_query("x[y]=1&x[]=1") }.
232
- should.raise(Rack::Utils::ParameterTypeError).
233
- message.should.match(/expected Array \(got [^)]*\) for param `x'/)
222
+ must_raise(Rack::Utils::ParameterTypeError).
223
+ message.must_match(/expected Array \(got [^)]*\) for param `x'/)
234
224
 
235
225
  lambda { Rack::Utils.parse_nested_query("x[y]=1&x[y][][w]=2") }.
236
- should.raise(Rack::Utils::ParameterTypeError).
237
- message.should.equal "expected Array (got String) for param `y'"
238
-
239
- if RUBY_VERSION.to_f > 1.9
240
- lambda { Rack::Utils.parse_nested_query("foo%81E=1") }.
241
- should.raise(Rack::Utils::InvalidParameterError).
242
- message.should.equal "invalid byte sequence in UTF-8"
226
+ must_raise(Rack::Utils::ParameterTypeError).
227
+ message.must_equal "expected Array (got String) for param `y'"
228
+
229
+ lambda { Rack::Utils.parse_nested_query("foo%81E=1") }.
230
+ must_raise(Rack::Utils::InvalidParameterError).
231
+ message.must_equal "invalid byte sequence in UTF-8"
232
+ end
233
+
234
+ it "only moves to a new array when the full key has been seen" do
235
+ Rack::Utils.parse_nested_query("x[][y][][z]=1&x[][y][][w]=2").
236
+ must_equal "x" => [{"y" => [{"z" => "1", "w" => "2"}]}]
237
+
238
+ Rack::Utils.parse_nested_query(
239
+ "x[][id]=1&x[][y][a]=5&x[][y][b]=7&x[][z][id]=3&x[][z][w]=0&x[][id]=2&x[][y][a]=6&x[][y][b]=8&x[][z][id]=4&x[][z][w]=0"
240
+ ).must_equal "x" => [
241
+ {"id" => "1", "y" => {"a" => "5", "b" => "7"}, "z" => {"id" => "3", "w" => "0"}},
242
+ {"id" => "2", "y" => {"a" => "6", "b" => "8"}, "z" => {"id" => "4", "w" => "0"}},
243
+ ]
244
+ end
245
+
246
+ it "allow setting the params hash class to use for parsing query strings" do
247
+ begin
248
+ default_parser = Rack::Utils.default_query_parser
249
+ param_parser_class = Class.new(Rack::QueryParser::Params) do
250
+ def initialize(*)
251
+ super
252
+ @params = Hash.new{|h,k| h[k.to_s] if k.is_a?(Symbol)}
253
+ end
254
+ end
255
+ Rack::Utils.default_query_parser = Rack::QueryParser.new(param_parser_class, 65536, 100)
256
+ Rack::Utils.parse_query(",foo=bar;,", ";,")[:foo].must_equal "bar"
257
+ Rack::Utils.parse_nested_query("x[y][][z]=1&x[y][][w]=2")[:x][:y][0][:z].must_equal "1"
258
+ ensure
259
+ Rack::Utils.default_query_parser = default_parser
243
260
  end
244
261
  end
245
262
 
246
- should "build query strings correctly" do
247
- Rack::Utils.build_query("foo" => "bar").should.be equal_query_to("foo=bar")
248
- Rack::Utils.build_query("foo" => ["bar", "quux"]).
249
- should.be equal_query_to("foo=bar&foo=quux")
250
- Rack::Utils.build_query("foo" => "1", "bar" => "2").
251
- should.be equal_query_to("foo=1&bar=2")
252
- Rack::Utils.build_query("my weird field" => "q1!2\"'w$5&7/z8)?").
253
- should.be equal_query_to("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F")
254
- end
255
-
256
- should "build nested query strings correctly" do
257
- Rack::Utils.build_nested_query("foo" => nil).should.equal "foo"
258
- Rack::Utils.build_nested_query("foo" => "").should.equal "foo="
259
- Rack::Utils.build_nested_query("foo" => "bar").should.equal "foo=bar"
260
-
261
- Rack::Utils.build_nested_query("foo" => "1", "bar" => "2").
262
- should.be equal_query_to("foo=1&bar=2")
263
- Rack::Utils.build_nested_query("foo" => 1, "bar" => 2).
264
- should.be equal_query_to("foo=1&bar=2")
265
- Rack::Utils.build_nested_query("my weird field" => "q1!2\"'w$5&7/z8)?").
266
- should.be equal_query_to("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F")
267
-
268
- Rack::Utils.build_nested_query("foo" => [nil]).
269
- should.equal "foo[]"
270
- Rack::Utils.build_nested_query("foo" => [""]).
271
- should.equal "foo[]="
272
- Rack::Utils.build_nested_query("foo" => ["bar"]).
273
- should.equal "foo[]=bar"
274
- Rack::Utils.build_nested_query('foo' => []).
275
- should.equal ''
276
- Rack::Utils.build_nested_query('foo' => {}).
277
- should.equal ''
278
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => []).
279
- should.equal 'foo=bar'
280
- Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => {}).
281
- should.equal 'foo=bar'
282
-
283
- # The ordering of the output query string is unpredictable with 1.8's
284
- # unordered hash. Test that build_nested_query performs the inverse
285
- # function of parse_nested_query.
263
+ it "build query strings correctly" do
264
+ assert_query "foo=bar", "foo" => "bar"
265
+ assert_query "foo=bar&foo=quux", "foo" => ["bar", "quux"]
266
+ assert_query "foo=1&bar=2", "foo" => "1", "bar" => "2"
267
+ assert_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F",
268
+ "my weird field" => "q1!2\"'w$5&7/z8)?")
269
+ end
270
+
271
+ it "build nested query strings correctly" do
272
+ Rack::Utils.build_nested_query("foo" => nil).must_equal "foo"
273
+ Rack::Utils.build_nested_query("foo" => "").must_equal "foo="
274
+ Rack::Utils.build_nested_query("foo" => "bar").must_equal "foo=bar"
275
+
276
+ assert_nested_query("foo=1&bar=2",
277
+ "foo" => "1", "bar" => "2")
278
+ assert_nested_query("foo=1&bar=2",
279
+ "foo" => 1, "bar" => 2)
280
+ assert_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F",
281
+ "my weird field" => "q1!2\"'w$5&7/z8)?")
282
+
283
+ Rack::Utils.build_nested_query("foo" => [nil]).must_equal "foo[]"
284
+ Rack::Utils.build_nested_query("foo" => [""]).must_equal "foo[]="
285
+ Rack::Utils.build_nested_query("foo" => ["bar"]).must_equal "foo[]=bar"
286
+ Rack::Utils.build_nested_query('foo' => []).must_equal ''
287
+ Rack::Utils.build_nested_query('foo' => {}).must_equal ''
288
+ Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => []).must_equal 'foo=bar'
289
+ Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => {}).must_equal 'foo=bar'
290
+
291
+ Rack::Utils.build_nested_query('foo' => nil, 'bar' => '').
292
+ must_equal 'foo&bar='
293
+ Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => '').
294
+ must_equal 'foo=bar&baz='
295
+ Rack::Utils.build_nested_query('foo' => ['1', '2']).
296
+ must_equal 'foo[]=1&foo[]=2'
297
+ Rack::Utils.build_nested_query('foo' => 'bar', 'baz' => ['1', '2', '3']).
298
+ must_equal 'foo=bar&baz[]=1&baz[]=2&baz[]=3'
299
+ Rack::Utils.build_nested_query('foo' => ['bar'], 'baz' => ['1', '2', '3']).
300
+ must_equal 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3'
301
+ Rack::Utils.build_nested_query('foo' => ['bar'], 'baz' => ['1', '2', '3']).
302
+ must_equal 'foo[]=bar&baz[]=1&baz[]=2&baz[]=3'
303
+ Rack::Utils.build_nested_query('x' => { 'y' => { 'z' => '1' } }).
304
+ must_equal 'x[y][z]=1'
305
+ Rack::Utils.build_nested_query('x' => { 'y' => { 'z' => ['1'] } }).
306
+ must_equal 'x[y][z][]=1'
307
+ Rack::Utils.build_nested_query('x' => { 'y' => { 'z' => ['1', '2'] } }).
308
+ must_equal 'x[y][z][]=1&x[y][z][]=2'
309
+ Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1' }] }).
310
+ must_equal 'x[y][][z]=1'
311
+ Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => ['1'] }] }).
312
+ must_equal 'x[y][][z][]=1'
313
+ Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1', 'w' => '2' }] }).
314
+ must_equal 'x[y][][z]=1&x[y][][w]=2'
315
+ Rack::Utils.build_nested_query('x' => { 'y' => [{ 'v' => { 'w' => '1' } }] }).
316
+ must_equal 'x[y][][v][w]=1'
317
+ Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1', 'v' => { 'w' => '2' } }] }).
318
+ must_equal 'x[y][][z]=1&x[y][][v][w]=2'
319
+ Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1' }, { 'z' => '2' }] }).
320
+ must_equal 'x[y][][z]=1&x[y][][z]=2'
321
+ Rack::Utils.build_nested_query('x' => { 'y' => [{ 'z' => '1', 'w' => 'a' }, { 'z' => '2', 'w' => '3' }] }).
322
+ must_equal 'x[y][][z]=1&x[y][][w]=a&x[y][][z]=2&x[y][][w]=3'
323
+ Rack::Utils.build_nested_query({"foo" => ["1", ["2"]]}).
324
+ must_equal 'foo[]=1&foo[][]=2'
325
+
326
+ lambda { Rack::Utils.build_nested_query("foo=bar") }.
327
+ must_raise(ArgumentError).
328
+ message.must_equal "value must be a Hash"
329
+ end
330
+
331
+ it 'performs the inverse function of #parse_nested_query' do
286
332
  [{"foo" => nil, "bar" => ""},
287
333
  {"foo" => "bar", "baz" => ""},
288
334
  {"foo" => ["1", "2"]},
@@ -299,296 +345,345 @@ describe Rack::Utils do
299
345
  {"x" => {"y" => [{"v" => {"w" => "1"}}]}},
300
346
  {"x" => {"y" => [{"z" => "1", "v" => {"w" => "2"}}]}},
301
347
  {"x" => {"y" => [{"z" => "1"}, {"z" => "2"}]}},
302
- {"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}}
348
+ {"x" => {"y" => [{"z" => "1", "w" => "a"}, {"z" => "2", "w" => "3"}]}},
349
+ {"foo" => ["1", ["2"]]},
303
350
  ].each { |params|
304
351
  qs = Rack::Utils.build_nested_query(params)
305
- Rack::Utils.parse_nested_query(qs).should.equal params
352
+ Rack::Utils.parse_nested_query(qs).must_equal params
306
353
  }
307
354
 
308
355
  lambda { Rack::Utils.build_nested_query("foo=bar") }.
309
- should.raise(ArgumentError).
310
- message.should.equal "value must be a Hash"
356
+ must_raise(ArgumentError).
357
+ message.must_equal "value must be a Hash"
311
358
  end
312
359
 
313
- should "parse query strings that have a non-existent value" do
360
+ it "parse query strings that have a non-existent value" do
314
361
  key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
315
- Rack::Utils.parse_query(key).should.equal Rack::Utils.unescape(key) => nil
362
+ Rack::Utils.parse_query(key).must_equal Rack::Utils.unescape(key) => nil
316
363
  end
317
364
 
318
- should "build query strings without = with non-existent values" do
365
+ it "build query strings without = with non-existent values" do
319
366
  key = "post/2011/08/27/Deux-%22rat%C3%A9s%22-de-l-Universit"
320
367
  key = Rack::Utils.unescape(key)
321
- Rack::Utils.build_query(key => nil).should.equal Rack::Utils.escape(key)
368
+ Rack::Utils.build_query(key => nil).must_equal Rack::Utils.escape(key)
322
369
  end
323
370
 
324
- should "parse q-values" do
371
+ it "parse q-values" do
325
372
  # XXX handle accept-extension
326
- Rack::Utils.q_values("foo;q=0.5,bar,baz;q=0.9").should.equal [
373
+ Rack::Utils.q_values("foo;q=0.5,bar,baz;q=0.9").must_equal [
327
374
  [ 'foo', 0.5 ],
328
375
  [ 'bar', 1.0 ],
329
376
  [ 'baz', 0.9 ]
330
377
  ]
331
378
  end
332
379
 
333
- should "select best quality match" do
334
- Rack::Utils.best_q_match("text/html", %w[text/html]).should.equal "text/html"
380
+ it "select best quality match" do
381
+ Rack::Utils.best_q_match("text/html", %w[text/html]).must_equal "text/html"
335
382
 
336
383
  # More specific matches are preferred
337
- Rack::Utils.best_q_match("text/*;q=0.5,text/html;q=1.0", %w[text/html]).should.equal "text/html"
384
+ Rack::Utils.best_q_match("text/*;q=0.5,text/html;q=1.0", %w[text/html]).must_equal "text/html"
338
385
 
339
386
  # Higher quality matches are preferred
340
- Rack::Utils.best_q_match("text/*;q=0.5,text/plain;q=1.0", %w[text/plain text/html]).should.equal "text/plain"
387
+ Rack::Utils.best_q_match("text/*;q=0.5,text/plain;q=1.0", %w[text/plain text/html]).must_equal "text/plain"
341
388
 
342
389
  # Respect requested content type
343
- Rack::Utils.best_q_match("application/json", %w[application/vnd.lotus-1-2-3 application/json]).should.equal "application/json"
390
+ Rack::Utils.best_q_match("application/json", %w[application/vnd.lotus-1-2-3 application/json]).must_equal "application/json"
344
391
 
345
392
  # All else equal, the available mimes are preferred in order
346
- Rack::Utils.best_q_match("text/*", %w[text/html text/plain]).should.equal "text/html"
347
- Rack::Utils.best_q_match("text/plain,text/html", %w[text/html text/plain]).should.equal "text/html"
393
+ Rack::Utils.best_q_match("text/*", %w[text/html text/plain]).must_equal "text/html"
394
+ Rack::Utils.best_q_match("text/plain,text/html", %w[text/html text/plain]).must_equal "text/html"
348
395
 
349
396
  # When there are no matches, return nil:
350
- Rack::Utils.best_q_match("application/json", %w[text/html text/plain]).should.equal nil
397
+ Rack::Utils.best_q_match("application/json", %w[text/html text/plain]).must_equal nil
351
398
  end
352
399
 
353
- should "escape html entities [&><'\"/]" do
354
- Rack::Utils.escape_html("foo").should.equal "foo"
355
- Rack::Utils.escape_html("f&o").should.equal "f&amp;o"
356
- Rack::Utils.escape_html("f<o").should.equal "f&lt;o"
357
- Rack::Utils.escape_html("f>o").should.equal "f&gt;o"
358
- Rack::Utils.escape_html("f'o").should.equal "f&#x27;o"
359
- Rack::Utils.escape_html('f"o').should.equal "f&quot;o"
360
- Rack::Utils.escape_html("f/o").should.equal "f&#x2F;o"
361
- Rack::Utils.escape_html("<foo></foo>").should.equal "&lt;foo&gt;&lt;&#x2F;foo&gt;"
400
+ it "escape html entities [&><'\"/]" do
401
+ Rack::Utils.escape_html("foo").must_equal "foo"
402
+ Rack::Utils.escape_html("f&o").must_equal "f&amp;o"
403
+ Rack::Utils.escape_html("f<o").must_equal "f&lt;o"
404
+ Rack::Utils.escape_html("f>o").must_equal "f&gt;o"
405
+ Rack::Utils.escape_html("f'o").must_equal "f&#x27;o"
406
+ Rack::Utils.escape_html('f"o').must_equal "f&quot;o"
407
+ Rack::Utils.escape_html("f/o").must_equal "f&#x2F;o"
408
+ Rack::Utils.escape_html("<foo></foo>").must_equal "&lt;foo&gt;&lt;&#x2F;foo&gt;"
362
409
  end
363
410
 
364
- should "escape html entities even on MRI when it's bugged" do
411
+ it "escape html entities even on MRI when it's bugged" do
365
412
  test_escape = lambda do
366
- kcodeu do
367
- Rack::Utils.escape_html("\300<").should.equal "\300&lt;"
368
- end
413
+ Rack::Utils.escape_html("\300<").must_equal "\300&lt;"
369
414
  end
370
415
 
371
- if RUBY_VERSION.to_f < 1.9
372
- test_escape.call
373
- else
374
- test_escape.should.raise(ArgumentError)
375
- end
416
+ test_escape.must_raise ArgumentError
376
417
  end
377
418
 
378
- if "".respond_to?(:encode)
379
- should "escape html entities in unicode strings" do
419
+ it "escape html entities in unicode strings" do
380
420
  # the following will cause warnings if the regex is poorly encoded:
381
- Rack::Utils.escape_html("☃").should.equal "☃"
382
- end
421
+ Rack::Utils.escape_html("☃").must_equal "☃"
383
422
  end
384
423
 
385
- should "figure out which encodings are acceptable" do
424
+ it "figure out which encodings are acceptable" do
386
425
  helper = lambda do |a, b|
387
426
  Rack::Request.new(Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => a))
388
427
  Rack::Utils.select_best_encoding(a, b)
389
428
  end
390
429
 
391
- helper.call(%w(), [["x", 1]]).should.equal(nil)
392
- helper.call(%w(identity), [["identity", 0.0]]).should.equal(nil)
393
- helper.call(%w(identity), [["*", 0.0]]).should.equal(nil)
430
+ helper.call(%w(), [["x", 1]]).must_equal nil
431
+ helper.call(%w(identity), [["identity", 0.0]]).must_equal nil
432
+ helper.call(%w(identity), [["*", 0.0]]).must_equal nil
433
+
434
+ helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).must_equal "identity"
435
+
436
+ helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).must_equal "compress"
437
+ helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).must_equal "gzip"
394
438
 
395
- helper.call(%w(identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("identity")
439
+ helper.call(%w(foo bar identity), []).must_equal "identity"
440
+ helper.call(%w(foo bar identity), [["*", 1.0]]).must_equal "foo"
441
+ helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).must_equal "bar"
442
+
443
+ helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).must_equal "identity"
444
+ helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).must_equal "identity"
445
+ end
446
+
447
+ it "should perform constant time string comparison" do
448
+ Rack::Utils.secure_compare('a', 'a').must_equal true
449
+ Rack::Utils.secure_compare('a', 'b').must_equal false
450
+ end
451
+
452
+ it "return status code for integer" do
453
+ Rack::Utils.status_code(200).must_equal 200
454
+ end
396
455
 
397
- helper.call(%w(compress gzip identity), [["compress", 1.0], ["gzip", 1.0]]).should.equal("compress")
398
- helper.call(%w(compress gzip identity), [["compress", 0.5], ["gzip", 1.0]]).should.equal("gzip")
456
+ it "return status code for string" do
457
+ Rack::Utils.status_code("200").must_equal 200
458
+ end
399
459
 
400
- helper.call(%w(foo bar identity), []).should.equal("identity")
401
- helper.call(%w(foo bar identity), [["*", 1.0]]).should.equal("foo")
402
- helper.call(%w(foo bar identity), [["*", 1.0], ["foo", 0.9]]).should.equal("bar")
460
+ it "return status code for symbol" do
461
+ Rack::Utils.status_code(:ok).must_equal 200
462
+ end
403
463
 
404
- helper.call(%w(foo bar identity), [["foo", 0], ["bar", 0]]).should.equal("identity")
405
- helper.call(%w(foo bar baz identity), [["*", 0], ["identity", 0.1]]).should.equal("identity")
464
+ it "return rfc2822 format from rfc2822 helper" do
465
+ Rack::Utils.rfc2822(Time.at(0).gmtime).must_equal "Thu, 01 Jan 1970 00:00:00 -0000"
406
466
  end
407
467
 
408
- should "return the bytesize of String" do
409
- Rack::Utils.bytesize("FOO\xE2\x82\xAC").should.equal 6
468
+ it "return rfc2109 format from rfc2109 helper" do
469
+ Rack::Utils.rfc2109(Time.at(0).gmtime).must_equal "Thu, 01-Jan-1970 00:00:00 GMT"
410
470
  end
411
471
 
412
- should "should perform constant time string comparison" do
413
- Rack::Utils.secure_compare('a', 'a').should.equal true
414
- Rack::Utils.secure_compare('a', 'b').should.equal false
472
+ it "clean directory traversal" do
473
+ Rack::Utils.clean_path_info("/cgi/../cgi/test").must_equal "/cgi/test"
474
+ Rack::Utils.clean_path_info(".").must_be_empty
475
+ Rack::Utils.clean_path_info("test/..").must_be_empty
415
476
  end
416
477
 
417
- should "return status code for integer" do
418
- Rack::Utils.status_code(200).should.equal 200
478
+ it "clean unsafe directory traversal to safe path" do
479
+ Rack::Utils.clean_path_info("/../README.rdoc").must_equal "/README.rdoc"
480
+ Rack::Utils.clean_path_info("../test/spec_utils.rb").must_equal "test/spec_utils.rb"
419
481
  end
420
482
 
421
- should "return status code for string" do
422
- Rack::Utils.status_code("200").should.equal 200
483
+ it "not clean directory traversal with encoded periods" do
484
+ Rack::Utils.clean_path_info("/%2E%2E/README").must_equal "/%2E%2E/README"
423
485
  end
424
486
 
425
- should "return status code for symbol" do
426
- Rack::Utils.status_code(:ok).should.equal 200
487
+ it "clean slash only paths" do
488
+ Rack::Utils.clean_path_info("/").must_equal "/"
427
489
  end
490
+ end
491
+
492
+ describe Rack::Utils, "cookies" do
493
+ it "parses cookies" do
494
+ env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "zoo=m")
495
+ Rack::Utils.parse_cookies(env).must_equal({"zoo" => "m"})
496
+
497
+ env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=%")
498
+ Rack::Utils.parse_cookies(env).must_equal({"foo" => "%"})
499
+
500
+ env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;foo=car")
501
+ Rack::Utils.parse_cookies(env).must_equal({"foo" => "bar"})
502
+
503
+ env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar;quux=h&m")
504
+ Rack::Utils.parse_cookies(env).must_equal({"foo" => "bar", "quux" => "h&m"})
428
505
 
429
- should "return rfc2822 format from rfc2822 helper" do
430
- Rack::Utils.rfc2822(Time.at(0).gmtime).should == "Thu, 01 Jan 1970 00:00:00 -0000"
506
+ env = Rack::MockRequest.env_for("", "HTTP_COOKIE" => "foo=bar").freeze
507
+ Rack::Utils.parse_cookies(env).must_equal({"foo" => "bar"})
431
508
  end
432
509
 
433
- should "return rfc2109 format from rfc2109 helper" do
434
- Rack::Utils.rfc2109(Time.at(0).gmtime).should == "Thu, 01-Jan-1970 00:00:00 GMT"
510
+ it "adds new cookies to nil header" do
511
+ Rack::Utils.add_cookie_to_header(nil, 'name', 'value').must_equal 'name=value'
435
512
  end
436
513
 
437
- should "clean directory traversal" do
438
- Rack::Utils.clean_path_info("/cgi/../cgi/test").should.equal "/cgi/test"
439
- Rack::Utils.clean_path_info(".").should.empty
440
- Rack::Utils.clean_path_info("test/..").should.empty
514
+ it "adds new cookies to blank header" do
515
+ header = ''
516
+ Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal 'name=value'
517
+ header.must_equal ''
441
518
  end
442
519
 
443
- should "clean unsafe directory traversal to safe path" do
444
- Rack::Utils.clean_path_info("/../README.rdoc").should.equal "/README.rdoc"
445
- Rack::Utils.clean_path_info("../test/spec_utils.rb").should.equal "test/spec_utils.rb"
520
+ it "adds new cookies to string header" do
521
+ header = 'existing-cookie'
522
+ Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal "existing-cookie\nname=value"
523
+ header.must_equal 'existing-cookie'
446
524
  end
447
525
 
448
- should "not clean directory traversal with encoded periods" do
449
- Rack::Utils.clean_path_info("/%2E%2E/README").should.equal "/%2E%2E/README"
526
+ it "adds new cookies to array header" do
527
+ header = %w[ existing-cookie ]
528
+ Rack::Utils.add_cookie_to_header(header, 'name', 'value').must_equal "existing-cookie\nname=value"
529
+ header.must_equal %w[ existing-cookie ]
450
530
  end
451
531
 
452
- should "clean slash only paths" do
453
- Rack::Utils.clean_path_info("/").should.equal "/"
532
+ it "adds new cookies to an unrecognized header" do
533
+ lambda {
534
+ Rack::Utils.add_cookie_to_header(Object.new, 'name', 'value')
535
+ }.must_raise ArgumentError
454
536
  end
455
537
  end
456
538
 
457
539
  describe Rack::Utils, "byte_range" do
458
- should "ignore missing or syntactically invalid byte ranges" do
459
- Rack::Utils.byte_ranges({},500).should.equal nil
460
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).should.equal nil
461
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).should.equal nil
462
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).should.equal nil
463
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).should.equal nil
464
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).should.equal nil
540
+ it "ignore missing or syntactically invalid byte ranges" do
541
+ Rack::Utils.byte_ranges({},500).must_equal nil
542
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "foobar"},500).must_equal nil
543
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "furlongs=123-456"},500).must_equal nil
544
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes="},500).must_equal nil
545
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-"},500).must_equal nil
546
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123,456"},500).must_equal nil
465
547
  # A range of non-positive length is syntactically invalid and ignored:
466
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).should.equal nil
467
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).should.equal nil
548
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-123"},500).must_equal nil
549
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=456-455"},500).must_equal nil
468
550
  end
469
551
 
470
- should "parse simple byte ranges" do
471
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},500).should.equal [(123..456)]
472
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-"},500).should.equal [(123..499)]
473
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},500).should.equal [(400..499)]
474
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},500).should.equal [(0..0)]
475
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).should.equal [(499..499)]
552
+ it "parse simple byte ranges" do
553
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},500).must_equal [(123..456)]
554
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-"},500).must_equal [(123..499)]
555
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},500).must_equal [(400..499)]
556
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},500).must_equal [(0..0)]
557
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=499-499"},500).must_equal [(499..499)]
476
558
  end
477
559
 
478
- should "parse several byte ranges" do
479
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-600,601-999"},1000).should.equal [(500..600),(601..999)]
560
+ it "parse several byte ranges" do
561
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-600,601-999"},1000).must_equal [(500..600),(601..999)]
480
562
  end
481
563
 
482
- should "truncate byte ranges" do
483
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).should.equal [(123..499)]
484
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).should.equal []
485
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-999"},500).should.equal [(0..499)]
564
+ it "truncate byte ranges" do
565
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-999"},500).must_equal [(123..499)]
566
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=600-999"},500).must_equal []
567
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-999"},500).must_equal [(0..499)]
486
568
  end
487
569
 
488
- should "ignore unsatisfiable byte ranges" do
489
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-501"},500).should.equal []
490
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-"},500).should.equal []
491
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=999-"},500).should.equal []
492
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},500).should.equal []
570
+ it "ignore unsatisfiable byte ranges" do
571
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-501"},500).must_equal []
572
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=500-"},500).must_equal []
573
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=999-"},500).must_equal []
574
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},500).must_equal []
493
575
  end
494
576
 
495
- should "handle byte ranges of empty files" do
496
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},0).should.equal []
497
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-"},0).should.equal []
498
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},0).should.equal []
499
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},0).should.equal []
500
- Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},0).should.equal []
577
+ it "handle byte ranges of empty files" do
578
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=123-456"},0).must_equal []
579
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-"},0).must_equal []
580
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-100"},0).must_equal []
581
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=0-0"},0).must_equal []
582
+ Rack::Utils.byte_ranges({"HTTP_RANGE" => "bytes=-0"},0).must_equal []
501
583
  end
502
584
  end
503
585
 
504
586
  describe Rack::Utils::HeaderHash do
505
- should "retain header case" do
587
+ it "retain header case" do
506
588
  h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
507
589
  h['ETag'] = 'Boo!'
508
- h.to_hash.should.equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
590
+ h.to_hash.must_equal "Content-MD5" => "d5ff4e2a0 ...", "ETag" => 'Boo!'
509
591
  end
510
592
 
511
- should "check existence of keys case insensitively" do
593
+ it "check existence of keys case insensitively" do
512
594
  h = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
513
- h.should.include 'content-md5'
514
- h.should.not.include 'ETag'
595
+ h.must_include 'content-md5'
596
+ h.wont_include 'ETag'
597
+ end
598
+
599
+ it "create deep HeaderHash copy on dup" do
600
+ h1 = Rack::Utils::HeaderHash.new("Content-MD5" => "d5ff4e2a0 ...")
601
+ h2 = h1.dup
602
+
603
+ h1.must_include 'content-md5'
604
+ h2.must_include 'content-md5'
605
+
606
+ h2.delete("Content-MD5")
607
+
608
+ h2.wont_include 'content-md5'
609
+ h1.must_include 'content-md5'
515
610
  end
516
611
 
517
- should "merge case-insensitively" do
612
+ it "merge case-insensitively" do
518
613
  h = Rack::Utils::HeaderHash.new("ETag" => 'HELLO', "content-length" => '123')
519
614
  merged = h.merge("Etag" => 'WORLD', 'Content-Length' => '321', "Foo" => 'BAR')
520
- merged.should.equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
615
+ merged.must_equal "Etag"=>'WORLD', "Content-Length"=>'321', "Foo"=>'BAR'
521
616
  end
522
617
 
523
- should "overwrite case insensitively and assume the new key's case" do
618
+ it "overwrite case insensitively and assume the new key's case" do
524
619
  h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
525
620
  h["foo-bar"] = "bizzle"
526
- h["FOO-BAR"].should.equal "bizzle"
527
- h.length.should.equal 1
528
- h.to_hash.should.equal "foo-bar" => "bizzle"
621
+ h["FOO-BAR"].must_equal "bizzle"
622
+ h.length.must_equal 1
623
+ h.to_hash.must_equal "foo-bar" => "bizzle"
529
624
  end
530
625
 
531
- should "be converted to real Hash" do
626
+ it "be converted to real Hash" do
532
627
  h = Rack::Utils::HeaderHash.new("foo" => "bar")
533
- h.to_hash.should.be.instance_of Hash
628
+ h.to_hash.must_be_instance_of Hash
534
629
  end
535
630
 
536
- should "convert Array values to Strings when converting to Hash" do
631
+ it "convert Array values to Strings when converting to Hash" do
537
632
  h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
538
- h.to_hash.should.equal({ "foo" => "bar\nbaz" })
633
+ h.to_hash.must_equal({ "foo" => "bar\nbaz" })
539
634
  end
540
635
 
541
- should "replace hashes correctly" do
636
+ it "replace hashes correctly" do
542
637
  h = Rack::Utils::HeaderHash.new("Foo-Bar" => "baz")
543
638
  j = {"foo" => "bar"}
544
639
  h.replace(j)
545
- h["foo"].should.equal "bar"
640
+ h["foo"].must_equal "bar"
546
641
  end
547
642
 
548
- should "be able to delete the given key case-sensitively" do
643
+ it "be able to delete the given key case-sensitively" do
549
644
  h = Rack::Utils::HeaderHash.new("foo" => "bar")
550
645
  h.delete("foo")
551
- h["foo"].should.be.nil
552
- h["FOO"].should.be.nil
646
+ h["foo"].must_be_nil
647
+ h["FOO"].must_be_nil
553
648
  end
554
649
 
555
- should "be able to delete the given key case-insensitively" do
650
+ it "be able to delete the given key case-insensitively" do
556
651
  h = Rack::Utils::HeaderHash.new("foo" => "bar")
557
652
  h.delete("FOO")
558
- h["foo"].should.be.nil
559
- h["FOO"].should.be.nil
653
+ h["foo"].must_be_nil
654
+ h["FOO"].must_be_nil
560
655
  end
561
656
 
562
- should "return the deleted value when #delete is called on an existing key" do
657
+ it "return the deleted value when #delete is called on an existing key" do
563
658
  h = Rack::Utils::HeaderHash.new("foo" => "bar")
564
- h.delete("Foo").should.equal("bar")
659
+ h.delete("Foo").must_equal "bar"
565
660
  end
566
661
 
567
- should "return nil when #delete is called on a non-existant key" do
662
+ it "return nil when #delete is called on a non-existant key" do
568
663
  h = Rack::Utils::HeaderHash.new("foo" => "bar")
569
- h.delete("Hello").should.be.nil
664
+ h.delete("Hello").must_be_nil
570
665
  end
571
666
 
572
- should "avoid unnecessary object creation if possible" do
667
+ it "avoid unnecessary object creation if possible" do
573
668
  a = Rack::Utils::HeaderHash.new("foo" => "bar")
574
669
  b = Rack::Utils::HeaderHash.new(a)
575
- b.object_id.should.equal(a.object_id)
576
- b.should.equal(a)
670
+ b.object_id.must_equal a.object_id
671
+ b.must_equal a
577
672
  end
578
673
 
579
- should "convert Array values to Strings when responding to #each" do
674
+ it "convert Array values to Strings when responding to #each" do
580
675
  h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
581
676
  h.each do |k,v|
582
- k.should.equal("foo")
583
- v.should.equal("bar\nbaz")
677
+ k.must_equal "foo"
678
+ v.must_equal "bar\nbaz"
584
679
  end
585
680
  end
586
681
 
587
- should "not create headers out of thin air" do
682
+ it "not create headers out of thin air" do
588
683
  h = Rack::Utils::HeaderHash.new
589
684
  h['foo']
590
- h['foo'].should.be.nil
591
- h.should.not.include 'foo'
685
+ h['foo'].must_be_nil
686
+ h.wont_include 'foo'
592
687
  end
593
688
  end
594
689
 
@@ -605,27 +700,27 @@ describe Rack::Utils::Context do
605
700
  test_target4 = proc{|e| [200,{'Content-Type'=>'text/plain', 'Content-Length'=>'0'},['']] }
606
701
  test_app = ContextTest.new test_target4
607
702
 
608
- should "set context correctly" do
609
- test_app.app.should.equal test_target4
703
+ it "set context correctly" do
704
+ test_app.app.must_equal test_target4
610
705
  c1 = Rack::Utils::Context.new(test_app, test_target1)
611
- c1.for.should.equal test_app
612
- c1.app.should.equal test_target1
706
+ c1.for.must_equal test_app
707
+ c1.app.must_equal test_target1
613
708
  c2 = Rack::Utils::Context.new(test_app, test_target2)
614
- c2.for.should.equal test_app
615
- c2.app.should.equal test_target2
709
+ c2.for.must_equal test_app
710
+ c2.app.must_equal test_target2
616
711
  end
617
712
 
618
- should "alter app on recontexting" do
713
+ it "alter app on recontexting" do
619
714
  c1 = Rack::Utils::Context.new(test_app, test_target1)
620
715
  c2 = c1.recontext(test_target2)
621
- c2.for.should.equal test_app
622
- c2.app.should.equal test_target2
716
+ c2.for.must_equal test_app
717
+ c2.app.must_equal test_target2
623
718
  c3 = c2.recontext(test_target3)
624
- c3.for.should.equal test_app
625
- c3.app.should.equal test_target3
719
+ c3.for.must_equal test_app
720
+ c3.app.must_equal test_target3
626
721
  end
627
722
 
628
- should "run different apps" do
723
+ it "run different apps" do
629
724
  c1 = Rack::Utils::Context.new test_app, test_target1
630
725
  c2 = c1.recontext test_target2
631
726
  c3 = c2.recontext test_target3
@@ -633,15 +728,15 @@ describe Rack::Utils::Context do
633
728
  a4 = Rack::Lint.new c4
634
729
  a5 = Rack::Lint.new test_app
635
730
  r1 = c1.call('hello')
636
- r1.should.equal 'hello world'
731
+ r1.must_equal 'hello world'
637
732
  r2 = c2.call(2)
638
- r2.should.equal 4
733
+ r2.must_equal 4
639
734
  r3 = c3.call(:misc_symbol)
640
- r3.should.be.nil
735
+ r3.must_be_nil
641
736
  r4 = Rack::MockRequest.new(a4).get('/')
642
- r4.status.should.equal 200
737
+ r4.status.must_equal 200
643
738
  r5 = Rack::MockRequest.new(a5).get('/')
644
- r5.status.should.equal 200
645
- r4.body.should.equal r5.body
739
+ r5.status.must_equal 200
740
+ r4.body.must_equal r5.body
646
741
  end
647
742
  end