rack 1.6.11 → 2.2.0

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.

Files changed (190) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +675 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +157 -163
  6. data/Rakefile +38 -32
  7. data/{SPEC → SPEC.rdoc} +41 -13
  8. data/bin/rackup +1 -0
  9. data/contrib/rack_logo.svg +164 -111
  10. data/example/lobster.ru +2 -0
  11. data/example/protectedlobster.rb +4 -2
  12. data/example/protectedlobster.ru +3 -1
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +6 -2
  15. data/lib/rack/auth/basic.rb +7 -4
  16. data/lib/rack/auth/digest/md5.rb +13 -11
  17. data/lib/rack/auth/digest/nonce.rb +6 -3
  18. data/lib/rack/auth/digest/params.rb +5 -4
  19. data/lib/rack/auth/digest/request.rb +6 -4
  20. data/lib/rack/body_proxy.rb +21 -15
  21. data/lib/rack/builder.rb +119 -26
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +70 -22
  24. data/lib/rack/common_logger.rb +80 -0
  25. data/lib/rack/{conditionalget.rb → conditional_get.rb} +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +9 -8
  28. data/lib/rack/content_type.rb +5 -4
  29. data/lib/rack/core_ext/regexp.rb +14 -0
  30. data/lib/rack/deflater.rb +60 -70
  31. data/lib/rack/directory.rb +117 -85
  32. data/lib/rack/etag.rb +9 -7
  33. data/lib/rack/events.rb +153 -0
  34. data/lib/rack/file.rb +4 -149
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler/cgi.rb +17 -19
  37. data/lib/rack/handler/fastcgi.rb +17 -18
  38. data/lib/rack/handler/lsws.rb +14 -14
  39. data/lib/rack/handler/scgi.rb +22 -21
  40. data/lib/rack/handler/thin.rb +20 -11
  41. data/lib/rack/handler/webrick.rb +39 -32
  42. data/lib/rack/handler.rb +9 -26
  43. data/lib/rack/head.rb +16 -18
  44. data/lib/rack/lint.rb +110 -64
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +17 -11
  47. data/lib/rack/logger.rb +4 -2
  48. data/lib/rack/media_type.rb +43 -0
  49. data/lib/rack/{methodoverride.rb → method_override.rb} +10 -8
  50. data/lib/rack/mime.rb +27 -6
  51. data/lib/rack/mock.rb +124 -65
  52. data/lib/rack/multipart/generator.rb +20 -16
  53. data/lib/rack/multipart/parser.rb +273 -162
  54. data/lib/rack/multipart/uploaded_file.rb +15 -8
  55. data/lib/rack/multipart.rb +39 -8
  56. data/lib/rack/{nulllogger.rb → null_logger.rb} +3 -1
  57. data/lib/rack/query_parser.rb +217 -0
  58. data/lib/rack/recursive.rb +11 -9
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +543 -305
  61. data/lib/rack/response.rb +244 -88
  62. data/lib/rack/rewindable_input.rb +5 -15
  63. data/lib/rack/runtime.rb +12 -18
  64. data/lib/rack/sendfile.rb +17 -15
  65. data/lib/rack/server.rb +125 -47
  66. data/lib/rack/session/abstract/id.rb +216 -93
  67. data/lib/rack/session/cookie.rb +47 -31
  68. data/lib/rack/session/memcache.rb +4 -87
  69. data/lib/rack/session/pool.rb +26 -17
  70. data/lib/rack/show_exceptions.rb +390 -0
  71. data/lib/rack/{showstatus.rb → show_status.rb} +8 -8
  72. data/lib/rack/static.rb +48 -11
  73. data/lib/rack/tempfile_reaper.rb +3 -3
  74. data/lib/rack/urlmap.rb +26 -19
  75. data/lib/rack/utils.rb +208 -294
  76. data/lib/rack/version.rb +29 -0
  77. data/lib/rack.rb +76 -33
  78. data/rack.gemspec +43 -30
  79. metadata +62 -183
  80. data/HISTORY.md +0 -375
  81. data/KNOWN-ISSUES +0 -44
  82. data/lib/rack/backports/uri/common_18.rb +0 -56
  83. data/lib/rack/backports/uri/common_192.rb +0 -52
  84. data/lib/rack/backports/uri/common_193.rb +0 -29
  85. data/lib/rack/commonlogger.rb +0 -72
  86. data/lib/rack/handler/evented_mongrel.rb +0 -8
  87. data/lib/rack/handler/mongrel.rb +0 -106
  88. data/lib/rack/handler/swiftiplied_mongrel.rb +0 -8
  89. data/lib/rack/showexceptions.rb +0 -387
  90. data/lib/rack/utils/okjson.rb +0 -600
  91. data/test/builder/anything.rb +0 -5
  92. data/test/builder/comment.ru +0 -4
  93. data/test/builder/end.ru +0 -5
  94. data/test/builder/line.ru +0 -1
  95. data/test/builder/options.ru +0 -2
  96. data/test/cgi/assets/folder/test.js +0 -1
  97. data/test/cgi/assets/fonts/font.eot +0 -1
  98. data/test/cgi/assets/images/image.png +0 -1
  99. data/test/cgi/assets/index.html +0 -1
  100. data/test/cgi/assets/javascripts/app.js +0 -1
  101. data/test/cgi/assets/stylesheets/app.css +0 -1
  102. data/test/cgi/lighttpd.conf +0 -26
  103. data/test/cgi/rackup_stub.rb +0 -6
  104. data/test/cgi/sample_rackup.ru +0 -5
  105. data/test/cgi/test +0 -9
  106. data/test/cgi/test+directory/test+file +0 -1
  107. data/test/cgi/test.fcgi +0 -8
  108. data/test/cgi/test.ru +0 -5
  109. data/test/gemloader.rb +0 -10
  110. data/test/multipart/bad_robots +0 -259
  111. data/test/multipart/binary +0 -0
  112. data/test/multipart/content_type_and_no_filename +0 -6
  113. data/test/multipart/empty +0 -10
  114. data/test/multipart/fail_16384_nofile +0 -814
  115. data/test/multipart/file1.txt +0 -1
  116. data/test/multipart/filename_and_modification_param +0 -7
  117. data/test/multipart/filename_and_no_name +0 -6
  118. data/test/multipart/filename_with_escaped_quotes +0 -6
  119. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  120. data/test/multipart/filename_with_null_byte +0 -7
  121. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  122. data/test/multipart/filename_with_unescaped_percentages +0 -6
  123. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  124. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  125. data/test/multipart/filename_with_unescaped_quotes +0 -6
  126. data/test/multipart/ie +0 -6
  127. data/test/multipart/invalid_character +0 -6
  128. data/test/multipart/mixed_files +0 -21
  129. data/test/multipart/nested +0 -10
  130. data/test/multipart/none +0 -9
  131. data/test/multipart/semicolon +0 -6
  132. data/test/multipart/text +0 -15
  133. data/test/multipart/three_files_three_fields +0 -31
  134. data/test/multipart/webkit +0 -32
  135. data/test/rackup/config.ru +0 -31
  136. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  137. data/test/spec_auth_basic.rb +0 -81
  138. data/test/spec_auth_digest.rb +0 -259
  139. data/test/spec_body_proxy.rb +0 -85
  140. data/test/spec_builder.rb +0 -223
  141. data/test/spec_cascade.rb +0 -61
  142. data/test/spec_cgi.rb +0 -102
  143. data/test/spec_chunked.rb +0 -101
  144. data/test/spec_commonlogger.rb +0 -93
  145. data/test/spec_conditionalget.rb +0 -102
  146. data/test/spec_config.rb +0 -22
  147. data/test/spec_content_length.rb +0 -85
  148. data/test/spec_content_type.rb +0 -45
  149. data/test/spec_deflater.rb +0 -339
  150. data/test/spec_directory.rb +0 -88
  151. data/test/spec_etag.rb +0 -107
  152. data/test/spec_fastcgi.rb +0 -107
  153. data/test/spec_file.rb +0 -221
  154. data/test/spec_handler.rb +0 -72
  155. data/test/spec_head.rb +0 -45
  156. data/test/spec_lint.rb +0 -550
  157. data/test/spec_lobster.rb +0 -58
  158. data/test/spec_lock.rb +0 -164
  159. data/test/spec_logger.rb +0 -23
  160. data/test/spec_methodoverride.rb +0 -111
  161. data/test/spec_mime.rb +0 -51
  162. data/test/spec_mock.rb +0 -297
  163. data/test/spec_mongrel.rb +0 -182
  164. data/test/spec_multipart.rb +0 -600
  165. data/test/spec_nulllogger.rb +0 -20
  166. data/test/spec_recursive.rb +0 -72
  167. data/test/spec_request.rb +0 -1232
  168. data/test/spec_response.rb +0 -407
  169. data/test/spec_rewindable_input.rb +0 -118
  170. data/test/spec_runtime.rb +0 -49
  171. data/test/spec_sendfile.rb +0 -130
  172. data/test/spec_server.rb +0 -167
  173. data/test/spec_session_abstract_id.rb +0 -53
  174. data/test/spec_session_cookie.rb +0 -410
  175. data/test/spec_session_memcache.rb +0 -321
  176. data/test/spec_session_pool.rb +0 -209
  177. data/test/spec_showexceptions.rb +0 -98
  178. data/test/spec_showstatus.rb +0 -103
  179. data/test/spec_static.rb +0 -145
  180. data/test/spec_tempfile_reaper.rb +0 -63
  181. data/test/spec_thin.rb +0 -91
  182. data/test/spec_urlmap.rb +0 -236
  183. data/test/spec_utils.rb +0 -647
  184. data/test/spec_version.rb +0 -17
  185. data/test/spec_webrick.rb +0 -184
  186. data/test/static/another/index.html +0 -1
  187. data/test/static/index.html +0 -1
  188. data/test/testrequest.rb +0 -78
  189. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  190. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,102 +0,0 @@
1
- require 'time'
2
- require 'rack/conditionalget'
3
- require 'rack/mock'
4
-
5
- describe Rack::ConditionalGet do
6
- def conditional_get(app)
7
- Rack::Lint.new Rack::ConditionalGet.new(app)
8
- end
9
-
10
- should "set a 304 status and truncate body when If-Modified-Since hits" do
11
- timestamp = Time.now.httpdate
12
- app = conditional_get(lambda { |env|
13
- [200, {'Last-Modified'=>timestamp}, ['TEST']] })
14
-
15
- response = Rack::MockRequest.new(app).
16
- get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp)
17
-
18
- response.status.should.equal 304
19
- response.body.should.be.empty
20
- end
21
-
22
- should "set a 304 status and truncate body when If-Modified-Since hits and is higher than current time" do
23
- app = conditional_get(lambda { |env|
24
- [200, {'Last-Modified'=>(Time.now - 3600).httpdate}, ['TEST']] })
25
-
26
- response = Rack::MockRequest.new(app).
27
- get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate)
28
-
29
- response.status.should.equal 304
30
- response.body.should.be.empty
31
- end
32
-
33
- should "set a 304 status and truncate body when If-None-Match hits" do
34
- app = conditional_get(lambda { |env|
35
- [200, {'Etag'=>'1234'}, ['TEST']] })
36
-
37
- response = Rack::MockRequest.new(app).
38
- get("/", 'HTTP_IF_NONE_MATCH' => '1234')
39
-
40
- response.status.should.equal 304
41
- response.body.should.be.empty
42
- end
43
-
44
- should "not set a 304 status if If-Modified-Since hits but Etag does not" do
45
- timestamp = Time.now.httpdate
46
- app = conditional_get(lambda { |env|
47
- [200, {'Last-Modified'=>timestamp, 'Etag'=>'1234', 'Content-Type' => 'text/plain'}, ['TEST']] })
48
-
49
- response = Rack::MockRequest.new(app).
50
- get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp, 'HTTP_IF_NONE_MATCH' => '4321')
51
-
52
- response.status.should.equal 200
53
- response.body.should.equal 'TEST'
54
- end
55
-
56
- should "set a 304 status and truncate body when both If-None-Match and If-Modified-Since hits" do
57
- timestamp = Time.now.httpdate
58
- app = conditional_get(lambda { |env|
59
- [200, {'Last-Modified'=>timestamp, 'Etag'=>'1234'}, ['TEST']] })
60
-
61
- response = Rack::MockRequest.new(app).
62
- get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp, 'HTTP_IF_NONE_MATCH' => '1234')
63
-
64
- response.status.should.equal 304
65
- response.body.should.be.empty
66
- end
67
-
68
- should "not affect non-GET/HEAD requests" do
69
- app = conditional_get(lambda { |env|
70
- [200, {'Etag'=>'1234', 'Content-Type' => 'text/plain'}, ['TEST']] })
71
-
72
- response = Rack::MockRequest.new(app).
73
- post("/", 'HTTP_IF_NONE_MATCH' => '1234')
74
-
75
- response.status.should.equal 200
76
- response.body.should.equal 'TEST'
77
- end
78
-
79
- should "not affect non-200 requests" do
80
- app = conditional_get(lambda { |env|
81
- [302, {'Etag'=>'1234', 'Content-Type' => 'text/plain'}, ['TEST']] })
82
-
83
- response = Rack::MockRequest.new(app).
84
- get("/", 'HTTP_IF_NONE_MATCH' => '1234')
85
-
86
- response.status.should.equal 302
87
- response.body.should.equal 'TEST'
88
- end
89
-
90
- should "not affect requests with malformed HTTP_IF_NONE_MATCH" do
91
- bad_timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S %z')
92
- app = conditional_get(lambda { |env|
93
- [200,{'Last-Modified'=>(Time.now - 3600).httpdate, 'Content-Type' => 'text/plain'}, ['TEST']] })
94
-
95
- response = Rack::MockRequest.new(app).
96
- get("/", 'HTTP_IF_MODIFIED_SINCE' => bad_timestamp)
97
-
98
- response.status.should.equal 200
99
- response.body.should.equal 'TEST'
100
- end
101
-
102
- end
data/test/spec_config.rb DELETED
@@ -1,22 +0,0 @@
1
- require 'rack/builder'
2
- require 'rack/config'
3
- require 'rack/content_length'
4
- require 'rack/lint'
5
- require 'rack/mock'
6
-
7
- describe Rack::Config do
8
- should "accept a block that modifies the environment" do
9
- app = Rack::Builder.new do
10
- use Rack::Lint
11
- use Rack::Config do |env|
12
- env['greeting'] = 'hello'
13
- end
14
- run lambda { |env|
15
- [200, {'Content-Type' => 'text/plain'}, [env['greeting'] || '']]
16
- }
17
- end
18
-
19
- response = Rack::MockRequest.new(app).get('/')
20
- response.body.should.equal('hello')
21
- end
22
- end
@@ -1,85 +0,0 @@
1
- require 'rack/content_length'
2
- require 'rack/lint'
3
- require 'rack/mock'
4
-
5
- describe Rack::ContentLength do
6
- def content_length(app)
7
- Rack::Lint.new Rack::ContentLength.new(app)
8
- end
9
-
10
- def request
11
- Rack::MockRequest.env_for
12
- end
13
-
14
- should "set Content-Length on Array bodies if none is set" do
15
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
16
- response = content_length(app).call(request)
17
- response[1]['Content-Length'].should.equal '13'
18
- end
19
-
20
- should "not set Content-Length on variable length bodies" do
21
- body = lambda { "Hello World!" }
22
- def body.each ; yield call ; end
23
-
24
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
25
- response = content_length(app).call(request)
26
- response[1]['Content-Length'].should.be.nil
27
- end
28
-
29
- should "not change Content-Length if it is already set" do
30
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Length' => '1'}, "Hello, World!"] }
31
- response = content_length(app).call(request)
32
- response[1]['Content-Length'].should.equal '1'
33
- end
34
-
35
- should "not set Content-Length on 304 responses" do
36
- app = lambda { |env| [304, {}, []] }
37
- response = content_length(app).call(request)
38
- response[1]['Content-Length'].should.equal nil
39
- end
40
-
41
- should "not set Content-Length when Transfer-Encoding is chunked" do
42
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Transfer-Encoding' => 'chunked'}, []] }
43
- response = content_length(app).call(request)
44
- response[1]['Content-Length'].should.equal nil
45
- end
46
-
47
- # Using "Connection: close" for this is fairly contended. It might be useful
48
- # to have some other way to signal this.
49
- #
50
- # should "not force a Content-Length when Connection:close" do
51
- # app = lambda { |env| [200, {'Connection' => 'close'}, []] }
52
- # response = content_length(app).call({})
53
- # response[1]['Content-Length'].should.equal nil
54
- # end
55
-
56
- should "close bodies that need to be closed" do
57
- body = Struct.new(:body) do
58
- attr_reader :closed
59
- def each; body.join; end
60
- def close; @closed = true; end
61
- def to_ary; end
62
- end.new(%w[one two three])
63
-
64
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
65
- response = content_length(app).call(request)
66
- body.closed.should.equal nil
67
- response[2].close
68
- body.closed.should.equal true
69
- end
70
-
71
- should "support single-execute bodies" do
72
- body = Struct.new(:body) do
73
- def each
74
- yield body.shift until body.empty?
75
- end
76
- def to_ary; end
77
- end.new(%w[one two three])
78
-
79
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
80
- response = content_length(app).call(request)
81
- expected = %w[one two three]
82
- response[1]['Content-Length'].should.equal expected.join.size.to_s
83
- response[2].to_enum.to_a.should.equal expected
84
- end
85
- end
@@ -1,45 +0,0 @@
1
- require 'rack/content_type'
2
- require 'rack/lint'
3
- require 'rack/mock'
4
-
5
- describe Rack::ContentType do
6
- def content_type(app, *args)
7
- Rack::Lint.new Rack::ContentType.new(app, *args)
8
- end
9
-
10
- def request
11
- Rack::MockRequest.env_for
12
- end
13
-
14
- should "set Content-Type to default text/html if none is set" do
15
- app = lambda { |env| [200, {}, "Hello, World!"] }
16
- headers = content_type(app).call(request)[1]
17
- headers['Content-Type'].should.equal 'text/html'
18
- end
19
-
20
- should "set Content-Type to chosen default if none is set" do
21
- app = lambda { |env| [200, {}, "Hello, World!"] }
22
- headers =
23
- content_type(app, 'application/octet-stream').call(request)[1]
24
- headers['Content-Type'].should.equal 'application/octet-stream'
25
- end
26
-
27
- should "not change Content-Type if it is already set" do
28
- app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] }
29
- headers = content_type(app).call(request)[1]
30
- headers['Content-Type'].should.equal 'foo/bar'
31
- end
32
-
33
- should "detect Content-Type case insensitive" do
34
- app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] }
35
- headers = content_type(app).call(request)[1]
36
- headers.to_a.select { |k,v| k.downcase == "content-type" }.
37
- should.equal [["CONTENT-Type","foo/bar"]]
38
- end
39
-
40
- should "not set Content-Type on 304 responses" do
41
- app = lambda { |env| [304, {}, []] }
42
- response = content_type(app, "text/html").call(request)
43
- response[1]['Content-Type'].should.equal nil
44
- end
45
- end
@@ -1,339 +0,0 @@
1
- require 'stringio'
2
- require 'time' # for Time#httpdate
3
- require 'rack/deflater'
4
- require 'rack/lint'
5
- require 'rack/mock'
6
- require 'zlib'
7
-
8
- describe Rack::Deflater do
9
-
10
- def build_response(status, body, accept_encoding, options = {})
11
- body = [body] if body.respond_to? :to_str
12
- app = lambda do |env|
13
- res = [status, options['response_headers'] || {}, body]
14
- res[1]['Content-Type'] = 'text/plain' unless res[0] == 304
15
- res
16
- end
17
-
18
- request = Rack::MockRequest.env_for('', (options['request_headers'] || {}).merge('HTTP_ACCEPT_ENCODING' => accept_encoding))
19
- deflater = Rack::Lint.new Rack::Deflater.new(app, options['deflater_options'] || {})
20
-
21
- deflater.call(request)
22
- end
23
-
24
- ##
25
- # Constructs response object and verifies if it yields right results
26
- #
27
- # [expected_status] expected response status, e.g. 200, 304
28
- # [expected_body] expected response body
29
- # [accept_encoing] what Accept-Encoding header to send and expect, e.g.
30
- # 'deflate' - accepts and expects deflate encoding in response
31
- # { 'gzip' => nil } - accepts gzip but expects no encoding in response
32
- # [options] hash of request options, i.e.
33
- # 'app_status' - what status dummy app should return (may be changed by deflater at some point)
34
- # 'app_body' - what body dummy app should return (may be changed by deflater at some point)
35
- # 'request_headers' - extra reqest headers to be sent
36
- # 'response_headers' - extra response headers to be returned
37
- # 'deflater_options' - options passed to deflater middleware
38
- # [block] useful for doing some extra verification
39
- def verify(expected_status, expected_body, accept_encoding, options = {}, &block)
40
- accept_encoding, expected_encoding = if accept_encoding.kind_of?(Hash)
41
- [accept_encoding.keys.first, accept_encoding.values.first]
42
- else
43
- [accept_encoding, accept_encoding.dup]
44
- end
45
-
46
- # build response
47
- status, headers, body = build_response(
48
- options['app_status'] || expected_status,
49
- options['app_body'] || expected_body,
50
- accept_encoding,
51
- options
52
- )
53
-
54
- # verify status
55
- status.should.equal(expected_status)
56
-
57
- # verify body
58
- unless options['skip_body_verify']
59
- body_text = ''
60
- body.each { |part| body_text << part }
61
-
62
- deflated_body = case expected_encoding
63
- when 'deflate'
64
- inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
65
- inflater.inflate(body_text) << inflater.finish
66
- when 'gzip'
67
- io = StringIO.new(body_text)
68
- gz = Zlib::GzipReader.new(io)
69
- tmp = gz.read
70
- gz.close
71
- tmp
72
- else
73
- body_text
74
- end
75
-
76
- deflated_body.should.equal(expected_body)
77
- end
78
-
79
- # yield full response verification
80
- yield(status, headers, body) if block_given?
81
- end
82
-
83
- should 'be able to deflate bodies that respond to each' do
84
- app_body = Object.new
85
- class << app_body; def each; yield('foo'); yield('bar'); end; end
86
-
87
- verify(200, 'foobar', 'deflate', { 'app_body' => app_body }) do |status, headers, body|
88
- headers.should.equal({
89
- 'Content-Encoding' => 'deflate',
90
- 'Vary' => 'Accept-Encoding',
91
- 'Content-Type' => 'text/plain'
92
- })
93
- end
94
- end
95
-
96
- should 'flush deflated chunks to the client as they become ready' do
97
- app_body = Object.new
98
- class << app_body; def each; yield('foo'); yield('bar'); end; end
99
-
100
- verify(200, app_body, 'deflate', { 'skip_body_verify' => true }) do |status, headers, body|
101
- headers.should.equal({
102
- 'Content-Encoding' => 'deflate',
103
- 'Vary' => 'Accept-Encoding',
104
- 'Content-Type' => 'text/plain'
105
- })
106
-
107
- buf = []
108
- inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
109
- body.each { |part| buf << inflater.inflate(part) }
110
- buf << inflater.finish
111
-
112
- buf.delete_if { |part| part.empty? }.join.should.equal('foobar')
113
- end
114
- end
115
-
116
- # TODO: This is really just a special case of the above...
117
- should 'be able to deflate String bodies' do
118
- verify(200, 'Hello world!', 'deflate') do |status, headers, body|
119
- headers.should.equal({
120
- 'Content-Encoding' => 'deflate',
121
- 'Vary' => 'Accept-Encoding',
122
- 'Content-Type' => 'text/plain'
123
- })
124
- end
125
- end
126
-
127
- should 'be able to gzip bodies that respond to each' do
128
- app_body = Object.new
129
- class << app_body; def each; yield('foo'); yield('bar'); end; end
130
-
131
- verify(200, 'foobar', 'gzip', { 'app_body' => app_body }) do |status, headers, body|
132
- headers.should.equal({
133
- 'Content-Encoding' => 'gzip',
134
- 'Vary' => 'Accept-Encoding',
135
- 'Content-Type' => 'text/plain'
136
- })
137
- end
138
- end
139
-
140
- should 'flush gzipped chunks to the client as they become ready' do
141
- app_body = Object.new
142
- class << app_body; def each; yield('foo'); yield('bar'); end; end
143
-
144
- verify(200, app_body, 'gzip', { 'skip_body_verify' => true }) do |status, headers, body|
145
- headers.should.equal({
146
- 'Content-Encoding' => 'gzip',
147
- 'Vary' => 'Accept-Encoding',
148
- 'Content-Type' => 'text/plain'
149
- })
150
-
151
- buf = []
152
- inflater = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
153
- body.each { |part| buf << inflater.inflate(part) }
154
- buf << inflater.finish
155
-
156
- buf.delete_if { |part| part.empty? }.join.should.equal('foobar')
157
- end
158
- end
159
-
160
- should 'be able to fallback to no deflation' do
161
- verify(200, 'Hello world!', 'superzip') do |status, headers, body|
162
- headers.should.equal({
163
- 'Vary' => 'Accept-Encoding',
164
- 'Content-Type' => 'text/plain'
165
- })
166
- end
167
- end
168
-
169
- should 'be able to skip when there is no response entity body' do
170
- verify(304, '', { 'gzip' => nil }, { 'app_body' => [] }) do |status, headers, body|
171
- headers.should.equal({})
172
- end
173
- end
174
-
175
- should 'handle the lack of an acceptable encoding' do
176
- app_body = 'Hello world!'
177
- not_found_body1 = 'An acceptable encoding for the requested resource / could not be found.'
178
- not_found_body2 = 'An acceptable encoding for the requested resource /foo/bar could not be found.'
179
- options1 = {
180
- 'app_status' => 200,
181
- 'app_body' => app_body,
182
- 'request_headers' => {
183
- 'PATH_INFO' => '/'
184
- }
185
- }
186
- options2 = {
187
- 'app_status' => 200,
188
- 'app_body' => app_body,
189
- 'request_headers' => {
190
- 'PATH_INFO' => '/foo/bar'
191
- }
192
- }
193
-
194
- verify(406, not_found_body1, 'identity;q=0', options1) do |status, headers, body|
195
- headers.should.equal({
196
- 'Content-Type' => 'text/plain',
197
- 'Content-Length' => not_found_body1.length.to_s
198
- })
199
- end
200
-
201
- verify(406, not_found_body2, 'identity;q=0', options2) do |status, headers, body|
202
- headers.should.equal({
203
- 'Content-Type' => 'text/plain',
204
- 'Content-Length' => not_found_body2.length.to_s
205
- })
206
- end
207
- end
208
-
209
- should 'handle gzip response with Last-Modified header' do
210
- last_modified = Time.now.httpdate
211
- options = {
212
- 'response_headers' => {
213
- 'Content-Type' => 'text/plain',
214
- 'Last-Modified' => last_modified
215
- }
216
- }
217
-
218
- verify(200, 'Hello World!', 'gzip', options) do |status, headers, body|
219
- headers.should.equal({
220
- 'Content-Encoding' => 'gzip',
221
- 'Vary' => 'Accept-Encoding',
222
- 'Last-Modified' => last_modified,
223
- 'Content-Type' => 'text/plain'
224
- })
225
- end
226
- end
227
-
228
- should 'do nothing when no-transform Cache-Control directive present' do
229
- options = {
230
- 'response_headers' => {
231
- 'Content-Type' => 'text/plain',
232
- 'Cache-Control' => 'no-transform'
233
- }
234
- }
235
- verify(200, 'Hello World!', { 'gzip' => nil }, options) do |status, headers, body|
236
- headers.should.not.include 'Content-Encoding'
237
- end
238
- end
239
-
240
- should 'do nothing when Content-Encoding already present' do
241
- options = {
242
- 'response_headers' => {
243
- 'Content-Type' => 'text/plain',
244
- 'Content-Encoding' => 'gzip'
245
- }
246
- }
247
- verify(200, 'Hello World!', { 'gzip' => nil }, options)
248
- end
249
-
250
- should 'deflate when Content-Encoding is identity' do
251
- options = {
252
- 'response_headers' => {
253
- 'Content-Type' => 'text/plain',
254
- 'Content-Encoding' => 'identity'
255
- }
256
- }
257
- verify(200, 'Hello World!', 'deflate', options)
258
- end
259
-
260
- should "deflate if content-type matches :include" do
261
- options = {
262
- 'response_headers' => {
263
- 'Content-Type' => 'text/plain'
264
- },
265
- 'deflater_options' => {
266
- :include => %w(text/plain)
267
- }
268
- }
269
- verify(200, 'Hello World!', 'gzip', options)
270
- end
271
-
272
- should "deflate if content-type is included it :include" do
273
- options = {
274
- 'response_headers' => {
275
- 'Content-Type' => 'text/plain; charset=us-ascii'
276
- },
277
- 'deflater_options' => {
278
- :include => %w(text/plain)
279
- }
280
- }
281
- verify(200, 'Hello World!', 'gzip', options)
282
- end
283
-
284
- should "not deflate if content-type is not set but given in :include" do
285
- options = {
286
- 'deflater_options' => {
287
- :include => %w(text/plain)
288
- }
289
- }
290
- verify(304, 'Hello World!', { 'gzip' => nil }, options)
291
- end
292
-
293
- should "not deflate if content-type do not match :include" do
294
- options = {
295
- 'response_headers' => {
296
- 'Content-Type' => 'text/plain'
297
- },
298
- 'deflater_options' => {
299
- :include => %w(text/json)
300
- }
301
- }
302
- verify(200, 'Hello World!', { 'gzip' => nil }, options)
303
- end
304
-
305
- should "deflate response if :if lambda evaluates to true" do
306
- options = {
307
- 'deflater_options' => {
308
- :if => lambda { |env, status, headers, body| true }
309
- }
310
- }
311
- verify(200, 'Hello World!', 'deflate', options)
312
- end
313
-
314
- should "not deflate if :if lambda evaluates to false" do
315
- options = {
316
- 'deflater_options' => {
317
- :if => lambda { |env, status, headers, body| false }
318
- }
319
- }
320
- verify(200, 'Hello World!', { 'gzip' => nil }, options)
321
- end
322
-
323
- should "check for Content-Length via :if" do
324
- body = 'Hello World!'
325
- body_len = body.length
326
- options = {
327
- 'response_headers' => {
328
- 'Content-Length' => body_len.to_s
329
- },
330
- 'deflater_options' => {
331
- :if => lambda { |env, status, headers, body|
332
- headers['Content-Length'].to_i >= body_len
333
- }
334
- }
335
- }
336
-
337
- verify(200, body, 'gzip', options)
338
- end
339
- end
@@ -1,88 +0,0 @@
1
- require 'rack/directory'
2
- require 'rack/lint'
3
- require 'rack/mock'
4
-
5
- describe Rack::Directory do
6
- DOCROOT = File.expand_path(File.dirname(__FILE__)) unless defined? DOCROOT
7
- FILE_CATCH = proc{|env| [200, {'Content-Type'=>'text/plain', "Content-Length" => "7"}, ['passed!']] }
8
- app = Rack::Lint.new(Rack::Directory.new(DOCROOT, FILE_CATCH))
9
-
10
- should "serve directory indices" do
11
- res = Rack::MockRequest.new(Rack::Lint.new(app)).
12
- get("/cgi/")
13
-
14
- res.should.be.ok
15
- res.should =~ /<html><head>/
16
- end
17
-
18
- should "pass to app if file found" do
19
- res = Rack::MockRequest.new(Rack::Lint.new(app)).
20
- get("/cgi/test")
21
-
22
- res.should.be.ok
23
- res.should =~ /passed!/
24
- end
25
-
26
- should "serve uri with URL encoded filenames" do
27
- res = Rack::MockRequest.new(Rack::Lint.new(app)).
28
- get("/%63%67%69/") # "/cgi/test"
29
-
30
- res.should.be.ok
31
- res.should =~ /<html><head>/
32
-
33
- res = Rack::MockRequest.new(Rack::Lint.new(app)).
34
- get("/cgi/%74%65%73%74") # "/cgi/test"
35
-
36
- res.should.be.ok
37
- res.should =~ /passed!/
38
- end
39
-
40
- should "not allow directory traversal" do
41
- res = Rack::MockRequest.new(Rack::Lint.new(app)).
42
- get("/cgi/../test")
43
-
44
- res.should.be.forbidden
45
-
46
- res = Rack::MockRequest.new(Rack::Lint.new(app)).
47
- get("/cgi/%2E%2E/test")
48
-
49
- res.should.be.forbidden
50
- end
51
-
52
- should "404 if it can't find the file" do
53
- res = Rack::MockRequest.new(Rack::Lint.new(app)).
54
- get("/cgi/blubb")
55
-
56
- res.should.be.not_found
57
- end
58
-
59
- should "uri escape path parts" do # #265, properly escape file names
60
- mr = Rack::MockRequest.new(Rack::Lint.new(app))
61
-
62
- res = mr.get("/cgi/test%2bdirectory")
63
-
64
- res.should.be.ok
65
- res.body.should =~ %r[/cgi/test%2Bdirectory/test%2Bfile]
66
-
67
- res = mr.get("/cgi/test%2bdirectory/test%2bfile")
68
- res.should.be.ok
69
- end
70
-
71
- should "correctly escape script name" do
72
- app2 = Rack::Builder.new do
73
- map '/script-path' do
74
- run app
75
- end
76
- end
77
-
78
- mr = Rack::MockRequest.new(Rack::Lint.new(app2))
79
-
80
- res = mr.get("/script-path/cgi/test%2bdirectory")
81
-
82
- res.should.be.ok
83
- res.body.should =~ %r[/script-path/cgi/test%2Bdirectory/test%2Bfile]
84
-
85
- res = mr.get("/script-path/cgi/test%2bdirectory/test%2bfile")
86
- res.should.be.ok
87
- end
88
- end