rack 1.0.1 → 1.1.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.
- data/COPYING +1 -1
- data/KNOWN-ISSUES +3 -0
- data/RDOX +0 -428
- data/README +61 -26
- data/SPEC +8 -1
- data/bin/rackup +2 -174
- data/lib/rack.rb +10 -8
- data/lib/rack/builder.rb +17 -0
- data/lib/rack/cascade.rb +17 -12
- data/lib/rack/chunked.rb +2 -2
- data/lib/rack/commonlogger.rb +31 -43
- data/lib/rack/config.rb +15 -0
- data/lib/rack/content_type.rb +1 -1
- data/lib/rack/directory.rb +6 -2
- data/lib/rack/etag.rb +23 -0
- data/lib/rack/file.rb +4 -2
- data/lib/rack/handler.rb +19 -0
- data/lib/rack/handler/cgi.rb +1 -1
- data/lib/rack/handler/fastcgi.rb +2 -3
- data/lib/rack/handler/lsws.rb +4 -1
- data/lib/rack/handler/mongrel.rb +8 -5
- data/lib/rack/handler/scgi.rb +4 -4
- data/lib/rack/handler/webrick.rb +2 -4
- data/lib/rack/lint.rb +44 -15
- data/lib/rack/logger.rb +20 -0
- data/lib/rack/mime.rb +3 -1
- data/lib/rack/mock.rb +30 -4
- data/lib/rack/nulllogger.rb +18 -0
- data/lib/rack/reloader.rb +4 -1
- data/lib/rack/request.rb +40 -15
- data/lib/rack/response.rb +5 -39
- data/lib/rack/runtime.rb +27 -0
- data/lib/rack/sendfile.rb +142 -0
- data/lib/rack/server.rb +212 -0
- data/lib/rack/session/abstract/id.rb +3 -5
- data/lib/rack/session/cookie.rb +3 -4
- data/lib/rack/session/memcache.rb +53 -43
- data/lib/rack/session/pool.rb +1 -1
- data/lib/rack/urlmap.rb +9 -8
- data/lib/rack/utils.rb +230 -11
- data/rack.gemspec +33 -49
- data/test/spec_rack_cascade.rb +3 -5
- data/test/spec_rack_cgi.rb +3 -3
- data/test/spec_rack_commonlogger.rb +39 -10
- data/test/spec_rack_config.rb +24 -0
- data/test/spec_rack_directory.rb +1 -1
- data/test/spec_rack_etag.rb +17 -0
- data/test/spec_rack_fastcgi.rb +2 -2
- data/test/spec_rack_file.rb +1 -1
- data/test/spec_rack_lint.rb +26 -19
- data/test/spec_rack_logger.rb +21 -0
- data/test/spec_rack_mock.rb +87 -1
- data/test/spec_rack_mongrel.rb +4 -4
- data/test/spec_rack_nulllogger.rb +13 -0
- data/test/spec_rack_request.rb +47 -6
- data/test/spec_rack_response.rb +3 -0
- data/test/spec_rack_runtime.rb +35 -0
- data/test/spec_rack_sendfile.rb +86 -0
- data/test/spec_rack_session_cookie.rb +1 -10
- data/test/spec_rack_session_memcache.rb +53 -20
- data/test/spec_rack_urlmap.rb +30 -0
- data/test/spec_rack_utils.rb +171 -6
- data/test/spec_rack_webrick.rb +4 -4
- data/test/spec_rackup.rb +154 -0
- metadata +37 -79
- data/Rakefile +0 -164
- data/lib/rack/auth/openid.rb +0 -480
- data/test/cgi/lighttpd.conf +0 -20
- data/test/cgi/test +0 -9
- data/test/cgi/test.fcgi +0 -8
- data/test/cgi/test.ru +0 -7
- data/test/multipart/binary +0 -0
- data/test/multipart/empty +0 -10
- data/test/multipart/ie +0 -6
- data/test/multipart/nested +0 -10
- data/test/multipart/none +0 -9
- data/test/multipart/semicolon +0 -6
- data/test/multipart/text +0 -10
- data/test/spec_rack_auth_openid.rb +0 -84
- data/test/testrequest.rb +0 -57
- data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
- data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
data/SPEC
CHANGED
@@ -52,7 +52,7 @@ below.
|
|
52
52
|
request.
|
53
53
|
In addition to this, the Rack environment must include these
|
54
54
|
Rack-specific variables:
|
55
|
-
<tt>rack.version</tt>:: The Array [1,
|
55
|
+
<tt>rack.version</tt>:: The Array [1,1], representing this version of Rack.
|
56
56
|
<tt>rack.url_scheme</tt>:: +http+ or +https+, depending on the request URL.
|
57
57
|
<tt>rack.input</tt>:: See below, the input stream.
|
58
58
|
<tt>rack.errors</tt>:: See below, the error stream.
|
@@ -68,6 +68,13 @@ be implemented by the server.
|
|
68
68
|
fetch(key, default = nil) (aliased as []);
|
69
69
|
delete(key);
|
70
70
|
clear;
|
71
|
+
<tt>rack.logger</tt>:: A common object interface for logging messages.
|
72
|
+
The object must implement:
|
73
|
+
info(message, &block)
|
74
|
+
debug(message, &block)
|
75
|
+
warn(message, &block)
|
76
|
+
error(message, &block)
|
77
|
+
fatal(message, &block)
|
71
78
|
The server or the application can store their own data in the
|
72
79
|
environment, too. The keys must contain at least one dot,
|
73
80
|
and should be prefixed uniquely. The prefix <tt>rack.</tt>
|
data/bin/rackup
CHANGED
@@ -1,176 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
# -*- ruby -*-
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
require 'optparse'
|
8
|
-
|
9
|
-
automatic = false
|
10
|
-
server = nil
|
11
|
-
env = "development"
|
12
|
-
daemonize = false
|
13
|
-
pid = nil
|
14
|
-
options = {:Port => 9292, :Host => "0.0.0.0", :AccessLog => []}
|
15
|
-
|
16
|
-
# Don't evaluate CGI ISINDEX parameters.
|
17
|
-
# http://hoohoo.ncsa.uiuc.edu/cgi/cl.html
|
18
|
-
ARGV.clear if ENV.include?("REQUEST_METHOD")
|
19
|
-
|
20
|
-
opts = OptionParser.new("", 24, ' ') { |opts|
|
21
|
-
opts.banner = "Usage: rackup [ruby options] [rack options] [rackup config]"
|
22
|
-
|
23
|
-
opts.separator ""
|
24
|
-
opts.separator "Ruby options:"
|
25
|
-
|
26
|
-
lineno = 1
|
27
|
-
opts.on("-e", "--eval LINE", "evaluate a LINE of code") { |line|
|
28
|
-
eval line, TOPLEVEL_BINDING, "-e", lineno
|
29
|
-
lineno += 1
|
30
|
-
}
|
31
|
-
|
32
|
-
opts.on("-d", "--debug", "set debugging flags (set $DEBUG to true)") {
|
33
|
-
$DEBUG = true
|
34
|
-
}
|
35
|
-
opts.on("-w", "--warn", "turn warnings on for your script") {
|
36
|
-
$-w = true
|
37
|
-
}
|
38
|
-
|
39
|
-
opts.on("-I", "--include PATH",
|
40
|
-
"specify $LOAD_PATH (may be used more than once)") { |path|
|
41
|
-
$LOAD_PATH.unshift(*path.split(":"))
|
42
|
-
}
|
43
|
-
|
44
|
-
opts.on("-r", "--require LIBRARY",
|
45
|
-
"require the library, before executing your script") { |library|
|
46
|
-
require library
|
47
|
-
}
|
48
|
-
|
49
|
-
opts.separator ""
|
50
|
-
opts.separator "Rack options:"
|
51
|
-
opts.on("-s", "--server SERVER", "serve using SERVER (webrick/mongrel)") { |s|
|
52
|
-
server = s
|
53
|
-
}
|
54
|
-
|
55
|
-
opts.on("-o", "--host HOST", "listen on HOST (default: 0.0.0.0)") { |host|
|
56
|
-
options[:Host] = host
|
57
|
-
}
|
58
|
-
|
59
|
-
opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port|
|
60
|
-
options[:Port] = port
|
61
|
-
}
|
62
|
-
|
63
|
-
opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e|
|
64
|
-
env = e
|
65
|
-
}
|
66
|
-
|
67
|
-
opts.on("-D", "--daemonize", "run daemonized in the background") { |d|
|
68
|
-
daemonize = d ? true : false
|
69
|
-
}
|
70
|
-
|
71
|
-
opts.on("-P", "--pid FILE", "file to store PID (default: rack.pid)") { |f|
|
72
|
-
pid = File.expand_path(f)
|
73
|
-
}
|
74
|
-
|
75
|
-
opts.separator ""
|
76
|
-
opts.separator "Common options:"
|
77
|
-
|
78
|
-
opts.on_tail("-h", "--help", "Show this message") do
|
79
|
-
puts opts
|
80
|
-
exit
|
81
|
-
end
|
82
|
-
|
83
|
-
opts.on_tail("--version", "Show version") do
|
84
|
-
puts "Rack #{Rack.version}"
|
85
|
-
exit
|
86
|
-
end
|
87
|
-
|
88
|
-
opts.parse! ARGV
|
89
|
-
}
|
90
|
-
|
91
|
-
require 'pp' if $DEBUG
|
92
|
-
|
93
|
-
config = ARGV[0] || "config.ru"
|
94
|
-
if !File.exist? config
|
95
|
-
abort "configuration #{config} not found"
|
96
|
-
end
|
97
|
-
|
98
|
-
if config =~ /\.ru$/
|
99
|
-
cfgfile = File.read(config)
|
100
|
-
if cfgfile[/^#\\(.*)/]
|
101
|
-
opts.parse! $1.split(/\s+/)
|
102
|
-
end
|
103
|
-
inner_app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
|
104
|
-
nil, config
|
105
|
-
else
|
106
|
-
require config
|
107
|
-
inner_app = Object.const_get(File.basename(config, '.rb').capitalize)
|
108
|
-
end
|
109
|
-
|
110
|
-
unless server = Rack::Handler.get(server)
|
111
|
-
# Guess.
|
112
|
-
if ENV.include?("PHP_FCGI_CHILDREN")
|
113
|
-
server = Rack::Handler::FastCGI
|
114
|
-
|
115
|
-
# We already speak FastCGI
|
116
|
-
options.delete :File
|
117
|
-
options.delete :Port
|
118
|
-
elsif ENV.include?("REQUEST_METHOD")
|
119
|
-
server = Rack::Handler::CGI
|
120
|
-
else
|
121
|
-
begin
|
122
|
-
server = Rack::Handler::Mongrel
|
123
|
-
rescue LoadError => e
|
124
|
-
server = Rack::Handler::WEBrick
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
p server if $DEBUG
|
130
|
-
|
131
|
-
case env
|
132
|
-
when "development"
|
133
|
-
app = Rack::Builder.new {
|
134
|
-
use Rack::CommonLogger, $stderr unless server.name =~ /CGI/
|
135
|
-
use Rack::ShowExceptions
|
136
|
-
use Rack::Lint
|
137
|
-
run inner_app
|
138
|
-
}.to_app
|
139
|
-
|
140
|
-
when "deployment"
|
141
|
-
app = Rack::Builder.new {
|
142
|
-
use Rack::CommonLogger, $stderr unless server.name =~ /CGI/
|
143
|
-
run inner_app
|
144
|
-
}.to_app
|
145
|
-
|
146
|
-
when "none"
|
147
|
-
app = inner_app
|
148
|
-
|
149
|
-
end
|
150
|
-
|
151
|
-
if $DEBUG
|
152
|
-
pp app
|
153
|
-
pp inner_app
|
154
|
-
end
|
155
|
-
|
156
|
-
if daemonize
|
157
|
-
if RUBY_VERSION < "1.9"
|
158
|
-
exit if fork
|
159
|
-
Process.setsid
|
160
|
-
exit if fork
|
161
|
-
Dir.chdir "/"
|
162
|
-
File.umask 0000
|
163
|
-
STDIN.reopen "/dev/null"
|
164
|
-
STDOUT.reopen "/dev/null", "a"
|
165
|
-
STDERR.reopen "/dev/null", "a"
|
166
|
-
else
|
167
|
-
Process.daemon
|
168
|
-
end
|
169
|
-
|
170
|
-
if pid
|
171
|
-
File.open(pid, 'w'){ |f| f.write("#{Process.pid}") }
|
172
|
-
at_exit { File.delete(pid) if File.exist?(pid) }
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
server.run app, options
|
3
|
+
require "rack"
|
4
|
+
Rack::Server.start
|
data/lib/rack.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
|
-
# Copyright (C) 2007, 2008, 2009 Christian Neukirchen <purl.org/net/chneukirchen>
|
1
|
+
# Copyright (C) 2007, 2008, 2009, 2010 Christian Neukirchen <purl.org/net/chneukirchen>
|
2
2
|
#
|
3
3
|
# Rack is freely distributable under the terms of an MIT-style license.
|
4
4
|
# See COPYING or http://www.opensource.org/licenses/mit-license.php.
|
5
5
|
|
6
|
-
path = File.expand_path(File.dirname(__FILE__))
|
7
|
-
$:.unshift(path) unless $:.include?(path)
|
8
|
-
|
9
|
-
|
10
6
|
# The Rack main module, serving as a namespace for all core Rack
|
11
7
|
# modules and classes.
|
12
8
|
#
|
@@ -15,7 +11,7 @@ $:.unshift(path) unless $:.include?(path)
|
|
15
11
|
|
16
12
|
module Rack
|
17
13
|
# The Rack protocol version number implemented.
|
18
|
-
VERSION = [1,
|
14
|
+
VERSION = [1,1]
|
19
15
|
|
20
16
|
# Return the Rack protocol version as a dotted string.
|
21
17
|
def self.version
|
@@ -24,7 +20,7 @@ module Rack
|
|
24
20
|
|
25
21
|
# Return the Rack release as a dotted string.
|
26
22
|
def self.release
|
27
|
-
"1.
|
23
|
+
"1.1"
|
28
24
|
end
|
29
25
|
|
30
26
|
autoload :Builder, "rack/builder"
|
@@ -32,8 +28,10 @@ module Rack
|
|
32
28
|
autoload :Chunked, "rack/chunked"
|
33
29
|
autoload :CommonLogger, "rack/commonlogger"
|
34
30
|
autoload :ConditionalGet, "rack/conditionalget"
|
31
|
+
autoload :Config, "rack/config"
|
35
32
|
autoload :ContentLength, "rack/content_length"
|
36
33
|
autoload :ContentType, "rack/content_type"
|
34
|
+
autoload :ETag, "rack/etag"
|
37
35
|
autoload :File, "rack/file"
|
38
36
|
autoload :Deflater, "rack/deflater"
|
39
37
|
autoload :Directory, "rack/directory"
|
@@ -42,10 +40,15 @@ module Rack
|
|
42
40
|
autoload :Head, "rack/head"
|
43
41
|
autoload :Lint, "rack/lint"
|
44
42
|
autoload :Lock, "rack/lock"
|
43
|
+
autoload :Logger, "rack/logger"
|
45
44
|
autoload :MethodOverride, "rack/methodoverride"
|
46
45
|
autoload :Mime, "rack/mime"
|
46
|
+
autoload :NullLogger, "rack/nulllogger"
|
47
47
|
autoload :Recursive, "rack/recursive"
|
48
48
|
autoload :Reloader, "rack/reloader"
|
49
|
+
autoload :Runtime, "rack/runtime"
|
50
|
+
autoload :Sendfile, "rack/sendfile"
|
51
|
+
autoload :Server, "rack/server"
|
49
52
|
autoload :ShowExceptions, "rack/showexceptions"
|
50
53
|
autoload :ShowStatus, "rack/showstatus"
|
51
54
|
autoload :Static, "rack/static"
|
@@ -62,7 +65,6 @@ module Rack
|
|
62
65
|
autoload :Basic, "rack/auth/basic"
|
63
66
|
autoload :AbstractRequest, "rack/auth/abstract/request"
|
64
67
|
autoload :AbstractHandler, "rack/auth/abstract/handler"
|
65
|
-
autoload :OpenID, "rack/auth/openid"
|
66
68
|
module Digest
|
67
69
|
autoload :MD5, "rack/auth/digest/md5"
|
68
70
|
autoload :Nonce, "rack/auth/digest/nonce"
|
data/lib/rack/builder.rb
CHANGED
@@ -24,6 +24,23 @@ module Rack
|
|
24
24
|
# You can use +map+ to construct a Rack::URLMap in a convenient way.
|
25
25
|
|
26
26
|
class Builder
|
27
|
+
def self.parse_file(config, opts = Server::Options.new)
|
28
|
+
options = {}
|
29
|
+
if config =~ /\.ru$/
|
30
|
+
cfgfile = ::File.read(config)
|
31
|
+
if cfgfile[/^#\\(.*)/] && opts
|
32
|
+
options = opts.parse! $1.split(/\s+/)
|
33
|
+
end
|
34
|
+
cfgfile.sub!(/^__END__\n.*/, '')
|
35
|
+
app = eval "Rack::Builder.new {( " + cfgfile + "\n )}.to_app",
|
36
|
+
TOPLEVEL_BINDING, config
|
37
|
+
else
|
38
|
+
require config
|
39
|
+
app = Object.const_get(::File.basename(config, '.rb').capitalize)
|
40
|
+
end
|
41
|
+
return app, options
|
42
|
+
end
|
43
|
+
|
27
44
|
def initialize(&block)
|
28
45
|
@ins = []
|
29
46
|
instance_eval(&block) if block_given?
|
data/lib/rack/cascade.rb
CHANGED
@@ -4,31 +4,36 @@ module Rack
|
|
4
4
|
# status codes).
|
5
5
|
|
6
6
|
class Cascade
|
7
|
+
NotFound = [404, {}, []]
|
8
|
+
|
7
9
|
attr_reader :apps
|
8
10
|
|
9
11
|
def initialize(apps, catch=404)
|
10
|
-
@apps =
|
11
|
-
|
12
|
+
@apps = []; @has_app = {}
|
13
|
+
apps.each { |app| add app }
|
14
|
+
|
15
|
+
@catch = {}
|
16
|
+
[*catch].each { |status| @catch[status] = true }
|
12
17
|
end
|
13
18
|
|
14
19
|
def call(env)
|
15
|
-
|
16
|
-
|
17
|
-
@apps.each
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
[status, headers, body]
|
20
|
+
result = NotFound
|
21
|
+
|
22
|
+
@apps.each do |app|
|
23
|
+
result = app.call(env)
|
24
|
+
break unless @catch.include?(result[0].to_i)
|
25
|
+
end
|
26
|
+
|
27
|
+
result
|
24
28
|
end
|
25
29
|
|
26
30
|
def add app
|
31
|
+
@has_app[app] = true
|
27
32
|
@apps << app
|
28
33
|
end
|
29
34
|
|
30
35
|
def include? app
|
31
|
-
@
|
36
|
+
@has_app.include? app
|
32
37
|
end
|
33
38
|
|
34
39
|
alias_method :<<, :add
|
data/lib/rack/chunked.rb
CHANGED
@@ -19,7 +19,7 @@ module Rack
|
|
19
19
|
STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
|
20
20
|
headers['Content-Length'] ||
|
21
21
|
headers['Transfer-Encoding']
|
22
|
-
[status, headers
|
22
|
+
[status, headers, body]
|
23
23
|
else
|
24
24
|
dup.chunk(status, headers, body)
|
25
25
|
end
|
@@ -29,7 +29,7 @@ module Rack
|
|
29
29
|
@body = body
|
30
30
|
headers.delete('Content-Length')
|
31
31
|
headers['Transfer-Encoding'] = 'chunked'
|
32
|
-
[status, headers
|
32
|
+
[status, headers, self]
|
33
33
|
end
|
34
34
|
|
35
35
|
def each
|
data/lib/rack/commonlogger.rb
CHANGED
@@ -2,60 +2,48 @@ module Rack
|
|
2
2
|
# Rack::CommonLogger forwards every request to an +app+ given, and
|
3
3
|
# logs a line in the Apache common log format to the +logger+, or
|
4
4
|
# rack.errors by default.
|
5
|
-
|
6
5
|
class CommonLogger
|
6
|
+
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
7
|
+
# lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
|
8
|
+
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
9
|
+
FORMAT = %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n}
|
10
|
+
|
7
11
|
def initialize(app, logger=nil)
|
8
12
|
@app = app
|
9
13
|
@logger = logger
|
10
14
|
end
|
11
15
|
|
12
16
|
def call(env)
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
@logger ||= self
|
19
|
-
@time = Time.now
|
20
|
-
@status, @header, @body = @app.call(env)
|
21
|
-
[@status, @header, self]
|
17
|
+
began_at = Time.now
|
18
|
+
status, header, body = @app.call(env)
|
19
|
+
header = Utils::HeaderHash.new(header)
|
20
|
+
log(env, status, header, began_at)
|
21
|
+
[status, header, body]
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
private
|
25
|
+
|
26
|
+
def log(env, status, header, began_at)
|
27
|
+
now = Time.now
|
28
|
+
length = extract_content_length(header)
|
29
|
+
|
30
|
+
logger = @logger || env['rack.errors']
|
31
|
+
logger.write FORMAT % [
|
32
|
+
env['HTTP_X_FORWARDED_FOR'] || env["REMOTE_ADDR"] || "-",
|
33
|
+
env["REMOTE_USER"] || "-",
|
34
|
+
now.strftime("%d/%b/%Y %H:%M:%S"),
|
35
|
+
env["REQUEST_METHOD"],
|
36
|
+
env["PATH_INFO"],
|
37
|
+
env["QUERY_STRING"].empty? ? "" : "?"+env["QUERY_STRING"],
|
38
|
+
env["HTTP_VERSION"],
|
39
|
+
status.to_s[0..3],
|
40
|
+
length,
|
41
|
+
now - began_at ]
|
26
42
|
end
|
27
43
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
@env["rack.errors"].flush
|
32
|
-
end
|
33
|
-
|
34
|
-
def each
|
35
|
-
length = 0
|
36
|
-
@body.each { |part|
|
37
|
-
length += part.size
|
38
|
-
yield part
|
39
|
-
}
|
40
|
-
|
41
|
-
@now = Time.now
|
42
|
-
|
43
|
-
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
44
|
-
# lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
|
45
|
-
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
46
|
-
@logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} %
|
47
|
-
[
|
48
|
-
@env['HTTP_X_FORWARDED_FOR'] || @env["REMOTE_ADDR"] || "-",
|
49
|
-
@env["REMOTE_USER"] || "-",
|
50
|
-
@now.strftime("%d/%b/%Y %H:%M:%S"),
|
51
|
-
@env["REQUEST_METHOD"],
|
52
|
-
@env["PATH_INFO"],
|
53
|
-
@env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"],
|
54
|
-
@env["HTTP_VERSION"],
|
55
|
-
@status.to_s[0..3],
|
56
|
-
(length.zero? ? "-" : length.to_s),
|
57
|
-
@now - @time
|
58
|
-
]
|
44
|
+
def extract_content_length(headers)
|
45
|
+
value = headers['Content-Length'] or return '-'
|
46
|
+
value.to_s == '0' ? '-' : value
|
59
47
|
end
|
60
48
|
end
|
61
49
|
end
|