rack 1.6.13 → 2.0.9.3
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.
- checksums.yaml +4 -4
- data/COPYING +1 -1
- data/HISTORY.md +153 -8
- data/README.rdoc +35 -31
- data/Rakefile +6 -14
- data/SPEC +10 -11
- data/contrib/rack_logo.svg +164 -111
- data/example/protectedlobster.rb +1 -1
- data/example/protectedlobster.ru +1 -1
- data/lib/rack/auth/abstract/request.rb +5 -1
- data/lib/rack/auth/digest/params.rb +2 -3
- data/lib/rack/auth/digest/request.rb +1 -1
- data/lib/rack/body_proxy.rb +14 -9
- data/lib/rack/builder.rb +3 -3
- data/lib/rack/chunked.rb +5 -5
- data/lib/rack/{commonlogger.rb → common_logger.rb} +6 -3
- data/lib/rack/content_length.rb +2 -2
- data/lib/rack/deflater.rb +4 -39
- data/lib/rack/directory.rb +66 -54
- data/lib/rack/etag.rb +5 -4
- data/lib/rack/events.rb +154 -0
- data/lib/rack/file.rb +64 -40
- data/lib/rack/handler/cgi.rb +15 -16
- data/lib/rack/handler/fastcgi.rb +13 -14
- data/lib/rack/handler/lsws.rb +11 -11
- data/lib/rack/handler/scgi.rb +15 -15
- data/lib/rack/handler/thin.rb +3 -0
- data/lib/rack/handler/webrick.rb +24 -26
- data/lib/rack/handler.rb +3 -25
- data/lib/rack/head.rb +15 -17
- data/lib/rack/lint.rb +41 -41
- data/lib/rack/lobster.rb +1 -1
- data/lib/rack/lock.rb +15 -10
- data/lib/rack/logger.rb +2 -2
- data/lib/rack/media_type.rb +38 -0
- data/lib/rack/{methodoverride.rb → method_override.rb} +6 -6
- data/lib/rack/mime.rb +18 -5
- data/lib/rack/mock.rb +36 -54
- data/lib/rack/multipart/generator.rb +5 -5
- data/lib/rack/multipart/parser.rb +283 -157
- data/lib/rack/multipart/uploaded_file.rb +1 -2
- data/lib/rack/multipart.rb +36 -8
- data/lib/rack/{nulllogger.rb → null_logger.rb} +1 -1
- data/lib/rack/query_parser.rb +192 -0
- data/lib/rack/recursive.rb +8 -8
- data/lib/rack/request.rb +394 -305
- data/lib/rack/response.rb +130 -57
- data/lib/rack/rewindable_input.rb +1 -12
- data/lib/rack/runtime.rb +10 -18
- data/lib/rack/sendfile.rb +5 -7
- data/lib/rack/server.rb +30 -23
- data/lib/rack/session/abstract/id.rb +110 -75
- data/lib/rack/session/cookie.rb +24 -17
- data/lib/rack/session/memcache.rb +9 -9
- data/lib/rack/session/pool.rb +8 -8
- data/lib/rack/show_exceptions.rb +386 -0
- data/lib/rack/{showstatus.rb → show_status.rb} +3 -3
- data/lib/rack/static.rb +30 -5
- data/lib/rack/tempfile_reaper.rb +2 -2
- data/lib/rack/urlmap.rb +15 -14
- data/lib/rack/utils.rb +156 -217
- data/lib/rack.rb +70 -21
- data/rack.gemspec +10 -9
- data/test/builder/an_underscore_app.rb +5 -0
- data/test/builder/options.ru +1 -1
- data/test/cgi/test.fcgi +1 -0
- data/test/cgi/test.gz +0 -0
- data/test/helper.rb +34 -0
- data/test/multipart/filename_with_encoded_words +7 -0
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +1 -1
- data/test/multipart/filename_with_single_quote +7 -0
- data/test/multipart/quoted +15 -0
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/unity3d_wwwform +11 -0
- data/test/registering_handler/rack/handler/registering_myself.rb +1 -1
- data/test/spec_auth_basic.rb +27 -19
- data/test/spec_auth_digest.rb +47 -46
- data/test/spec_body_proxy.rb +27 -27
- data/test/spec_builder.rb +51 -41
- data/test/spec_cascade.rb +24 -22
- data/test/spec_cgi.rb +49 -67
- data/test/spec_chunked.rb +37 -35
- data/test/{spec_commonlogger.rb → spec_common_logger.rb} +35 -21
- data/test/{spec_conditionalget.rb → spec_conditional_get.rb} +29 -28
- data/test/spec_config.rb +3 -2
- data/test/spec_content_length.rb +18 -17
- data/test/spec_content_type.rb +13 -12
- data/test/spec_deflater.rb +85 -49
- data/test/spec_directory.rb +87 -27
- data/test/spec_etag.rb +32 -31
- data/test/spec_events.rb +133 -0
- data/test/spec_fastcgi.rb +50 -72
- data/test/spec_file.rb +120 -77
- data/test/spec_handler.rb +19 -34
- data/test/spec_head.rb +15 -14
- data/test/spec_lint.rb +169 -199
- data/test/spec_lobster.rb +24 -23
- data/test/spec_lock.rb +79 -39
- data/test/spec_logger.rb +4 -3
- data/test/spec_media_type.rb +42 -0
- data/test/{spec_methodoverride.rb → spec_method_override.rb} +34 -35
- data/test/spec_mime.rb +19 -19
- data/test/spec_mock.rb +206 -144
- data/test/spec_multipart.rb +329 -208
- data/test/{spec_nulllogger.rb → spec_null_logger.rb} +5 -4
- data/test/spec_recursive.rb +17 -14
- data/test/spec_request.rb +796 -605
- data/test/spec_response.rb +233 -112
- data/test/spec_rewindable_input.rb +50 -40
- data/test/spec_runtime.rb +11 -10
- data/test/spec_sendfile.rb +30 -35
- data/test/spec_server.rb +78 -52
- data/test/spec_session_abstract_id.rb +11 -33
- data/test/spec_session_abstract_session_hash.rb +45 -0
- data/test/spec_session_cookie.rb +99 -67
- data/test/spec_session_memcache.rb +67 -68
- data/test/spec_session_pool.rb +52 -51
- data/test/{spec_showexceptions.rb → spec_show_exceptions.rb} +23 -28
- data/test/{spec_showstatus.rb → spec_show_status.rb} +36 -35
- data/test/spec_static.rb +71 -32
- data/test/spec_tempfile_reaper.rb +11 -10
- data/test/spec_thin.rb +55 -50
- data/test/spec_urlmap.rb +79 -78
- data/test/spec_utils.rb +441 -346
- data/test/spec_version.rb +2 -8
- data/test/spec_webrick.rb +93 -71
- data/test/static/foo.html +1 -0
- data/test/testrequest.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered.rb +1 -1
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +1 -1
- metadata +95 -74
- data/KNOWN-ISSUES +0 -44
- data/lib/rack/backports/uri/common_18.rb +0 -56
- data/lib/rack/backports/uri/common_192.rb +0 -52
- data/lib/rack/backports/uri/common_193.rb +0 -29
- data/lib/rack/handler/evented_mongrel.rb +0 -8
- data/lib/rack/handler/mongrel.rb +0 -106
- data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
- data/lib/rack/showexceptions.rb +0 -387
- data/lib/rack/utils/okjson.rb +0 -600
- data/test/spec_mongrel.rb +0 -182
- /data/lib/rack/{conditionalget.rb → conditional_get.rb} +0 -0
data/test/spec_lint.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'minitest/autorun'
|
1
2
|
require 'stringio'
|
2
3
|
require 'tempfile'
|
3
4
|
require 'rack/lint'
|
@@ -8,129 +9,132 @@ describe Rack::Lint do
|
|
8
9
|
Rack::MockRequest.env_for("/", *args)
|
9
10
|
end
|
10
11
|
|
11
|
-
|
12
|
-
lambda {
|
13
|
-
|
14
|
-
|
15
|
-
}).call(env({}))
|
16
|
-
}.should.not.raise
|
12
|
+
it "pass valid request" do
|
13
|
+
Rack::Lint.new(lambda { |env|
|
14
|
+
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
|
15
|
+
}).call(env({})).first.must_equal 200
|
17
16
|
end
|
18
17
|
|
19
|
-
|
20
|
-
lambda { Rack::Lint.new(nil).call }.
|
21
|
-
message.
|
18
|
+
it "notice fatal errors" do
|
19
|
+
lambda { Rack::Lint.new(nil).call }.must_raise(Rack::Lint::LintError).
|
20
|
+
message.must_match(/No env given/)
|
22
21
|
end
|
23
22
|
|
24
|
-
|
25
|
-
lambda { Rack::Lint.new(nil).call 5 }.
|
26
|
-
message.
|
23
|
+
it "notice environment errors" do
|
24
|
+
lambda { Rack::Lint.new(nil).call 5 }.must_raise(Rack::Lint::LintError).
|
25
|
+
message.must_match(/not a Hash/)
|
27
26
|
|
28
27
|
lambda {
|
29
28
|
e = env
|
30
29
|
e.delete("REQUEST_METHOD")
|
31
30
|
Rack::Lint.new(nil).call(e)
|
32
|
-
}.
|
33
|
-
message.
|
31
|
+
}.must_raise(Rack::Lint::LintError).
|
32
|
+
message.must_match(/missing required key REQUEST_METHOD/)
|
34
33
|
|
35
34
|
lambda {
|
36
35
|
e = env
|
37
36
|
e.delete("SERVER_NAME")
|
38
37
|
Rack::Lint.new(nil).call(e)
|
39
|
-
}.
|
40
|
-
message.
|
38
|
+
}.must_raise(Rack::Lint::LintError).
|
39
|
+
message.must_match(/missing required key SERVER_NAME/)
|
41
40
|
|
42
41
|
|
43
42
|
lambda {
|
44
43
|
Rack::Lint.new(nil).call(env("HTTP_CONTENT_TYPE" => "text/plain"))
|
45
|
-
}.
|
46
|
-
message.
|
44
|
+
}.must_raise(Rack::Lint::LintError).
|
45
|
+
message.must_match(/contains HTTP_CONTENT_TYPE/)
|
47
46
|
|
48
47
|
lambda {
|
49
48
|
Rack::Lint.new(nil).call(env("HTTP_CONTENT_LENGTH" => "42"))
|
50
|
-
}.
|
51
|
-
message.
|
49
|
+
}.must_raise(Rack::Lint::LintError).
|
50
|
+
message.must_match(/contains HTTP_CONTENT_LENGTH/)
|
52
51
|
|
53
52
|
lambda {
|
54
53
|
Rack::Lint.new(nil).call(env("FOO" => Object.new))
|
55
|
-
}.
|
56
|
-
message.
|
54
|
+
}.must_raise(Rack::Lint::LintError).
|
55
|
+
message.must_match(/non-string value/)
|
57
56
|
|
58
57
|
lambda {
|
59
58
|
Rack::Lint.new(nil).call(env("rack.version" => "0.2"))
|
60
|
-
}.
|
61
|
-
message.
|
59
|
+
}.must_raise(Rack::Lint::LintError).
|
60
|
+
message.must_match(/must be an Array/)
|
62
61
|
|
63
62
|
lambda {
|
64
63
|
Rack::Lint.new(nil).call(env("rack.url_scheme" => "gopher"))
|
65
|
-
}.
|
66
|
-
message.
|
64
|
+
}.must_raise(Rack::Lint::LintError).
|
65
|
+
message.must_match(/url_scheme unknown/)
|
67
66
|
|
68
67
|
lambda {
|
69
68
|
Rack::Lint.new(nil).call(env("rack.session" => []))
|
70
|
-
}.
|
71
|
-
message.
|
69
|
+
}.must_raise(Rack::Lint::LintError).
|
70
|
+
message.must_equal "session [] must respond to store and []="
|
72
71
|
|
73
72
|
lambda {
|
74
73
|
Rack::Lint.new(nil).call(env("rack.logger" => []))
|
75
|
-
}.
|
76
|
-
message.
|
74
|
+
}.must_raise(Rack::Lint::LintError).
|
75
|
+
message.must_equal "logger [] must respond to info"
|
77
76
|
|
78
77
|
lambda {
|
79
78
|
Rack::Lint.new(nil).call(env("rack.multipart.buffer_size" => 0))
|
80
|
-
}.
|
81
|
-
message.
|
79
|
+
}.must_raise(Rack::Lint::LintError).
|
80
|
+
message.must_equal "rack.multipart.buffer_size must be an Integer > 0 if specified"
|
82
81
|
|
83
82
|
lambda {
|
84
83
|
Rack::Lint.new(nil).call(env("rack.multipart.tempfile_factory" => Tempfile))
|
85
|
-
}.
|
86
|
-
message.
|
84
|
+
}.must_raise(Rack::Lint::LintError).
|
85
|
+
message.must_equal "rack.multipart.tempfile_factory must respond to #call"
|
87
86
|
|
88
87
|
lambda {
|
89
88
|
Rack::Lint.new(lambda { |env|
|
90
89
|
env['rack.multipart.tempfile_factory'].call("testfile", "text/plain")
|
91
90
|
}).call(env("rack.multipart.tempfile_factory" => lambda { |filename, content_type| Object.new }))
|
92
|
-
}.
|
93
|
-
message.
|
91
|
+
}.must_raise(Rack::Lint::LintError).
|
92
|
+
message.must_equal "rack.multipart.tempfile_factory return value must respond to #<<"
|
94
93
|
|
95
94
|
lambda {
|
96
95
|
Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP?"))
|
97
|
-
}.
|
98
|
-
message.
|
96
|
+
}.must_raise(Rack::Lint::LintError).
|
97
|
+
message.must_match(/REQUEST_METHOD/)
|
98
|
+
|
99
|
+
lambda {
|
100
|
+
Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "OOPS?\b!"))
|
101
|
+
}.must_raise(Rack::Lint::LintError).
|
102
|
+
message.must_match(/OOPS\?\\/)
|
99
103
|
|
100
104
|
lambda {
|
101
105
|
Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "howdy"))
|
102
|
-
}.
|
103
|
-
message.
|
106
|
+
}.must_raise(Rack::Lint::LintError).
|
107
|
+
message.must_match(/must start with/)
|
104
108
|
|
105
109
|
lambda {
|
106
110
|
Rack::Lint.new(nil).call(env("PATH_INFO" => "../foo"))
|
107
|
-
}.
|
108
|
-
message.
|
111
|
+
}.must_raise(Rack::Lint::LintError).
|
112
|
+
message.must_match(/must start with/)
|
109
113
|
|
110
114
|
lambda {
|
111
115
|
Rack::Lint.new(nil).call(env("CONTENT_LENGTH" => "xcii"))
|
112
|
-
}.
|
113
|
-
message.
|
116
|
+
}.must_raise(Rack::Lint::LintError).
|
117
|
+
message.must_match(/Invalid CONTENT_LENGTH/)
|
114
118
|
|
115
119
|
lambda {
|
116
120
|
e = env
|
117
121
|
e.delete("PATH_INFO")
|
118
122
|
e.delete("SCRIPT_NAME")
|
119
123
|
Rack::Lint.new(nil).call(e)
|
120
|
-
}.
|
121
|
-
message.
|
124
|
+
}.must_raise(Rack::Lint::LintError).
|
125
|
+
message.must_match(/One of .* must be set/)
|
122
126
|
|
123
127
|
lambda {
|
124
128
|
Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "/"))
|
125
|
-
}.
|
126
|
-
message.
|
129
|
+
}.must_raise(Rack::Lint::LintError).
|
130
|
+
message.must_match(/cannot be .* make it ''/)
|
127
131
|
end
|
128
132
|
|
129
|
-
|
133
|
+
it "notice input errors" do
|
130
134
|
lambda {
|
131
135
|
Rack::Lint.new(nil).call(env("rack.input" => ""))
|
132
|
-
}.
|
133
|
-
message.
|
136
|
+
}.must_raise(Rack::Lint::LintError).
|
137
|
+
message.must_match(/does not respond to #gets/)
|
134
138
|
|
135
139
|
lambda {
|
136
140
|
input = Object.new
|
@@ -138,8 +142,8 @@ describe Rack::Lint do
|
|
138
142
|
false
|
139
143
|
end
|
140
144
|
Rack::Lint.new(nil).call(env("rack.input" => input))
|
141
|
-
}.
|
142
|
-
message.
|
145
|
+
}.must_raise(Rack::Lint::LintError).
|
146
|
+
message.must_match(/is not opened in binary mode/)
|
143
147
|
|
144
148
|
lambda {
|
145
149
|
input = Object.new
|
@@ -151,54 +155,54 @@ describe Rack::Lint do
|
|
151
155
|
result
|
152
156
|
end
|
153
157
|
Rack::Lint.new(nil).call(env("rack.input" => input))
|
154
|
-
}.
|
155
|
-
message.
|
158
|
+
}.must_raise(Rack::Lint::LintError).
|
159
|
+
message.must_match(/does not have ASCII-8BIT as its external encoding/)
|
156
160
|
end
|
157
161
|
|
158
|
-
|
162
|
+
it "notice error errors" do
|
159
163
|
lambda {
|
160
164
|
Rack::Lint.new(nil).call(env("rack.errors" => ""))
|
161
|
-
}.
|
162
|
-
message.
|
165
|
+
}.must_raise(Rack::Lint::LintError).
|
166
|
+
message.must_match(/does not respond to #puts/)
|
163
167
|
end
|
164
168
|
|
165
|
-
|
169
|
+
it "notice status errors" do
|
166
170
|
lambda {
|
167
171
|
Rack::Lint.new(lambda { |env|
|
168
172
|
["cc", {}, ""]
|
169
173
|
}).call(env({}))
|
170
|
-
}.
|
171
|
-
message.
|
174
|
+
}.must_raise(Rack::Lint::LintError).
|
175
|
+
message.must_match(/must be >=100 seen as integer/)
|
172
176
|
|
173
177
|
lambda {
|
174
178
|
Rack::Lint.new(lambda { |env|
|
175
179
|
[42, {}, ""]
|
176
180
|
}).call(env({}))
|
177
|
-
}.
|
178
|
-
message.
|
181
|
+
}.must_raise(Rack::Lint::LintError).
|
182
|
+
message.must_match(/must be >=100 seen as integer/)
|
179
183
|
end
|
180
184
|
|
181
|
-
|
185
|
+
it "notice header errors" do
|
182
186
|
lambda {
|
183
187
|
Rack::Lint.new(lambda { |env|
|
184
188
|
[200, Object.new, []]
|
185
189
|
}).call(env({}))
|
186
|
-
}.
|
187
|
-
message.
|
190
|
+
}.must_raise(Rack::Lint::LintError).
|
191
|
+
message.must_equal "headers object should respond to #each, but doesn't (got Object as headers)"
|
188
192
|
|
189
193
|
lambda {
|
190
194
|
Rack::Lint.new(lambda { |env|
|
191
195
|
[200, {true=>false}, []]
|
192
196
|
}).call(env({}))
|
193
|
-
}.
|
194
|
-
message.
|
197
|
+
}.must_raise(Rack::Lint::LintError).
|
198
|
+
message.must_equal "header key must be a string, was TrueClass"
|
195
199
|
|
196
200
|
lambda {
|
197
201
|
Rack::Lint.new(lambda { |env|
|
198
202
|
[200, {"Status" => "404"}, []]
|
199
203
|
}).call(env({}))
|
200
|
-
}.
|
201
|
-
message.
|
204
|
+
}.must_raise(Rack::Lint::LintError).
|
205
|
+
message.must_match(/must not contain Status/)
|
202
206
|
|
203
207
|
# From RFC 7230:<F24><F25>
|
204
208
|
# Most HTTP header field values are defined using common syntax
|
@@ -206,9 +210,9 @@ describe Rack::Lint do
|
|
206
210
|
# whitespace or specific delimiting characters. Delimiters are chosen
|
207
211
|
# from the set of US-ASCII visual characters not allowed in a token
|
208
212
|
# (DQUOTE and "(),/:;<=>?@[\]{}").
|
209
|
-
#
|
213
|
+
#
|
210
214
|
# token = 1*tchar
|
211
|
-
#
|
215
|
+
#
|
212
216
|
# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*"
|
213
217
|
# / "+" / "-" / "." / "^" / "_" / "`" / "|" / "~"
|
214
218
|
# / DIGIT / ALPHA
|
@@ -219,157 +223,151 @@ describe Rack::Lint do
|
|
219
223
|
Rack::Lint.new(lambda { |env|
|
220
224
|
[200, {invalid_header => "text/plain"}, []]
|
221
225
|
}).call(env({}))
|
222
|
-
}.
|
223
|
-
message.
|
226
|
+
}.must_raise(Rack::Lint::LintError, "on invalid header: #{invalid_header}").
|
227
|
+
message.must_equal("invalid header name: #{invalid_header}")
|
224
228
|
end
|
225
229
|
valid_headers = 0.upto(127).map(&:chr) - invalid_headers
|
226
230
|
valid_headers.each do |valid_header|
|
227
|
-
lambda {
|
228
|
-
|
229
|
-
|
230
|
-
}).call(env({}))
|
231
|
-
}.should.not.raise(Rack::Lint::LintError, "on valid header: #{valid_header}")
|
231
|
+
Rack::Lint.new(lambda { |env|
|
232
|
+
[200, {valid_header => "text/plain"}, []]
|
233
|
+
}).call(env({})).first.must_equal 200
|
232
234
|
end
|
233
235
|
|
234
236
|
lambda {
|
235
237
|
Rack::Lint.new(lambda { |env|
|
236
238
|
[200, {"Foo" => Object.new}, []]
|
237
239
|
}).call(env({}))
|
238
|
-
}.
|
239
|
-
message.
|
240
|
+
}.must_raise(Rack::Lint::LintError).
|
241
|
+
message.must_equal "a header value must be a String, but the value of 'Foo' is a Object"
|
240
242
|
|
241
243
|
lambda {
|
242
244
|
Rack::Lint.new(lambda { |env|
|
243
245
|
[200, {"Foo" => [1, 2, 3]}, []]
|
244
246
|
}).call(env({}))
|
245
|
-
}.
|
246
|
-
message.
|
247
|
+
}.must_raise(Rack::Lint::LintError).
|
248
|
+
message.must_equal "a header value must be a String, but the value of 'Foo' is a Array"
|
247
249
|
|
248
250
|
|
249
251
|
lambda {
|
250
252
|
Rack::Lint.new(lambda { |env|
|
251
253
|
[200, {"Foo-Bar" => "text\000plain"}, []]
|
252
254
|
}).call(env({}))
|
253
|
-
}.
|
254
|
-
message.
|
255
|
-
|
256
|
-
# line ends (010)
|
257
|
-
lambda {
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
Rack::Lint.new(lambda { |env|
|
266
|
-
[200, [%w(Content-Type text/plain), %w(Content-Length 0)], []]
|
267
|
-
}).call(env({}))
|
268
|
-
}.should.not.raise(TypeError)
|
255
|
+
}.must_raise(Rack::Lint::LintError).
|
256
|
+
message.must_match(/invalid header/)
|
257
|
+
|
258
|
+
# line ends (010).must_be :allowed in header values.?
|
259
|
+
Rack::Lint.new(lambda { |env|
|
260
|
+
[200, {"Foo-Bar" => "one\ntwo\nthree", "Content-Length" => "0", "Content-Type" => "text/plain" }, []]
|
261
|
+
}).call(env({})).first.must_equal 200
|
262
|
+
|
263
|
+
# non-Hash header responses.must_be :allowed?
|
264
|
+
Rack::Lint.new(lambda { |env|
|
265
|
+
[200, [%w(Content-Type text/plain), %w(Content-Length 0)], []]
|
266
|
+
}).call(env({})).first.must_equal 200
|
269
267
|
end
|
270
268
|
|
271
|
-
|
269
|
+
it "notice content-type errors" do
|
272
270
|
# lambda {
|
273
271
|
# Rack::Lint.new(lambda { |env|
|
274
272
|
# [200, {"Content-length" => "0"}, []]
|
275
273
|
# }).call(env({}))
|
276
|
-
# }.
|
277
|
-
# message.
|
274
|
+
# }.must_raise(Rack::Lint::LintError).
|
275
|
+
# message.must_match(/No Content-Type/)
|
278
276
|
|
279
|
-
[100, 101, 204,
|
277
|
+
[100, 101, 204, 304].each do |status|
|
280
278
|
lambda {
|
281
279
|
Rack::Lint.new(lambda { |env|
|
282
280
|
[status, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
283
281
|
}).call(env({}))
|
284
|
-
}.
|
285
|
-
message.
|
282
|
+
}.must_raise(Rack::Lint::LintError).
|
283
|
+
message.must_match(/Content-Type header found/)
|
286
284
|
end
|
287
285
|
end
|
288
286
|
|
289
|
-
|
290
|
-
[100, 101, 204,
|
287
|
+
it "notice content-length errors" do
|
288
|
+
[100, 101, 204, 304].each do |status|
|
291
289
|
lambda {
|
292
290
|
Rack::Lint.new(lambda { |env|
|
293
291
|
[status, {"Content-length" => "0"}, []]
|
294
292
|
}).call(env({}))
|
295
|
-
}.
|
296
|
-
message.
|
293
|
+
}.must_raise(Rack::Lint::LintError).
|
294
|
+
message.must_match(/Content-Length header found/)
|
297
295
|
end
|
298
296
|
|
299
297
|
lambda {
|
300
298
|
Rack::Lint.new(lambda { |env|
|
301
299
|
[200, {"Content-type" => "text/plain", "Content-Length" => "1"}, []]
|
302
300
|
}).call(env({}))[2].each { }
|
303
|
-
}.
|
304
|
-
message.
|
301
|
+
}.must_raise(Rack::Lint::LintError).
|
302
|
+
message.must_match(/Content-Length header was 1, but should be 0/)
|
305
303
|
end
|
306
304
|
|
307
|
-
|
305
|
+
it "notice body errors" do
|
308
306
|
lambda {
|
309
307
|
body = Rack::Lint.new(lambda { |env|
|
310
308
|
[200, {"Content-type" => "text/plain","Content-length" => "3"}, [1,2,3]]
|
311
309
|
}).call(env({}))[2]
|
312
310
|
body.each { |part| }
|
313
|
-
}.
|
314
|
-
message.
|
311
|
+
}.must_raise(Rack::Lint::LintError).
|
312
|
+
message.must_match(/yielded non-string/)
|
315
313
|
end
|
316
314
|
|
317
|
-
|
315
|
+
it "notice input handling errors" do
|
318
316
|
lambda {
|
319
317
|
Rack::Lint.new(lambda { |env|
|
320
318
|
env["rack.input"].gets("\r\n")
|
321
319
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
322
320
|
}).call(env({}))
|
323
|
-
}.
|
324
|
-
message.
|
321
|
+
}.must_raise(Rack::Lint::LintError).
|
322
|
+
message.must_match(/gets called with arguments/)
|
325
323
|
|
326
324
|
lambda {
|
327
325
|
Rack::Lint.new(lambda { |env|
|
328
326
|
env["rack.input"].read(1, 2, 3)
|
329
327
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
330
328
|
}).call(env({}))
|
331
|
-
}.
|
332
|
-
message.
|
329
|
+
}.must_raise(Rack::Lint::LintError).
|
330
|
+
message.must_match(/read called with too many arguments/)
|
333
331
|
|
334
332
|
lambda {
|
335
333
|
Rack::Lint.new(lambda { |env|
|
336
334
|
env["rack.input"].read("foo")
|
337
335
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
338
336
|
}).call(env({}))
|
339
|
-
}.
|
340
|
-
message.
|
337
|
+
}.must_raise(Rack::Lint::LintError).
|
338
|
+
message.must_match(/read called with non-integer and non-nil length/)
|
341
339
|
|
342
340
|
lambda {
|
343
341
|
Rack::Lint.new(lambda { |env|
|
344
342
|
env["rack.input"].read(-1)
|
345
343
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
346
344
|
}).call(env({}))
|
347
|
-
}.
|
348
|
-
message.
|
345
|
+
}.must_raise(Rack::Lint::LintError).
|
346
|
+
message.must_match(/read called with a negative length/)
|
349
347
|
|
350
348
|
lambda {
|
351
349
|
Rack::Lint.new(lambda { |env|
|
352
350
|
env["rack.input"].read(nil, nil)
|
353
351
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
354
352
|
}).call(env({}))
|
355
|
-
}.
|
356
|
-
message.
|
353
|
+
}.must_raise(Rack::Lint::LintError).
|
354
|
+
message.must_match(/read called with non-String buffer/)
|
357
355
|
|
358
356
|
lambda {
|
359
357
|
Rack::Lint.new(lambda { |env|
|
360
358
|
env["rack.input"].read(nil, 1)
|
361
359
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
362
360
|
}).call(env({}))
|
363
|
-
}.
|
364
|
-
message.
|
361
|
+
}.must_raise(Rack::Lint::LintError).
|
362
|
+
message.must_match(/read called with non-String buffer/)
|
365
363
|
|
366
364
|
lambda {
|
367
365
|
Rack::Lint.new(lambda { |env|
|
368
366
|
env["rack.input"].rewind(0)
|
369
367
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
370
368
|
}).call(env({}))
|
371
|
-
}.
|
372
|
-
message.
|
369
|
+
}.must_raise(Rack::Lint::LintError).
|
370
|
+
message.must_match(/rewind called with arguments/)
|
373
371
|
|
374
372
|
weirdio = Object.new
|
375
373
|
class << weirdio
|
@@ -413,40 +411,40 @@ describe Rack::Lint do
|
|
413
411
|
env["rack.input"].gets
|
414
412
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
415
413
|
}).call(env("rack.input" => weirdio))
|
416
|
-
}.
|
417
|
-
message.
|
414
|
+
}.must_raise(Rack::Lint::LintError).
|
415
|
+
message.must_match(/gets didn't return a String/)
|
418
416
|
|
419
417
|
lambda {
|
420
418
|
Rack::Lint.new(lambda { |env|
|
421
419
|
env["rack.input"].each { |x| }
|
422
420
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
423
421
|
}).call(env("rack.input" => weirdio))
|
424
|
-
}.
|
425
|
-
message.
|
422
|
+
}.must_raise(Rack::Lint::LintError).
|
423
|
+
message.must_match(/each didn't yield a String/)
|
426
424
|
|
427
425
|
lambda {
|
428
426
|
Rack::Lint.new(lambda { |env|
|
429
427
|
env["rack.input"].read
|
430
428
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
431
429
|
}).call(env("rack.input" => weirdio))
|
432
|
-
}.
|
433
|
-
message.
|
430
|
+
}.must_raise(Rack::Lint::LintError).
|
431
|
+
message.must_match(/read didn't return nil or a String/)
|
434
432
|
|
435
433
|
lambda {
|
436
434
|
Rack::Lint.new(lambda { |env|
|
437
435
|
env["rack.input"].read
|
438
436
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
439
437
|
}).call(env("rack.input" => eof_weirdio))
|
440
|
-
}.
|
441
|
-
message.
|
438
|
+
}.must_raise(Rack::Lint::LintError).
|
439
|
+
message.must_match(/read\(nil\) returned nil on EOF/)
|
442
440
|
|
443
441
|
lambda {
|
444
442
|
Rack::Lint.new(lambda { |env|
|
445
443
|
env["rack.input"].rewind
|
446
444
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
447
445
|
}).call(env("rack.input" => weirdio))
|
448
|
-
}.
|
449
|
-
message.
|
446
|
+
}.must_raise(Rack::Lint::LintError).
|
447
|
+
message.must_match(/rewind raised Errno::ESPIPE/)
|
450
448
|
|
451
449
|
|
452
450
|
lambda {
|
@@ -454,97 +452,69 @@ describe Rack::Lint do
|
|
454
452
|
env["rack.input"].close
|
455
453
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
456
454
|
}).call(env({}))
|
457
|
-
}.
|
458
|
-
message.
|
455
|
+
}.must_raise(Rack::Lint::LintError).
|
456
|
+
message.must_match(/close must not be called/)
|
459
457
|
end
|
460
458
|
|
461
|
-
|
459
|
+
it "notice error handling errors" do
|
462
460
|
lambda {
|
463
461
|
Rack::Lint.new(lambda { |env|
|
464
462
|
env["rack.errors"].write(42)
|
465
463
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
466
464
|
}).call(env({}))
|
467
|
-
}.
|
468
|
-
message.
|
465
|
+
}.must_raise(Rack::Lint::LintError).
|
466
|
+
message.must_match(/write not called with a String/)
|
469
467
|
|
470
468
|
lambda {
|
471
469
|
Rack::Lint.new(lambda { |env|
|
472
470
|
env["rack.errors"].close
|
473
471
|
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
474
472
|
}).call(env({}))
|
475
|
-
}.
|
476
|
-
message.
|
473
|
+
}.must_raise(Rack::Lint::LintError).
|
474
|
+
message.must_match(/close must not be called/)
|
477
475
|
end
|
478
476
|
|
479
|
-
|
480
|
-
lambda {
|
481
|
-
|
482
|
-
|
483
|
-
}).call(env({"REQUEST_METHOD" => "HEAD"}))
|
484
|
-
}.should.not.raise
|
477
|
+
it "notice HEAD errors" do
|
478
|
+
Rack::Lint.new(lambda { |env|
|
479
|
+
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, []]
|
480
|
+
}).call(env({"REQUEST_METHOD" => "HEAD"})).first.must_equal 200
|
485
481
|
|
486
482
|
lambda {
|
487
483
|
Rack::Lint.new(lambda { |env|
|
488
484
|
[200, {"Content-type" => "test/plain", "Content-length" => "3"}, ["foo"]]
|
489
485
|
}).call(env({"REQUEST_METHOD" => "HEAD"}))[2].each { }
|
490
|
-
}.
|
491
|
-
message.
|
486
|
+
}.must_raise(Rack::Lint::LintError).
|
487
|
+
message.must_match(/body was given for HEAD/)
|
492
488
|
end
|
493
489
|
|
494
|
-
|
490
|
+
def assert_lint(*args)
|
495
491
|
hello_str = "hello world"
|
496
|
-
hello_str.force_encoding(
|
497
|
-
lambda {
|
498
|
-
Rack::Lint.new(lambda { |env|
|
499
|
-
env["rack.input"].read
|
500
|
-
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
501
|
-
}).call(env({"rack.input" => StringIO.new(hello_str)}))
|
502
|
-
}.should.not.raise(Rack::Lint::LintError)
|
503
|
-
|
504
|
-
lambda {
|
505
|
-
Rack::Lint.new(lambda { |env|
|
506
|
-
env["rack.input"].read(0)
|
507
|
-
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
508
|
-
}).call(env({"rack.input" => StringIO.new(hello_str)}))
|
509
|
-
}.should.not.raise(Rack::Lint::LintError)
|
492
|
+
hello_str.force_encoding(Encoding::ASCII_8BIT)
|
510
493
|
|
511
|
-
lambda {
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
lambda {
|
519
|
-
Rack::Lint.new(lambda { |env|
|
520
|
-
env["rack.input"].read(nil)
|
521
|
-
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
522
|
-
}).call(env({"rack.input" => StringIO.new(hello_str)}))
|
523
|
-
}.should.not.raise(Rack::Lint::LintError)
|
524
|
-
|
525
|
-
lambda {
|
526
|
-
Rack::Lint.new(lambda { |env|
|
527
|
-
env["rack.input"].read(nil, '')
|
528
|
-
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
529
|
-
}).call(env({"rack.input" => StringIO.new(hello_str)}))
|
530
|
-
}.should.not.raise(Rack::Lint::LintError)
|
494
|
+
Rack::Lint.new(lambda { |env|
|
495
|
+
env["rack.input"].send(:read, *args)
|
496
|
+
[201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
|
497
|
+
}).call(env({"rack.input" => StringIO.new(hello_str)})).
|
498
|
+
first.must_equal 201
|
499
|
+
end
|
531
500
|
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
|
537
|
-
|
501
|
+
it "pass valid read calls" do
|
502
|
+
assert_lint
|
503
|
+
assert_lint 0
|
504
|
+
assert_lint 1
|
505
|
+
assert_lint nil
|
506
|
+
assert_lint nil, ''
|
507
|
+
assert_lint 1, ''
|
538
508
|
end
|
539
509
|
end
|
540
510
|
|
541
511
|
describe "Rack::Lint::InputWrapper" do
|
542
|
-
|
512
|
+
it "delegate :rewind to underlying IO object" do
|
543
513
|
io = StringIO.new("123")
|
544
514
|
wrapper = Rack::Lint::InputWrapper.new(io)
|
545
|
-
wrapper.read.
|
546
|
-
wrapper.read.
|
515
|
+
wrapper.read.must_equal "123"
|
516
|
+
wrapper.read.must_equal ""
|
547
517
|
wrapper.rewind
|
548
|
-
wrapper.read.
|
518
|
+
wrapper.read.must_equal "123"
|
549
519
|
end
|
550
520
|
end
|