kastner-rack 0.3.171

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. data/AUTHORS +8 -0
  2. data/COPYING +18 -0
  3. data/KNOWN-ISSUES +18 -0
  4. data/README +273 -0
  5. data/Rakefile +185 -0
  6. data/bin/rackup +172 -0
  7. data/contrib/rack_logo.svg +111 -0
  8. data/example/lobster.ru +4 -0
  9. data/example/protectedlobster.rb +14 -0
  10. data/example/protectedlobster.ru +8 -0
  11. data/lib/rack.rb +85 -0
  12. data/lib/rack/adapter/camping.rb +22 -0
  13. data/lib/rack/auth/abstract/handler.rb +28 -0
  14. data/lib/rack/auth/abstract/request.rb +37 -0
  15. data/lib/rack/auth/basic.rb +58 -0
  16. data/lib/rack/auth/digest/md5.rb +124 -0
  17. data/lib/rack/auth/digest/nonce.rb +51 -0
  18. data/lib/rack/auth/digest/params.rb +55 -0
  19. data/lib/rack/auth/digest/request.rb +40 -0
  20. data/lib/rack/auth/openid.rb +437 -0
  21. data/lib/rack/builder.rb +67 -0
  22. data/lib/rack/cascade.rb +36 -0
  23. data/lib/rack/commonlogger.rb +61 -0
  24. data/lib/rack/conditionalget.rb +42 -0
  25. data/lib/rack/deflater.rb +63 -0
  26. data/lib/rack/directory.rb +149 -0
  27. data/lib/rack/file.rb +84 -0
  28. data/lib/rack/handler.rb +46 -0
  29. data/lib/rack/handler/cgi.rb +57 -0
  30. data/lib/rack/handler/evented_mongrel.rb +8 -0
  31. data/lib/rack/handler/fastcgi.rb +86 -0
  32. data/lib/rack/handler/lsws.rb +52 -0
  33. data/lib/rack/handler/mongrel.rb +78 -0
  34. data/lib/rack/handler/scgi.rb +57 -0
  35. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  36. data/lib/rack/handler/webrick.rb +61 -0
  37. data/lib/rack/head.rb +19 -0
  38. data/lib/rack/lint.rb +463 -0
  39. data/lib/rack/lobster.rb +65 -0
  40. data/lib/rack/methodoverride.rb +21 -0
  41. data/lib/rack/mime.rb +204 -0
  42. data/lib/rack/mock.rb +160 -0
  43. data/lib/rack/recursive.rb +57 -0
  44. data/lib/rack/reloader.rb +64 -0
  45. data/lib/rack/request.rb +217 -0
  46. data/lib/rack/response.rb +171 -0
  47. data/lib/rack/session/abstract/id.rb +140 -0
  48. data/lib/rack/session/cookie.rb +89 -0
  49. data/lib/rack/session/memcache.rb +97 -0
  50. data/lib/rack/session/pool.rb +73 -0
  51. data/lib/rack/showexceptions.rb +348 -0
  52. data/lib/rack/showstatus.rb +105 -0
  53. data/lib/rack/static.rb +38 -0
  54. data/lib/rack/urlmap.rb +48 -0
  55. data/lib/rack/utils.rb +318 -0
  56. data/rack.gemspec +31 -0
  57. data/test/cgi/lighttpd.conf +20 -0
  58. data/test/cgi/test +9 -0
  59. data/test/cgi/test.fcgi +8 -0
  60. data/test/cgi/test.ru +7 -0
  61. data/test/spec_rack_auth_basic.rb +69 -0
  62. data/test/spec_rack_auth_digest.rb +169 -0
  63. data/test/spec_rack_auth_openid.rb +137 -0
  64. data/test/spec_rack_builder.rb +84 -0
  65. data/test/spec_rack_camping.rb +51 -0
  66. data/test/spec_rack_cascade.rb +50 -0
  67. data/test/spec_rack_cgi.rb +89 -0
  68. data/test/spec_rack_commonlogger.rb +32 -0
  69. data/test/spec_rack_conditionalget.rb +41 -0
  70. data/test/spec_rack_deflater.rb +70 -0
  71. data/test/spec_rack_directory.rb +56 -0
  72. data/test/spec_rack_fastcgi.rb +89 -0
  73. data/test/spec_rack_file.rb +57 -0
  74. data/test/spec_rack_handler.rb +24 -0
  75. data/test/spec_rack_head.rb +30 -0
  76. data/test/spec_rack_lint.rb +371 -0
  77. data/test/spec_rack_lobster.rb +45 -0
  78. data/test/spec_rack_methodoverride.rb +31 -0
  79. data/test/spec_rack_mock.rb +152 -0
  80. data/test/spec_rack_mongrel.rb +170 -0
  81. data/test/spec_rack_recursive.rb +77 -0
  82. data/test/spec_rack_request.rb +426 -0
  83. data/test/spec_rack_response.rb +173 -0
  84. data/test/spec_rack_session_cookie.rb +78 -0
  85. data/test/spec_rack_session_memcache.rb +132 -0
  86. data/test/spec_rack_session_pool.rb +84 -0
  87. data/test/spec_rack_showexceptions.rb +21 -0
  88. data/test/spec_rack_showstatus.rb +72 -0
  89. data/test/spec_rack_static.rb +37 -0
  90. data/test/spec_rack_urlmap.rb +175 -0
  91. data/test/spec_rack_utils.rb +174 -0
  92. data/test/spec_rack_webrick.rb +123 -0
  93. data/test/testrequest.rb +45 -0
  94. metadata +177 -0
@@ -0,0 +1,84 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/builder'
4
+ require 'rack/mock'
5
+ require 'rack/showexceptions'
6
+ require 'rack/auth/basic'
7
+
8
+ context "Rack::Builder" do
9
+ specify "chains apps by default" do
10
+ app = Rack::Builder.new do
11
+ use Rack::ShowExceptions
12
+ run lambda { |env| raise "bzzzt" }
13
+ end.to_app
14
+
15
+ Rack::MockRequest.new(app).get("/").should.be.server_error
16
+ Rack::MockRequest.new(app).get("/").should.be.server_error
17
+ Rack::MockRequest.new(app).get("/").should.be.server_error
18
+ end
19
+
20
+ specify "has implicit #to_app" do
21
+ app = Rack::Builder.new do
22
+ use Rack::ShowExceptions
23
+ run lambda { |env| raise "bzzzt" }
24
+ end
25
+
26
+ Rack::MockRequest.new(app).get("/").should.be.server_error
27
+ Rack::MockRequest.new(app).get("/").should.be.server_error
28
+ Rack::MockRequest.new(app).get("/").should.be.server_error
29
+ end
30
+
31
+ specify "supports blocks on use" do
32
+ app = Rack::Builder.new do
33
+ use Rack::ShowExceptions
34
+ use Rack::Auth::Basic do |username, password|
35
+ 'secret' == password
36
+ end
37
+
38
+ run lambda { |env| [200, {}, 'Hi Boss'] }
39
+ end
40
+
41
+ response = Rack::MockRequest.new(app).get("/")
42
+ response.should.be.client_error
43
+ response.status.should.equal 401
44
+
45
+ # with auth...
46
+ response = Rack::MockRequest.new(app).get("/",
47
+ 'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
48
+ response.status.should.equal 200
49
+ response.body.to_s.should.equal 'Hi Boss'
50
+ end
51
+
52
+ specify "has explicit #to_app" do
53
+ app = Rack::Builder.app do
54
+ use Rack::ShowExceptions
55
+ run lambda { |env| raise "bzzzt" }
56
+ end
57
+
58
+ Rack::MockRequest.new(app).get("/").should.be.server_error
59
+ Rack::MockRequest.new(app).get("/").should.be.server_error
60
+ Rack::MockRequest.new(app).get("/").should.be.server_error
61
+ end
62
+
63
+ specify "apps are initialized once" do
64
+ class AppClass
65
+ def initialize
66
+ @called = 0
67
+ end
68
+ def call(env)
69
+ raise "bzzzt" if @called > 0
70
+ @called += 1
71
+ [200, {'Content-Type' => 'text/plain'}, 'OK']
72
+ end
73
+ end
74
+
75
+ app = Rack::Builder.new do
76
+ use Rack::ShowExceptions
77
+ run AppClass.new
78
+ end
79
+
80
+ Rack::MockRequest.new(app).get("/").status.should.equal 200
81
+ Rack::MockRequest.new(app).get("/").should.be.server_error
82
+ end
83
+
84
+ end
@@ -0,0 +1,51 @@
1
+ require 'test/spec'
2
+ require 'stringio'
3
+ require 'uri'
4
+
5
+ begin
6
+ require 'rack/mock'
7
+
8
+ $-w, w = nil, $-w # yuck
9
+ require 'camping'
10
+ require 'rack/adapter/camping'
11
+
12
+ Camping.goes :CampApp
13
+ module CampApp
14
+ module Controllers
15
+ class HW < R('/')
16
+ def get
17
+ @headers["X-Served-By"] = URI("http://rack.rubyforge.org")
18
+ "Camping works!"
19
+ end
20
+
21
+ def post
22
+ "Data: #{input.foo}"
23
+ end
24
+ end
25
+ end
26
+ end
27
+ $-w = w
28
+
29
+ context "Rack::Adapter::Camping" do
30
+ specify "works with GET" do
31
+ res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)).
32
+ get("/")
33
+
34
+ res.should.be.ok
35
+ res["Content-Type"].should.equal "text/html"
36
+ res["X-Served-By"].should.equal "http://rack.rubyforge.org"
37
+
38
+ res.body.should.equal "Camping works!"
39
+ end
40
+
41
+ specify "works with POST" do
42
+ res = Rack::MockRequest.new(Rack::Adapter::Camping.new(CampApp)).
43
+ post("/", :input => "foo=bar")
44
+
45
+ res.should.be.ok
46
+ res.body.should.equal "Data: bar"
47
+ end
48
+ end
49
+ rescue LoadError
50
+ $stderr.puts "Skipping Rack::Adapter::Camping tests (Camping is required). `gem install camping` and try again."
51
+ 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,89 @@
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
+ Dir.chdir(File.join(File.dirname(__FILE__), "..", "test", "cgi"))
16
+ exec "lighttpd -D -f lighttpd.conf"
17
+ }
18
+ end
19
+
20
+ specify "should respond" do
21
+ sleep 1
22
+ lambda {
23
+ GET("/test")
24
+ }.should.not.raise
25
+ end
26
+
27
+ specify "should be a lighttpd" do
28
+ GET("/test")
29
+ status.should.be 200
30
+ response["SERVER_SOFTWARE"].should =~ /lighttpd/
31
+ response["HTTP_VERSION"].should.equal "HTTP/1.1"
32
+ response["SERVER_PROTOCOL"].should.equal "HTTP/1.1"
33
+ response["SERVER_PORT"].should.equal @port.to_s
34
+ response["SERVER_NAME"].should =~ @host
35
+ end
36
+
37
+ specify "should have rack headers" do
38
+ GET("/test")
39
+ response["rack.version"].should.equal [0,1]
40
+ response["rack.multithread"].should.be false
41
+ response["rack.multiprocess"].should.be true
42
+ response["rack.run_once"].should.be true
43
+ end
44
+
45
+ specify "should have CGI headers on GET" do
46
+ GET("/test")
47
+ response["REQUEST_METHOD"].should.equal "GET"
48
+ response["SCRIPT_NAME"].should.equal "/test"
49
+ response["REQUEST_PATH"].should.equal "/"
50
+ response["PATH_INFO"].should.be.nil
51
+ response["QUERY_STRING"].should.equal ""
52
+ response["test.postdata"].should.equal ""
53
+
54
+ GET("/test/foo?quux=1")
55
+ response["REQUEST_METHOD"].should.equal "GET"
56
+ response["SCRIPT_NAME"].should.equal "/test"
57
+ response["REQUEST_PATH"].should.equal "/"
58
+ response["PATH_INFO"].should.equal "/foo"
59
+ response["QUERY_STRING"].should.equal "quux=1"
60
+ end
61
+
62
+ specify "should have CGI headers on POST" do
63
+ POST("/test", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
64
+ status.should.equal 200
65
+ response["REQUEST_METHOD"].should.equal "POST"
66
+ response["SCRIPT_NAME"].should.equal "/test"
67
+ response["REQUEST_PATH"].should.equal "/"
68
+ response["QUERY_STRING"].should.equal ""
69
+ response["HTTP_X_TEST_HEADER"].should.equal "42"
70
+ response["test.postdata"].should.equal "rack-form-data=23"
71
+ end
72
+
73
+ specify "should support HTTP auth" do
74
+ GET("/test", {:user => "ruth", :passwd => "secret"})
75
+ response["HTTP_AUTHORIZATION"].should.equal "Basic cnV0aDpzZWNyZXQ="
76
+ end
77
+
78
+ specify "should set status" do
79
+ GET("/test?secret")
80
+ status.should.equal 403
81
+ response["rack.url_scheme"].should.equal "http"
82
+ end
83
+
84
+ # Keep this last.
85
+ specify "shutdown" do
86
+ Process.kill 15, $pid
87
+ Process.wait($pid).should.equal $pid
88
+ end
89
+ 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,41 @@
1
+ require 'test/spec'
2
+ require 'time'
3
+
4
+ require 'rack/mock'
5
+ require 'rack/conditionalget'
6
+
7
+ context "Rack::ConditionalGet" do
8
+ specify "should set a 304 status and truncate body when If-Modified-Since hits" do
9
+ timestamp = Time.now.httpdate
10
+ app = Rack::ConditionalGet.new(lambda { |env|
11
+ [200, {'Last-Modified'=>timestamp}, 'TEST'] })
12
+
13
+ response = Rack::MockRequest.new(app).
14
+ get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp)
15
+
16
+ response.status.should.be == 304
17
+ response.body.should.be.empty
18
+ end
19
+
20
+ specify "should set a 304 status and truncate body when If-None-Match hits" do
21
+ app = Rack::ConditionalGet.new(lambda { |env|
22
+ [200, {'Etag'=>'1234'}, 'TEST'] })
23
+
24
+ response = Rack::MockRequest.new(app).
25
+ get("/", 'HTTP_IF_NONE_MATCH' => '1234')
26
+
27
+ response.status.should.be == 304
28
+ response.body.should.be.empty
29
+ end
30
+
31
+ specify "should not affect non-GET/HEAD requests" do
32
+ app = Rack::ConditionalGet.new(lambda { |env|
33
+ [200, {'Etag'=>'1234'}, 'TEST'] })
34
+
35
+ response = Rack::MockRequest.new(app).
36
+ post("/", 'HTTP_IF_NONE_MATCH' => '1234')
37
+
38
+ response.status.should.be == 200
39
+ response.body.should.be == 'TEST'
40
+ end
41
+ end
@@ -0,0 +1,70 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/mock'
4
+ require 'rack/deflater'
5
+ require 'stringio'
6
+
7
+ context "Rack::Deflater" do
8
+ def build_response(body, accept_encoding, headers = {})
9
+ app = lambda { |env| [200, {}, body] }
10
+ request = Rack::MockRequest.env_for("", headers.merge("HTTP_ACCEPT_ENCODING" => accept_encoding))
11
+ response = Rack::Deflater.new(app).call(request)
12
+
13
+ return response
14
+ end
15
+
16
+ specify "should be able to deflate bodies that respond to each" do
17
+ body = Object.new
18
+ class << body; def each; yield("foo"); yield("bar"); end; end
19
+
20
+ response = build_response(body, "deflate")
21
+
22
+ response[0].should.equal(200)
23
+ response[1].should.equal({ "Content-Encoding" => "deflate" })
24
+ response[2].to_s.should.equal("K\313\317OJ,\002\000")
25
+ end
26
+
27
+ # TODO: This is really just a special case of the above...
28
+ specify "should be able to deflate String bodies" do
29
+ response = build_response("Hello world!", "deflate")
30
+
31
+ response[0].should.equal(200)
32
+ response[1].should.equal({ "Content-Encoding" => "deflate" })
33
+ response[2].to_s.should.equal("\363H\315\311\311W(\317/\312IQ\004\000")
34
+ end
35
+
36
+ specify "should be able to gzip bodies that respond to each" do
37
+ body = Object.new
38
+ class << body; def each; yield("foo"); yield("bar"); end; end
39
+
40
+ response = build_response(body, "gzip")
41
+
42
+ response[0].should.equal(200)
43
+ response[1].should.equal({ "Content-Encoding" => "gzip" })
44
+
45
+ io = StringIO.new(response[2].to_s)
46
+ gz = Zlib::GzipReader.new(io)
47
+ gz.read.should.equal("foobar")
48
+ gz.close
49
+ end
50
+
51
+ specify "should be able to fallback to no deflation" do
52
+ response = build_response("Hello world!", "superzip")
53
+
54
+ response[0].should.equal(200)
55
+ response[1].should.equal({})
56
+ response[2].should.equal("Hello world!")
57
+ end
58
+
59
+ specify "should handle the lack of an acceptable encoding" do
60
+ response1 = build_response("Hello world!", "identity;q=0", "PATH_INFO" => "/")
61
+ response1[0].should.equal(406)
62
+ response1[1].should.equal({"Content-Type" => "text/plain"})
63
+ response1[2].should.equal("An acceptable encoding for the requested resource / could not be found.")
64
+
65
+ response2 = build_response("Hello world!", "identity;q=0", "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/bar")
66
+ response2[0].should.equal(406)
67
+ response2[1].should.equal({"Content-Type" => "text/plain"})
68
+ response2[2].should.equal("An acceptable encoding for the requested resource /foo/bar could not be found.")
69
+ end
70
+ end
@@ -0,0 +1,56 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/directory'
4
+ require 'rack/lint'
5
+
6
+ require 'rack/mock'
7
+
8
+ context "Rack::Directory" do
9
+ DOCROOT = File.expand_path(File.dirname(__FILE__))
10
+ FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, 'passed!'] }
11
+ app = Rack::Directory.new DOCROOT, FILE_CATCH
12
+
13
+ specify "serves directory indices" do
14
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
15
+ get("/cgi/")
16
+
17
+ res.should.be.ok
18
+ res.should =~ /<html><head>/
19
+ end
20
+
21
+ specify "passes to app if file found" do
22
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
23
+ get("/cgi/test")
24
+
25
+ res.should.be.ok
26
+ res.should =~ /passed!/
27
+ end
28
+
29
+ specify "serves uri with URL encoded filenames" do
30
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
31
+ get("/%63%67%69/") # "/cgi/test"
32
+
33
+ res.should.be.ok
34
+ res.should =~ /<html><head>/
35
+
36
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
37
+ get("/cgi/%74%65%73%74") # "/cgi/test"
38
+
39
+ res.should.be.ok
40
+ res.should =~ /passed!/
41
+ end
42
+
43
+ specify "does not allow directory traversal" do
44
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
45
+ get("/cgi/../test")
46
+
47
+ res.should.be.forbidden
48
+ end
49
+
50
+ specify "404s if it can't find the file" do
51
+ res = Rack::MockRequest.new(Rack::Lint.new(app)).
52
+ get("/cgi/blubb")
53
+
54
+ res.should.be.not_found
55
+ end
56
+ end