rack 2.0.6 → 2.2.3

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 +694 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +152 -148
  6. data/Rakefile +37 -23
  7. data/{SPEC → SPEC.rdoc} +38 -10
  8. data/bin/rackup +1 -0
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +3 -1
  11. data/example/protectedlobster.ru +2 -0
  12. data/lib/rack.rb +67 -73
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +1 -1
  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 +4 -2
  19. data/lib/rack/auth/digest/request.rb +5 -3
  20. data/lib/rack/body_proxy.rb +15 -14
  21. data/lib/rack/builder.rb +116 -23
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +68 -20
  24. data/lib/rack/common_logger.rb +33 -25
  25. data/lib/rack/conditional_get.rb +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +8 -7
  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 +59 -34
  31. data/lib/rack/directory.rb +84 -64
  32. data/lib/rack/etag.rb +5 -4
  33. data/lib/rack/events.rb +19 -20
  34. data/lib/rack/file.rb +4 -173
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler.rb +7 -2
  37. data/lib/rack/handler/cgi.rb +2 -3
  38. data/lib/rack/handler/fastcgi.rb +4 -4
  39. data/lib/rack/handler/lsws.rb +3 -3
  40. data/lib/rack/handler/scgi.rb +9 -8
  41. data/lib/rack/handler/thin.rb +3 -3
  42. data/lib/rack/handler/webrick.rb +15 -6
  43. data/lib/rack/head.rb +1 -1
  44. data/lib/rack/lint.rb +71 -25
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +2 -1
  47. data/lib/rack/logger.rb +2 -0
  48. data/lib/rack/media_type.rb +10 -5
  49. data/lib/rack/method_override.rb +4 -2
  50. data/lib/rack/mime.rb +9 -1
  51. data/lib/rack/mock.rb +97 -20
  52. data/lib/rack/multipart.rb +6 -4
  53. data/lib/rack/multipart/generator.rb +17 -13
  54. data/lib/rack/multipart/parser.rb +57 -62
  55. data/lib/rack/multipart/uploaded_file.rb +15 -7
  56. data/lib/rack/null_logger.rb +2 -0
  57. data/lib/rack/query_parser.rb +53 -28
  58. data/lib/rack/recursive.rb +7 -5
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +220 -61
  61. data/lib/rack/response.rb +127 -44
  62. data/lib/rack/rewindable_input.rb +4 -3
  63. data/lib/rack/runtime.rb +6 -4
  64. data/lib/rack/sendfile.rb +13 -9
  65. data/lib/rack/server.rb +95 -24
  66. data/lib/rack/session/abstract/id.rb +100 -22
  67. data/lib/rack/session/cookie.rb +22 -14
  68. data/lib/rack/session/memcache.rb +4 -87
  69. data/lib/rack/session/pool.rb +18 -9
  70. data/lib/rack/show_exceptions.rb +21 -17
  71. data/lib/rack/show_status.rb +9 -9
  72. data/lib/rack/static.rb +23 -11
  73. data/lib/rack/tempfile_reaper.rb +1 -1
  74. data/lib/rack/urlmap.rb +12 -6
  75. data/lib/rack/utils.rb +102 -109
  76. data/lib/rack/version.rb +29 -0
  77. data/rack.gemspec +40 -28
  78. metadata +39 -181
  79. data/HISTORY.md +0 -505
  80. data/test/builder/an_underscore_app.rb +0 -5
  81. data/test/builder/anything.rb +0 -5
  82. data/test/builder/comment.ru +0 -4
  83. data/test/builder/end.ru +0 -5
  84. data/test/builder/line.ru +0 -1
  85. data/test/builder/options.ru +0 -2
  86. data/test/cgi/assets/folder/test.js +0 -1
  87. data/test/cgi/assets/fonts/font.eot +0 -1
  88. data/test/cgi/assets/images/image.png +0 -1
  89. data/test/cgi/assets/index.html +0 -1
  90. data/test/cgi/assets/javascripts/app.js +0 -1
  91. data/test/cgi/assets/stylesheets/app.css +0 -1
  92. data/test/cgi/lighttpd.conf +0 -26
  93. data/test/cgi/rackup_stub.rb +0 -6
  94. data/test/cgi/sample_rackup.ru +0 -5
  95. data/test/cgi/test +0 -9
  96. data/test/cgi/test+directory/test+file +0 -1
  97. data/test/cgi/test.fcgi +0 -9
  98. data/test/cgi/test.gz +0 -0
  99. data/test/cgi/test.ru +0 -5
  100. data/test/gemloader.rb +0 -10
  101. data/test/helper.rb +0 -34
  102. data/test/multipart/bad_robots +0 -259
  103. data/test/multipart/binary +0 -0
  104. data/test/multipart/content_type_and_no_filename +0 -6
  105. data/test/multipart/empty +0 -10
  106. data/test/multipart/fail_16384_nofile +0 -814
  107. data/test/multipart/file1.txt +0 -1
  108. data/test/multipart/filename_and_modification_param +0 -7
  109. data/test/multipart/filename_and_no_name +0 -6
  110. data/test/multipart/filename_with_encoded_words +0 -7
  111. data/test/multipart/filename_with_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  113. data/test/multipart/filename_with_null_byte +0 -7
  114. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  115. data/test/multipart/filename_with_single_quote +0 -7
  116. data/test/multipart/filename_with_unescaped_percentages +0 -6
  117. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  119. data/test/multipart/filename_with_unescaped_quotes +0 -6
  120. data/test/multipart/ie +0 -6
  121. data/test/multipart/invalid_character +0 -6
  122. data/test/multipart/mixed_files +0 -21
  123. data/test/multipart/nested +0 -10
  124. data/test/multipart/none +0 -9
  125. data/test/multipart/quoted +0 -15
  126. data/test/multipart/rack-logo.png +0 -0
  127. data/test/multipart/semicolon +0 -6
  128. data/test/multipart/text +0 -15
  129. data/test/multipart/three_files_three_fields +0 -31
  130. data/test/multipart/unity3d_wwwform +0 -11
  131. data/test/multipart/webkit +0 -32
  132. data/test/rackup/config.ru +0 -31
  133. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  134. data/test/spec_auth_basic.rb +0 -89
  135. data/test/spec_auth_digest.rb +0 -260
  136. data/test/spec_body_proxy.rb +0 -85
  137. data/test/spec_builder.rb +0 -233
  138. data/test/spec_cascade.rb +0 -63
  139. data/test/spec_cgi.rb +0 -84
  140. data/test/spec_chunked.rb +0 -103
  141. data/test/spec_common_logger.rb +0 -95
  142. data/test/spec_conditional_get.rb +0 -103
  143. data/test/spec_config.rb +0 -23
  144. data/test/spec_content_length.rb +0 -86
  145. data/test/spec_content_type.rb +0 -46
  146. data/test/spec_deflater.rb +0 -375
  147. data/test/spec_directory.rb +0 -148
  148. data/test/spec_etag.rb +0 -108
  149. data/test/spec_events.rb +0 -133
  150. data/test/spec_fastcgi.rb +0 -85
  151. data/test/spec_file.rb +0 -264
  152. data/test/spec_handler.rb +0 -57
  153. data/test/spec_head.rb +0 -46
  154. data/test/spec_lint.rb +0 -515
  155. data/test/spec_lobster.rb +0 -59
  156. data/test/spec_lock.rb +0 -204
  157. data/test/spec_logger.rb +0 -24
  158. data/test/spec_media_type.rb +0 -42
  159. data/test/spec_method_override.rb +0 -110
  160. data/test/spec_mime.rb +0 -51
  161. data/test/spec_mock.rb +0 -359
  162. data/test/spec_multipart.rb +0 -722
  163. data/test/spec_null_logger.rb +0 -21
  164. data/test/spec_recursive.rb +0 -75
  165. data/test/spec_request.rb +0 -1398
  166. data/test/spec_response.rb +0 -510
  167. data/test/spec_rewindable_input.rb +0 -128
  168. data/test/spec_runtime.rb +0 -50
  169. data/test/spec_sendfile.rb +0 -125
  170. data/test/spec_server.rb +0 -193
  171. data/test/spec_session_abstract_id.rb +0 -31
  172. data/test/spec_session_abstract_session_hash.rb +0 -45
  173. data/test/spec_session_cookie.rb +0 -442
  174. data/test/spec_session_memcache.rb +0 -320
  175. data/test/spec_session_pool.rb +0 -210
  176. data/test/spec_show_exceptions.rb +0 -93
  177. data/test/spec_show_status.rb +0 -104
  178. data/test/spec_static.rb +0 -184
  179. data/test/spec_tempfile_reaper.rb +0 -64
  180. data/test/spec_thin.rb +0 -96
  181. data/test/spec_urlmap.rb +0 -237
  182. data/test/spec_utils.rb +0 -742
  183. data/test/spec_version.rb +0 -11
  184. data/test/spec_webrick.rb +0 -206
  185. data/test/static/another/index.html +0 -1
  186. data/test/static/foo.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,103 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/chunked'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::Chunked do
7
- def chunked(app)
8
- proc do |env|
9
- app = Rack::Chunked.new(app)
10
- response = Rack::Lint.new(app).call(env)
11
- # we want to use body like an array, but it only has #each
12
- response[2] = response[2].to_enum.to_a
13
- response
14
- end
15
- end
16
-
17
- before do
18
- @env = Rack::MockRequest.
19
- env_for('/', 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => 'GET')
20
- end
21
-
22
- it 'chunk responses with no Content-Length' do
23
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
24
- response = Rack::MockResponse.new(*chunked(app).call(@env))
25
- response.headers.wont_include 'Content-Length'
26
- response.headers['Transfer-Encoding'].must_equal 'chunked'
27
- response.body.must_equal "5\r\nHello\r\n1\r\n \r\n6\r\nWorld!\r\n0\r\n\r\n"
28
- end
29
-
30
- it 'chunks empty bodies properly' do
31
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, []] }
32
- response = Rack::MockResponse.new(*chunked(app).call(@env))
33
- response.headers.wont_include 'Content-Length'
34
- response.headers['Transfer-Encoding'].must_equal 'chunked'
35
- response.body.must_equal "0\r\n\r\n"
36
- end
37
-
38
- it 'chunks encoded bodies properly' do
39
- body = ["\uFFFEHello", " ", "World"].map {|t| t.encode("UTF-16LE") }
40
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, body] }
41
- response = Rack::MockResponse.new(*chunked(app).call(@env))
42
- response.headers.wont_include 'Content-Length'
43
- response.headers['Transfer-Encoding'].must_equal 'chunked'
44
- response.body.encoding.to_s.must_equal "ASCII-8BIT"
45
- response.body.must_equal "c\r\n\xFE\xFFH\x00e\x00l\x00l\x00o\x00\r\n2\r\n \x00\r\na\r\nW\x00o\x00r\x00l\x00d\x00\r\n0\r\n\r\n".force_encoding("BINARY")
46
- response.body.must_equal "c\r\n\xFE\xFFH\x00e\x00l\x00l\x00o\x00\r\n2\r\n \x00\r\na\r\nW\x00o\x00r\x00l\x00d\x00\r\n0\r\n\r\n".force_encoding(Encoding::BINARY)
47
- end
48
-
49
- it 'not modify response when Content-Length header present' do
50
- app = lambda { |env|
51
- [200, {"Content-Type" => "text/plain", 'Content-Length'=>'12'}, ['Hello', ' ', 'World!']]
52
- }
53
- status, headers, body = chunked(app).call(@env)
54
- status.must_equal 200
55
- headers.wont_include 'Transfer-Encoding'
56
- headers.must_include 'Content-Length'
57
- body.join.must_equal 'Hello World!'
58
- end
59
-
60
- it 'not modify response when client is HTTP/1.0' do
61
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
62
- @env['HTTP_VERSION'] = 'HTTP/1.0'
63
- status, headers, body = chunked(app).call(@env)
64
- status.must_equal 200
65
- headers.wont_include 'Transfer-Encoding'
66
- body.join.must_equal 'Hello World!'
67
- end
68
-
69
- it 'not modify response when client is ancient, pre-HTTP/1.0' do
70
- app = lambda { |env| [200, {"Content-Type" => "text/plain"}, ['Hello', ' ', 'World!']] }
71
- check = lambda do
72
- status, headers, body = chunked(app).call(@env.dup)
73
- status.must_equal 200
74
- headers.wont_include 'Transfer-Encoding'
75
- body.join.must_equal 'Hello World!'
76
- end
77
-
78
- @env.delete('HTTP_VERSION') # unicorn will do this on pre-HTTP/1.0 requests
79
- check.call
80
-
81
- @env['HTTP_VERSION'] = 'HTTP/0.9' # not sure if this happens in practice
82
- check.call
83
- end
84
-
85
- it 'not modify response when Transfer-Encoding header already present' do
86
- app = lambda { |env|
87
- [200, {"Content-Type" => "text/plain", 'Transfer-Encoding' => 'identity'}, ['Hello', ' ', 'World!']]
88
- }
89
- status, headers, body = chunked(app).call(@env)
90
- status.must_equal 200
91
- headers['Transfer-Encoding'].must_equal 'identity'
92
- body.join.must_equal 'Hello World!'
93
- end
94
-
95
- [100, 204, 304].each do |status_code|
96
- it "not modify response when status code is #{status_code}" do
97
- app = lambda { |env| [status_code, {}, []] }
98
- status, headers, _ = chunked(app).call(@env)
99
- status.must_equal status_code
100
- headers.wont_include 'Transfer-Encoding'
101
- end
102
- end
103
- end
@@ -1,95 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/common_logger'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- require 'logger'
7
-
8
- describe Rack::CommonLogger do
9
- obj = 'foobar'
10
- length = obj.size
11
-
12
- app = Rack::Lint.new lambda { |env|
13
- [200,
14
- {"Content-Type" => "text/html", "Content-Length" => length.to_s},
15
- [obj]]}
16
- app_without_length = Rack::Lint.new lambda { |env|
17
- [200,
18
- {"Content-Type" => "text/html"},
19
- []]}
20
- app_with_zero_length = Rack::Lint.new lambda { |env|
21
- [200,
22
- {"Content-Type" => "text/html", "Content-Length" => "0"},
23
- []]}
24
-
25
- it "log to rack.errors by default" do
26
- res = Rack::MockRequest.new(Rack::CommonLogger.new(app)).get("/")
27
-
28
- res.errors.wont_be :empty?
29
- res.errors.must_match(/"GET \/ " 200 #{length} /)
30
- end
31
-
32
- it "log to anything with +write+" do
33
- log = StringIO.new
34
- Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
35
-
36
- log.string.must_match(/"GET \/ " 200 #{length} /)
37
- end
38
-
39
- it "work with standartd library logger" do
40
- logdev = StringIO.new
41
- log = Logger.new(logdev)
42
- Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
43
-
44
- logdev.string.must_match(/"GET \/ " 200 #{length} /)
45
- end
46
-
47
- it "log - content length if header is missing" do
48
- res = Rack::MockRequest.new(Rack::CommonLogger.new(app_without_length)).get("/")
49
-
50
- res.errors.wont_be :empty?
51
- res.errors.must_match(/"GET \/ " 200 - /)
52
- end
53
-
54
- it "log - content length if header is zero" do
55
- res = Rack::MockRequest.new(Rack::CommonLogger.new(app_with_zero_length)).get("/")
56
-
57
- res.errors.wont_be :empty?
58
- res.errors.must_match(/"GET \/ " 200 - /)
59
- end
60
-
61
- def with_mock_time(t = 0)
62
- mc = class << Time; self; end
63
- mc.send :alias_method, :old_now, :now
64
- mc.send :define_method, :now do
65
- at(t)
66
- end
67
- yield
68
- ensure
69
- mc.send :undef_method, :now
70
- mc.send :alias_method, :now, :old_now
71
- end
72
-
73
- it "log in common log format" do
74
- log = StringIO.new
75
- with_mock_time do
76
- Rack::MockRequest.new(Rack::CommonLogger.new(app, log)).get("/")
77
- end
78
-
79
- md = /- - - \[([^\]]+)\] "(\w+) \/ " (\d{3}) \d+ ([\d\.]+)/.match(log.string)
80
- md.wont_equal nil
81
- time, method, status, duration = *md.captures
82
- time.must_equal Time.at(0).strftime("%d/%b/%Y:%H:%M:%S %z")
83
- method.must_equal "GET"
84
- status.must_equal "200"
85
- (0..1).must_include duration.to_f
86
- end
87
-
88
- def length
89
- 123
90
- end
91
-
92
- def self.obj
93
- "hello world"
94
- end
95
- end
@@ -1,103 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'time'
3
- require 'rack/conditional_get'
4
- require 'rack/mock'
5
-
6
- describe Rack::ConditionalGet do
7
- def conditional_get(app)
8
- Rack::Lint.new Rack::ConditionalGet.new(app)
9
- end
10
-
11
- it "set a 304 status and truncate body when If-Modified-Since hits" do
12
- timestamp = Time.now.httpdate
13
- app = conditional_get(lambda { |env|
14
- [200, {'Last-Modified'=>timestamp}, ['TEST']] })
15
-
16
- response = Rack::MockRequest.new(app).
17
- get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp)
18
-
19
- response.status.must_equal 304
20
- response.body.must_be :empty?
21
- end
22
-
23
- it "set a 304 status and truncate body when If-Modified-Since hits and is higher than current time" do
24
- app = conditional_get(lambda { |env|
25
- [200, {'Last-Modified'=>(Time.now - 3600).httpdate}, ['TEST']] })
26
-
27
- response = Rack::MockRequest.new(app).
28
- get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate)
29
-
30
- response.status.must_equal 304
31
- response.body.must_be :empty?
32
- end
33
-
34
- it "set a 304 status and truncate body when If-None-Match hits" do
35
- app = conditional_get(lambda { |env|
36
- [200, {'ETag'=>'1234'}, ['TEST']] })
37
-
38
- response = Rack::MockRequest.new(app).
39
- get("/", 'HTTP_IF_NONE_MATCH' => '1234')
40
-
41
- response.status.must_equal 304
42
- response.body.must_be :empty?
43
- end
44
-
45
- it "not set a 304 status if If-Modified-Since hits but Etag does not" do
46
- timestamp = Time.now.httpdate
47
- app = conditional_get(lambda { |env|
48
- [200, {'Last-Modified'=>timestamp, 'Etag'=>'1234', 'Content-Type' => 'text/plain'}, ['TEST']] })
49
-
50
- response = Rack::MockRequest.new(app).
51
- get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp, 'HTTP_IF_NONE_MATCH' => '4321')
52
-
53
- response.status.must_equal 200
54
- response.body.must_equal 'TEST'
55
- end
56
-
57
- it "set a 304 status and truncate body when both If-None-Match and If-Modified-Since hits" do
58
- timestamp = Time.now.httpdate
59
- app = conditional_get(lambda { |env|
60
- [200, {'Last-Modified'=>timestamp, 'ETag'=>'1234'}, ['TEST']] })
61
-
62
- response = Rack::MockRequest.new(app).
63
- get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp, 'HTTP_IF_NONE_MATCH' => '1234')
64
-
65
- response.status.must_equal 304
66
- response.body.must_be :empty?
67
- end
68
-
69
- it "not affect non-GET/HEAD requests" do
70
- app = conditional_get(lambda { |env|
71
- [200, {'Etag'=>'1234', 'Content-Type' => 'text/plain'}, ['TEST']] })
72
-
73
- response = Rack::MockRequest.new(app).
74
- post("/", 'HTTP_IF_NONE_MATCH' => '1234')
75
-
76
- response.status.must_equal 200
77
- response.body.must_equal 'TEST'
78
- end
79
-
80
- it "not affect non-200 requests" do
81
- app = conditional_get(lambda { |env|
82
- [302, {'Etag'=>'1234', 'Content-Type' => 'text/plain'}, ['TEST']] })
83
-
84
- response = Rack::MockRequest.new(app).
85
- get("/", 'HTTP_IF_NONE_MATCH' => '1234')
86
-
87
- response.status.must_equal 302
88
- response.body.must_equal 'TEST'
89
- end
90
-
91
- it "not affect requests with malformed HTTP_IF_NONE_MATCH" do
92
- bad_timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S %z')
93
- app = conditional_get(lambda { |env|
94
- [200,{'Last-Modified'=>(Time.now - 3600).httpdate, 'Content-Type' => 'text/plain'}, ['TEST']] })
95
-
96
- response = Rack::MockRequest.new(app).
97
- get("/", 'HTTP_IF_MODIFIED_SINCE' => bad_timestamp)
98
-
99
- response.status.must_equal 200
100
- response.body.must_equal 'TEST'
101
- end
102
-
103
- end
@@ -1,23 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/builder'
3
- require 'rack/config'
4
- require 'rack/content_length'
5
- require 'rack/lint'
6
- require 'rack/mock'
7
-
8
- describe Rack::Config do
9
- it "accept a block that modifies the environment" do
10
- app = Rack::Builder.new do
11
- use Rack::Lint
12
- use Rack::Config do |env|
13
- env['greeting'] = 'hello'
14
- end
15
- run lambda { |env|
16
- [200, {'Content-Type' => 'text/plain'}, [env['greeting'] || '']]
17
- }
18
- end
19
-
20
- response = Rack::MockRequest.new(app).get('/')
21
- response.body.must_equal 'hello'
22
- end
23
- end
@@ -1,86 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/content_length'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::ContentLength do
7
- def content_length(app)
8
- Rack::Lint.new Rack::ContentLength.new(app)
9
- end
10
-
11
- def request
12
- Rack::MockRequest.env_for
13
- end
14
-
15
- it "set Content-Length on Array bodies if none is set" do
16
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ["Hello, World!"]] }
17
- response = content_length(app).call(request)
18
- response[1]['Content-Length'].must_equal '13'
19
- end
20
-
21
- it "not set Content-Length on variable length bodies" do
22
- body = lambda { "Hello World!" }
23
- def body.each ; yield call ; end
24
-
25
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
26
- response = content_length(app).call(request)
27
- response[1]['Content-Length'].must_be_nil
28
- end
29
-
30
- it "not change Content-Length if it is already set" do
31
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Length' => '1'}, "Hello, World!"] }
32
- response = content_length(app).call(request)
33
- response[1]['Content-Length'].must_equal '1'
34
- end
35
-
36
- it "not set Content-Length on 304 responses" do
37
- app = lambda { |env| [304, {}, []] }
38
- response = content_length(app).call(request)
39
- response[1]['Content-Length'].must_be_nil
40
- end
41
-
42
- it "not set Content-Length when Transfer-Encoding is chunked" do
43
- app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Transfer-Encoding' => 'chunked'}, []] }
44
- response = content_length(app).call(request)
45
- response[1]['Content-Length'].must_be_nil
46
- end
47
-
48
- # Using "Connection: close" for this is fairly contended. It might be useful
49
- # to have some other way to signal this.
50
- #
51
- # should "not force a Content-Length when Connection:close" do
52
- # app = lambda { |env| [200, {'Connection' => 'close'}, []] }
53
- # response = content_length(app).call({})
54
- # response[1]['Content-Length'].must_be_nil
55
- # end
56
-
57
- it "close bodies that need to be closed" do
58
- body = Struct.new(:body) do
59
- attr_reader :closed
60
- def each; body.join; end
61
- def close; @closed = true; end
62
- def to_ary; end
63
- end.new(%w[one two three])
64
-
65
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
66
- response = content_length(app).call(request)
67
- body.closed.must_be_nil
68
- response[2].close
69
- body.closed.must_equal true
70
- end
71
-
72
- it "support single-execute bodies" do
73
- body = Struct.new(:body) do
74
- def each
75
- yield body.shift until body.empty?
76
- end
77
- def to_ary; end
78
- end.new(%w[one two three])
79
-
80
- app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, body] }
81
- response = content_length(app).call(request)
82
- expected = %w[one two three]
83
- response[1]['Content-Length'].must_equal expected.join.size.to_s
84
- response[2].to_enum.to_a.must_equal expected
85
- end
86
- end
@@ -1,46 +0,0 @@
1
- require 'minitest/autorun'
2
- require 'rack/content_type'
3
- require 'rack/lint'
4
- require 'rack/mock'
5
-
6
- describe Rack::ContentType do
7
- def content_type(app, *args)
8
- Rack::Lint.new Rack::ContentType.new(app, *args)
9
- end
10
-
11
- def request
12
- Rack::MockRequest.env_for
13
- end
14
-
15
- it "set Content-Type to default text/html if none is set" do
16
- app = lambda { |env| [200, {}, "Hello, World!"] }
17
- headers = content_type(app).call(request)[1]
18
- headers['Content-Type'].must_equal 'text/html'
19
- end
20
-
21
- it "set Content-Type to chosen default if none is set" do
22
- app = lambda { |env| [200, {}, "Hello, World!"] }
23
- headers =
24
- content_type(app, 'application/octet-stream').call(request)[1]
25
- headers['Content-Type'].must_equal 'application/octet-stream'
26
- end
27
-
28
- it "not change Content-Type if it is already set" do
29
- app = lambda { |env| [200, {'Content-Type' => 'foo/bar'}, "Hello, World!"] }
30
- headers = content_type(app).call(request)[1]
31
- headers['Content-Type'].must_equal 'foo/bar'
32
- end
33
-
34
- it "detect Content-Type case insensitive" do
35
- app = lambda { |env| [200, {'CONTENT-Type' => 'foo/bar'}, "Hello, World!"] }
36
- headers = content_type(app).call(request)[1]
37
- headers.to_a.select { |k,v| k.downcase == "content-type" }.
38
- must_equal [["CONTENT-Type","foo/bar"]]
39
- end
40
-
41
- it "not set Content-Type on 304 responses" do
42
- app = lambda { |env| [304, {}, []] }
43
- response = content_type(app, "text/html").call(request)
44
- response[1]['Content-Type'].must_be_nil
45
- end
46
- end