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/lib/rack/config.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Rack
|
2
|
+
# Rack::Config modifies the environment using the block given during
|
3
|
+
# initialization.
|
4
|
+
class Config
|
5
|
+
def initialize(app, &block)
|
6
|
+
@app = app
|
7
|
+
@block = block
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
@block.call(env)
|
12
|
+
@app.call(env)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/rack/content_type.rb
CHANGED
data/lib/rack/directory.rb
CHANGED
@@ -71,7 +71,9 @@ table { width:100%%; }
|
|
71
71
|
|
72
72
|
body = "Forbidden\n"
|
73
73
|
size = Rack::Utils.bytesize(body)
|
74
|
-
return [403, {"Content-Type" => "text/plain",
|
74
|
+
return [403, {"Content-Type" => "text/plain",
|
75
|
+
"Content-Length" => size.to_s,
|
76
|
+
"X-Cascade" => "pass"}, [body]]
|
75
77
|
end
|
76
78
|
|
77
79
|
def list_directory
|
@@ -123,7 +125,9 @@ table { width:100%%; }
|
|
123
125
|
def entity_not_found
|
124
126
|
body = "Entity not found: #{@path_info}\n"
|
125
127
|
size = Rack::Utils.bytesize(body)
|
126
|
-
return [404, {"Content-Type" => "text/plain",
|
128
|
+
return [404, {"Content-Type" => "text/plain",
|
129
|
+
"Content-Length" => size.to_s,
|
130
|
+
"X-Cascade" => "pass"}, [body]]
|
127
131
|
end
|
128
132
|
|
129
133
|
def each
|
data/lib/rack/etag.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'digest/md5'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
# Automatically sets the ETag header on all String bodies
|
5
|
+
class ETag
|
6
|
+
def initialize(app)
|
7
|
+
@app = app
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
status, headers, body = @app.call(env)
|
12
|
+
|
13
|
+
if !headers.has_key?('ETag')
|
14
|
+
parts = []
|
15
|
+
body.each { |part| parts << part.to_s }
|
16
|
+
headers['ETag'] = %("#{Digest::MD5.hexdigest(parts.join(""))}")
|
17
|
+
[status, headers, parts]
|
18
|
+
else
|
19
|
+
[status, headers, body]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/rack/file.rb
CHANGED
@@ -45,7 +45,8 @@ module Rack
|
|
45
45
|
def forbidden
|
46
46
|
body = "Forbidden\n"
|
47
47
|
[403, {"Content-Type" => "text/plain",
|
48
|
-
"Content-Length" => body.size.to_s
|
48
|
+
"Content-Length" => body.size.to_s,
|
49
|
+
"X-Cascade" => "pass"},
|
49
50
|
[body]]
|
50
51
|
end
|
51
52
|
|
@@ -73,7 +74,8 @@ module Rack
|
|
73
74
|
def not_found
|
74
75
|
body = "File not found: #{@path_info}\n"
|
75
76
|
[404, {"Content-Type" => "text/plain",
|
76
|
-
"Content-Length" => body.size.to_s
|
77
|
+
"Content-Length" => body.size.to_s,
|
78
|
+
"X-Cascade" => "pass"},
|
77
79
|
[body]]
|
78
80
|
end
|
79
81
|
|
data/lib/rack/handler.rb
CHANGED
@@ -22,6 +22,25 @@ module Rack
|
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
+
def self.default(options = {})
|
26
|
+
# Guess.
|
27
|
+
if ENV.include?("PHP_FCGI_CHILDREN")
|
28
|
+
# We already speak FastCGI
|
29
|
+
options.delete :File
|
30
|
+
options.delete :Port
|
31
|
+
|
32
|
+
Rack::Handler::FastCGI
|
33
|
+
elsif ENV.include?("REQUEST_METHOD")
|
34
|
+
Rack::Handler::CGI
|
35
|
+
else
|
36
|
+
begin
|
37
|
+
Rack::Handler::Mongrel
|
38
|
+
rescue LoadError => e
|
39
|
+
Rack::Handler::WEBrick
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
25
44
|
# Transforms server-name constants to their canonical form as filenames,
|
26
45
|
# then tries to require them but silences the LoadError if not found
|
27
46
|
#
|
data/lib/rack/handler/cgi.rb
CHANGED
data/lib/rack/handler/fastcgi.rb
CHANGED
@@ -33,10 +33,10 @@ module Rack
|
|
33
33
|
env.delete "HTTP_CONTENT_LENGTH"
|
34
34
|
|
35
35
|
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
36
|
-
|
36
|
+
|
37
37
|
rack_input = RewindableInput.new(request.in)
|
38
38
|
|
39
|
-
env.update({"rack.version" => [1,
|
39
|
+
env.update({"rack.version" => [1,1],
|
40
40
|
"rack.input" => rack_input,
|
41
41
|
"rack.errors" => request.err,
|
42
42
|
|
@@ -50,7 +50,6 @@ module Rack
|
|
50
50
|
env["QUERY_STRING"] ||= ""
|
51
51
|
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
52
52
|
env["REQUEST_PATH"] ||= "/"
|
53
|
-
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
54
53
|
env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
|
55
54
|
env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
|
56
55
|
|
data/lib/rack/handler/lsws.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'lsapi'
|
2
2
|
require 'rack/content_length'
|
3
|
+
require 'rack/rewindable_input'
|
3
4
|
|
4
5
|
module Rack
|
5
6
|
module Handler
|
@@ -19,7 +20,7 @@ module Rack
|
|
19
20
|
rack_input = RewindableInput.new($stdin.read.to_s)
|
20
21
|
|
21
22
|
env.update(
|
22
|
-
"rack.version" => [1,
|
23
|
+
"rack.version" => [1,1],
|
23
24
|
"rack.input" => rack_input,
|
24
25
|
"rack.errors" => $stderr,
|
25
26
|
"rack.multithread" => false,
|
@@ -38,6 +39,8 @@ module Rack
|
|
38
39
|
ensure
|
39
40
|
body.close if body.respond_to? :close
|
40
41
|
end
|
42
|
+
ensure
|
43
|
+
rack_input.close
|
41
44
|
end
|
42
45
|
def self.send_headers(status, headers)
|
43
46
|
print "Status: #{status}\r\n"
|
data/lib/rack/handler/mongrel.rb
CHANGED
@@ -7,10 +7,14 @@ module Rack
|
|
7
7
|
module Handler
|
8
8
|
class Mongrel < ::Mongrel::HttpHandler
|
9
9
|
def self.run(app, options={})
|
10
|
-
server = ::Mongrel::HttpServer.new(
|
11
|
-
|
10
|
+
server = ::Mongrel::HttpServer.new(
|
11
|
+
options[:Host] || '0.0.0.0',
|
12
|
+
options[:Port] || 8080,
|
13
|
+
options[:num_processors] || 950,
|
14
|
+
options[:throttle] || 0,
|
15
|
+
options[:timeout] || 60)
|
12
16
|
# Acts like Rack::URLMap, utilizing Mongrel's own path finding methods.
|
13
|
-
# Use is similar to #run, replacing the app argument with a hash of
|
17
|
+
# Use is similar to #run, replacing the app argument with a hash of
|
14
18
|
# { path=>app, ... } or an instance of Rack::URLMap.
|
15
19
|
if options[:map]
|
16
20
|
if app.is_a? Hash
|
@@ -48,7 +52,7 @@ module Rack
|
|
48
52
|
rack_input = request.body || StringIO.new('')
|
49
53
|
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
50
54
|
|
51
|
-
env.update({"rack.version" => [1,
|
55
|
+
env.update({"rack.version" => [1,1],
|
52
56
|
"rack.input" => rack_input,
|
53
57
|
"rack.errors" => $stderr,
|
54
58
|
|
@@ -59,7 +63,6 @@ module Rack
|
|
59
63
|
"rack.url_scheme" => "http",
|
60
64
|
})
|
61
65
|
env["QUERY_STRING"] ||= ""
|
62
|
-
env.delete "PATH_INFO" if env["PATH_INFO"] == ""
|
63
66
|
|
64
67
|
status, headers, body = @app.call(env)
|
65
68
|
|
data/lib/rack/handler/scgi.rb
CHANGED
@@ -7,14 +7,14 @@ module Rack
|
|
7
7
|
module Handler
|
8
8
|
class SCGI < ::SCGI::Processor
|
9
9
|
attr_accessor :app
|
10
|
-
|
10
|
+
|
11
11
|
def self.run(app, options=nil)
|
12
12
|
new(options.merge(:app=>app,
|
13
13
|
:host=>options[:Host],
|
14
14
|
:port=>options[:Port],
|
15
15
|
:socket=>options[:Socket])).listen
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
def initialize(settings = {})
|
19
19
|
@app = Rack::Chunked.new(Rack::ContentLength.new(settings[:app]))
|
20
20
|
@log = Object.new
|
@@ -22,7 +22,7 @@ module Rack
|
|
22
22
|
def @log.error(*args); end
|
23
23
|
super(settings)
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def process_request(request, input_body, socket)
|
27
27
|
env = {}.replace(request)
|
28
28
|
env.delete "HTTP_CONTENT_TYPE"
|
@@ -36,7 +36,7 @@ module Rack
|
|
36
36
|
rack_input = StringIO.new(input_body)
|
37
37
|
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
38
38
|
|
39
|
-
env.update({"rack.version" => [1,
|
39
|
+
env.update({"rack.version" => [1,1],
|
40
40
|
"rack.input" => rack_input,
|
41
41
|
"rack.errors" => $stderr,
|
42
42
|
"rack.multithread" => true,
|
data/lib/rack/handler/webrick.rb
CHANGED
@@ -26,7 +26,7 @@ module Rack
|
|
26
26
|
rack_input = StringIO.new(req.body.to_s)
|
27
27
|
rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
|
28
28
|
|
29
|
-
env.update({"rack.version" => [1,
|
29
|
+
env.update({"rack.version" => [1,1],
|
30
30
|
"rack.input" => rack_input,
|
31
31
|
"rack.errors" => $stderr,
|
32
32
|
|
@@ -40,9 +40,7 @@ module Rack
|
|
40
40
|
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
41
41
|
env["QUERY_STRING"] ||= ""
|
42
42
|
env["REQUEST_PATH"] ||= "/"
|
43
|
-
|
44
|
-
env.delete "PATH_INFO"
|
45
|
-
else
|
43
|
+
unless env["PATH_INFO"] == ""
|
46
44
|
path, n = req.request_uri.path, env["SCRIPT_NAME"].length
|
47
45
|
env["PATH_INFO"] = path[n, path.length-n]
|
48
46
|
end
|
data/lib/rack/lint.rb
CHANGED
@@ -61,7 +61,7 @@ module Rack
|
|
61
61
|
## subclassing allowed) that includes CGI-like headers.
|
62
62
|
## The application is free to modify the environment.
|
63
63
|
assert("env #{env.inspect} is not a Hash, but #{env.class}") {
|
64
|
-
env.
|
64
|
+
env.kind_of? Hash
|
65
65
|
}
|
66
66
|
|
67
67
|
##
|
@@ -111,7 +111,7 @@ module Rack
|
|
111
111
|
## In addition to this, the Rack environment must include these
|
112
112
|
## Rack-specific variables:
|
113
113
|
|
114
|
-
## <tt>rack.version</tt>:: The Array [1,
|
114
|
+
## <tt>rack.version</tt>:: The Array [1,1], representing this version of Rack.
|
115
115
|
## <tt>rack.url_scheme</tt>:: +http+ or +https+, depending on the request URL.
|
116
116
|
## <tt>rack.input</tt>:: See below, the input stream.
|
117
117
|
## <tt>rack.errors</tt>:: See below, the error stream.
|
@@ -148,6 +148,35 @@ module Rack
|
|
148
148
|
}
|
149
149
|
end
|
150
150
|
|
151
|
+
## <tt>rack.logger</tt>:: A common object interface for logging messages.
|
152
|
+
## The object must implement:
|
153
|
+
if logger = env['rack.logger']
|
154
|
+
## info(message, &block)
|
155
|
+
assert("logger #{logger.inspect} must respond to info") {
|
156
|
+
logger.respond_to?(:info)
|
157
|
+
}
|
158
|
+
|
159
|
+
## debug(message, &block)
|
160
|
+
assert("logger #{logger.inspect} must respond to debug") {
|
161
|
+
logger.respond_to?(:debug)
|
162
|
+
}
|
163
|
+
|
164
|
+
## warn(message, &block)
|
165
|
+
assert("logger #{logger.inspect} must respond to warn") {
|
166
|
+
logger.respond_to?(:warn)
|
167
|
+
}
|
168
|
+
|
169
|
+
## error(message, &block)
|
170
|
+
assert("logger #{logger.inspect} must respond to error") {
|
171
|
+
logger.respond_to?(:error)
|
172
|
+
}
|
173
|
+
|
174
|
+
## fatal(message, &block)
|
175
|
+
assert("logger #{logger.inspect} must respond to fatal") {
|
176
|
+
logger.respond_to?(:fatal)
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
151
180
|
## The server or the application can store their own data in the
|
152
181
|
## environment, too. The keys must contain at least one dot,
|
153
182
|
## and should be prefixed uniquely. The prefix <tt>rack.</tt>
|
@@ -175,7 +204,7 @@ module Rack
|
|
175
204
|
env.each { |key, value|
|
176
205
|
next if key.include? "." # Skip extensions
|
177
206
|
assert("env variable #{key} has non-string value #{value.inspect}") {
|
178
|
-
value.
|
207
|
+
value.kind_of? String
|
179
208
|
}
|
180
209
|
}
|
181
210
|
|
@@ -184,7 +213,7 @@ module Rack
|
|
184
213
|
|
185
214
|
## * <tt>rack.version</tt> must be an array of Integers.
|
186
215
|
assert("rack.version must be an Array, was #{env["rack.version"].class}") {
|
187
|
-
env["rack.version"].
|
216
|
+
env["rack.version"].kind_of? Array
|
188
217
|
}
|
189
218
|
## * <tt>rack.url_scheme</tt> must either be +http+ or +https+.
|
190
219
|
assert("rack.url_scheme unknown: #{env["rack.url_scheme"].inspect}") {
|
@@ -243,7 +272,7 @@ module Rack
|
|
243
272
|
assert("rack.input #{input} is not opened in binary mode") {
|
244
273
|
input.binmode?
|
245
274
|
} if input.respond_to?(:binmode?)
|
246
|
-
|
275
|
+
|
247
276
|
## The input stream must respond to +gets+, +each+, +read+ and +rewind+.
|
248
277
|
[:gets, :each, :read, :rewind].each { |method|
|
249
278
|
assert("rack.input #{input} does not respond to ##{method}") {
|
@@ -269,7 +298,7 @@ module Rack
|
|
269
298
|
assert("rack.input#gets called with arguments") { args.size == 0 }
|
270
299
|
v = @input.gets
|
271
300
|
assert("rack.input#gets didn't return a String") {
|
272
|
-
v.nil? or v.
|
301
|
+
v.nil? or v.kind_of? String
|
273
302
|
}
|
274
303
|
v
|
275
304
|
end
|
@@ -300,18 +329,18 @@ module Rack
|
|
300
329
|
args[1].kind_of?(String)
|
301
330
|
}
|
302
331
|
end
|
303
|
-
|
332
|
+
|
304
333
|
v = @input.read(*args)
|
305
|
-
|
334
|
+
|
306
335
|
assert("rack.input#read didn't return nil or a String") {
|
307
|
-
v.nil? or v.
|
336
|
+
v.nil? or v.kind_of? String
|
308
337
|
}
|
309
338
|
if args[0].nil?
|
310
339
|
assert("rack.input#read(nil) returned nil on EOF") {
|
311
340
|
!v.nil?
|
312
341
|
}
|
313
342
|
end
|
314
|
-
|
343
|
+
|
315
344
|
v
|
316
345
|
end
|
317
346
|
|
@@ -320,12 +349,12 @@ module Rack
|
|
320
349
|
assert("rack.input#each called with arguments") { args.size == 0 }
|
321
350
|
@input.each { |line|
|
322
351
|
assert("rack.input#each didn't yield a String") {
|
323
|
-
line.
|
352
|
+
line.kind_of? String
|
324
353
|
}
|
325
354
|
yield line
|
326
355
|
}
|
327
356
|
end
|
328
|
-
|
357
|
+
|
329
358
|
## * +rewind+ must be called without arguments. It rewinds the input
|
330
359
|
## stream back to the beginning. It must not raise Errno::ESPIPE:
|
331
360
|
## that is, it may not be a pipe or a socket. Therefore, handler
|
@@ -373,7 +402,7 @@ module Rack
|
|
373
402
|
|
374
403
|
## * +write+ must be called with a single argument that is a String.
|
375
404
|
def write(str)
|
376
|
-
assert("rack.errors#write not called with a String") { str.
|
405
|
+
assert("rack.errors#write not called with a String") { str.kind_of? String }
|
377
406
|
@error.write str
|
378
407
|
end
|
379
408
|
|
@@ -407,7 +436,7 @@ module Rack
|
|
407
436
|
header.each { |key, value|
|
408
437
|
## The header keys must be Strings.
|
409
438
|
assert("header key must be a string, was #{key.class}") {
|
410
|
-
key.
|
439
|
+
key.kind_of? String
|
411
440
|
}
|
412
441
|
## The header must not contain a +Status+ key,
|
413
442
|
assert("header must not contain Status") { key.downcase != "status" }
|
@@ -499,7 +528,7 @@ module Rack
|
|
499
528
|
@body.each { |part|
|
500
529
|
## and must only yield String values.
|
501
530
|
assert("Body yielded non-string value #{part.inspect}") {
|
502
|
-
part.
|
531
|
+
part.kind_of? String
|
503
532
|
}
|
504
533
|
yield part
|
505
534
|
}
|
data/lib/rack/logger.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
# Sets up rack.logger to write to rack.errors stream
|
5
|
+
class Logger
|
6
|
+
def initialize(app, level = ::Logger::INFO)
|
7
|
+
@app, @level = app, level
|
8
|
+
end
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
logger = ::Logger.new(env['rack.errors'])
|
12
|
+
logger.level = @level
|
13
|
+
|
14
|
+
env['rack.logger'] = logger
|
15
|
+
@app.call(env)
|
16
|
+
ensure
|
17
|
+
logger.close
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/rack/mime.rb
CHANGED
@@ -14,7 +14,7 @@ module Rack
|
|
14
14
|
# Rack::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream')
|
15
15
|
|
16
16
|
def mime_type(ext, fallback='application/octet-stream')
|
17
|
-
MIME_TYPES.fetch(ext, fallback)
|
17
|
+
MIME_TYPES.fetch(ext.to_s.downcase, fallback)
|
18
18
|
end
|
19
19
|
module_function :mime_type
|
20
20
|
|
@@ -105,6 +105,7 @@ module Rack
|
|
105
105
|
".m3u" => "audio/x-mpegurl",
|
106
106
|
".m4v" => "video/mp4",
|
107
107
|
".man" => "text/troff",
|
108
|
+
".manifest"=> "text/cache-manifest",
|
108
109
|
".mathml" => "application/mathml+xml",
|
109
110
|
".mbox" => "application/mbox",
|
110
111
|
".mdoc" => "text/troff",
|
@@ -126,6 +127,7 @@ module Rack
|
|
126
127
|
".ods" => "application/vnd.oasis.opendocument.spreadsheet",
|
127
128
|
".odt" => "application/vnd.oasis.opendocument.text",
|
128
129
|
".ogg" => "application/ogg",
|
130
|
+
".ogv" => "video/ogg",
|
129
131
|
".p" => "text/x-pascal",
|
130
132
|
".pas" => "text/x-pascal",
|
131
133
|
".pbm" => "image/x-portable-bitmap",
|