rack 0.4.0 → 0.9.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/RDOX +61 -3
- data/README +52 -37
- data/Rakefile +9 -0
- data/SPEC +6 -3
- data/bin/rackup +0 -0
- data/lib/rack.rb +7 -2
- data/lib/rack/adapter/camping.rb +1 -1
- data/lib/rack/auth/openid.rb +4 -3
- data/lib/rack/builder.rb +12 -1
- data/lib/rack/conditionalget.rb +43 -0
- data/lib/rack/content_length.rb +25 -0
- data/lib/rack/deflater.rb +29 -5
- data/lib/rack/directory.rb +82 -91
- data/lib/rack/file.rb +45 -76
- data/lib/rack/handler.rb +4 -0
- data/lib/rack/handler/evented_mongrel.rb +1 -1
- data/lib/rack/handler/fastcgi.rb +2 -0
- data/lib/rack/handler/mongrel.rb +6 -2
- data/lib/rack/handler/swiftiplied_mongrel.rb +8 -0
- data/lib/rack/handler/thin.rb +15 -0
- data/lib/rack/handler/webrick.rb +8 -4
- data/lib/rack/head.rb +19 -0
- data/lib/rack/lint.rb +74 -10
- data/lib/rack/lobster.rb +13 -13
- data/lib/rack/methodoverride.rb +27 -0
- data/lib/rack/mime.rb +204 -0
- data/lib/rack/request.rb +10 -1
- data/lib/rack/response.rb +7 -2
- data/lib/rack/session/abstract/id.rb +14 -1
- data/lib/rack/session/cookie.rb +19 -1
- data/lib/rack/session/memcache.rb +1 -1
- data/lib/rack/session/pool.rb +1 -1
- data/lib/rack/showexceptions.rb +5 -1
- data/lib/rack/showstatus.rb +3 -2
- data/lib/rack/urlmap.rb +1 -1
- data/lib/rack/utils.rb +42 -13
- data/test/cgi/lighttpd.conf +1 -1
- data/test/cgi/test +0 -0
- data/test/cgi/test.fcgi +0 -0
- data/test/cgi/test.ru +0 -0
- data/test/spec_rack_builder.rb +34 -0
- data/test/spec_rack_conditionalget.rb +41 -0
- data/test/spec_rack_content_length.rb +43 -0
- data/test/spec_rack_deflater.rb +49 -14
- data/test/spec_rack_file.rb +7 -0
- data/test/spec_rack_handler.rb +3 -3
- data/test/spec_rack_head.rb +30 -0
- data/test/spec_rack_lint.rb +79 -2
- data/test/spec_rack_methodoverride.rb +60 -0
- data/test/spec_rack_mock.rb +1 -1
- data/test/spec_rack_mongrel.rb +20 -1
- data/test/spec_rack_request.rb +46 -1
- data/test/spec_rack_response.rb +10 -3
- data/test/spec_rack_session_cookie.rb +33 -0
- data/test/spec_rack_thin.rb +90 -0
- data/test/spec_rack_utils.rb +20 -18
- data/test/spec_rack_webrick.rb +17 -0
- data/test/testrequest.rb +12 -0
- metadata +91 -5
data/lib/rack/builder.rb
CHANGED
@@ -13,6 +13,13 @@ module Rack
|
|
13
13
|
# end
|
14
14
|
# }
|
15
15
|
#
|
16
|
+
# Or
|
17
|
+
#
|
18
|
+
# app = Rack::Builder.app do
|
19
|
+
# use Rack::CommonLogger
|
20
|
+
# lambda { |env| [200, {'Content-Type' => 'text/plain'}, 'OK'] }
|
21
|
+
# end
|
22
|
+
#
|
16
23
|
# +use+ adds a middleware to the stack, +run+ dispatches to an application.
|
17
24
|
# You can use +map+ to construct a Rack::URLMap in a convenient way.
|
18
25
|
|
@@ -22,6 +29,10 @@ module Rack
|
|
22
29
|
instance_eval(&block) if block_given?
|
23
30
|
end
|
24
31
|
|
32
|
+
def self.app(&block)
|
33
|
+
self.new(&block).to_app
|
34
|
+
end
|
35
|
+
|
25
36
|
def use(middleware, *args, &block)
|
26
37
|
@ins << if block_given?
|
27
38
|
lambda { |app| middleware.new(app, *args, &block) }
|
@@ -36,7 +47,7 @@ module Rack
|
|
36
47
|
|
37
48
|
def map(path, &block)
|
38
49
|
if @ins.last.kind_of? Hash
|
39
|
-
@ins.last[path] =
|
50
|
+
@ins.last[path] = self.class.new(&block).to_app
|
40
51
|
else
|
41
52
|
@ins << {}
|
42
53
|
map(path, &block)
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Rack
|
2
|
+
|
3
|
+
# Middleware that enables conditional GET using If-None-Match and
|
4
|
+
# If-Modified-Since. The application should set either or both of the
|
5
|
+
# Last-Modified or Etag response headers according to RFC 2616. When
|
6
|
+
# either of the conditions is met, the response body is set to be zero
|
7
|
+
# length and the response status is set to 304 Not Modified.
|
8
|
+
#
|
9
|
+
# Applications that defer response body generation until the body's each
|
10
|
+
# message is received will avoid response body generation completely when
|
11
|
+
# a conditional GET matches.
|
12
|
+
#
|
13
|
+
# Adapted from Michael Klishin's Merb implementation:
|
14
|
+
# http://github.com/wycats/merb-core/tree/master/lib/merb-core/rack/middleware/conditional_get.rb
|
15
|
+
class ConditionalGet
|
16
|
+
def initialize(app)
|
17
|
+
@app = app
|
18
|
+
end
|
19
|
+
|
20
|
+
def call(env)
|
21
|
+
return @app.call(env) unless %w[GET HEAD].include?(env['REQUEST_METHOD'])
|
22
|
+
|
23
|
+
status, headers, body = @app.call(env)
|
24
|
+
headers = Utils::HeaderHash.new(headers)
|
25
|
+
if etag_matches?(env, headers) || modified_since?(env, headers)
|
26
|
+
status = 304
|
27
|
+
body = []
|
28
|
+
end
|
29
|
+
[status, headers, body]
|
30
|
+
end
|
31
|
+
|
32
|
+
private
|
33
|
+
def etag_matches?(env, headers)
|
34
|
+
etag = headers['Etag'] and etag == env['HTTP_IF_NONE_MATCH']
|
35
|
+
end
|
36
|
+
|
37
|
+
def modified_since?(env, headers)
|
38
|
+
last_modified = headers['Last-Modified'] and
|
39
|
+
last_modified == env['HTTP_IF_MODIFIED_SINCE']
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Rack
|
2
|
+
# Sets the Content-Length header on responses with fixed-length bodies.
|
3
|
+
class ContentLength
|
4
|
+
def initialize(app)
|
5
|
+
@app = app
|
6
|
+
end
|
7
|
+
|
8
|
+
def call(env)
|
9
|
+
status, headers, body = @app.call(env)
|
10
|
+
headers = Utils::HeaderHash.new(headers)
|
11
|
+
|
12
|
+
if !Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) &&
|
13
|
+
!headers['Content-Length'] &&
|
14
|
+
!headers['Transfer-Encoding'] &&
|
15
|
+
(body.respond_to?(:to_ary) || body.respond_to?(:to_str))
|
16
|
+
|
17
|
+
body = [body] if body.respond_to?(:to_str) # rack 0.4 compat
|
18
|
+
length = body.to_ary.inject(0) { |len, part| len + part.length }
|
19
|
+
headers['Content-Length'] = length.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
[status, headers, body]
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/rack/deflater.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require "zlib"
|
2
2
|
require "stringio"
|
3
|
+
require "time" # for Time.httpdate
|
3
4
|
|
4
5
|
module Rack
|
5
6
|
|
@@ -10,21 +11,44 @@ class Deflater
|
|
10
11
|
|
11
12
|
def call(env)
|
12
13
|
status, headers, body = @app.call(env)
|
14
|
+
headers = Utils::HeaderHash.new(headers)
|
15
|
+
|
16
|
+
# Skip compressing empty entity body responses and responses with
|
17
|
+
# no-transform set.
|
18
|
+
if Utils::STATUS_WITH_NO_ENTITY_BODY.include?(status) ||
|
19
|
+
headers['Cache-Control'].to_s =~ /\bno-transform\b/
|
20
|
+
return [status, headers, body]
|
21
|
+
end
|
13
22
|
|
14
23
|
request = Request.new(env)
|
15
24
|
|
16
|
-
encoding = Utils.select_best_encoding(%w(gzip deflate identity),
|
25
|
+
encoding = Utils.select_best_encoding(%w(gzip deflate identity),
|
26
|
+
request.accept_encoding)
|
27
|
+
|
28
|
+
# Set the Vary HTTP header.
|
29
|
+
vary = headers["Vary"].to_s.split(",").map { |v| v.strip }
|
30
|
+
unless vary.include?("*") || vary.include?("Accept-Encoding")
|
31
|
+
headers["Vary"] = vary.push("Accept-Encoding").join(",")
|
32
|
+
end
|
17
33
|
|
18
34
|
case encoding
|
19
35
|
when "gzip"
|
20
|
-
mtime = headers
|
21
|
-
|
36
|
+
mtime = if headers.key?("Last-Modified")
|
37
|
+
Time.httpdate(headers["Last-Modified"])
|
38
|
+
else
|
39
|
+
Time.now
|
40
|
+
end
|
41
|
+
[status,
|
42
|
+
headers.merge("Content-Encoding" => "gzip"),
|
43
|
+
self.class.gzip(body, mtime)]
|
22
44
|
when "deflate"
|
23
|
-
[status,
|
45
|
+
[status,
|
46
|
+
headers.merge("Content-Encoding" => "deflate"),
|
47
|
+
self.class.deflate(body)]
|
24
48
|
when "identity"
|
25
49
|
[status, headers, body]
|
26
50
|
when nil
|
27
|
-
message = "An acceptable encoding for the requested resource #{request.fullpath} could not be found."
|
51
|
+
message = ["An acceptable encoding for the requested resource #{request.fullpath} could not be found."]
|
28
52
|
[406, {"Content-Type" => "text/plain"}, message]
|
29
53
|
end
|
30
54
|
end
|
data/lib/rack/directory.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'time'
|
2
|
+
require 'rack/mime'
|
2
3
|
|
3
4
|
module Rack
|
4
5
|
# Rack::Directory serves entries below the +root+ given, according to the
|
@@ -13,10 +14,13 @@ module Rack
|
|
13
14
|
DIR_PAGE = <<-PAGE
|
14
15
|
<html><head>
|
15
16
|
<title>%s</title>
|
17
|
+
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
16
18
|
<style type='text/css'>
|
17
19
|
table { width:100%%; }
|
18
20
|
.name { text-align:left; }
|
19
21
|
.size, .mtime { text-align:right; }
|
22
|
+
.type { width:11em; }
|
23
|
+
.mtime { width:15em; }
|
20
24
|
</style>
|
21
25
|
</head><body>
|
22
26
|
<h1>%s</h1>
|
@@ -38,11 +42,8 @@ table { width:100%%; }
|
|
38
42
|
attr_accessor :root, :path
|
39
43
|
|
40
44
|
def initialize(root, app=nil)
|
41
|
-
@root = root
|
42
|
-
@app = app
|
43
|
-
unless defined? @app
|
44
|
-
@app = Rack::File.new(@root)
|
45
|
-
end
|
45
|
+
@root = F.expand_path(root)
|
46
|
+
@app = app || Rack::File.new(@root)
|
46
47
|
end
|
47
48
|
|
48
49
|
def call(env)
|
@@ -52,36 +53,71 @@ table { width:100%%; }
|
|
52
53
|
F = ::File
|
53
54
|
|
54
55
|
def _call(env)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
@env = env
|
57
|
+
@path_info, @script_name = env.values_at('PATH_INFO', 'SCRIPT_NAME')
|
58
|
+
|
59
|
+
if forbidden = check_forbidden
|
60
|
+
forbidden
|
61
|
+
else
|
62
|
+
@path = F.join(@root, Utils.unescape(@path_info))
|
63
|
+
list_path
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def check_forbidden
|
68
|
+
return unless @path_info.include? ".."
|
69
|
+
|
70
|
+
body = "Forbidden\n"
|
71
|
+
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
72
|
+
return [403, {"Content-Type" => "text/plain","Content-Length" => size.to_s}, [body]]
|
73
|
+
end
|
74
|
+
|
75
|
+
def list_directory
|
76
|
+
@files = [['../','Parent Directory','','','']]
|
77
|
+
glob = F.join(@path, '*')
|
78
|
+
|
79
|
+
Dir[glob].sort.each do |node|
|
80
|
+
stat = stat(node)
|
81
|
+
next unless stat
|
82
|
+
basename = F.basename(node)
|
83
|
+
ext = F.extname(node)
|
84
|
+
|
85
|
+
url = F.join(@script_name, @path_info, basename)
|
86
|
+
size = stat.size
|
87
|
+
type = stat.directory? ? 'directory' : Mime.mime_type(ext)
|
88
|
+
size = stat.directory? ? '-' : filesize_format(size)
|
89
|
+
mtime = stat.mtime.httpdate
|
90
|
+
|
91
|
+
@files << [ url, basename, size, type, mtime ]
|
59
92
|
end
|
60
93
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
return [ 200, {'Content-Type'=>'text/html'}, self ]
|
81
|
-
end
|
94
|
+
return [ 200, {'Content-Type'=>'text/html; charset=utf-8'}, self ]
|
95
|
+
end
|
96
|
+
|
97
|
+
def stat(node, max = 10)
|
98
|
+
F.stat(node)
|
99
|
+
rescue Errno::ENOENT, Errno::ELOOP
|
100
|
+
return nil
|
101
|
+
end
|
102
|
+
|
103
|
+
# TODO: add correct response if not readable, not sure if 404 is the best
|
104
|
+
# option
|
105
|
+
def list_path
|
106
|
+
@stat = F.stat(@path)
|
107
|
+
|
108
|
+
if @stat.readable?
|
109
|
+
return @app.call(@env) if @stat.file?
|
110
|
+
return list_directory if @stat.directory?
|
111
|
+
else
|
112
|
+
raise Errno::ENOENT, 'No such file or directory'
|
82
113
|
end
|
83
114
|
|
84
|
-
|
115
|
+
rescue Errno::ENOENT, Errno::ELOOP
|
116
|
+
return entity_not_found
|
117
|
+
end
|
118
|
+
|
119
|
+
def entity_not_found
|
120
|
+
body = "Entity not found: #{@path_info}\n"
|
85
121
|
size = body.respond_to?(:bytesize) ? body.bytesize : body.size
|
86
122
|
return [404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]]
|
87
123
|
end
|
@@ -93,66 +129,21 @@ table { width:100%%; }
|
|
93
129
|
page.each_line{|l| yield l }
|
94
130
|
end
|
95
131
|
|
96
|
-
|
97
|
-
|
98
|
-
|
132
|
+
# Stolen from Ramaze
|
133
|
+
|
134
|
+
FILESIZE_FORMAT = [
|
135
|
+
['%.1fT', 1 << 40],
|
136
|
+
['%.1fG', 1 << 30],
|
137
|
+
['%.1fM', 1 << 20],
|
138
|
+
['%.1fK', 1 << 10],
|
139
|
+
]
|
99
140
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
"class" => "application/octet-stream",
|
108
|
-
"cer" => "application/pkix-cert",
|
109
|
-
"crl" => "application/pkix-crl",
|
110
|
-
"crt" => "application/x-x509-ca-cert",
|
111
|
-
#"crl" => "application/x-pkcs7-crl",
|
112
|
-
"css" => "text/css",
|
113
|
-
"dms" => "application/octet-stream",
|
114
|
-
"doc" => "application/msword",
|
115
|
-
"dvi" => "application/x-dvi",
|
116
|
-
"eps" => "application/postscript",
|
117
|
-
"etx" => "text/x-setext",
|
118
|
-
"exe" => "application/octet-stream",
|
119
|
-
"gif" => "image/gif",
|
120
|
-
"htm" => "text/html",
|
121
|
-
"html" => "text/html",
|
122
|
-
"jpe" => "image/jpeg",
|
123
|
-
"jpeg" => "image/jpeg",
|
124
|
-
"jpg" => "image/jpeg",
|
125
|
-
"js" => "text/javascript",
|
126
|
-
"lha" => "application/octet-stream",
|
127
|
-
"lzh" => "application/octet-stream",
|
128
|
-
"mov" => "video/quicktime",
|
129
|
-
"mpe" => "video/mpeg",
|
130
|
-
"mpeg" => "video/mpeg",
|
131
|
-
"mpg" => "video/mpeg",
|
132
|
-
"pbm" => "image/x-portable-bitmap",
|
133
|
-
"pdf" => "application/pdf",
|
134
|
-
"pgm" => "image/x-portable-graymap",
|
135
|
-
"png" => "image/png",
|
136
|
-
"pnm" => "image/x-portable-anymap",
|
137
|
-
"ppm" => "image/x-portable-pixmap",
|
138
|
-
"ppt" => "application/vnd.ms-powerpoint",
|
139
|
-
"ps" => "application/postscript",
|
140
|
-
"qt" => "video/quicktime",
|
141
|
-
"ras" => "image/x-cmu-raster",
|
142
|
-
"rb" => "text/plain",
|
143
|
-
"rd" => "text/plain",
|
144
|
-
"rtf" => "application/rtf",
|
145
|
-
"sgm" => "text/sgml",
|
146
|
-
"sgml" => "text/sgml",
|
147
|
-
"tif" => "image/tiff",
|
148
|
-
"tiff" => "image/tiff",
|
149
|
-
"txt" => "text/plain",
|
150
|
-
"xbm" => "image/x-xbitmap",
|
151
|
-
"xls" => "application/vnd.ms-excel",
|
152
|
-
"xml" => "text/xml",
|
153
|
-
"xpm" => "image/x-xpixmap",
|
154
|
-
"xwd" => "image/x-xwindowdump",
|
155
|
-
"zip" => "application/zip",
|
156
|
-
}
|
141
|
+
def filesize_format(int)
|
142
|
+
FILESIZE_FORMAT.each do |format, size|
|
143
|
+
return format % (int.to_f / size) if int >= size
|
144
|
+
end
|
145
|
+
|
146
|
+
int.to_s + 'B'
|
147
|
+
end
|
157
148
|
end
|
158
149
|
end
|
data/lib/rack/file.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'time'
|
2
|
+
require 'rack/mime'
|
2
3
|
|
3
4
|
module Rack
|
4
5
|
# Rack::File serves files below the +root+ given, according to the
|
@@ -22,26 +23,55 @@ module Rack
|
|
22
23
|
F = ::File
|
23
24
|
|
24
25
|
def _call(env)
|
25
|
-
if env["PATH_INFO"].include? ".."
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
return forbidden if env["PATH_INFO"].include? ".."
|
27
|
+
|
28
|
+
@path_info = Utils.unescape(env["PATH_INFO"])
|
29
|
+
@path = F.join(@root, @path_info)
|
30
|
+
|
31
|
+
begin
|
32
|
+
if F.file?(@path) && F.readable?(@path)
|
33
|
+
serving
|
34
|
+
else
|
35
|
+
raise Errno::EPERM
|
36
|
+
end
|
37
|
+
rescue SystemCallError
|
38
|
+
not_found
|
29
39
|
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def forbidden
|
43
|
+
body = "Forbidden\n"
|
44
|
+
[403, {"Content-Type" => "text/plain",
|
45
|
+
"Content-Length" => body.size.to_s},
|
46
|
+
[body]]
|
47
|
+
end
|
30
48
|
|
31
|
-
|
32
|
-
|
49
|
+
# NOTE:
|
50
|
+
# We check via File::size? whether this file provides size info
|
51
|
+
# via stat (e.g. /proc files often don't), otherwise we have to
|
52
|
+
# figure it out by reading the whole file into memory. And while
|
53
|
+
# we're at it we also use this as body then.
|
33
54
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
"Content-Type" => MIME_TYPES[ext] || "text/plain",
|
38
|
-
"Content-Length" => F.size(@path).to_s
|
39
|
-
}, self]
|
55
|
+
def serving
|
56
|
+
if size = F.size?(@path)
|
57
|
+
body = self
|
40
58
|
else
|
41
|
-
body =
|
42
|
-
size = body.
|
43
|
-
[404, {"Content-Type" => "text/plain", "Content-Length" => size.to_s}, [body]]
|
59
|
+
body = [F.read(@path)]
|
60
|
+
size = body.first.size
|
44
61
|
end
|
62
|
+
|
63
|
+
[200, {
|
64
|
+
"Last-Modified" => F.mtime(@path).httpdate,
|
65
|
+
"Content-Type" => Mime.mime_type(F.extname(@path), 'text/plain'),
|
66
|
+
"Content-Length" => size.to_s
|
67
|
+
}, body]
|
68
|
+
end
|
69
|
+
|
70
|
+
def not_found
|
71
|
+
body = "File not found: #{@path_info}\n"
|
72
|
+
[404, {"Content-Type" => "text/plain",
|
73
|
+
"Content-Length" => body.size.to_s},
|
74
|
+
[body]]
|
45
75
|
end
|
46
76
|
|
47
77
|
def each
|
@@ -51,66 +81,5 @@ module Rack
|
|
51
81
|
end
|
52
82
|
}
|
53
83
|
end
|
54
|
-
|
55
|
-
# :stopdoc:
|
56
|
-
# From WEBrick with some additions.
|
57
|
-
MIME_TYPES = {
|
58
|
-
"ai" => "application/postscript",
|
59
|
-
"asc" => "text/plain",
|
60
|
-
"avi" => "video/x-msvideo",
|
61
|
-
"bin" => "application/octet-stream",
|
62
|
-
"bmp" => "image/bmp",
|
63
|
-
"class" => "application/octet-stream",
|
64
|
-
"cer" => "application/pkix-cert",
|
65
|
-
"crl" => "application/pkix-crl",
|
66
|
-
"crt" => "application/x-x509-ca-cert",
|
67
|
-
#"crl" => "application/x-pkcs7-crl",
|
68
|
-
"css" => "text/css",
|
69
|
-
"dms" => "application/octet-stream",
|
70
|
-
"doc" => "application/msword",
|
71
|
-
"dvi" => "application/x-dvi",
|
72
|
-
"eps" => "application/postscript",
|
73
|
-
"etx" => "text/x-setext",
|
74
|
-
"exe" => "application/octet-stream",
|
75
|
-
"gif" => "image/gif",
|
76
|
-
"htm" => "text/html",
|
77
|
-
"html" => "text/html",
|
78
|
-
"jpe" => "image/jpeg",
|
79
|
-
"jpeg" => "image/jpeg",
|
80
|
-
"jpg" => "image/jpeg",
|
81
|
-
"js" => "text/javascript",
|
82
|
-
"lha" => "application/octet-stream",
|
83
|
-
"lzh" => "application/octet-stream",
|
84
|
-
"mov" => "video/quicktime",
|
85
|
-
"mp3" => "audio/mpeg",
|
86
|
-
"mpe" => "video/mpeg",
|
87
|
-
"mpeg" => "video/mpeg",
|
88
|
-
"mpg" => "video/mpeg",
|
89
|
-
"pbm" => "image/x-portable-bitmap",
|
90
|
-
"pdf" => "application/pdf",
|
91
|
-
"pgm" => "image/x-portable-graymap",
|
92
|
-
"png" => "image/png",
|
93
|
-
"pnm" => "image/x-portable-anymap",
|
94
|
-
"ppm" => "image/x-portable-pixmap",
|
95
|
-
"ppt" => "application/vnd.ms-powerpoint",
|
96
|
-
"ps" => "application/postscript",
|
97
|
-
"qt" => "video/quicktime",
|
98
|
-
"ras" => "image/x-cmu-raster",
|
99
|
-
"rb" => "text/plain",
|
100
|
-
"rd" => "text/plain",
|
101
|
-
"rtf" => "application/rtf",
|
102
|
-
"sgm" => "text/sgml",
|
103
|
-
"sgml" => "text/sgml",
|
104
|
-
"tif" => "image/tiff",
|
105
|
-
"tiff" => "image/tiff",
|
106
|
-
"txt" => "text/plain",
|
107
|
-
"xbm" => "image/x-xbitmap",
|
108
|
-
"xls" => "application/vnd.ms-excel",
|
109
|
-
"xml" => "text/xml",
|
110
|
-
"xpm" => "image/x-xpixmap",
|
111
|
-
"xwd" => "image/x-xwindowdump",
|
112
|
-
"zip" => "application/zip",
|
113
|
-
}
|
114
|
-
# :startdoc:
|
115
84
|
end
|
116
85
|
end
|