sinatra 0.2.1 → 0.2.2

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

Potentially problematic release.


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

Files changed (83) hide show
  1. data/CHANGELOG +1 -0
  2. data/LICENSE +22 -0
  3. data/Manifest +78 -1
  4. data/lib/sinatra.rb +12 -1
  5. data/sinatra.gemspec +7 -14
  6. data/vendor/rack/AUTHORS +7 -0
  7. data/vendor/rack/COPYING +18 -0
  8. data/vendor/rack/KNOWN-ISSUES +18 -0
  9. data/vendor/rack/README +242 -0
  10. data/vendor/rack/Rakefile +174 -0
  11. data/vendor/rack/bin/rackup +153 -0
  12. data/vendor/rack/contrib/rack_logo.svg +111 -0
  13. data/vendor/rack/example/lobster.ru +4 -0
  14. data/vendor/rack/example/protectedlobster.rb +14 -0
  15. data/vendor/rack/example/protectedlobster.ru +8 -0
  16. data/vendor/rack/lib/rack.rb +92 -0
  17. data/vendor/rack/lib/rack/adapter/camping.rb +22 -0
  18. data/vendor/rack/lib/rack/auth/abstract/handler.rb +28 -0
  19. data/vendor/rack/lib/rack/auth/abstract/request.rb +37 -0
  20. data/vendor/rack/lib/rack/auth/basic.rb +58 -0
  21. data/vendor/rack/lib/rack/auth/digest/md5.rb +124 -0
  22. data/vendor/rack/lib/rack/auth/digest/nonce.rb +51 -0
  23. data/vendor/rack/lib/rack/auth/digest/params.rb +55 -0
  24. data/vendor/rack/lib/rack/auth/digest/request.rb +40 -0
  25. data/vendor/rack/lib/rack/auth/openid.rb +116 -0
  26. data/vendor/rack/lib/rack/builder.rb +56 -0
  27. data/vendor/rack/lib/rack/cascade.rb +36 -0
  28. data/vendor/rack/lib/rack/commonlogger.rb +56 -0
  29. data/vendor/rack/lib/rack/file.rb +112 -0
  30. data/vendor/rack/lib/rack/handler/cgi.rb +57 -0
  31. data/vendor/rack/lib/rack/handler/fastcgi.rb +83 -0
  32. data/vendor/rack/lib/rack/handler/lsws.rb +52 -0
  33. data/vendor/rack/lib/rack/handler/mongrel.rb +78 -0
  34. data/vendor/rack/lib/rack/handler/scgi.rb +57 -0
  35. data/vendor/rack/lib/rack/handler/webrick.rb +57 -0
  36. data/vendor/rack/lib/rack/lint.rb +394 -0
  37. data/vendor/rack/lib/rack/lobster.rb +65 -0
  38. data/vendor/rack/lib/rack/mock.rb +160 -0
  39. data/vendor/rack/lib/rack/recursive.rb +57 -0
  40. data/vendor/rack/lib/rack/reloader.rb +64 -0
  41. data/vendor/rack/lib/rack/request.rb +197 -0
  42. data/vendor/rack/lib/rack/response.rb +166 -0
  43. data/vendor/rack/lib/rack/session/abstract/id.rb +126 -0
  44. data/vendor/rack/lib/rack/session/cookie.rb +71 -0
  45. data/vendor/rack/lib/rack/session/memcache.rb +83 -0
  46. data/vendor/rack/lib/rack/session/pool.rb +67 -0
  47. data/vendor/rack/lib/rack/showexceptions.rb +344 -0
  48. data/vendor/rack/lib/rack/showstatus.rb +103 -0
  49. data/vendor/rack/lib/rack/static.rb +38 -0
  50. data/vendor/rack/lib/rack/urlmap.rb +48 -0
  51. data/vendor/rack/lib/rack/utils.rb +240 -0
  52. data/vendor/rack/test/cgi/lighttpd.conf +20 -0
  53. data/vendor/rack/test/cgi/test +9 -0
  54. data/vendor/rack/test/cgi/test.fcgi +7 -0
  55. data/vendor/rack/test/cgi/test.ru +7 -0
  56. data/vendor/rack/test/spec_rack_auth_basic.rb +69 -0
  57. data/vendor/rack/test/spec_rack_auth_digest.rb +169 -0
  58. data/vendor/rack/test/spec_rack_builder.rb +50 -0
  59. data/vendor/rack/test/spec_rack_camping.rb +47 -0
  60. data/vendor/rack/test/spec_rack_cascade.rb +50 -0
  61. data/vendor/rack/test/spec_rack_cgi.rb +91 -0
  62. data/vendor/rack/test/spec_rack_commonlogger.rb +32 -0
  63. data/vendor/rack/test/spec_rack_fastcgi.rb +91 -0
  64. data/vendor/rack/test/spec_rack_file.rb +40 -0
  65. data/vendor/rack/test/spec_rack_lint.rb +317 -0
  66. data/vendor/rack/test/spec_rack_lobster.rb +45 -0
  67. data/vendor/rack/test/spec_rack_mock.rb +152 -0
  68. data/vendor/rack/test/spec_rack_mongrel.rb +165 -0
  69. data/vendor/rack/test/spec_rack_recursive.rb +77 -0
  70. data/vendor/rack/test/spec_rack_request.rb +384 -0
  71. data/vendor/rack/test/spec_rack_response.rb +167 -0
  72. data/vendor/rack/test/spec_rack_session_cookie.rb +49 -0
  73. data/vendor/rack/test/spec_rack_session_memcache.rb +100 -0
  74. data/vendor/rack/test/spec_rack_session_pool.rb +84 -0
  75. data/vendor/rack/test/spec_rack_showexceptions.rb +21 -0
  76. data/vendor/rack/test/spec_rack_showstatus.rb +71 -0
  77. data/vendor/rack/test/spec_rack_static.rb +37 -0
  78. data/vendor/rack/test/spec_rack_urlmap.rb +175 -0
  79. data/vendor/rack/test/spec_rack_utils.rb +57 -0
  80. data/vendor/rack/test/spec_rack_webrick.rb +106 -0
  81. data/vendor/rack/test/testrequest.rb +43 -0
  82. metadata +81 -4
  83. data/Rakefile +0 -24
@@ -0,0 +1,50 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/builder'
4
+ require 'rack/mock'
5
+
6
+ context "Rack::Builder" do
7
+ specify "chains apps by default" do
8
+ app = Rack::Builder.new do
9
+ use Rack::ShowExceptions
10
+ run lambda { |env| raise "bzzzt" }
11
+ end.to_app
12
+
13
+ Rack::MockRequest.new(app).get("/").should.be.server_error
14
+ Rack::MockRequest.new(app).get("/").should.be.server_error
15
+ Rack::MockRequest.new(app).get("/").should.be.server_error
16
+ end
17
+
18
+ specify "has implicit #to_app" do
19
+ app = Rack::Builder.new do
20
+ use Rack::ShowExceptions
21
+ run lambda { |env| raise "bzzzt" }
22
+ end
23
+
24
+ Rack::MockRequest.new(app).get("/").should.be.server_error
25
+ Rack::MockRequest.new(app).get("/").should.be.server_error
26
+ Rack::MockRequest.new(app).get("/").should.be.server_error
27
+ end
28
+
29
+ specify "supports blocks on use" do
30
+ app = Rack::Builder.new do
31
+ use Rack::ShowExceptions
32
+ use Rack::Auth::Basic do |username, password|
33
+ 'secret' == password
34
+ end
35
+
36
+ run lambda { |env| [200, {}, 'Hi Boss'] }
37
+ end
38
+
39
+ response = Rack::MockRequest.new(app).get("/")
40
+ response.should.be.client_error
41
+ response.status.should.equal 401
42
+
43
+ # with auth...
44
+ response = Rack::MockRequest.new(app).get("/",
45
+ 'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
46
+ response.status.should.equal 200
47
+ response.body.to_s.should.equal 'Hi Boss'
48
+ end
49
+
50
+ end
@@ -0,0 +1,47 @@
1
+ require 'test/spec'
2
+ require 'stringio'
3
+ require 'uri'
4
+
5
+ require 'rack/mock'
6
+
7
+ $-w, w = nil, $-w # yuck
8
+ require 'camping'
9
+ require 'rack/adapter/camping'
10
+
11
+ Camping.goes :CampApp
12
+ module CampApp
13
+ module Controllers
14
+ class HW < R('/')
15
+ def get
16
+ @headers["X-Served-By"] = URI("http://rack.rubyforge.org")
17
+ "Camping works!"
18
+ end
19
+
20
+ def post
21
+ "Data: #{input.foo}"
22
+ end
23
+ end
24
+ end
25
+ end
26
+ $-w = w
27
+
28
+ context "Rack::Adapter::Camping" do
29
+ specify "works with GET" do
30
+ res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)).
31
+ get("/")
32
+
33
+ res.should.be.ok
34
+ res["Content-Type"].should.equal "text/html"
35
+ res["X-Served-By"].should.equal "http://rack.rubyforge.org"
36
+
37
+ res.body.should.equal "Camping works!"
38
+ end
39
+
40
+ specify "works with POST" do
41
+ res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)).
42
+ post("/", :input => "foo=bar")
43
+
44
+ res.should.be.ok
45
+ res.body.should.equal "Data: bar"
46
+ end
47
+ end
@@ -0,0 +1,50 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/cascade'
4
+ require 'rack/mock'
5
+
6
+ require 'rack/urlmap'
7
+ require 'rack/file'
8
+
9
+ context "Rack::Cascade" do
10
+ docroot = File.expand_path(File.dirname(__FILE__))
11
+ app1 = Rack::File.new(docroot)
12
+
13
+ app2 = Rack::URLMap.new("/crash" => lambda { |env| raise "boom" })
14
+
15
+ app3 = Rack::URLMap.new("/foo" => lambda { |env|
16
+ [200, { "Content-Type" => "text/plain"}, [""]]})
17
+
18
+ specify "should dispatch onward on 404 by default" do
19
+ cascade = Rack::Cascade.new([app1, app2, app3])
20
+ Rack::MockRequest.new(cascade).get("/cgi/test").should.be.ok
21
+ Rack::MockRequest.new(cascade).get("/foo").should.be.ok
22
+ Rack::MockRequest.new(cascade).get("/toobad").should.be.not_found
23
+ Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.forbidden
24
+ end
25
+
26
+ specify "should dispatch onward on whatever is passed" do
27
+ cascade = Rack::Cascade.new([app1, app2, app3], [404, 403])
28
+ Rack::MockRequest.new(cascade).get("/cgi/../bla").should.be.not_found
29
+ end
30
+
31
+ specify "should fail if empty" do
32
+ lambda { Rack::MockRequest.new(Rack::Cascade.new([])).get("/") }.
33
+ should.raise(ArgumentError)
34
+ end
35
+
36
+ specify "should append new app" do
37
+ cascade = Rack::Cascade.new([], [404, 403])
38
+ lambda { Rack::MockRequest.new(cascade).get('/cgi/test') }.
39
+ should.raise(ArgumentError)
40
+ cascade << app2
41
+ Rack::MockRequest.new(cascade).get('/cgi/test').should.be.not_found
42
+ Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.not_found
43
+ cascade << app1
44
+ Rack::MockRequest.new(cascade).get('/cgi/test').should.be.ok
45
+ Rack::MockRequest.new(cascade).get('/cgi/../bla').should.be.forbidden
46
+ Rack::MockRequest.new(cascade).get('/foo').should.be.not_found
47
+ cascade << app3
48
+ Rack::MockRequest.new(cascade).get('/foo').should.be.ok
49
+ end
50
+ end
@@ -0,0 +1,91 @@
1
+ require 'test/spec'
2
+ require 'testrequest'
3
+
4
+ context "Rack::Handler::CGI" do
5
+ include TestRequest::Helpers
6
+
7
+ setup do
8
+ @host = '0.0.0.0'
9
+ @port = 9203
10
+ end
11
+
12
+ # Keep this first.
13
+ specify "startup" do
14
+ $pid = fork {
15
+ rack_home = File.expand_path(File.join(File.dirname(__FILE__), ".."))
16
+ ENV['RUBYLIB'] = File.join(rack_home, "lib")
17
+ Dir.chdir(File.join(rack_home, "test", "cgi"))
18
+ exec "lighttpd -D -f lighttpd.conf"
19
+ }
20
+ end
21
+
22
+ specify "should respond" do
23
+ sleep 1
24
+ lambda {
25
+ GET("/test")
26
+ }.should.not.raise
27
+ end
28
+
29
+ specify "should be a lighttpd" do
30
+ GET("/test")
31
+ status.should.be 200
32
+ response["SERVER_SOFTWARE"].should =~ /lighttpd/
33
+ response["HTTP_VERSION"].should.equal "HTTP/1.1"
34
+ response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
35
+ response["SERVER_PORT"].should.equal @port.to_s
36
+ response["SERVER_NAME"].should =~ @host
37
+ end
38
+
39
+ specify "should have rack headers" do
40
+ GET("/test")
41
+ response["rack.version"].should.equal [0,1]
42
+ response["rack.multithread"].should.be false
43
+ response["rack.multiprocess"].should.be true
44
+ response["rack.run_once"].should.be true
45
+ end
46
+
47
+ specify "should have CGI headers on GET" do
48
+ GET("/test")
49
+ response["REQUEST_METHOD"].should.equal "GET"
50
+ response["SCRIPT_NAME"].should.equal "/test"
51
+ response["REQUEST_PATH"].should.equal "/"
52
+ response["PATH_INFO"].should.be.nil
53
+ response["QUERY_STRING"].should.equal ""
54
+ response["test.postdata"].should.equal ""
55
+
56
+ GET("/test/foo?quux=1")
57
+ response["REQUEST_METHOD"].should.equal "GET"
58
+ response["SCRIPT_NAME"].should.equal "/test"
59
+ response["REQUEST_PATH"].should.equal "/"
60
+ response["PATH_INFO"].should.equal "/foo"
61
+ response["QUERY_STRING"].should.equal "quux=1"
62
+ end
63
+
64
+ specify "should have CGI headers on POST" do
65
+ POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
66
+ status.should.equal 200
67
+ response["REQUEST_METHOD"].should.equal "POST"
68
+ response["SCRIPT_NAME"].should.equal "/test"
69
+ response["REQUEST_PATH"].should.equal "/"
70
+ response["QUERY_STRING"].should.equal ""
71
+ response["HTTP_X_TEST_HEADER"].should.equal "42"
72
+ response["test.postdata"].should.equal "rack-form-data=23"
73
+ end
74
+
75
+ specify "should support HTTP auth" do
76
+ GET("/test", {:user => "ruth", :passwd => "secret"})
77
+ response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
78
+ end
79
+
80
+ specify "should set status" do
81
+ GET("/test?secret")
82
+ status.should.equal 403
83
+ response["rack.url_scheme"].should.equal "http"
84
+ end
85
+
86
+ # Keep this last.
87
+ specify "shutdown" do
88
+ Process.kill 15, $pid
89
+ Process.wait($pid).should.equal $pid
90
+ end
91
+ end
@@ -0,0 +1,32 @@
1
+ require 'test/spec'
2
+ require 'stringio'
3
+
4
+ require 'rack/commonlogger'
5
+ require 'rack/lobster'
6
+ require 'rack/mock'
7
+
8
+ context "Rack::CommonLogger" do
9
+ app = lambda { |env|
10
+ [200,
11
+ {"Content-Type" => "text/html"},
12
+ ["foo"]]}
13
+
14
+ specify "should log to rack.errors by default" do
15
+ log = StringIO.new
16
+ res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
17
+
18
+ res.errors.should.not.be.empty
19
+ res.errors.should =~ /GET /
20
+ res.errors.should =~ / 200 / # status
21
+ res.errors.should =~ / 3 / # length
22
+ end
23
+
24
+ specify "should log to anything with <<" do
25
+ log = ""
26
+ res = Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
27
+
28
+ log.should =~ /GET /
29
+ log.should =~ / 200 / # status
30
+ log.should =~ / 3 / # length
31
+ end
32
+ end
@@ -0,0 +1,91 @@
1
+ require 'test/spec'
2
+ require 'testrequest'
3
+
4
+ context "Rack::Handler::FastCGI" do
5
+ include TestRequest::Helpers
6
+
7
+ setup do
8
+ @host = '0.0.0.0'
9
+ @port = 9203
10
+ end
11
+
12
+ # Keep this first.
13
+ specify "startup" do
14
+ $pid = fork {
15
+ rack_home = File.expand_path(File.join(File.dirname(__FILE__), ".."))
16
+ ENV['RUBYLIB'] = File.join(rack_home, "lib")
17
+ Dir.chdir(File.join(rack_home, "test", "cgi"))
18
+ exec "lighttpd -D -f lighttpd.conf"
19
+ }
20
+ end
21
+
22
+ specify "should respond" do
23
+ sleep 1
24
+ lambda {
25
+ GET("/test.fcgi")
26
+ }.should.not.raise
27
+ end
28
+
29
+ specify "should be a lighttpd" do
30
+ GET("/test.fcgi")
31
+ status.should.be 200
32
+ response["SERVER_SOFTWARE"].should =~ /lighttpd/
33
+ response["HTTP_VERSION"].should.equal "HTTP/1.1"
34
+ response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
35
+ response["SERVER_PORT"].should.equal @port.to_s
36
+ response["SERVER_NAME"].should =~ @host
37
+ end
38
+
39
+ specify "should have rack headers" do
40
+ GET("/test.fcgi")
41
+ response["rack.version"].should.equal [0,1]
42
+ response["rack.multithread"].should.be false
43
+ response["rack.multiprocess"].should.be true
44
+ response["rack.run_once"].should.be false
45
+ end
46
+
47
+ specify "should have CGI headers on GET" do
48
+ GET("/test.fcgi")
49
+ response["REQUEST_METHOD"].should.equal "GET"
50
+ response["SCRIPT_NAME"].should.equal "/test.fcgi"
51
+ response["REQUEST_PATH"].should.equal "/"
52
+ response["PATH_INFO"].should.be.nil
53
+ response["QUERY_STRING"].should.equal ""
54
+ response["test.postdata"].should.equal ""
55
+
56
+ GET("/test.fcgi/foo?quux=1")
57
+ response["REQUEST_METHOD"].should.equal "GET"
58
+ response["SCRIPT_NAME"].should.equal "/test.fcgi"
59
+ response["REQUEST_PATH"].should.equal "/"
60
+ response["PATH_INFO"].should.equal "/foo"
61
+ response["QUERY_STRING"].should.equal "quux=1"
62
+ end
63
+
64
+ specify "should have CGI headers on POST" do
65
+ POST("/test.fcgi", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
66
+ status.should.equal 200
67
+ response["REQUEST_METHOD"].should.equal "POST"
68
+ response["SCRIPT_NAME"].should.equal "/test.fcgi"
69
+ response["REQUEST_PATH"].should.equal "/"
70
+ response["QUERY_STRING"].should.equal ""
71
+ response["HTTP_X_TEST_HEADER"].should.equal "42"
72
+ response["test.postdata"].should.equal "rack-form-data=23"
73
+ end
74
+
75
+ specify "should support HTTP auth" do
76
+ GET("/test.fcgi", {:user => "ruth", :passwd => "secret"})
77
+ response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
78
+ end
79
+
80
+ specify "should set status" do
81
+ GET("/test.fcgi?secret")
82
+ status.should.equal 403
83
+ response["rack.url_scheme"].should.equal "http"
84
+ end
85
+
86
+ # Keep this last.
87
+ specify "shutdown" do
88
+ Process.kill 15, $pid
89
+ Process.wait($pid).should.equal $pid
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/file'
4
+ require 'rack/lint'
5
+
6
+ require 'rack/mock'
7
+
8
+ context "Rack::File" do
9
+ DOCROOT = File.expand_path(File.dirname(__FILE__))
10
+
11
+ specify "serves files" do
12
+ res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
13
+ get("/cgi/test")
14
+
15
+ res.should.be.ok
16
+ res.should =~ /ruby/
17
+ end
18
+
19
+ specify "serves files with URL encoded filenames" do
20
+ res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
21
+ get("/cgi/%74%65%73%74") # "/cgi/test"
22
+
23
+ res.should.be.ok
24
+ res.should =~ /ruby/
25
+ end
26
+
27
+ specify "does not allow directory traversal" do
28
+ res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
29
+ get("/cgi/../test")
30
+
31
+ res.should.be.forbidden
32
+ end
33
+
34
+ specify "404s if it can't find the file" do
35
+ res = Rack::MockRequest.new(Rack::Lint.new(Rack::File.new(DOCROOT))).
36
+ get("/cgi/blubb")
37
+
38
+ res.should.be.not_found
39
+ end
40
+ end
@@ -0,0 +1,317 @@
1
+ require 'test/spec'
2
+ require 'stringio'
3
+
4
+ require 'rack/lint'
5
+ require 'rack/mock'
6
+
7
+ context "Rack::Lint" do
8
+ def env(*args)
9
+ Rack::MockRequest.env_for("/", *args)
10
+ end
11
+
12
+ specify "passes valid request" do
13
+ lambda {
14
+ Rack::Lint.new(lambda { |env|
15
+ [200, {"Content-type" => "test/plain"}, "foo"]
16
+ }).call(env({}))
17
+ }.should.not.raise
18
+ end
19
+
20
+ specify "notices fatal errors" do
21
+ lambda { Rack::Lint.new(nil).call }.should.raise(Rack::Lint::LintError).
22
+ message.should.match(/No env given/)
23
+ end
24
+
25
+ specify "notices environment errors" do
26
+ lambda { Rack::Lint.new(nil).call 5 }.should.raise(Rack::Lint::LintError).
27
+ message.should.match(/not a Hash/)
28
+
29
+ lambda {
30
+ e = env
31
+ e.delete("REQUEST_METHOD")
32
+ Rack::Lint.new(nil).call(e)
33
+ }.should.raise(Rack::Lint::LintError).
34
+ message.should.match(/missing required key REQUEST_METHOD/)
35
+
36
+ lambda {
37
+ e = env
38
+ e.delete("SERVER_NAME")
39
+ Rack::Lint.new(nil).call(e)
40
+ }.should.raise(Rack::Lint::LintError).
41
+ message.should.match(/missing required key SERVER_NAME/)
42
+
43
+
44
+ lambda {
45
+ Rack::Lint.new(nil).call(env("HTTP_CONTENT_TYPE" => "text/plain"))
46
+ }.should.raise(Rack::Lint::LintError).
47
+ message.should.match(/contains HTTP_CONTENT_TYPE/)
48
+
49
+ lambda {
50
+ Rack::Lint.new(nil).call(env("HTTP_CONTENT_LENGTH" => "42"))
51
+ }.should.raise(Rack::Lint::LintError).
52
+ message.should.match(/contains HTTP_CONTENT_LENGTH/)
53
+
54
+ lambda {
55
+ Rack::Lint.new(nil).call(env("FOO" => Object.new))
56
+ }.should.raise(Rack::Lint::LintError).
57
+ message.should.match(/non-string value/)
58
+
59
+ lambda {
60
+ Rack::Lint.new(nil).call(env("rack.version" => "0.2"))
61
+ }.should.raise(Rack::Lint::LintError).
62
+ message.should.match(/must be an Array/)
63
+
64
+ lambda {
65
+ Rack::Lint.new(nil).call(env("rack.url_scheme" => "gopher"))
66
+ }.should.raise(Rack::Lint::LintError).
67
+ message.should.match(/url_scheme unknown/)
68
+
69
+ lambda {
70
+ Rack::Lint.new(nil).call(env("REQUEST_METHOD" => "FUCKUP"))
71
+ }.should.raise(Rack::Lint::LintError).
72
+ message.should.match(/REQUEST_METHOD unknown/)
73
+
74
+ lambda {
75
+ Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "howdy"))
76
+ }.should.raise(Rack::Lint::LintError).
77
+ message.should.match(/must start with/)
78
+
79
+ lambda {
80
+ Rack::Lint.new(nil).call(env("PATH_INFO" => "../foo"))
81
+ }.should.raise(Rack::Lint::LintError).
82
+ message.should.match(/must start with/)
83
+
84
+ lambda {
85
+ Rack::Lint.new(nil).call(env("CONTENT_LENGTH" => "xcii"))
86
+ }.should.raise(Rack::Lint::LintError).
87
+ message.should.match(/Invalid CONTENT_LENGTH/)
88
+
89
+ lambda {
90
+ e = env
91
+ e.delete("PATH_INFO")
92
+ e.delete("SCRIPT_NAME")
93
+ Rack::Lint.new(nil).call(e)
94
+ }.should.raise(Rack::Lint::LintError).
95
+ message.should.match(/One of .* must be set/)
96
+
97
+ lambda {
98
+ Rack::Lint.new(nil).call(env("SCRIPT_NAME" => "/"))
99
+ }.should.raise(Rack::Lint::LintError).
100
+ message.should.match(/cannot be .* make it ''/)
101
+ end
102
+
103
+ specify "notices input errors" do
104
+ lambda {
105
+ Rack::Lint.new(nil).call(env("rack.input" => ""))
106
+ }.should.raise(Rack::Lint::LintError).
107
+ message.should.match(/does not respond to #gets/)
108
+ end
109
+
110
+ specify "notices error errors" do
111
+ lambda {
112
+ Rack::Lint.new(nil).call(env("rack.errors" => ""))
113
+ }.should.raise(Rack::Lint::LintError).
114
+ message.should.match(/does not respond to #puts/)
115
+ end
116
+
117
+ specify "notices status errors" do
118
+ lambda {
119
+ Rack::Lint.new(lambda { |env|
120
+ ["cc", {}, ""]
121
+ }).call(env({}))
122
+ }.should.raise(Rack::Lint::LintError).
123
+ message.should.match(/must be >100 seen as integer/)
124
+
125
+ lambda {
126
+ Rack::Lint.new(lambda { |env|
127
+ [42, {}, ""]
128
+ }).call(env({}))
129
+ }.should.raise(Rack::Lint::LintError).
130
+ message.should.match(/must be >100 seen as integer/)
131
+ end
132
+
133
+ specify "notices header errors" do
134
+ lambda {
135
+ Rack::Lint.new(lambda { |env|
136
+ [200, Object.new, ""]
137
+ }).call(env({}))
138
+ }.should.raise(Rack::Lint::LintError).
139
+ message.should.match(/should respond to #each/)
140
+
141
+ lambda {
142
+ Rack::Lint.new(lambda { |env|
143
+ [200, {true=>false}, ""]
144
+ }).call(env({}))
145
+ }.should.raise(Rack::Lint::LintError).
146
+ message.should.match(/header key must be a string/)
147
+
148
+ lambda {
149
+ Rack::Lint.new(lambda { |env|
150
+ [200, {"Status" => "404"}, ""]
151
+ }).call(env({}))
152
+ }.should.raise(Rack::Lint::LintError).
153
+ message.should.match(/must not contain Status/)
154
+
155
+ lambda {
156
+ Rack::Lint.new(lambda { |env|
157
+ [200, {"Content-Type:" => "text/plain"}, ""]
158
+ }).call(env({}))
159
+ }.should.raise(Rack::Lint::LintError).
160
+ message.should.match(/must not contain :/)
161
+
162
+ lambda {
163
+ Rack::Lint.new(lambda { |env|
164
+ [200, {"Content-" => "text/plain"}, ""]
165
+ }).call(env({}))
166
+ }.should.raise(Rack::Lint::LintError).
167
+ message.should.match(/must not end/)
168
+
169
+ lambda {
170
+ Rack::Lint.new(lambda { |env|
171
+ [200, {"..%%quark%%.." => "text/plain"}, ""]
172
+ }).call(env({}))
173
+ }.should.raise(Rack::Lint::LintError).
174
+ message.should.match(/invalid header/)
175
+
176
+ lambda {
177
+ Rack::Lint.new(lambda { |env|
178
+ [200, {"Foo" => Object.new}, ""]
179
+ }).call(env({}))
180
+ }.should.raise(Rack::Lint::LintError).
181
+ message.should.match(/must respond to #each/)
182
+
183
+ lambda {
184
+ Rack::Lint.new(lambda { |env|
185
+ [200, {"Foo" => [1,2,3]}, ""]
186
+ }).call(env({}))
187
+ }.should.raise(Rack::Lint::LintError).
188
+ message.should.match(/must consist of Strings/)
189
+
190
+
191
+ lambda {
192
+ Rack::Lint.new(lambda { |env|
193
+ [200, {"Foo-Bar" => "text\000plain"}, ""]
194
+ }).call(env({}))
195
+ }.should.raise(Rack::Lint::LintError).
196
+ message.should.match(/invalid header/)
197
+ end
198
+
199
+ specify "notices content-type errors" do
200
+ lambda {
201
+ Rack::Lint.new(lambda { |env|
202
+ [200, {}, ""]
203
+ }).call(env({}))
204
+ }.should.raise(Rack::Lint::LintError).
205
+ message.should.match(/No Content-Type/)
206
+
207
+ lambda {
208
+ Rack::Lint.new(lambda { |env|
209
+ [204, {"Content-Type" => "text/plain"}, ""]
210
+ }).call(env({}))
211
+ }.should.raise(Rack::Lint::LintError).
212
+ message.should.match(/Content-Type header found/)
213
+
214
+ lambda {
215
+ Rack::Lint.new(lambda { |env|
216
+ [204, {"Content-type" => "text/plain"}, ""]
217
+ }).call(env({}))
218
+ }.should.raise(Rack::Lint::LintError).
219
+ message.should.match(/Content-Type header found/)
220
+ end
221
+
222
+ specify "notices body errors" do
223
+ lambda {
224
+ status, header, body = Rack::Lint.new(lambda { |env|
225
+ [200, {"Content-type" => "text/plain"}, [1,2,3]]
226
+ }).call(env({}))
227
+ body.each { |part| }
228
+ }.should.raise(Rack::Lint::LintError).
229
+ message.should.match(/yielded non-string/)
230
+ end
231
+
232
+ specify "notices input handling errors" do
233
+ lambda {
234
+ Rack::Lint.new(lambda { |env|
235
+ env["rack.input"].gets("\r\n")
236
+ [201, {"Content-type" => "text/plain"}, ""]
237
+ }).call(env({}))
238
+ }.should.raise(Rack::Lint::LintError).
239
+ message.should.match(/gets called with arguments/)
240
+
241
+ lambda {
242
+ Rack::Lint.new(lambda { |env|
243
+ env["rack.input"].read("foo")
244
+ [201, {"Content-type" => "text/plain"}, ""]
245
+ }).call(env({}))
246
+ }.should.raise(Rack::Lint::LintError).
247
+ message.should.match(/read called with non-integer argument/)
248
+
249
+ weirdio = Object.new
250
+ class << weirdio
251
+ def gets
252
+ 42
253
+ end
254
+
255
+ def read
256
+ 23
257
+ end
258
+
259
+ def each
260
+ yield 23
261
+ yield 42
262
+ end
263
+ end
264
+
265
+ lambda {
266
+ Rack::Lint.new(lambda { |env|
267
+ env["rack.input"].gets
268
+ [201, {"Content-type" => "text/plain"}, ""]
269
+ }).call(env("rack.input" => weirdio))
270
+ }.should.raise(Rack::Lint::LintError).
271
+ message.should.match(/gets didn't return a String/)
272
+
273
+ lambda {
274
+ Rack::Lint.new(lambda { |env|
275
+ env["rack.input"].each { |x| }
276
+ [201, {"Content-type" => "text/plain"}, ""]
277
+ }).call(env("rack.input" => weirdio))
278
+ }.should.raise(Rack::Lint::LintError).
279
+ message.should.match(/each didn't yield a String/)
280
+
281
+ lambda {
282
+ Rack::Lint.new(lambda { |env|
283
+ env["rack.input"].read
284
+ [201, {"Content-type" => "text/plain"}, ""]
285
+ }).call(env("rack.input" => weirdio))
286
+ }.should.raise(Rack::Lint::LintError).
287
+ message.should.match(/read didn't return a String/)
288
+
289
+
290
+ lambda {
291
+ Rack::Lint.new(lambda { |env|
292
+ env["rack.input"].close
293
+ [201, {"Content-type" => "text/plain"}, ""]
294
+ }).call(env({}))
295
+ }.should.raise(Rack::Lint::LintError).
296
+ message.should.match(/close must not be called/)
297
+ end
298
+
299
+ specify "notices error handling errors" do
300
+ lambda {
301
+ Rack::Lint.new(lambda { |env|
302
+ env["rack.errors"].write(42)
303
+ [201, {"Content-type" => "text/plain"}, ""]
304
+ }).call(env({}))
305
+ }.should.raise(Rack::Lint::LintError).
306
+ message.should.match(/write not called with a String/)
307
+
308
+ lambda {
309
+ Rack::Lint.new(lambda { |env|
310
+ env["rack.errors"].close
311
+ [201, {"Content-type" => "text/plain"}, ""]
312
+ }).call(env({}))
313
+ }.should.raise(Rack::Lint::LintError).
314
+ message.should.match(/close must not be called/)
315
+ end
316
+
317
+ end