eac-rack 1.1.1

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 (111) hide show
  1. data/COPYING +18 -0
  2. data/KNOWN-ISSUES +21 -0
  3. data/README +399 -0
  4. data/bin/rackup +4 -0
  5. data/contrib/rack_logo.svg +111 -0
  6. data/example/lobster.ru +4 -0
  7. data/example/protectedlobster.rb +14 -0
  8. data/example/protectedlobster.ru +8 -0
  9. data/lib/rack.rb +92 -0
  10. data/lib/rack/adapter/camping.rb +22 -0
  11. data/lib/rack/auth/abstract/handler.rb +37 -0
  12. data/lib/rack/auth/abstract/request.rb +37 -0
  13. data/lib/rack/auth/basic.rb +58 -0
  14. data/lib/rack/auth/digest/md5.rb +124 -0
  15. data/lib/rack/auth/digest/nonce.rb +51 -0
  16. data/lib/rack/auth/digest/params.rb +55 -0
  17. data/lib/rack/auth/digest/request.rb +40 -0
  18. data/lib/rack/builder.rb +80 -0
  19. data/lib/rack/cascade.rb +41 -0
  20. data/lib/rack/chunked.rb +49 -0
  21. data/lib/rack/commonlogger.rb +49 -0
  22. data/lib/rack/conditionalget.rb +47 -0
  23. data/lib/rack/config.rb +15 -0
  24. data/lib/rack/content_length.rb +29 -0
  25. data/lib/rack/content_type.rb +23 -0
  26. data/lib/rack/deflater.rb +96 -0
  27. data/lib/rack/directory.rb +157 -0
  28. data/lib/rack/etag.rb +23 -0
  29. data/lib/rack/file.rb +90 -0
  30. data/lib/rack/handler.rb +88 -0
  31. data/lib/rack/handler/cgi.rb +61 -0
  32. data/lib/rack/handler/evented_mongrel.rb +8 -0
  33. data/lib/rack/handler/fastcgi.rb +89 -0
  34. data/lib/rack/handler/lsws.rb +63 -0
  35. data/lib/rack/handler/mongrel.rb +90 -0
  36. data/lib/rack/handler/scgi.rb +62 -0
  37. data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
  38. data/lib/rack/handler/thin.rb +18 -0
  39. data/lib/rack/handler/webrick.rb +69 -0
  40. data/lib/rack/head.rb +19 -0
  41. data/lib/rack/lint.rb +575 -0
  42. data/lib/rack/lobster.rb +65 -0
  43. data/lib/rack/lock.rb +16 -0
  44. data/lib/rack/logger.rb +20 -0
  45. data/lib/rack/methodoverride.rb +27 -0
  46. data/lib/rack/mime.rb +206 -0
  47. data/lib/rack/mock.rb +189 -0
  48. data/lib/rack/nulllogger.rb +18 -0
  49. data/lib/rack/recursive.rb +57 -0
  50. data/lib/rack/reloader.rb +109 -0
  51. data/lib/rack/request.rb +271 -0
  52. data/lib/rack/response.rb +149 -0
  53. data/lib/rack/rewindable_input.rb +100 -0
  54. data/lib/rack/runtime.rb +27 -0
  55. data/lib/rack/sendfile.rb +142 -0
  56. data/lib/rack/server.rb +212 -0
  57. data/lib/rack/session/abstract/id.rb +140 -0
  58. data/lib/rack/session/cookie.rb +90 -0
  59. data/lib/rack/session/memcache.rb +119 -0
  60. data/lib/rack/session/pool.rb +100 -0
  61. data/lib/rack/showexceptions.rb +349 -0
  62. data/lib/rack/showstatus.rb +106 -0
  63. data/lib/rack/static.rb +38 -0
  64. data/lib/rack/urlmap.rb +56 -0
  65. data/lib/rack/utils.rb +614 -0
  66. data/rack.gemspec +38 -0
  67. data/test/spec_rack_auth_basic.rb +73 -0
  68. data/test/spec_rack_auth_digest.rb +226 -0
  69. data/test/spec_rack_builder.rb +84 -0
  70. data/test/spec_rack_camping.rb +51 -0
  71. data/test/spec_rack_cascade.rb +48 -0
  72. data/test/spec_rack_cgi.rb +89 -0
  73. data/test/spec_rack_chunked.rb +62 -0
  74. data/test/spec_rack_commonlogger.rb +61 -0
  75. data/test/spec_rack_conditionalget.rb +41 -0
  76. data/test/spec_rack_config.rb +24 -0
  77. data/test/spec_rack_content_length.rb +43 -0
  78. data/test/spec_rack_content_type.rb +30 -0
  79. data/test/spec_rack_deflater.rb +127 -0
  80. data/test/spec_rack_directory.rb +61 -0
  81. data/test/spec_rack_etag.rb +17 -0
  82. data/test/spec_rack_fastcgi.rb +89 -0
  83. data/test/spec_rack_file.rb +75 -0
  84. data/test/spec_rack_handler.rb +43 -0
  85. data/test/spec_rack_head.rb +30 -0
  86. data/test/spec_rack_lint.rb +528 -0
  87. data/test/spec_rack_lobster.rb +45 -0
  88. data/test/spec_rack_lock.rb +38 -0
  89. data/test/spec_rack_logger.rb +21 -0
  90. data/test/spec_rack_methodoverride.rb +60 -0
  91. data/test/spec_rack_mock.rb +243 -0
  92. data/test/spec_rack_mongrel.rb +189 -0
  93. data/test/spec_rack_nulllogger.rb +13 -0
  94. data/test/spec_rack_recursive.rb +77 -0
  95. data/test/spec_rack_request.rb +545 -0
  96. data/test/spec_rack_response.rb +221 -0
  97. data/test/spec_rack_rewindable_input.rb +118 -0
  98. data/test/spec_rack_runtime.rb +35 -0
  99. data/test/spec_rack_sendfile.rb +86 -0
  100. data/test/spec_rack_session_cookie.rb +73 -0
  101. data/test/spec_rack_session_memcache.rb +273 -0
  102. data/test/spec_rack_session_pool.rb +172 -0
  103. data/test/spec_rack_showexceptions.rb +21 -0
  104. data/test/spec_rack_showstatus.rb +72 -0
  105. data/test/spec_rack_static.rb +37 -0
  106. data/test/spec_rack_thin.rb +91 -0
  107. data/test/spec_rack_urlmap.rb +215 -0
  108. data/test/spec_rack_utils.rb +554 -0
  109. data/test/spec_rack_webrick.rb +130 -0
  110. data/test/spec_rackup.rb +154 -0
  111. metadata +311 -0
@@ -0,0 +1,38 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "eac-rack"
3
+ s.version = "1.1.1"
4
+ s.platform = Gem::Platform::RUBY
5
+ s.summary = "a modular Ruby webserver interface"
6
+
7
+ s.description = <<-EOF
8
+ Rack provides minimal, modular and adaptable interface for developing
9
+ web applications in Ruby. By wrapping HTTP requests and responses in
10
+ the simplest way possible, it unifies and distills the API for web
11
+ servers, web frameworks, and software in between (the so-called
12
+ middleware) into a single method call.
13
+
14
+ Also see http://rack.rubyforge.org.
15
+ EOF
16
+
17
+ s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*}'] +
18
+ %w(COPYING KNOWN-ISSUES rack.gemspec README)
19
+ s.bindir = 'bin'
20
+ s.executables << 'rackup'
21
+ s.require_path = 'lib'
22
+ s.has_rdoc = true
23
+ s.extra_rdoc_files = ['README', 'KNOWN-ISSUES']
24
+ s.test_files = Dir['test/{test,spec}_*.rb']
25
+
26
+ s.author = 'Christian Neukirchen'
27
+ s.email = 'chneukirchen@gmail.com'
28
+ s.homepage = 'http://rack.rubyforge.org'
29
+ #s.rubyforge_project = 'rack'
30
+
31
+ s.add_development_dependency 'test-spec'
32
+
33
+ s.add_development_dependency 'camping'
34
+ s.add_development_dependency 'fcgi'
35
+ s.add_development_dependency 'memcache-client'
36
+ s.add_development_dependency 'mongrel'
37
+ s.add_development_dependency 'thin'
38
+ end
@@ -0,0 +1,73 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/auth/basic'
4
+ require 'rack/mock'
5
+
6
+ context 'Rack::Auth::Basic' do
7
+
8
+ def realm
9
+ 'WallysWorld'
10
+ end
11
+
12
+ def unprotected_app
13
+ lambda { |env| [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ] }
14
+ end
15
+
16
+ def protected_app
17
+ app = Rack::Auth::Basic.new(unprotected_app) { |username, password| 'Boss' == username }
18
+ app.realm = realm
19
+ app
20
+ end
21
+
22
+ setup do
23
+ @request = Rack::MockRequest.new(protected_app)
24
+ end
25
+
26
+ def request_with_basic_auth(username, password, &block)
27
+ request 'HTTP_AUTHORIZATION' => 'Basic ' + ["#{username}:#{password}"].pack("m*"), &block
28
+ end
29
+
30
+ def request(headers = {})
31
+ yield @request.get('/', headers)
32
+ end
33
+
34
+ def assert_basic_auth_challenge(response)
35
+ response.should.be.a.client_error
36
+ response.status.should.equal 401
37
+ response.should.include 'WWW-Authenticate'
38
+ response.headers['WWW-Authenticate'].should =~ /Basic realm="#{Regexp.escape(realm)}"/
39
+ response.body.should.be.empty
40
+ end
41
+
42
+ specify 'should challenge correctly when no credentials are specified' do
43
+ request do |response|
44
+ assert_basic_auth_challenge response
45
+ end
46
+ end
47
+
48
+ specify 'should rechallenge if incorrect credentials are specified' do
49
+ request_with_basic_auth 'joe', 'password' do |response|
50
+ assert_basic_auth_challenge response
51
+ end
52
+ end
53
+
54
+ specify 'should return application output if correct credentials are specified' do
55
+ request_with_basic_auth 'Boss', 'password' do |response|
56
+ response.status.should.equal 200
57
+ response.body.to_s.should.equal 'Hi Boss'
58
+ end
59
+ end
60
+
61
+ specify 'should return 400 Bad Request if different auth scheme used' do
62
+ request 'HTTP_AUTHORIZATION' => 'Digest params' do |response|
63
+ response.should.be.a.client_error
64
+ response.status.should.equal 400
65
+ response.should.not.include 'WWW-Authenticate'
66
+ end
67
+ end
68
+
69
+ specify 'realm as optional constructor arg' do
70
+ app = Rack::Auth::Basic.new(unprotected_app, realm) { true }
71
+ assert_equal realm, app.realm
72
+ end
73
+ end
@@ -0,0 +1,226 @@
1
+ require 'test/spec'
2
+
3
+ require 'rack/auth/digest/md5'
4
+ require 'rack/mock'
5
+
6
+ context 'Rack::Auth::Digest::MD5' do
7
+
8
+ def realm
9
+ 'WallysWorld'
10
+ end
11
+
12
+ def unprotected_app
13
+ lambda do |env|
14
+ [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ]
15
+ end
16
+ end
17
+
18
+ def protected_app
19
+ app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
20
+ { 'Alice' => 'correct-password' }[username]
21
+ end
22
+ app.realm = realm
23
+ app.opaque = 'this-should-be-secret'
24
+ app
25
+ end
26
+
27
+ def protected_app_with_hashed_passwords
28
+ app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
29
+ username == 'Alice' ? Digest::MD5.hexdigest("Alice:#{realm}:correct-password") : nil
30
+ end
31
+ app.realm = realm
32
+ app.opaque = 'this-should-be-secret'
33
+ app.passwords_hashed = true
34
+ app
35
+ end
36
+
37
+ def partially_protected_app
38
+ Rack::URLMap.new({
39
+ '/' => unprotected_app,
40
+ '/protected' => protected_app
41
+ })
42
+ end
43
+
44
+ def protected_app_with_method_override
45
+ Rack::MethodOverride.new(protected_app)
46
+ end
47
+
48
+ setup do
49
+ @request = Rack::MockRequest.new(protected_app)
50
+ end
51
+
52
+ def request(method, path, headers = {}, &block)
53
+ response = @request.request(method, path, headers)
54
+ block.call(response) if block
55
+ return response
56
+ end
57
+
58
+ class MockDigestRequest
59
+ def initialize(params)
60
+ @params = params
61
+ end
62
+ def method_missing(sym)
63
+ if @params.has_key? k = sym.to_s
64
+ return @params[k]
65
+ end
66
+ super
67
+ end
68
+ def method
69
+ @params['method']
70
+ end
71
+ def response(password)
72
+ Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
73
+ end
74
+ end
75
+
76
+ def request_with_digest_auth(method, path, username, password, options = {}, &block)
77
+ request_options = {}
78
+ request_options[:input] = options.delete(:input) if options.include? :input
79
+
80
+ response = request(method, path, request_options)
81
+
82
+ return response unless response.status == 401
83
+
84
+ if wait = options.delete(:wait)
85
+ sleep wait
86
+ end
87
+
88
+ challenge = response['WWW-Authenticate'].split(' ', 2).last
89
+
90
+ params = Rack::Auth::Digest::Params.parse(challenge)
91
+
92
+ params['username'] = username
93
+ params['nc'] = '00000001'
94
+ params['cnonce'] = 'nonsensenonce'
95
+ params['uri'] = path
96
+
97
+ params['method'] = method
98
+
99
+ params.update options
100
+
101
+ params['response'] = MockDigestRequest.new(params).response(password)
102
+
103
+ request(method, path, request_options.merge('HTTP_AUTHORIZATION' => "Digest #{params}"), &block)
104
+ end
105
+
106
+ def assert_digest_auth_challenge(response)
107
+ response.should.be.a.client_error
108
+ response.status.should.equal 401
109
+ response.should.include 'WWW-Authenticate'
110
+ response.headers['WWW-Authenticate'].should =~ /^Digest /
111
+ response.body.should.be.empty
112
+ end
113
+
114
+ def assert_bad_request(response)
115
+ response.should.be.a.client_error
116
+ response.status.should.equal 400
117
+ response.should.not.include 'WWW-Authenticate'
118
+ end
119
+
120
+ specify 'should challenge when no credentials are specified' do
121
+ request 'GET', '/' do |response|
122
+ assert_digest_auth_challenge response
123
+ end
124
+ end
125
+
126
+ specify 'should return application output if correct credentials given' do
127
+ request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
128
+ response.status.should.equal 200
129
+ response.body.to_s.should.equal 'Hi Alice'
130
+ end
131
+ end
132
+
133
+ specify 'should return application output if correct credentials given (hashed passwords)' do
134
+ @request = Rack::MockRequest.new(protected_app_with_hashed_passwords)
135
+
136
+ request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
137
+ response.status.should.equal 200
138
+ response.body.to_s.should.equal 'Hi Alice'
139
+ end
140
+ end
141
+
142
+ specify 'should rechallenge if incorrect username given' do
143
+ request_with_digest_auth 'GET', '/', 'Bob', 'correct-password' do |response|
144
+ assert_digest_auth_challenge response
145
+ end
146
+ end
147
+
148
+ specify 'should rechallenge if incorrect password given' do
149
+ request_with_digest_auth 'GET', '/', 'Alice', 'wrong-password' do |response|
150
+ assert_digest_auth_challenge response
151
+ end
152
+ end
153
+
154
+ specify 'should rechallenge with stale parameter if nonce is stale' do
155
+ begin
156
+ Rack::Auth::Digest::Nonce.time_limit = 1
157
+
158
+ request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', :wait => 2 do |response|
159
+ assert_digest_auth_challenge response
160
+ response.headers['WWW-Authenticate'].should =~ /\bstale=true\b/
161
+ end
162
+ ensure
163
+ Rack::Auth::Digest::Nonce.time_limit = nil
164
+ end
165
+ end
166
+
167
+ specify 'should return 400 Bad Request if incorrect qop given' do
168
+ request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'qop' => 'auth-int' do |response|
169
+ assert_bad_request response
170
+ end
171
+ end
172
+
173
+ specify 'should return 400 Bad Request if incorrect uri given' do
174
+ request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'uri' => '/foo' do |response|
175
+ assert_bad_request response
176
+ end
177
+ end
178
+
179
+ specify 'should return 400 Bad Request if different auth scheme used' do
180
+ request 'GET', '/', 'HTTP_AUTHORIZATION' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' do |response|
181
+ assert_bad_request response
182
+ end
183
+ end
184
+
185
+ specify 'should not require credentials for unprotected path' do
186
+ @request = Rack::MockRequest.new(partially_protected_app)
187
+ request 'GET', '/' do |response|
188
+ response.should.be.ok
189
+ end
190
+ end
191
+
192
+ specify 'should challenge when no credentials are specified for protected path' do
193
+ @request = Rack::MockRequest.new(partially_protected_app)
194
+ request 'GET', '/protected' do |response|
195
+ assert_digest_auth_challenge response
196
+ end
197
+ end
198
+
199
+ specify 'should return application output if correct credentials given for protected path' do
200
+ @request = Rack::MockRequest.new(partially_protected_app)
201
+ request_with_digest_auth 'GET', '/protected', 'Alice', 'correct-password' do |response|
202
+ response.status.should.equal 200
203
+ response.body.to_s.should.equal 'Hi Alice'
204
+ end
205
+ end
206
+
207
+ specify 'should return application output if correct credentials given for POST' do
208
+ request_with_digest_auth 'POST', '/', 'Alice', 'correct-password' do |response|
209
+ response.status.should.equal 200
210
+ response.body.to_s.should.equal 'Hi Alice'
211
+ end
212
+ end
213
+
214
+ specify 'should return application output if correct credentials given for PUT (using method override of POST)' do
215
+ @request = Rack::MockRequest.new(protected_app_with_method_override)
216
+ request_with_digest_auth 'POST', '/', 'Alice', 'correct-password', :input => "_method=put" do |response|
217
+ response.status.should.equal 200
218
+ response.body.to_s.should.equal 'Hi Alice'
219
+ end
220
+ end
221
+
222
+ specify 'realm as optional constructor arg' do
223
+ app = Rack::Auth::Digest::MD5.new(unprotected_app, realm) { true }
224
+ assert_equal realm, app.realm
225
+ end
226
+ end
@@ -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
+ app = Rack::Builder.new do
65
+ class AppClass
66
+ def initialize
67
+ @called = 0
68
+ end
69
+ def call(env)
70
+ raise "bzzzt" if @called > 0
71
+ @called += 1
72
+ [200, {'Content-Type' => 'text/plain'}, ['OK']]
73
+ end
74
+ end
75
+
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