rack 2.0.9 → 2.1.4
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +77 -0
- data/{COPYING → MIT-LICENSE} +4 -2
- data/README.rdoc +77 -117
- data/Rakefile +25 -18
- data/SPEC +3 -4
- data/bin/rackup +1 -0
- data/example/lobster.ru +2 -0
- data/example/protectedlobster.rb +3 -1
- data/example/protectedlobster.ru +2 -0
- data/lib/rack.rb +63 -60
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +2 -0
- data/lib/rack/auth/basic.rb +4 -1
- data/lib/rack/auth/digest/md5.rb +9 -7
- data/lib/rack/auth/digest/nonce.rb +6 -3
- data/lib/rack/auth/digest/params.rb +4 -2
- data/lib/rack/auth/digest/request.rb +2 -0
- data/lib/rack/body_proxy.rb +3 -6
- data/lib/rack/builder.rb +39 -15
- data/lib/rack/cascade.rb +6 -5
- data/lib/rack/chunked.rb +29 -6
- data/lib/rack/common_logger.rb +9 -8
- data/lib/rack/conditional_get.rb +3 -1
- data/lib/rack/config.rb +2 -0
- data/lib/rack/content_length.rb +3 -1
- data/lib/rack/content_type.rb +3 -1
- data/lib/rack/core_ext/regexp.rb +14 -0
- data/lib/rack/deflater.rb +32 -17
- data/lib/rack/directory.rb +19 -16
- data/lib/rack/etag.rb +3 -1
- data/lib/rack/events.rb +5 -3
- data/lib/rack/file.rb +4 -173
- data/lib/rack/files.rb +178 -0
- data/lib/rack/handler.rb +7 -2
- data/lib/rack/handler/cgi.rb +3 -1
- data/lib/rack/handler/fastcgi.rb +4 -2
- data/lib/rack/handler/lsws.rb +3 -1
- data/lib/rack/handler/scgi.rb +9 -6
- data/lib/rack/handler/thin.rb +3 -1
- data/lib/rack/handler/webrick.rb +4 -2
- data/lib/rack/head.rb +2 -0
- data/lib/rack/lint.rb +14 -11
- data/lib/rack/lobster.rb +7 -5
- data/lib/rack/lock.rb +2 -0
- data/lib/rack/logger.rb +2 -0
- data/lib/rack/media_type.rb +10 -5
- data/lib/rack/method_override.rb +4 -2
- data/lib/rack/mime.rb +9 -1
- data/lib/rack/mock.rb +74 -15
- data/lib/rack/multipart.rb +5 -3
- data/lib/rack/multipart/generator.rb +6 -7
- data/lib/rack/multipart/parser.rb +51 -45
- data/lib/rack/multipart/uploaded_file.rb +2 -0
- data/lib/rack/null_logger.rb +2 -0
- data/lib/rack/query_parser.rb +51 -25
- data/lib/rack/recursive.rb +7 -5
- data/lib/rack/reloader.rb +10 -4
- data/lib/rack/request.rb +79 -26
- data/lib/rack/response.rb +71 -31
- data/lib/rack/rewindable_input.rb +4 -2
- data/lib/rack/runtime.rb +4 -2
- data/lib/rack/sendfile.rb +15 -8
- data/lib/rack/server.rb +88 -18
- data/lib/rack/session/abstract/id.rb +30 -20
- data/lib/rack/session/cookie.rb +10 -9
- data/lib/rack/session/memcache.rb +4 -93
- data/lib/rack/session/pool.rb +4 -2
- data/lib/rack/show_exceptions.rb +15 -9
- data/lib/rack/show_status.rb +4 -2
- data/lib/rack/static.rb +15 -10
- data/lib/rack/tempfile_reaper.rb +2 -0
- data/lib/rack/urlmap.rb +11 -2
- data/lib/rack/utils.rb +59 -72
- data/rack.gemspec +17 -7
- metadata +33 -175
- data/HISTORY.md +0 -505
- data/test/builder/an_underscore_app.rb +0 -5
- data/test/builder/anything.rb +0 -5
- data/test/builder/comment.ru +0 -4
- data/test/builder/end.ru +0 -5
- data/test/builder/line.ru +0 -1
- data/test/builder/options.ru +0 -2
- data/test/cgi/assets/folder/test.js +0 -1
- data/test/cgi/assets/fonts/font.eot +0 -1
- data/test/cgi/assets/images/image.png +0 -1
- data/test/cgi/assets/index.html +0 -1
- data/test/cgi/assets/javascripts/app.js +0 -1
- data/test/cgi/assets/stylesheets/app.css +0 -1
- data/test/cgi/lighttpd.conf +0 -26
- data/test/cgi/rackup_stub.rb +0 -6
- data/test/cgi/sample_rackup.ru +0 -5
- data/test/cgi/test +0 -9
- data/test/cgi/test+directory/test+file +0 -1
- data/test/cgi/test.fcgi +0 -9
- data/test/cgi/test.gz +0 -0
- data/test/cgi/test.ru +0 -5
- data/test/gemloader.rb +0 -10
- data/test/helper.rb +0 -34
- data/test/multipart/bad_robots +0 -259
- data/test/multipart/binary +0 -0
- data/test/multipart/content_type_and_no_filename +0 -6
- data/test/multipart/empty +0 -10
- data/test/multipart/fail_16384_nofile +0 -814
- data/test/multipart/file1.txt +0 -1
- data/test/multipart/filename_and_modification_param +0 -7
- data/test/multipart/filename_and_no_name +0 -6
- data/test/multipart/filename_with_encoded_words +0 -7
- data/test/multipart/filename_with_escaped_quotes +0 -6
- data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
- data/test/multipart/filename_with_null_byte +0 -7
- data/test/multipart/filename_with_percent_escaped_quotes +0 -6
- data/test/multipart/filename_with_single_quote +0 -7
- data/test/multipart/filename_with_unescaped_percentages +0 -6
- data/test/multipart/filename_with_unescaped_percentages2 +0 -6
- data/test/multipart/filename_with_unescaped_percentages3 +0 -6
- data/test/multipart/filename_with_unescaped_quotes +0 -6
- data/test/multipart/ie +0 -6
- data/test/multipart/invalid_character +0 -6
- data/test/multipart/mixed_files +0 -21
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/quoted +0 -15
- data/test/multipart/rack-logo.png +0 -0
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -15
- data/test/multipart/three_files_three_fields +0 -31
- data/test/multipart/unity3d_wwwform +0 -11
- data/test/multipart/webkit +0 -32
- data/test/rackup/config.ru +0 -31
- data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
- data/test/spec_auth_basic.rb +0 -89
- data/test/spec_auth_digest.rb +0 -260
- data/test/spec_body_proxy.rb +0 -85
- data/test/spec_builder.rb +0 -233
- data/test/spec_cascade.rb +0 -63
- data/test/spec_cgi.rb +0 -84
- data/test/spec_chunked.rb +0 -103
- data/test/spec_common_logger.rb +0 -95
- data/test/spec_conditional_get.rb +0 -103
- data/test/spec_config.rb +0 -23
- data/test/spec_content_length.rb +0 -86
- data/test/spec_content_type.rb +0 -46
- data/test/spec_deflater.rb +0 -375
- data/test/spec_directory.rb +0 -148
- data/test/spec_etag.rb +0 -108
- data/test/spec_events.rb +0 -133
- data/test/spec_fastcgi.rb +0 -85
- data/test/spec_file.rb +0 -264
- data/test/spec_handler.rb +0 -57
- data/test/spec_head.rb +0 -46
- data/test/spec_lint.rb +0 -515
- data/test/spec_lobster.rb +0 -59
- data/test/spec_lock.rb +0 -204
- data/test/spec_logger.rb +0 -24
- data/test/spec_media_type.rb +0 -42
- data/test/spec_method_override.rb +0 -110
- data/test/spec_mime.rb +0 -51
- data/test/spec_mock.rb +0 -359
- data/test/spec_multipart.rb +0 -722
- data/test/spec_null_logger.rb +0 -21
- data/test/spec_recursive.rb +0 -75
- data/test/spec_request.rb +0 -1407
- data/test/spec_response.rb +0 -528
- data/test/spec_rewindable_input.rb +0 -128
- data/test/spec_runtime.rb +0 -50
- data/test/spec_sendfile.rb +0 -125
- data/test/spec_server.rb +0 -193
- data/test/spec_session_abstract_id.rb +0 -31
- data/test/spec_session_abstract_session_hash.rb +0 -45
- data/test/spec_session_cookie.rb +0 -442
- data/test/spec_session_memcache.rb +0 -357
- data/test/spec_session_persisted_secure_secure_session_hash.rb +0 -73
- data/test/spec_session_pool.rb +0 -247
- data/test/spec_show_exceptions.rb +0 -93
- data/test/spec_show_status.rb +0 -104
- data/test/spec_static.rb +0 -184
- data/test/spec_tempfile_reaper.rb +0 -64
- data/test/spec_thin.rb +0 -96
- data/test/spec_urlmap.rb +0 -237
- data/test/spec_utils.rb +0 -742
- data/test/spec_version.rb +0 -11
- data/test/spec_webrick.rb +0 -206
- data/test/static/another/index.html +0 -1
- data/test/static/foo.html +0 -1
- data/test/static/index.html +0 -1
- data/test/testrequest.rb +0 -78
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/lib/rack/cascade.rb
CHANGED
@@ -1,15 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Rack
|
2
4
|
# Rack::Cascade tries a request on several apps, and returns the
|
3
5
|
# first response that is not 404 or 405 (or in a list of configurable
|
4
6
|
# status codes).
|
5
7
|
|
6
8
|
class Cascade
|
7
|
-
NotFound = [404, {CONTENT_TYPE => "text/plain"}, []]
|
9
|
+
NotFound = [404, { CONTENT_TYPE => "text/plain" }, []]
|
8
10
|
|
9
11
|
attr_reader :apps
|
10
12
|
|
11
|
-
def initialize(apps, catch=[404, 405])
|
12
|
-
@apps = []
|
13
|
+
def initialize(apps, catch = [404, 405])
|
14
|
+
@apps = []
|
13
15
|
apps.each { |app| add app }
|
14
16
|
|
15
17
|
@catch = {}
|
@@ -39,12 +41,11 @@ module Rack
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def add(app)
|
42
|
-
@has_app[app] = true
|
43
44
|
@apps << app
|
44
45
|
end
|
45
46
|
|
46
47
|
def include?(app)
|
47
|
-
@
|
48
|
+
@apps.include?(app)
|
48
49
|
end
|
49
50
|
|
50
51
|
alias_method :<<, :add
|
data/lib/rack/chunked.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
|
3
5
|
module Rack
|
@@ -10,7 +12,7 @@ module Rack
|
|
10
12
|
# A body wrapper that emits chunked responses
|
11
13
|
class Body
|
12
14
|
TERM = "\r\n"
|
13
|
-
TAIL = "0#{TERM}
|
15
|
+
TAIL = "0#{TERM}"
|
14
16
|
|
15
17
|
include Rack::Utils
|
16
18
|
|
@@ -18,7 +20,7 @@ module Rack
|
|
18
20
|
@body = body
|
19
21
|
end
|
20
22
|
|
21
|
-
def each
|
23
|
+
def each(&block)
|
22
24
|
term = TERM
|
23
25
|
@body.each do |chunk|
|
24
26
|
size = chunk.bytesize
|
@@ -28,11 +30,28 @@ module Rack
|
|
28
30
|
yield [size.to_s(16), term, chunk, term].join
|
29
31
|
end
|
30
32
|
yield TAIL
|
33
|
+
insert_trailers(&block)
|
34
|
+
yield TERM
|
31
35
|
end
|
32
36
|
|
33
37
|
def close
|
34
38
|
@body.close if @body.respond_to?(:close)
|
35
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def insert_trailers(&block)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class TrailerBody < Body
|
48
|
+
private
|
49
|
+
|
50
|
+
def insert_trailers(&block)
|
51
|
+
@body.trailers.each_pair do |k, v|
|
52
|
+
yield "#{k}: #{v}\r\n"
|
53
|
+
end
|
54
|
+
end
|
36
55
|
end
|
37
56
|
|
38
57
|
def initialize(app)
|
@@ -43,7 +62,7 @@ module Rack
|
|
43
62
|
# a version (nor response headers)
|
44
63
|
def chunkable_version?(ver)
|
45
64
|
case ver
|
46
|
-
when
|
65
|
+
when 'HTTP/1.0', nil, 'HTTP/0.9'
|
47
66
|
false
|
48
67
|
else
|
49
68
|
true
|
@@ -54,15 +73,19 @@ module Rack
|
|
54
73
|
status, headers, body = @app.call(env)
|
55
74
|
headers = HeaderHash.new(headers)
|
56
75
|
|
57
|
-
if ! chunkable_version?(env[
|
58
|
-
STATUS_WITH_NO_ENTITY_BODY.
|
76
|
+
if ! chunkable_version?(env[SERVER_PROTOCOL]) ||
|
77
|
+
STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) ||
|
59
78
|
headers[CONTENT_LENGTH] ||
|
60
79
|
headers[TRANSFER_ENCODING]
|
61
80
|
[status, headers, body]
|
62
81
|
else
|
63
82
|
headers.delete(CONTENT_LENGTH)
|
64
83
|
headers[TRANSFER_ENCODING] = 'chunked'
|
65
|
-
|
84
|
+
if headers['Trailer']
|
85
|
+
[status, headers, TrailerBody.new(body)]
|
86
|
+
else
|
87
|
+
[status, headers, Body.new(body)]
|
88
|
+
end
|
66
89
|
end
|
67
90
|
end
|
68
91
|
end
|
data/lib/rack/common_logger.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/body_proxy'
|
2
4
|
|
3
5
|
module Rack
|
@@ -23,13 +25,13 @@ module Rack
|
|
23
25
|
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
24
26
|
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
|
25
27
|
|
26
|
-
def initialize(app, logger=nil)
|
28
|
+
def initialize(app, logger = nil)
|
27
29
|
@app = app
|
28
30
|
@logger = logger
|
29
31
|
end
|
30
32
|
|
31
33
|
def call(env)
|
32
|
-
began_at =
|
34
|
+
began_at = Utils.clock_time
|
33
35
|
status, header, body = @app.call(env)
|
34
36
|
header = Utils::HeaderHash.new(header)
|
35
37
|
body = BodyProxy.new(body) { log(env, status, header, began_at) }
|
@@ -39,20 +41,19 @@ module Rack
|
|
39
41
|
private
|
40
42
|
|
41
43
|
def log(env, status, header, began_at)
|
42
|
-
now = Time.now
|
43
44
|
length = extract_content_length(header)
|
44
45
|
|
45
46
|
msg = FORMAT % [
|
46
47
|
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
47
48
|
env["REMOTE_USER"] || "-",
|
48
|
-
now.strftime("%d/%b/%Y:%H:%M:%S %z"),
|
49
|
+
Time.now.strftime("%d/%b/%Y:%H:%M:%S %z"),
|
49
50
|
env[REQUEST_METHOD],
|
50
51
|
env[PATH_INFO],
|
51
52
|
env[QUERY_STRING].empty? ? "" : "?#{env[QUERY_STRING]}",
|
52
|
-
env[
|
53
|
+
env[SERVER_PROTOCOL],
|
53
54
|
status.to_s[0..3],
|
54
55
|
length,
|
55
|
-
|
56
|
+
Utils.clock_time - began_at ]
|
56
57
|
|
57
58
|
logger = @logger || env[RACK_ERRORS]
|
58
59
|
# Standard library logger doesn't support write but it supports << which actually
|
@@ -65,8 +66,8 @@ module Rack
|
|
65
66
|
end
|
66
67
|
|
67
68
|
def extract_content_length(headers)
|
68
|
-
value = headers[CONTENT_LENGTH]
|
69
|
-
value.to_s == '0' ? '-' : value
|
69
|
+
value = headers[CONTENT_LENGTH]
|
70
|
+
!value || value.to_s == '0' ? '-' : value
|
70
71
|
end
|
71
72
|
end
|
72
73
|
end
|
data/lib/rack/conditional_get.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
|
3
5
|
module Rack
|
@@ -68,7 +70,7 @@ module Rack
|
|
68
70
|
# anything shorter is invalid, this avoids exceptions for common cases
|
69
71
|
# most common being the empty string
|
70
72
|
if since && since.length >= 16
|
71
|
-
# NOTE: there is no trivial way to write this in a non
|
73
|
+
# NOTE: there is no trivial way to write this in a non exception way
|
72
74
|
# _rfc2822 returns a hash but is not that usable
|
73
75
|
Time.rfc2822(since) rescue nil
|
74
76
|
else
|
data/lib/rack/config.rb
CHANGED
data/lib/rack/content_length.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
require 'rack/body_proxy'
|
3
5
|
|
@@ -15,7 +17,7 @@ module Rack
|
|
15
17
|
status, headers, body = @app.call(env)
|
16
18
|
headers = HeaderHash.new(headers)
|
17
19
|
|
18
|
-
if !STATUS_WITH_NO_ENTITY_BODY.
|
20
|
+
if !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
|
19
21
|
!headers[CONTENT_LENGTH] &&
|
20
22
|
!headers[TRANSFER_ENCODING] &&
|
21
23
|
body.respond_to?(:to_ary)
|
data/lib/rack/content_type.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rack/utils'
|
2
4
|
|
3
5
|
module Rack
|
@@ -19,7 +21,7 @@ module Rack
|
|
19
21
|
status, headers, body = @app.call(env)
|
20
22
|
headers = Utils::HeaderHash.new(headers)
|
21
23
|
|
22
|
-
unless STATUS_WITH_NO_ENTITY_BODY.
|
24
|
+
unless STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i)
|
23
25
|
headers[CONTENT_TYPE] ||= @content_type
|
24
26
|
end
|
25
27
|
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Regexp has `match?` since Ruby 2.4
|
4
|
+
# so to support Ruby < 2.4 we need to define this method
|
5
|
+
|
6
|
+
module Rack
|
7
|
+
module RegexpExtensions
|
8
|
+
refine Regexp do
|
9
|
+
def match?(string, pos = 0)
|
10
|
+
!!match(string, pos)
|
11
|
+
end
|
12
|
+
end unless //.respond_to?(:match?)
|
13
|
+
end
|
14
|
+
end
|
data/lib/rack/deflater.rb
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require "zlib"
|
2
4
|
require "time" # for Time.httpdate
|
3
5
|
require 'rack/utils'
|
4
6
|
|
7
|
+
require_relative 'core_ext/regexp'
|
8
|
+
|
5
9
|
module Rack
|
6
10
|
# This middleware enables compression of http responses.
|
7
11
|
#
|
@@ -15,19 +19,26 @@ module Rack
|
|
15
19
|
# directive of 'no-transform' is present, or when the response status
|
16
20
|
# code is one that doesn't allow an entity body.
|
17
21
|
class Deflater
|
22
|
+
using ::Rack::RegexpExtensions
|
23
|
+
|
18
24
|
##
|
19
25
|
# Creates Rack::Deflater middleware.
|
20
26
|
#
|
21
27
|
# [app] rack app instance
|
22
28
|
# [options] hash of deflater options, i.e.
|
23
29
|
# 'if' - a lambda enabling / disabling deflation based on returned boolean value
|
24
|
-
# e.g use Rack::Deflater, :if => lambda { |
|
30
|
+
# e.g use Rack::Deflater, :if => lambda { |*, body| sum=0; body.each { |i| sum += i.length }; sum > 512 }
|
25
31
|
# 'include' - a list of content types that should be compressed
|
32
|
+
# 'sync' - determines if the stream is going to be flushed after every chunk.
|
33
|
+
# Flushing after every chunk reduces latency for
|
34
|
+
# time-sensitive streaming applications, but hurts
|
35
|
+
# compression and throughput. Defaults to `true'.
|
26
36
|
def initialize(app, options = {})
|
27
37
|
@app = app
|
28
38
|
|
29
39
|
@condition = options[:if]
|
30
40
|
@compressible_types = options[:include]
|
41
|
+
@sync = options[:sync] == false ? false : true
|
31
42
|
end
|
32
43
|
|
33
44
|
def call(env)
|
@@ -52,33 +63,34 @@ module Rack
|
|
52
63
|
case encoding
|
53
64
|
when "gzip"
|
54
65
|
headers['Content-Encoding'] = "gzip"
|
55
|
-
headers.delete(
|
56
|
-
mtime = headers
|
57
|
-
|
58
|
-
[status, headers, GzipStream.new(body, mtime)]
|
66
|
+
headers.delete('Content-Length')
|
67
|
+
mtime = headers["Last-Modified"]
|
68
|
+
mtime = Time.httpdate(mtime).to_i if mtime
|
69
|
+
[status, headers, GzipStream.new(body, mtime, @sync)]
|
59
70
|
when "identity"
|
60
71
|
[status, headers, body]
|
61
72
|
when nil
|
62
73
|
message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
|
63
74
|
bp = Rack::BodyProxy.new([message]) { body.close if body.respond_to?(:close) }
|
64
|
-
[406, {
|
75
|
+
[406, { 'Content-Type' => "text/plain", 'Content-Length' => message.length.to_s }, bp]
|
65
76
|
end
|
66
77
|
end
|
67
78
|
|
68
79
|
class GzipStream
|
69
|
-
def initialize(body, mtime)
|
80
|
+
def initialize(body, mtime, sync)
|
81
|
+
@sync = sync
|
70
82
|
@body = body
|
71
83
|
@mtime = mtime
|
72
|
-
@closed = false
|
73
84
|
end
|
74
85
|
|
75
86
|
def each(&block)
|
76
87
|
@writer = block
|
77
|
-
gzip
|
78
|
-
gzip.mtime = @mtime
|
88
|
+
gzip = ::Zlib::GzipWriter.new(self)
|
89
|
+
gzip.mtime = @mtime if @mtime
|
79
90
|
@body.each { |part|
|
80
|
-
gzip.write(part)
|
81
|
-
|
91
|
+
len = gzip.write(part)
|
92
|
+
# Flushing empty parts would raise Zlib::BufError.
|
93
|
+
gzip.flush if @sync && len > 0
|
82
94
|
}
|
83
95
|
ensure
|
84
96
|
gzip.close
|
@@ -90,9 +102,8 @@ module Rack
|
|
90
102
|
end
|
91
103
|
|
92
104
|
def close
|
93
|
-
return if @closed
|
94
|
-
@closed = true
|
95
105
|
@body.close if @body.respond_to?(:close)
|
106
|
+
@body = nil
|
96
107
|
end
|
97
108
|
end
|
98
109
|
|
@@ -101,18 +112,22 @@ module Rack
|
|
101
112
|
def should_deflate?(env, status, headers, body)
|
102
113
|
# Skip compressing empty entity body responses and responses with
|
103
114
|
# no-transform set.
|
104
|
-
if Utils::STATUS_WITH_NO_ENTITY_BODY.
|
105
|
-
|
115
|
+
if Utils::STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) ||
|
116
|
+
/\bno-transform\b/.match?(headers['Cache-Control'].to_s) ||
|
106
117
|
(headers['Content-Encoding'] && headers['Content-Encoding'] !~ /\bidentity\b/)
|
107
118
|
return false
|
108
119
|
end
|
109
120
|
|
110
121
|
# Skip if @compressible_types are given and does not include request's content type
|
111
|
-
return false if @compressible_types && !(headers.has_key?(
|
122
|
+
return false if @compressible_types && !(headers.has_key?('Content-Type') && @compressible_types.include?(headers['Content-Type'][/[^;]*/]))
|
112
123
|
|
113
124
|
# Skip if @condition lambda is given and evaluates to false
|
114
125
|
return false if @condition && !@condition.call(env, status, headers, body)
|
115
126
|
|
127
|
+
# No point in compressing empty body, also handles usage with
|
128
|
+
# Rack::Sendfile.
|
129
|
+
return false if headers[CONTENT_LENGTH] == '0'
|
130
|
+
|
116
131
|
true
|
117
132
|
end
|
118
133
|
end
|
data/lib/rack/directory.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'time'
|
2
4
|
require 'rack/utils'
|
3
5
|
require 'rack/mime'
|
6
|
+
require 'rack/files'
|
4
7
|
|
5
8
|
module Rack
|
6
9
|
# Rack::Directory serves entries below the +root+ given, according to the
|
@@ -8,7 +11,7 @@ module Rack
|
|
8
11
|
# will be presented in an html based index. If a file is found, the env will
|
9
12
|
# be passed to the specified +app+.
|
10
13
|
#
|
11
|
-
# If +app+ is not specified, a Rack::
|
14
|
+
# If +app+ is not specified, a Rack::Files of the same +root+ will be used.
|
12
15
|
|
13
16
|
class Directory
|
14
17
|
DIR_FILE = "<tr><td class='name'><a href='%s'>%s</a></td><td class='size'>%s</td><td class='type'>%s</td><td class='mtime'>%s</td></tr>"
|
@@ -41,9 +44,9 @@ table { width:100%%; }
|
|
41
44
|
|
42
45
|
class DirectoryBody < Struct.new(:root, :path, :files)
|
43
46
|
def each
|
44
|
-
show_path = Rack::Utils.escape_html(path.sub(/^#{root}/,''))
|
45
|
-
listings = files.map{|f| DIR_FILE % DIR_FILE_escape(*f) }*"\n"
|
46
|
-
page
|
47
|
+
show_path = Rack::Utils.escape_html(path.sub(/^#{root}/, ''))
|
48
|
+
listings = files.map{|f| DIR_FILE % DIR_FILE_escape(*f) } * "\n"
|
49
|
+
page = DIR_PAGE % [ show_path, show_path, listings ]
|
47
50
|
page.each_line{|l| yield l }
|
48
51
|
end
|
49
52
|
|
@@ -56,9 +59,9 @@ table { width:100%%; }
|
|
56
59
|
|
57
60
|
attr_reader :root, :path
|
58
61
|
|
59
|
-
def initialize(root, app=nil)
|
62
|
+
def initialize(root, app = nil)
|
60
63
|
@root = ::File.expand_path(root)
|
61
|
-
@app = app || Rack::
|
64
|
+
@app = app || Rack::Files.new(@root)
|
62
65
|
@head = Rack::Head.new(lambda { |env| get env })
|
63
66
|
end
|
64
67
|
|
@@ -86,9 +89,9 @@ table { width:100%%; }
|
|
86
89
|
|
87
90
|
body = "Bad Request\n"
|
88
91
|
size = body.bytesize
|
89
|
-
return [400, {CONTENT_TYPE => "text/plain",
|
92
|
+
return [400, { CONTENT_TYPE => "text/plain",
|
90
93
|
CONTENT_LENGTH => size.to_s,
|
91
|
-
"X-Cascade" => "pass"}, [body]]
|
94
|
+
"X-Cascade" => "pass" }, [body]]
|
92
95
|
end
|
93
96
|
|
94
97
|
def check_forbidden(path_info)
|
@@ -96,20 +99,20 @@ table { width:100%%; }
|
|
96
99
|
|
97
100
|
body = "Forbidden\n"
|
98
101
|
size = body.bytesize
|
99
|
-
return [403, {CONTENT_TYPE => "text/plain",
|
102
|
+
return [403, { CONTENT_TYPE => "text/plain",
|
100
103
|
CONTENT_LENGTH => size.to_s,
|
101
|
-
"X-Cascade" => "pass"}, [body]]
|
104
|
+
"X-Cascade" => "pass" }, [body]]
|
102
105
|
end
|
103
106
|
|
104
107
|
def list_directory(path_info, path, script_name)
|
105
|
-
files = [['../','Parent Directory','','','']]
|
106
|
-
glob = ::File.join(path, '*')
|
108
|
+
files = [['../', 'Parent Directory', '', '', '']]
|
107
109
|
|
108
110
|
url_head = (script_name.split('/') + path_info.split('/')).map do |part|
|
109
111
|
Rack::Utils.escape_path part
|
110
112
|
end
|
111
113
|
|
112
|
-
Dir
|
114
|
+
Dir.entries(path).reject { |e| e.start_with?('.') }.sort.each do |node|
|
115
|
+
node = ::File.join path, node
|
113
116
|
stat = stat(node)
|
114
117
|
next unless stat
|
115
118
|
basename = ::File.basename(node)
|
@@ -126,7 +129,7 @@ table { width:100%%; }
|
|
126
129
|
files << [ url, basename, size, type, mtime ]
|
127
130
|
end
|
128
131
|
|
129
|
-
return [ 200, { CONTENT_TYPE =>'text/html; charset=utf-8'}, DirectoryBody.new(@root, path, files) ]
|
132
|
+
return [ 200, { CONTENT_TYPE => 'text/html; charset=utf-8' }, DirectoryBody.new(@root, path, files) ]
|
130
133
|
end
|
131
134
|
|
132
135
|
def stat(node)
|
@@ -154,9 +157,9 @@ table { width:100%%; }
|
|
154
157
|
def entity_not_found(path_info)
|
155
158
|
body = "Entity not found: #{path_info}\n"
|
156
159
|
size = body.bytesize
|
157
|
-
return [404, {CONTENT_TYPE => "text/plain",
|
160
|
+
return [404, { CONTENT_TYPE => "text/plain",
|
158
161
|
CONTENT_LENGTH => size.to_s,
|
159
|
-
"X-Cascade" => "pass"}, [body]]
|
162
|
+
"X-Cascade" => "pass" }, [body]]
|
160
163
|
end
|
161
164
|
|
162
165
|
# Stolen from Ramaze
|