edgar-rack 1.2.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.
- data/COPYING +18 -0
- data/KNOWN-ISSUES +21 -0
- data/README +401 -0
- data/Rakefile +101 -0
- data/SPEC +171 -0
- data/bin/rackup +4 -0
- data/contrib/rack_logo.svg +111 -0
- data/example/lobster.ru +4 -0
- data/example/protectedlobster.rb +14 -0
- data/example/protectedlobster.ru +8 -0
- data/lib/rack.rb +81 -0
- data/lib/rack/auth/abstract/handler.rb +37 -0
- data/lib/rack/auth/abstract/request.rb +43 -0
- data/lib/rack/auth/basic.rb +58 -0
- data/lib/rack/auth/digest/md5.rb +124 -0
- data/lib/rack/auth/digest/nonce.rb +51 -0
- data/lib/rack/auth/digest/params.rb +53 -0
- data/lib/rack/auth/digest/request.rb +40 -0
- data/lib/rack/builder.rb +80 -0
- data/lib/rack/cascade.rb +41 -0
- data/lib/rack/chunked.rb +52 -0
- data/lib/rack/commonlogger.rb +49 -0
- data/lib/rack/conditionalget.rb +63 -0
- data/lib/rack/config.rb +15 -0
- data/lib/rack/content_length.rb +29 -0
- data/lib/rack/content_type.rb +23 -0
- data/lib/rack/deflater.rb +96 -0
- data/lib/rack/directory.rb +157 -0
- data/lib/rack/etag.rb +59 -0
- data/lib/rack/file.rb +118 -0
- data/lib/rack/handler.rb +88 -0
- data/lib/rack/handler/cgi.rb +61 -0
- data/lib/rack/handler/evented_mongrel.rb +8 -0
- data/lib/rack/handler/fastcgi.rb +90 -0
- data/lib/rack/handler/lsws.rb +61 -0
- data/lib/rack/handler/mongrel.rb +90 -0
- data/lib/rack/handler/scgi.rb +59 -0
- data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/rack/handler/thin.rb +17 -0
- data/lib/rack/handler/webrick.rb +73 -0
- data/lib/rack/head.rb +19 -0
- data/lib/rack/lint.rb +567 -0
- data/lib/rack/lobster.rb +65 -0
- data/lib/rack/lock.rb +44 -0
- data/lib/rack/logger.rb +18 -0
- data/lib/rack/methodoverride.rb +27 -0
- data/lib/rack/mime.rb +210 -0
- data/lib/rack/mock.rb +185 -0
- data/lib/rack/nulllogger.rb +18 -0
- data/lib/rack/recursive.rb +61 -0
- data/lib/rack/reloader.rb +109 -0
- data/lib/rack/request.rb +307 -0
- data/lib/rack/response.rb +151 -0
- data/lib/rack/rewindable_input.rb +104 -0
- data/lib/rack/runtime.rb +27 -0
- data/lib/rack/sendfile.rb +139 -0
- data/lib/rack/server.rb +289 -0
- data/lib/rack/session/abstract/id.rb +348 -0
- data/lib/rack/session/cookie.rb +152 -0
- data/lib/rack/session/memcache.rb +93 -0
- data/lib/rack/session/pool.rb +79 -0
- data/lib/rack/showexceptions.rb +378 -0
- data/lib/rack/showstatus.rb +113 -0
- data/lib/rack/static.rb +53 -0
- data/lib/rack/urlmap.rb +55 -0
- data/lib/rack/utils.rb +698 -0
- data/rack.gemspec +39 -0
- data/test/cgi/lighttpd.conf +25 -0
- data/test/cgi/rackup_stub.rb +6 -0
- data/test/cgi/sample_rackup.ru +5 -0
- data/test/cgi/test +9 -0
- data/test/cgi/test.fcgi +8 -0
- data/test/cgi/test.ru +5 -0
- data/test/gemloader.rb +6 -0
- data/test/multipart/bad_robots +259 -0
- data/test/multipart/binary +0 -0
- data/test/multipart/empty +10 -0
- data/test/multipart/fail_16384_nofile +814 -0
- data/test/multipart/file1.txt +1 -0
- data/test/multipart/filename_and_modification_param +7 -0
- data/test/multipart/filename_with_escaped_quotes +6 -0
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +7 -0
- data/test/multipart/filename_with_percent_escaped_quotes +6 -0
- data/test/multipart/filename_with_unescaped_quotes +6 -0
- data/test/multipart/ie +6 -0
- data/test/multipart/nested +10 -0
- data/test/multipart/none +9 -0
- data/test/multipart/semicolon +6 -0
- data/test/multipart/text +15 -0
- data/test/rackup/config.ru +31 -0
- data/test/spec_auth_basic.rb +70 -0
- data/test/spec_auth_digest.rb +241 -0
- data/test/spec_builder.rb +123 -0
- data/test/spec_cascade.rb +45 -0
- data/test/spec_cgi.rb +102 -0
- data/test/spec_chunked.rb +60 -0
- data/test/spec_commonlogger.rb +56 -0
- data/test/spec_conditionalget.rb +86 -0
- data/test/spec_config.rb +23 -0
- data/test/spec_content_length.rb +36 -0
- data/test/spec_content_type.rb +29 -0
- data/test/spec_deflater.rb +125 -0
- data/test/spec_directory.rb +57 -0
- data/test/spec_etag.rb +75 -0
- data/test/spec_fastcgi.rb +107 -0
- data/test/spec_file.rb +92 -0
- data/test/spec_handler.rb +49 -0
- data/test/spec_head.rb +30 -0
- data/test/spec_lint.rb +515 -0
- data/test/spec_lobster.rb +43 -0
- data/test/spec_lock.rb +142 -0
- data/test/spec_logger.rb +28 -0
- data/test/spec_methodoverride.rb +58 -0
- data/test/spec_mock.rb +241 -0
- data/test/spec_mongrel.rb +182 -0
- data/test/spec_nulllogger.rb +12 -0
- data/test/spec_recursive.rb +69 -0
- data/test/spec_request.rb +774 -0
- data/test/spec_response.rb +245 -0
- data/test/spec_rewindable_input.rb +118 -0
- data/test/spec_runtime.rb +39 -0
- data/test/spec_sendfile.rb +83 -0
- data/test/spec_server.rb +8 -0
- data/test/spec_session_abstract_id.rb +43 -0
- data/test/spec_session_cookie.rb +171 -0
- data/test/spec_session_memcache.rb +289 -0
- data/test/spec_session_pool.rb +200 -0
- data/test/spec_showexceptions.rb +87 -0
- data/test/spec_showstatus.rb +79 -0
- data/test/spec_static.rb +48 -0
- data/test/spec_thin.rb +86 -0
- data/test/spec_urlmap.rb +213 -0
- data/test/spec_utils.rb +678 -0
- data/test/spec_webrick.rb +141 -0
- data/test/testrequest.rb +78 -0
- data/test/unregistered_handler/rack/handler/unregistered.rb +7 -0
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +7 -0
- metadata +329 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
contents
|
data/test/multipart/ie
ADDED
data/test/multipart/none
ADDED
data/test/multipart/text
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
--AaB03x
|
|
2
|
+
Content-Disposition: form-data; name="submit-name"
|
|
3
|
+
|
|
4
|
+
Larry
|
|
5
|
+
--AaB03x
|
|
6
|
+
Content-Disposition: form-data; name="submit-name-with-content"
|
|
7
|
+
Content-Type: text/plain
|
|
8
|
+
|
|
9
|
+
Berry
|
|
10
|
+
--AaB03x
|
|
11
|
+
Content-Disposition: form-data; name="files"; filename="file1.txt"
|
|
12
|
+
Content-Type: text/plain
|
|
13
|
+
|
|
14
|
+
contents
|
|
15
|
+
--AaB03x--
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require "#{File.dirname(__FILE__)}/../testrequest"
|
|
2
|
+
|
|
3
|
+
$stderr = File.open("#{File.dirname(__FILE__)}/log_output", "w")
|
|
4
|
+
|
|
5
|
+
class EnvMiddleware
|
|
6
|
+
def initialize(app)
|
|
7
|
+
@app = app
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def call(env)
|
|
11
|
+
# provides a way to test that lint is present
|
|
12
|
+
if env["PATH_INFO"] == "/broken_lint"
|
|
13
|
+
return [200, {}, ["Broken Lint"]]
|
|
14
|
+
# provides a way to kill the process without knowing the pid
|
|
15
|
+
elsif env["PATH_INFO"] == "/die"
|
|
16
|
+
exit!
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
env["test.$DEBUG"] = $DEBUG
|
|
20
|
+
env["test.$EVAL"] = BUKKIT if defined?(BUKKIT)
|
|
21
|
+
env["test.$VERBOSE"] = $VERBOSE
|
|
22
|
+
env["test.$LOAD_PATH"] = $LOAD_PATH
|
|
23
|
+
env["test.stderr"] = File.expand_path($stderr.path)
|
|
24
|
+
env["test.Ping"] = defined?(Ping)
|
|
25
|
+
env["test.pid"] = Process.pid
|
|
26
|
+
@app.call(env)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
use EnvMiddleware
|
|
31
|
+
run TestRequest.new
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
require 'rack/auth/basic'
|
|
2
|
+
require 'rack/mock'
|
|
3
|
+
|
|
4
|
+
describe Rack::Auth::Basic do
|
|
5
|
+
def realm
|
|
6
|
+
'WallysWorld'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def unprotected_app
|
|
10
|
+
lambda { |env| [ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}"] ] }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def protected_app
|
|
14
|
+
app = Rack::Auth::Basic.new(unprotected_app) { |username, password| 'Boss' == username }
|
|
15
|
+
app.realm = realm
|
|
16
|
+
app
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
@request = Rack::MockRequest.new(protected_app)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def request_with_basic_auth(username, password, &block)
|
|
24
|
+
request 'HTTP_AUTHORIZATION' => 'Basic ' + ["#{username}:#{password}"].pack("m*"), &block
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def request(headers = {})
|
|
28
|
+
yield @request.get('/', headers)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def assert_basic_auth_challenge(response)
|
|
32
|
+
response.should.be.a.client_error
|
|
33
|
+
response.status.should.equal 401
|
|
34
|
+
response.should.include 'WWW-Authenticate'
|
|
35
|
+
response.headers['WWW-Authenticate'].should =~ /Basic realm="#{Regexp.escape(realm)}"/
|
|
36
|
+
response.body.should.be.empty
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
should 'challenge correctly when no credentials are specified' do
|
|
40
|
+
request do |response|
|
|
41
|
+
assert_basic_auth_challenge response
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
should 'rechallenge if incorrect credentials are specified' do
|
|
46
|
+
request_with_basic_auth 'joe', 'password' do |response|
|
|
47
|
+
assert_basic_auth_challenge response
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
should 'return application output if correct credentials are specified' do
|
|
52
|
+
request_with_basic_auth 'Boss', 'password' do |response|
|
|
53
|
+
response.status.should.equal 200
|
|
54
|
+
response.body.to_s.should.equal 'Hi Boss'
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
should 'return 400 Bad Request if different auth scheme used' do
|
|
59
|
+
request 'HTTP_AUTHORIZATION' => 'Digest params' do |response|
|
|
60
|
+
response.should.be.a.client_error
|
|
61
|
+
response.status.should.equal 400
|
|
62
|
+
response.should.not.include 'WWW-Authenticate'
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
it 'takes realm as optional constructor arg' do
|
|
67
|
+
app = Rack::Auth::Basic.new(unprotected_app, realm) { true }
|
|
68
|
+
realm.should == app.realm
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
require 'rack/auth/digest/md5'
|
|
2
|
+
require 'rack/mock'
|
|
3
|
+
|
|
4
|
+
describe Rack::Auth::Digest::MD5 do
|
|
5
|
+
def realm
|
|
6
|
+
'WallysWorld'
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def unprotected_app
|
|
10
|
+
lambda do |env|
|
|
11
|
+
friend = Rack::Utils.parse_query(env["QUERY_STRING"])["friend"]
|
|
12
|
+
[ 200, {'Content-Type' => 'text/plain'}, ["Hi #{env['REMOTE_USER']}#{friend ? " and #{friend}" : ''}"] ]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def protected_app
|
|
17
|
+
app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
|
|
18
|
+
{ 'Alice' => 'correct-password' }[username]
|
|
19
|
+
end
|
|
20
|
+
app.realm = realm
|
|
21
|
+
app.opaque = 'this-should-be-secret'
|
|
22
|
+
app
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def protected_app_with_hashed_passwords
|
|
26
|
+
app = Rack::Auth::Digest::MD5.new(unprotected_app) do |username|
|
|
27
|
+
username == 'Alice' ? Digest::MD5.hexdigest("Alice:#{realm}:correct-password") : nil
|
|
28
|
+
end
|
|
29
|
+
app.realm = realm
|
|
30
|
+
app.opaque = 'this-should-be-secret'
|
|
31
|
+
app.passwords_hashed = true
|
|
32
|
+
app
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def partially_protected_app
|
|
36
|
+
Rack::URLMap.new({
|
|
37
|
+
'/' => unprotected_app,
|
|
38
|
+
'/protected' => protected_app
|
|
39
|
+
})
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def protected_app_with_method_override
|
|
43
|
+
Rack::MethodOverride.new(protected_app)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
before do
|
|
47
|
+
@request = Rack::MockRequest.new(protected_app)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def request(method, path, headers = {}, &block)
|
|
51
|
+
response = @request.request(method, path, headers)
|
|
52
|
+
block.call(response) if block
|
|
53
|
+
return response
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class MockDigestRequest
|
|
57
|
+
def initialize(params)
|
|
58
|
+
@params = params
|
|
59
|
+
end
|
|
60
|
+
def method_missing(sym)
|
|
61
|
+
if @params.has_key? k = sym.to_s
|
|
62
|
+
return @params[k]
|
|
63
|
+
end
|
|
64
|
+
super
|
|
65
|
+
end
|
|
66
|
+
def method
|
|
67
|
+
@params['method']
|
|
68
|
+
end
|
|
69
|
+
def response(password)
|
|
70
|
+
Rack::Auth::Digest::MD5.new(nil).send :digest, self, password
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def request_with_digest_auth(method, path, username, password, options = {}, &block)
|
|
75
|
+
request_options = {}
|
|
76
|
+
request_options[:input] = options.delete(:input) if options.include? :input
|
|
77
|
+
|
|
78
|
+
response = request(method, path, request_options)
|
|
79
|
+
|
|
80
|
+
return response unless response.status == 401
|
|
81
|
+
|
|
82
|
+
if wait = options.delete(:wait)
|
|
83
|
+
sleep wait
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
challenge = response['WWW-Authenticate'].split(' ', 2).last
|
|
87
|
+
|
|
88
|
+
params = Rack::Auth::Digest::Params.parse(challenge)
|
|
89
|
+
|
|
90
|
+
params['username'] = username
|
|
91
|
+
params['nc'] = '00000001'
|
|
92
|
+
params['cnonce'] = 'nonsensenonce'
|
|
93
|
+
params['uri'] = path
|
|
94
|
+
|
|
95
|
+
params['method'] = method
|
|
96
|
+
|
|
97
|
+
params.update options
|
|
98
|
+
|
|
99
|
+
params['response'] = MockDigestRequest.new(params).response(password)
|
|
100
|
+
|
|
101
|
+
request(method, path, request_options.merge('HTTP_AUTHORIZATION' => "Digest #{params}"), &block)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def assert_digest_auth_challenge(response)
|
|
105
|
+
response.should.be.a.client_error
|
|
106
|
+
response.status.should.equal 401
|
|
107
|
+
response.should.include 'WWW-Authenticate'
|
|
108
|
+
response.headers['WWW-Authenticate'].should =~ /^Digest /
|
|
109
|
+
response.body.should.be.empty
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def assert_bad_request(response)
|
|
113
|
+
response.should.be.a.client_error
|
|
114
|
+
response.status.should.equal 400
|
|
115
|
+
response.should.not.include 'WWW-Authenticate'
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
should 'challenge when no credentials are specified' do
|
|
119
|
+
request 'GET', '/' do |response|
|
|
120
|
+
assert_digest_auth_challenge response
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
should 'return application output if correct credentials given' do
|
|
125
|
+
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
|
|
126
|
+
response.status.should.equal 200
|
|
127
|
+
response.body.to_s.should.equal 'Hi Alice'
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
should 'return application output if correct credentials given (hashed passwords)' do
|
|
132
|
+
@request = Rack::MockRequest.new(protected_app_with_hashed_passwords)
|
|
133
|
+
|
|
134
|
+
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password' do |response|
|
|
135
|
+
response.status.should.equal 200
|
|
136
|
+
response.body.to_s.should.equal 'Hi Alice'
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
should 'rechallenge if incorrect username given' do
|
|
141
|
+
request_with_digest_auth 'GET', '/', 'Bob', 'correct-password' do |response|
|
|
142
|
+
assert_digest_auth_challenge response
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
should 'rechallenge if incorrect password given' do
|
|
147
|
+
request_with_digest_auth 'GET', '/', 'Alice', 'wrong-password' do |response|
|
|
148
|
+
assert_digest_auth_challenge response
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
should 'rechallenge with stale parameter if nonce is stale' do
|
|
153
|
+
begin
|
|
154
|
+
Rack::Auth::Digest::Nonce.time_limit = 1
|
|
155
|
+
|
|
156
|
+
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', :wait => 2 do |response|
|
|
157
|
+
assert_digest_auth_challenge response
|
|
158
|
+
response.headers['WWW-Authenticate'].should =~ /\bstale=true\b/
|
|
159
|
+
end
|
|
160
|
+
ensure
|
|
161
|
+
Rack::Auth::Digest::Nonce.time_limit = nil
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
should 'return 400 Bad Request if incorrect qop given' do
|
|
166
|
+
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'qop' => 'auth-int' do |response|
|
|
167
|
+
assert_bad_request response
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
should 'return 400 Bad Request if incorrect uri given' do
|
|
172
|
+
request_with_digest_auth 'GET', '/', 'Alice', 'correct-password', 'uri' => '/foo' do |response|
|
|
173
|
+
assert_bad_request response
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
should 'return 400 Bad Request if different auth scheme used' do
|
|
178
|
+
request 'GET', '/', 'HTTP_AUTHORIZATION' => 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==' do |response|
|
|
179
|
+
assert_bad_request response
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
should 'not require credentials for unprotected path' do
|
|
184
|
+
@request = Rack::MockRequest.new(partially_protected_app)
|
|
185
|
+
request 'GET', '/' do |response|
|
|
186
|
+
response.should.be.ok
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
should 'challenge when no credentials are specified for protected path' do
|
|
191
|
+
@request = Rack::MockRequest.new(partially_protected_app)
|
|
192
|
+
request 'GET', '/protected' do |response|
|
|
193
|
+
assert_digest_auth_challenge response
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
should 'return application output if correct credentials given for protected path' do
|
|
198
|
+
@request = Rack::MockRequest.new(partially_protected_app)
|
|
199
|
+
request_with_digest_auth 'GET', '/protected', 'Alice', 'correct-password' do |response|
|
|
200
|
+
response.status.should.equal 200
|
|
201
|
+
response.body.to_s.should.equal 'Hi Alice'
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
should 'return application output when used with a query string and path as uri' do
|
|
206
|
+
@request = Rack::MockRequest.new(partially_protected_app)
|
|
207
|
+
request_with_digest_auth 'GET', '/protected?friend=Mike', 'Alice', 'correct-password' do |response|
|
|
208
|
+
response.status.should.equal 200
|
|
209
|
+
response.body.to_s.should.equal 'Hi Alice and Mike'
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
should 'return application output when used with a query string and fullpath as uri' do
|
|
214
|
+
@request = Rack::MockRequest.new(partially_protected_app)
|
|
215
|
+
qs_uri = '/protected?friend=Mike'
|
|
216
|
+
request_with_digest_auth 'GET', qs_uri, 'Alice', 'correct-password', 'uri' => qs_uri do |response|
|
|
217
|
+
response.status.should.equal 200
|
|
218
|
+
response.body.to_s.should.equal 'Hi Alice and Mike'
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
should 'return application output if correct credentials given for POST' do
|
|
223
|
+
request_with_digest_auth 'POST', '/', 'Alice', 'correct-password' do |response|
|
|
224
|
+
response.status.should.equal 200
|
|
225
|
+
response.body.to_s.should.equal 'Hi Alice'
|
|
226
|
+
end
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
should 'return application output if correct credentials given for PUT (using method override of POST)' do
|
|
230
|
+
@request = Rack::MockRequest.new(protected_app_with_method_override)
|
|
231
|
+
request_with_digest_auth 'POST', '/', 'Alice', 'correct-password', :input => "_method=put" do |response|
|
|
232
|
+
response.status.should.equal 200
|
|
233
|
+
response.body.to_s.should.equal 'Hi Alice'
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
it 'takes realm as optional constructor arg' do
|
|
238
|
+
app = Rack::Auth::Digest::MD5.new(unprotected_app, realm) { true }
|
|
239
|
+
realm.should == app.realm
|
|
240
|
+
end
|
|
241
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require 'rack/builder'
|
|
2
|
+
require 'rack/mock'
|
|
3
|
+
require 'rack/showexceptions'
|
|
4
|
+
require 'rack/urlmap'
|
|
5
|
+
|
|
6
|
+
class NothingMiddleware
|
|
7
|
+
def initialize(app)
|
|
8
|
+
@app = app
|
|
9
|
+
end
|
|
10
|
+
def call(env)
|
|
11
|
+
@@env = env
|
|
12
|
+
response = @app.call(env)
|
|
13
|
+
response
|
|
14
|
+
end
|
|
15
|
+
def self.env
|
|
16
|
+
@@env
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe Rack::Builder do
|
|
21
|
+
it "supports mapping" do
|
|
22
|
+
app = Rack::Builder.new do
|
|
23
|
+
map '/' do |outer_env|
|
|
24
|
+
run lambda { |inner_env| [200, {}, ['root']] }
|
|
25
|
+
end
|
|
26
|
+
map '/sub' do
|
|
27
|
+
run lambda { |inner_env| [200, {}, ['sub']] }
|
|
28
|
+
end
|
|
29
|
+
end.to_app
|
|
30
|
+
Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'root'
|
|
31
|
+
Rack::MockRequest.new(app).get("/sub").body.to_s.should.equal 'sub'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
it "doesn't dupe env even when mapping" do
|
|
35
|
+
app = Rack::Builder.new do
|
|
36
|
+
use NothingMiddleware
|
|
37
|
+
map '/' do |outer_env|
|
|
38
|
+
run lambda { |inner_env|
|
|
39
|
+
inner_env['new_key'] = 'new_value'
|
|
40
|
+
[200, {}, ['root']]
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
end.to_app
|
|
44
|
+
Rack::MockRequest.new(app).get("/").body.to_s.should.equal 'root'
|
|
45
|
+
NothingMiddleware.env['new_key'].should.equal 'new_value'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "chains apps by default" do
|
|
49
|
+
app = Rack::Builder.new do
|
|
50
|
+
use Rack::ShowExceptions
|
|
51
|
+
run lambda { |env| raise "bzzzt" }
|
|
52
|
+
end.to_app
|
|
53
|
+
|
|
54
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
55
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
56
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "has implicit #to_app" do
|
|
60
|
+
app = Rack::Builder.new do
|
|
61
|
+
use Rack::ShowExceptions
|
|
62
|
+
run lambda { |env| raise "bzzzt" }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
66
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
67
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "supports blocks on use" do
|
|
71
|
+
app = Rack::Builder.new do
|
|
72
|
+
use Rack::ShowExceptions
|
|
73
|
+
use Rack::Auth::Basic do |username, password|
|
|
74
|
+
'secret' == password
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
run lambda { |env| [200, {}, ['Hi Boss']] }
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
response = Rack::MockRequest.new(app).get("/")
|
|
81
|
+
response.should.be.client_error
|
|
82
|
+
response.status.should.equal 401
|
|
83
|
+
|
|
84
|
+
# with auth...
|
|
85
|
+
response = Rack::MockRequest.new(app).get("/",
|
|
86
|
+
'HTTP_AUTHORIZATION' => 'Basic ' + ["joe:secret"].pack("m*"))
|
|
87
|
+
response.status.should.equal 200
|
|
88
|
+
response.body.to_s.should.equal 'Hi Boss'
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
it "has explicit #to_app" do
|
|
92
|
+
app = Rack::Builder.app do
|
|
93
|
+
use Rack::ShowExceptions
|
|
94
|
+
run lambda { |env| raise "bzzzt" }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
98
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
99
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
should "initialize apps once" do
|
|
103
|
+
app = Rack::Builder.new do
|
|
104
|
+
class AppClass
|
|
105
|
+
def initialize
|
|
106
|
+
@called = 0
|
|
107
|
+
end
|
|
108
|
+
def call(env)
|
|
109
|
+
raise "bzzzt" if @called > 0
|
|
110
|
+
@called += 1
|
|
111
|
+
[200, {'Content-Type' => 'text/plain'}, ['OK']]
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
use Rack::ShowExceptions
|
|
116
|
+
run AppClass.new
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
Rack::MockRequest.new(app).get("/").status.should.equal 200
|
|
120
|
+
Rack::MockRequest.new(app).get("/").should.be.server_error
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|