thin 0.3.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of thin might be problematic. Click here for more details.

@@ -0,0 +1,40 @@
1
+ module Thin::Commands::Cluster
2
+ class Start < Base
3
+ def run
4
+ load_from_config
5
+
6
+ cluster = Thin::Cluster.new(cwd, address, port, servers)
7
+
8
+ cluster.environment = environment
9
+ cluster.log_file = log_file
10
+ cluster.pid_file = pid_file
11
+ cluster.trace = trace
12
+ cluster.user = user
13
+ cluster.group = group
14
+
15
+ cluster.start
16
+ end
17
+
18
+ def self.help
19
+ "Starts a bunch of servers"
20
+ end
21
+
22
+ def self.detailed_help
23
+ <<-EOF
24
+ usage: thin_cluster start [options]
25
+
26
+ Start multiple servers (--servers) starting on port --port.
27
+ One pid file and log file will be created for each.
28
+
29
+ By default 3 servers will be started:
30
+
31
+ 0.0.0.0:5000 pid-file=tmp/pids/thin.5000.pid log-file=log/thin.5000.log
32
+ 0.0.0.0:5001 pid-file=tmp/pids/thin.5001.pid log-file=log/thin.5001.log
33
+ 0.0.0.0:5002 pid-file=tmp/pids/thin.5002.pid log-file=log/thin.5002.log
34
+
35
+ Use 'thin_cluster config' to create a config file and use
36
+ it with the --config option.
37
+ EOF
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,28 @@
1
+ module Thin::Commands::Cluster
2
+ class Stop < Base
3
+ def run
4
+ load_from_config
5
+
6
+ cluster = Thin::Cluster.new(cwd, address, port, servers)
7
+
8
+ cluster.log_file = log_file
9
+ cluster.pid_file = pid_file
10
+ cluster.trace = trace
11
+
12
+ cluster.stop
13
+ end
14
+
15
+ def self.help
16
+ "Stops all servers in the cluster"
17
+ end
18
+
19
+ def self.detailed_help
20
+ <<-EOF
21
+ usage: thin_cluster stop [options]
22
+
23
+ Stop multiple servers (--servers) starting on port --port
24
+ which pids are stored in <pid-file>.<port>.pid
25
+ EOF
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,7 @@
1
+ module Thin::Commands::Server
2
+ class Base < Thin::Command
3
+ def cwd
4
+ args.first || '.'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,33 @@
1
+ module Thin::Commands::Server
2
+ class Start < Base
3
+ attr_accessor :address, :port, :environment, :log_file, :daemonize, :pid_file, :user, :group, :trace, :timeout
4
+
5
+ def run
6
+ Dir.chdir cwd
7
+ server = Thin::RailsServer.new(address, port)
8
+
9
+ server.log_file = log_file
10
+ server.pid_file = pid_file
11
+ server.trace = trace
12
+ server.timeout = timeout.to_i
13
+
14
+ server.change_privilege user, group || user if user
15
+ server.start
16
+ server.daemonize if daemonize
17
+ server.listen!
18
+ end
19
+
20
+ def self.help
21
+ "Starts a new Thin web server for a Rails application."
22
+ end
23
+
24
+ def self.detailed_help
25
+ <<-EOF
26
+ usage: thin start [PATH] [options]
27
+
28
+ Starts a new Thin web server for the Rails application in PATH
29
+ (default to current directory).
30
+ EOF
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module Thin::Commands::Server
2
+ class Stop < Base
3
+ attr_accessor :pid_file, :timeout
4
+
5
+ def cwd
6
+ args.first || '.'
7
+ end
8
+
9
+ def run
10
+ error 'PID file required' unless pid_file
11
+ Dir.chdir cwd
12
+ Thin::Server.kill(pid_file, timeout.to_i)
13
+ end
14
+
15
+ def self.help
16
+ "Stops the web server running in the background."
17
+ end
18
+
19
+ def self.detailed_help
20
+ <<-EOF
21
+ usage: thin stop [PATH] [options]
22
+
23
+ Stops the web server running in the background
24
+ which PID is in the file PATH/<pid-file>
25
+ (default to <current directory>/tmp/pids/thin.pid).
26
+ EOF
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,33 @@
1
+ module Thin
2
+ NAME = 'thin'.freeze
3
+ SERVER = "#{NAME} #{VERSION::STRING}".freeze
4
+
5
+ # The basic max request size we'll try to read.
6
+ CHUNK_SIZE = 16 * 1024
7
+
8
+ CONTENT_LENGTH = 'Content-Length'.freeze
9
+ CONTENT_TYPE = 'Content-Type'.freeze
10
+
11
+ HEADER_FORMAT = "%s: %s\r\n".freeze
12
+ LF = "\n".freeze
13
+
14
+ # The standard empty 404 response when the request was not processed.
15
+ ERROR_404_RESPONSE = <<-EOS.freeze
16
+ HTTP/1.1 404 Not Found
17
+ Connection: close
18
+ Server: #{SERVER}
19
+ Content-Type: text/html
20
+
21
+ <html><h1>Page not found</h1></html>
22
+ EOS
23
+
24
+ # The standard empty 400 response when the request was invalid.
25
+ ERROR_400_RESPONSE = <<-EOS.freeze
26
+ HTTP/1.1 400 Bad Request
27
+ Connection: close
28
+ Server: #{SERVER}
29
+ Content-Type: text/html
30
+
31
+ <html><h1>Bad request</h1></html>
32
+ EOS
33
+ end
@@ -0,0 +1,122 @@
1
+ require 'etc'
2
+
3
+ module Kernel
4
+ unless respond_to? :daemonize # Already part of Ruby 1.9, yeah!
5
+ # Turns the current script into a daemon process that detaches from the console.
6
+ # It can be shut down with a TERM signal. Taken from ActiveSupport.
7
+ def daemonize
8
+ exit if fork # Parent exits, child continues.
9
+ Process.setsid # Become session leader.
10
+ exit if fork # Zap session leader. See [1].
11
+ Dir.chdir "/" # Release old working directory.
12
+ File.umask 0000 # Ensure sensible umask. Adjust as needed.
13
+ STDIN.reopen "/dev/null" # Free file descriptors and
14
+ STDOUT.reopen "/dev/null", "a" # point them somewhere sensible.
15
+ STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile.
16
+ trap("TERM") { exit }
17
+ end
18
+ end
19
+ end
20
+
21
+ module Process
22
+ # Returns +true+ the process identied by +pid+ is running.
23
+ def running?(pid)
24
+ Process.getpgid(pid) != -1
25
+ rescue Errno::ESRCH
26
+ false
27
+ end
28
+ module_function :running?
29
+ end
30
+
31
+ module Thin
32
+ # Module included in classes that can be turned into a daemon.
33
+ # Handle stuff like:
34
+ # * storing the PID in a file
35
+ # * redirecting output to the log file
36
+ # * changing processs privileges
37
+ # * killing the process gracefully
38
+ module Daemonizable
39
+ attr_accessor :pid_file, :log_file
40
+
41
+ def self.included(base)
42
+ base.extend ClassMethods
43
+ end
44
+
45
+ # Turns the current script into a daemon process that detaches from the console.
46
+ def daemonize
47
+ raise ArgumentError, 'You must specify a pid_file to deamonize' unless @pid_file
48
+
49
+ pwd = Dir.pwd # Current directory is changed during daemonization, so store it
50
+ super # Calls Kernel#daemonize
51
+ Dir.chdir pwd
52
+
53
+ trap('HUP', 'IGNORE') # Don't die upon logout
54
+
55
+ # Redirect output to the logfile
56
+ [STDOUT, STDERR].each { |f| f.reopen @log_file, 'a' } if @log_file
57
+
58
+ write_pid_file
59
+ at_exit do
60
+ log ">> Exiting!"
61
+ remove_pid_file
62
+ end
63
+ end
64
+
65
+ # Change privileges of the process
66
+ # to the specified user and group.
67
+ def change_privilege(user, group=user)
68
+ log ">> Changing process privilege to #{user}:#{group}"
69
+
70
+ uid, gid = Process.euid, Process.egid
71
+ target_uid = Etc.getpwnam(user).uid
72
+ target_gid = Etc.getgrnam(group).gid
73
+
74
+ if uid != target_uid || gid != target_gid
75
+ # Change process ownership
76
+ Process.initgroups(user, target_gid)
77
+ Process::GID.change_privilege(target_gid)
78
+ Process::UID.change_privilege(target_uid)
79
+ end
80
+ rescue Errno::EPERM => e
81
+ log "Couldn't change user and group to #{user}:#{group}: #{e}"
82
+ end
83
+
84
+ module ClassMethods
85
+ # Kill the process which PID is stored in +pid_file+.
86
+ def kill(pid_file, timeout=60)
87
+ if File.exist?(pid_file) && pid = open(pid_file).read
88
+ pid = pid.to_i
89
+ print "Sending INT signal to process #{pid} ... "
90
+ begin
91
+ Process.kill('INT', pid)
92
+ Timeout.timeout(timeout) do
93
+ sleep 0.1 while Process.running?(pid)
94
+ end
95
+ rescue Timeout::Error
96
+ print "timeout, Sending KILL signal ... "
97
+ Process.kill('KILL', pid)
98
+ end
99
+ puts "stopped!"
100
+ else
101
+ puts "Can't stop process, no PID found in #{@pid_file}"
102
+ end
103
+ rescue Errno::ESRCH # No such process
104
+ puts "process not found!"
105
+ ensure
106
+ File.delete(pid_file) rescue nil
107
+ end
108
+ end
109
+
110
+ private
111
+ def remove_pid_file
112
+ File.delete(@pid_file) if @pid_file && File.exists?(@pid_file)
113
+ end
114
+
115
+ def write_pid_file
116
+ log ">> Writing PID to #{@pid_file}"
117
+ FileUtils.mkdir_p File.dirname(@pid_file)
118
+ open(@pid_file,"w") { |f| f.write(Process.pid) }
119
+ File.chmod(0644, @pid_file)
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,57 @@
1
+ module Thin
2
+ # Handle a request and populate a response.
3
+ class Handler
4
+ # Start the handler.
5
+ # Initialize resources, open files, that kinda thing.
6
+ def start
7
+ end
8
+
9
+ # Process the incoming +request+ into the +response+
10
+ # that will be sent to the client.
11
+ # Return +true+ to send the request to the next handler
12
+ # or +false+ to stop processing the request and send the
13
+ # response to the client right away.
14
+ def process(request, response)
15
+ raise NotImplemented
16
+ end
17
+ end
18
+
19
+ # Serve a directory from a URI.
20
+ class DirHandler < Handler
21
+ def initialize(pwd)
22
+ @pwd = pwd.dup
23
+ end
24
+
25
+ def process(request, response)
26
+ path = File.join(@pwd, request.path)
27
+ if File.directory?(path)
28
+ serve_dir request.path, path, response
29
+ return true
30
+ elsif File.file?(path)
31
+ serve_file path, response
32
+ return true
33
+ end
34
+ false
35
+ end
36
+
37
+ def serve_dir(base, path, response)
38
+ response.content_type = 'text/html'
39
+ response.body << '<html><head><title>Dir listing</title></head>'
40
+ response.body << "<body><h1>Listing #{base}</h1><ul>"
41
+ Dir.entries(path).each do |entry|
42
+ next if entry == '.'
43
+ response.body << %Q{<li><a href="#{File.join(base, entry)}">#{entry}</a></li>}
44
+ end
45
+ response.body << '</ul></body></html>'
46
+ end
47
+
48
+ def serve_file(path, response)
49
+ response.content_type = MIME_TYPES[File.extname(path)] || "application/octet-stream".freeze
50
+ File.open(path, "rb") { |f| response.body << f.read }
51
+ end
52
+
53
+ def to_s
54
+ "dir #{@pwd}"
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,36 @@
1
+ module Thin
2
+ # Acts like a Hash, but allows duplicated keys
3
+ class Headers
4
+ @@allowed_duplicates = %w(Set-Cookie Set-Cookie2 Warning WWW-Authenticate)
5
+
6
+ def initialize
7
+ @sent = {}
8
+ @items = []
9
+ end
10
+
11
+ def []=(key, value)
12
+ if @sent.has_key?(key) && !@@allowed_duplicates.include?(key)
13
+ # If we don't allow duplicate for that field
14
+ # we overwrite the one that is already there
15
+ @items.assoc(key)[1] = value
16
+ else
17
+ @sent[key] = true
18
+ @items << [key, value]
19
+ end
20
+ end
21
+
22
+ def [](key)
23
+ if item = @items.assoc(key)
24
+ item[1]
25
+ end
26
+ end
27
+
28
+ def size
29
+ @items.size
30
+ end
31
+
32
+ def to_s
33
+ @items.inject('') { |out, (name, value)| out << HEADER_FORMAT % [name, value] }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,30 @@
1
+ module Thin
2
+ # To be included into classes to allow some basic logging
3
+ # that can be silented (+silent+) or made more verbose (+trace+).
4
+ module Logging
5
+ # Output extra info about the request, response, errors and stuff like that.
6
+ attr_writer :trace
7
+
8
+ # Don't output any message if +true+.
9
+ attr_accessor :silent
10
+
11
+ protected
12
+ # Log a message to the console
13
+ def log(msg)
14
+ puts msg unless @silent
15
+ end
16
+
17
+ # Log a message to the console (no line feed)
18
+ def logc(msg)
19
+ unless @silent
20
+ print msg
21
+ STDOUT.flush # Make sure the msg is shown right away
22
+ end
23
+ end
24
+
25
+ # Log a message to the console if tracing is activated
26
+ def trace(msg=nil)
27
+ puts msg || yield if @trace && !@silent
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,619 @@
1
+ module Thin
2
+ MIME_TYPES = {
3
+ '.a' => 'application/octet-stream',
4
+ '.abc' => 'text/vnd.abc',
5
+ '.acgi' => 'text/html',
6
+ '.afl' => 'video/animaflex',
7
+ '.ai' => 'application/postscript',
8
+ '.aif' => 'audio/aiff',
9
+ '.aifc' => 'audio/aiff',
10
+ '.aiff' => 'audio/aiff',
11
+ '.aip' => 'text/x-audiosoft-intra',
12
+ '.ani' => 'application/x-navi-animation',
13
+ '.aps' => 'application/mime',
14
+ '.arc' => 'application/octet-stream',
15
+ '.arj' => 'application/octet-stream',
16
+ '.art' => 'image/x-jg',
17
+ '.asf' => 'video/x-ms-asf',
18
+ '.asm' => 'text/x-asm',
19
+ '.asp' => 'text/asp',
20
+ '.asr' => 'video/x-ms-asf',
21
+ '.asx' => 'video/x-ms-asf',
22
+ '.atom' => 'application/atom+xml',
23
+ '.au' => 'audio/basic',
24
+ '.au' => 'audio/x-au',
25
+ '.avi' => 'video/avi',
26
+ '.avs' => 'video/avs-video',
27
+ '.axs' => 'application/olescript',
28
+ '.bas' => 'text/plain',
29
+ '.bcpio' => 'application/x-bcpio',
30
+ '.bin' => 'application/octet-stream',
31
+ '.bm' => 'image/bmp',
32
+ '.bmp' => 'image/bmp',
33
+ '.boo' => 'application/book',
34
+ '.book' => 'application/book',
35
+ '.boz' => 'application/x-bzip2',
36
+ '.bsh' => 'application/x-bsh',
37
+ '.bz' => ' application/x-bzip2',
38
+ '.bz' => 'application/x-bzip',
39
+ '.c' => 'text/plain',
40
+ '.cat' => 'application/octet-stream',
41
+ '.cc' => 'text/plain',
42
+ '.ccad' => 'application/clariscad',
43
+ '.cco' => 'application/x-cocoa',
44
+ '.cdf' => 'application/cdf',
45
+ '.cer' => 'application/x-x509-ca-cert',
46
+ '.cha' => 'application/x-chat',
47
+ '.chat' => 'application/x-chat',
48
+ '.class' => 'application/java',
49
+ '.class' => 'application/octet-stream',
50
+ '.clp' => 'application/x-msclip',
51
+ '.cmx' => 'image/x-cmx',
52
+ '.cod' => 'image/cis-cod',
53
+ '.com' => 'application/octet-stream',
54
+ '.com' => 'text/plain',
55
+ '.conf' => 'text/plain',
56
+ '.cpio' => 'application/x-cpio',
57
+ '.cpp' => 'text/x-c',
58
+ '.cpt' => 'application/x-cpt',
59
+ '.crd' => 'application/x-mscardfile',
60
+ '.crl' => 'application/pkcs-crl',
61
+ '.crl' => 'application/pkix-crl',
62
+ '.crt' => 'application/x-x509-ca-cert',
63
+ '.csh' => 'application/x-csh',
64
+ '.csh' => 'text/x-script.csh',
65
+ '.css' => 'text/css',
66
+ '.cxx' => 'text/plain',
67
+ '.dcr' => 'application/x-director',
68
+ '.deb' => 'application/octet-stream',
69
+ '.deepv' => 'application/x-deepv',
70
+ '.def' => 'text/plain',
71
+ '.der' => 'application/x-x509-ca-cert',
72
+ '.dhh' => 'application/david-heinemeier-hansson',
73
+ '.dif' => 'video/x-dv',
74
+ '.dir' => 'application/x-director',
75
+ '.dl' => 'video/dl',
76
+ '.dll' => 'application/octet-stream',
77
+ '.dmg' => 'application/octet-stream',
78
+ '.dms' => 'application/octet-stream',
79
+ '.doc' => 'application/msword',
80
+ '.dp' => 'application/commonground',
81
+ '.drw' => 'application/drafting',
82
+ '.dump' => 'application/octet-stream',
83
+ '.dv' => 'video/x-dv',
84
+ '.dvi' => 'application/x-dvi',
85
+ '.dwg' => 'application/acad',
86
+ '.dwg' => 'image/x-dwg',
87
+ '.dxf' => 'application/dxf',
88
+ '.dxf' => 'image/x-dwg',
89
+ '.dxr' => 'application/x-director',
90
+ '.ear' => 'application/java-archive',
91
+ '.el' => 'text/x-script.elisp',
92
+ '.elc' => 'application/x-bytecode.elisp (compiled elisp)',
93
+ '.elc' => 'application/x-elc',
94
+ '.env' => 'application/x-envoy',
95
+ '.eot' => 'application/octet-stream',
96
+ '.eps' => 'application/postscript',
97
+ '.es' => 'application/x-esrehber',
98
+ '.etx' => 'text/x-setext',
99
+ '.evy' => 'application/envoy',
100
+ '.evy' => 'application/x-envoy',
101
+ '.exe' => 'application/octet-stream',
102
+ '.f' => ': text/x-fortran',
103
+ '.f' => ': text/plain',
104
+ '.f' => ': text/x-fortran',
105
+ '.f' => 'text/x-fortran',
106
+ '.fdf' => 'application/vnd.fdf',
107
+ '.fif' => 'application/fractals',
108
+ '.fif' => 'image/fif',
109
+ '.fli' => 'video/fli',
110
+ '.fli' => 'video/x-fli',
111
+ '.flo' => 'image/florian',
112
+ '.flr' => 'x-world/x-vrml',
113
+ '.flv' => 'video/x-flv',
114
+ '.flx' => 'text/vnd.fmi.flexstor',
115
+ '.fmf' => 'video/x-atomic3d-feature',
116
+ '.for' => 'text/plain',
117
+ '.for' => 'text/x-fortran',
118
+ '.fpx' => 'image/vnd.fpx',
119
+ '.fpx' => 'image/vnd.net-fpx',
120
+ '.frl' => 'application/freeloader',
121
+ '.funk' => 'audio/make',
122
+ '.g' => ' image/g3fax',
123
+ '.g' => 'text/plain',
124
+ '.gif' => 'image/gif',
125
+ '.gl' => 'video/gl',
126
+ '.gl' => 'video/x-gl',
127
+ '.gsd' => 'audio/x-gsm',
128
+ '.gsm' => 'audio/x-gsm',
129
+ '.gsp' => 'application/x-gsp',
130
+ '.gss' => 'application/x-gss',
131
+ '.gtar' => 'application/x-gtar',
132
+ '.gz' => 'application/x-compressed',
133
+ '.gzip' => 'application/x-gzip',
134
+ '.h' => 'text/plain',
135
+ '.hdf' => 'application/x-hdf',
136
+ '.help' => 'application/x-helpfile',
137
+ '.hgl' => 'application/vnd.hp-hpgl',
138
+ '.hh' => 'text/plain',
139
+ '.hlb' => 'text/x-script',
140
+ '.hlp' => 'application/hlp',
141
+ '.hpg' => 'application/vnd.hp-hpgl',
142
+ '.hpgl' => 'application/vnd.hp-hpgl',
143
+ '.hqx' => 'application/binhex',
144
+ '.hta' => 'application/hta',
145
+ '.htc' => 'text/x-component',
146
+ '.htm' => 'text/html',
147
+ '.html' => 'text/html',
148
+ '.htmls' => 'text/html',
149
+ '.htt' => 'text/webviewhtml',
150
+ '.htx' => 'text/html',
151
+ '.ico' => 'image/x-icon',
152
+ '.idc' => 'text/plain',
153
+ '.ief' => 'image/ief',
154
+ '.iefs' => 'image/ief',
155
+ '.iges' => 'application/iges',
156
+ '.igs' => 'application/iges',
157
+ '.iii' => 'application/x-iphone',
158
+ '.ima' => 'application/x-ima',
159
+ '.imap' => 'application/x-httpd-imap',
160
+ '.img' => 'application/octet-stream',
161
+ '.inf' => 'application/inf',
162
+ '.ins' => 'application/x-internet-signup',
163
+ '.ins' => 'application/x-internett-signup',
164
+ '.ip' => 'application/x-ip2',
165
+ '.iso' => 'application/octet-stream',
166
+ '.isp' => 'application/x-internet-signup',
167
+ '.isu' => 'video/x-isvideo',
168
+ '.it' => 'audio/it',
169
+ '.iv' => 'application/x-inventor',
170
+ '.ivr' => 'i-world/i-vrml',
171
+ '.ivy' => 'application/x-livescreen',
172
+ '.jam' => 'audio/x-jam',
173
+ '.jar' => 'application/java-archive',
174
+ '.jardiff' => 'application/x-java-archive-diff',
175
+ '.jav' => 'text/plain',
176
+ '.jav' => 'text/x-java-source',
177
+ '.java' => 'text/plain',
178
+ '.java' => 'text/x-java-source',
179
+ '.jcm' => 'application/x-java-commerce',
180
+ '.jfif' => 'bnl: image/jpeg',
181
+ '.jfif' => 'image/jpeg',
182
+ '.jfif' => 'image/pipeg',
183
+ '.jfif' => 'image/pjpeg',
184
+ '.jng' => 'image/x-jng',
185
+ '.jnlp' => 'application/x-java-jnlp-file',
186
+ '.jpe' => 'image/jpeg',
187
+ '.jpeg' => 'image/jpeg',
188
+ '.jpg' => 'image/jpeg',
189
+ '.jps' => 'image/x-jps',
190
+ '.js' => 'application/x-javascript',
191
+ '.js' => 'text/javascript',
192
+ '.jut' => 'image/jutvision',
193
+ '.kar' => 'audio/midi',
194
+ '.kar' => 'music/x-karaoke',
195
+ '.ksh' => 'application/x-ksh',
196
+ '.ksh' => 'text/x-script.ksh',
197
+ '.la' => 'audio/nspaudio',
198
+ '.la' => 'audio/x-nspaudio',
199
+ '.lam' => 'audio/x-liveaudio',
200
+ '.latex' => 'application/x-latex',
201
+ '.lha' => 'application/lha',
202
+ '.lha' => 'application/octet-stream',
203
+ '.lha' => 'application/x-lha',
204
+ '.lhx' => 'application/octet-stream',
205
+ '.list' => 'text/plain',
206
+ '.lma' => 'audio/nspaudio',
207
+ '.lma' => 'audio/x-nspaudio',
208
+ '.log' => 'text/plain',
209
+ '.lsf' => 'video/x-la-asf',
210
+ '.lsp' => 'application/x-lisp',
211
+ '.lsp' => 'text/x-script.lisp',
212
+ '.lst' => 'text/plain',
213
+ '.lsx' => 'text/x-la-asf',
214
+ '.lsx' => 'video/x-la-asf',
215
+ '.ltx' => 'application/x-latex',
216
+ '.lzh' => 'application/octet-stream',
217
+ '.lzh' => 'application/x-lzh',
218
+ '.lzx' => 'application/lzx',
219
+ '.lzx' => 'application/octet-stream',
220
+ '.lzx' => 'application/x-lzx',
221
+ '.m' => ': application/x-msmediaview',
222
+ '.m' => ': application/x-msmediaview',
223
+ '.m' => ': video/mpeg',
224
+ '.m' => ': audio/mpeg',
225
+ '.m' => ': video/mpeg',
226
+ '.m' => ': audio/x-mpegurl',
227
+ '.m' => 'text/x-m',
228
+ '.man' => 'application/x-troff-man',
229
+ '.map' => 'application/x-navimap',
230
+ '.mar' => 'text/plain',
231
+ '.mbd' => 'application/mbedlet',
232
+ '.mc' => 'application/x-magic-cap-package-1.0',
233
+ '.mcd' => 'application/mcad',
234
+ '.mcd' => 'application/x-mathcad',
235
+ '.mcf' => 'image/vasa',
236
+ '.mcf' => 'text/mcf',
237
+ '.mcp' => 'application/netmc',
238
+ '.mdb' => 'application/x-msaccess',
239
+ '.me' => 'application/x-troff-me',
240
+ '.mht' => 'message/rfc822',
241
+ '.mhtml' => 'message/rfc822',
242
+ '.mid' => 'audio/mid',
243
+ '.mid' => 'audio/midi',
244
+ '.mid' => 'audio/x-mid',
245
+ '.mid' => 'audio/x-midi',
246
+ '.midi' => 'audio/midi',
247
+ '.midi' => 'audio/x-mid',
248
+ '.midi' => 'audio/x-midi',
249
+ '.mif' => 'application/x-frame',
250
+ '.mif' => 'application/x-mif',
251
+ '.mime' => 'message/rfc822',
252
+ '.mime' => 'www/mime',
253
+ '.mjf' => 'audio/x-vnd.audioexplosion.mjuicemediafile',
254
+ '.mjpg' => 'video/x-motion-jpeg',
255
+ '.mm' => 'application/base64',
256
+ '.mm' => 'application/x-meme',
257
+ '.mme' => 'application/base64',
258
+ '.mml' => 'text/mathml',
259
+ '.mng' => 'video/x-mng',
260
+ '.mod' => 'audio/mod',
261
+ '.moov' => 'video/quicktime',
262
+ '.mov' => 'video/quicktime',
263
+ '.movie' => 'video/x-sgi-movie',
264
+ '.mp' => ' audio/mpeg',
265
+ '.mp' => ' audio/mpeg',
266
+ '.mpa' => 'audio/mpeg',
267
+ '.mpc' => 'application/x-project',
268
+ '.mpe' => 'video/mpeg',
269
+ '.mpeg' => 'video/mpeg',
270
+ '.mpg' => 'video/mpeg',
271
+ '.mpga' => 'audio/mpeg',
272
+ '.mpp' => 'application/vnd.ms-project',
273
+ '.mpt' => 'application/x-project',
274
+ '.mpv' => ' video/mpeg',
275
+ '.mpv' => 'application/x-project',
276
+ '.mpx' => 'application/x-project',
277
+ '.mrc' => 'application/marc',
278
+ '.ms' => 'application/x-troff-ms',
279
+ '.msi' => 'application/octet-stream',
280
+ '.msm' => 'application/octet-stream',
281
+ '.msp' => 'application/octet-stream',
282
+ '.mv' => 'video/x-sgi-movie',
283
+ '.mvb' => 'application/x-msmediaview',
284
+ '.my' => 'audio/make',
285
+ '.mzz' => 'application/x-vnd.audioexplosion.mzz',
286
+ '.nap' => 'image/naplps',
287
+ '.naplps' => 'image/naplps',
288
+ '.nc' => 'application/x-netcdf',
289
+ '.ncm' => 'application/vnd.nokia.configuration-message',
290
+ '.nif' => 'image/x-niff',
291
+ '.niff' => 'image/x-niff',
292
+ '.nix' => 'application/x-mix-transfer',
293
+ '.nsc' => 'application/x-conference',
294
+ '.nvd' => 'application/x-navidoc',
295
+ '.nws' => 'message/rfc822',
296
+ '.o' => 'application/octet-stream',
297
+ '.oda' => 'application/oda',
298
+ '.omc' => 'application/x-omc',
299
+ '.omcd' => 'application/x-omcdatamaker',
300
+ '.omcr' => 'application/x-omcregerator',
301
+ '.p' => ': application/pkcs10',
302
+ '.p' => ': application/x-pkcs10',
303
+ '.p' => ': application/pkcs-12',
304
+ '.p' => ': application/x-pkcs12',
305
+ '.p' => ': application/x-pkcs7-signature',
306
+ '.p' => ': application/x-pkcs7-certificates',
307
+ '.p' => ': application/pkcs7-mime',
308
+ '.p' => ': application/x-pkcs7-mime',
309
+ '.p' => ': application/pkcs7-mime',
310
+ '.p' => ': application/x-pkcs7-mime',
311
+ '.p' => ': application/x-pkcs7-certreqresp',
312
+ '.p' => ': application/pkcs7-signature',
313
+ '.p' => ': application/x-pkcs7-signature',
314
+ '.p' => 'text/x-pascal',
315
+ '.part' => 'application/pro_eng',
316
+ '.pas' => 'text/pascal',
317
+ '.pbm' => 'image/x-portable-bitmap',
318
+ '.pcl' => 'application/vnd.hp-pcl',
319
+ '.pcl' => 'application/x-pcl',
320
+ '.pct' => 'image/x-pict',
321
+ '.pcx' => 'image/x-pcx',
322
+ '.pdb' => 'application/x-pilot',
323
+ '.pdf' => 'application/pdf',
324
+ '.pem' => 'application/x-x509-ca-cert',
325
+ '.pfunk' => 'audio/make',
326
+ '.pfunk' => 'audio/make.my.funk',
327
+ '.pfx' => 'application/x-pkcs12',
328
+ '.pgm' => 'image/x-portable-graymap',
329
+ '.pgm' => 'image/x-portable-greymap',
330
+ '.pic' => 'image/pict',
331
+ '.pict' => 'image/pict',
332
+ '.pkg' => 'application/x-newton-compatible-pkg',
333
+ '.pko' => 'application/vnd.ms-pki.pko',
334
+ '.pko' => 'application/ynd.ms-pkipko',
335
+ '.pl' => 'application/x-perl',
336
+ '.pl' => 'text/plain',
337
+ '.pl' => 'text/x-script.perl',
338
+ '.plx' => 'application/x-pixclscript',
339
+ '.pm' => ' application/x-pagemaker',
340
+ '.pm' => ' application/x-pagemaker',
341
+ '.pm' => 'application/x-perl',
342
+ '.pm' => 'image/x-xpixmap',
343
+ '.pm' => 'text/x-script.perl-module',
344
+ '.pma' => 'application/x-perfmon',
345
+ '.pmc' => 'application/x-perfmon',
346
+ '.pml' => 'application/x-perfmon',
347
+ '.pmr' => 'application/x-perfmon',
348
+ '.pmw' => 'application/x-perfmon',
349
+ '.png' => 'image/png',
350
+ '.pnm' => 'application/x-portable-anymap',
351
+ '.pnm' => 'image/x-portable-anymap',
352
+ '.pot' => ' application/vnd.ms-powerpoint',
353
+ '.pot' => 'application/mspowerpoint',
354
+ '.pot' => 'application/vnd.ms-powerpoint',
355
+ '.pov' => 'model/x-pov',
356
+ '.ppa' => 'application/vnd.ms-powerpoint',
357
+ '.ppm' => 'image/x-portable-pixmap',
358
+ '.pps' => 'application/mspowerpoint',
359
+ '.ppt' => 'application/mspowerpoint',
360
+ '.ppz' => 'application/mspowerpoint',
361
+ '.prc' => 'application/x-pilot',
362
+ '.pre' => 'application/x-freelance',
363
+ '.prf' => 'application/pics-rules',
364
+ '.prt' => 'application/pro_eng',
365
+ '.ps' => 'application/postscript',
366
+ '.psd' => 'application/octet-stream',
367
+ '.pub' => 'application/x-mspublisher',
368
+ '.pvu' => 'paleovu/x-pv',
369
+ '.pwz' => 'application/vnd.ms-powerpoint',
370
+ '.py' => 'text/x-script.phyton',
371
+ '.pyc' => 'applicaiton/x-bytecode.python',
372
+ '.qcp' => 'audio/vnd.qcelp',
373
+ '.qd' => ' x-world/x-3dmf',
374
+ '.qd' => ': x-world/x-3dmf',
375
+ '.qif' => 'image/x-quicktime',
376
+ '.qt' => 'video/quicktime',
377
+ '.qtc' => 'video/x-qtc',
378
+ '.qti' => 'image/x-quicktime',
379
+ '.qtif' => 'image/x-quicktime',
380
+ '.ra' => 'audio/x-pn-realaudio',
381
+ '.ra' => 'audio/x-pn-realaudio-plugin',
382
+ '.ra' => 'audio/x-realaudio',
383
+ '.ram' => 'audio/x-pn-realaudio',
384
+ '.rar' => 'application/x-rar-compressed',
385
+ '.ras' => 'application/x-cmu-raster',
386
+ '.ras' => 'image/cmu-raster',
387
+ '.ras' => 'image/x-cmu-raster',
388
+ '.rast' => 'image/cmu-raster',
389
+ '.rexx' => 'text/x-script.rexx',
390
+ '.rf' => 'image/vnd.rn-realflash',
391
+ '.rgb' => 'image/x-rgb',
392
+ '.rm' => 'application/vnd.rn-realmedia',
393
+ '.rm' => 'audio/x-pn-realaudio',
394
+ '.rmi' => 'audio/mid',
395
+ '.rmm' => 'audio/x-pn-realaudio',
396
+ '.rmp' => 'audio/x-pn-realaudio',
397
+ '.rmp' => 'audio/x-pn-realaudio-plugin',
398
+ '.rng' => 'application/ringing-tones',
399
+ '.rng' => 'application/vnd.nokia.ringing-tone',
400
+ '.rnx' => 'application/vnd.rn-realplayer',
401
+ '.roff' => 'application/x-troff',
402
+ '.rp' => 'image/vnd.rn-realpix',
403
+ '.rpm' => 'application/x-redhat-package-manager',
404
+ '.rpm' => 'audio/x-pn-realaudio-plugin',
405
+ '.rss' => 'text/xml',
406
+ '.rt' => 'text/richtext',
407
+ '.rt' => 'text/vnd.rn-realtext',
408
+ '.rtf' => 'application/rtf',
409
+ '.rtf' => 'application/x-rtf',
410
+ '.rtf' => 'text/richtext',
411
+ '.rtx' => 'application/rtf',
412
+ '.rtx' => 'text/richtext',
413
+ '.run' => 'application/x-makeself',
414
+ '.rv' => 'video/vnd.rn-realvideo',
415
+ '.s' => ': audio/s3m',
416
+ '.s' => 'text/x-asm',
417
+ '.saveme' => 'application/octet-stream',
418
+ '.sbk' => 'application/x-tbook',
419
+ '.scd' => 'application/x-msschedule',
420
+ '.scm' => 'application/x-lotusscreencam',
421
+ '.scm' => 'text/x-script.guile',
422
+ '.scm' => 'text/x-script.scheme',
423
+ '.scm' => 'video/x-scm',
424
+ '.sct' => 'text/scriptlet',
425
+ '.sdml' => 'text/plain',
426
+ '.sdp' => 'application/sdp',
427
+ '.sdp' => 'application/x-sdp',
428
+ '.sdr' => 'application/sounder',
429
+ '.sea' => 'application/sea',
430
+ '.sea' => 'application/x-sea',
431
+ '.set' => 'application/set',
432
+ '.setpay' => 'application/set-payment-initiation',
433
+ '.setreg' => 'application/set-registration-initiation',
434
+ '.sgm' => 'text/sgml',
435
+ '.sgm' => 'text/x-sgml',
436
+ '.sgml' => 'text/sgml',
437
+ '.sgml' => 'text/x-sgml',
438
+ '.sh' => 'application/x-bsh',
439
+ '.sh' => 'application/x-sh',
440
+ '.sh' => 'application/x-shar',
441
+ '.sh' => 'text/x-script.sh',
442
+ '.shar' => 'application/x-bsh',
443
+ '.shar' => 'application/x-shar',
444
+ '.shtml' => 'text/html',
445
+ '.shtml' => 'text/x-server-parsed-html',
446
+ '.sid' => 'audio/x-psid',
447
+ '.sit' => 'application/x-sit',
448
+ '.sit' => 'application/x-stuffit',
449
+ '.skd' => 'application/x-koan',
450
+ '.skm' => 'application/x-koan',
451
+ '.skp' => 'application/x-koan',
452
+ '.skt' => 'application/x-koan',
453
+ '.sl' => 'application/x-seelogo',
454
+ '.smi' => 'application/smil',
455
+ '.smil' => 'application/smil',
456
+ '.snd' => 'audio/basic',
457
+ '.snd' => 'audio/x-adpcm',
458
+ '.sol' => 'application/solids',
459
+ '.spc' => 'application/x-pkcs7-certificates',
460
+ '.spc' => 'text/x-speech',
461
+ '.spl' => 'application/futuresplash',
462
+ '.spr' => 'application/x-sprite',
463
+ '.sprite' => 'application/x-sprite',
464
+ '.src' => 'application/x-wais-source',
465
+ '.ssi' => 'text/x-server-parsed-html',
466
+ '.ssm' => 'application/streamingmedia',
467
+ '.sst' => 'application/vnd.ms-pki.certstore',
468
+ '.sst' => 'application/vnd.ms-pkicertstore',
469
+ '.step' => 'application/step',
470
+ '.stl' => 'application/sla',
471
+ '.stl' => 'application/vnd.ms-pki.stl',
472
+ '.stl' => 'application/vnd.ms-pkistl',
473
+ '.stl' => 'application/x-navistyle',
474
+ '.stm' => 'text/html',
475
+ '.stp' => 'application/step',
476
+ '.sv' => 'pio: application/x-sv4cpio',
477
+ '.sv' => 'rc: application/x-sv4crc',
478
+ '.svf' => 'image/vnd.dwg',
479
+ '.svf' => 'image/x-dwg',
480
+ '.svg' => 'image/svg+xml',
481
+ '.svr' => 'application/x-world',
482
+ '.svr' => 'x-world/x-svr',
483
+ '.swf' => 'application/x-shockwave-flash',
484
+ '.t' => 'application/x-troff',
485
+ '.talk' => 'text/x-speech',
486
+ '.tar' => 'application/x-tar',
487
+ '.tbk' => 'application/toolbook',
488
+ '.tbk' => 'application/x-tbook',
489
+ '.tcl' => 'application/x-tcl',
490
+ '.tcl' => 'text/x-script.tcl',
491
+ '.tcsh' => 'text/x-script.tcsh',
492
+ '.tex' => 'application/x-tex',
493
+ '.texi' => 'application/x-texinfo',
494
+ '.texinfo' => 'application/x-texinfo',
495
+ '.text' => 'application/plain',
496
+ '.text' => 'text/plain',
497
+ '.tgz' => 'application/gnutar',
498
+ '.tgz' => 'application/x-compressed',
499
+ '.tif' => 'image/tiff',
500
+ '.tiff' => 'image/tiff',
501
+ '.tk' => 'application/x-tcl',
502
+ '.tr' => 'application/x-troff',
503
+ '.trm' => 'application/x-msterminal',
504
+ '.tsi' => 'audio/tsp-audio',
505
+ '.tsp' => 'application/dsptype',
506
+ '.tsp' => 'audio/tsplayer',
507
+ '.tsv' => 'text/tab-separated-values',
508
+ '.turbot' => 'image/florian',
509
+ '.txt' => 'text/plain',
510
+ '.uil' => 'text/x-uil',
511
+ '.uls' => 'text/iuls',
512
+ '.uni' => 'text/uri-list',
513
+ '.unis' => 'text/uri-list',
514
+ '.unv' => 'application/i-deas',
515
+ '.uri' => 'text/uri-list',
516
+ '.uris' => 'text/uri-list',
517
+ '.ustar' => 'application/x-ustar',
518
+ '.ustar' => 'multipart/x-ustar',
519
+ '.uu' => 'application/octet-stream',
520
+ '.uu' => 'text/x-uuencode',
521
+ '.uue' => 'text/x-uuencode',
522
+ '.vcd' => 'application/x-cdlink',
523
+ '.vcf' => 'text/x-vcard',
524
+ '.vcs' => 'text/x-vcalendar',
525
+ '.vda' => 'application/vda',
526
+ '.vdo' => 'video/vdo',
527
+ '.vew' => 'application/groupwise',
528
+ '.viv' => 'video/vivo',
529
+ '.viv' => 'video/vnd.vivo',
530
+ '.vivo' => 'video/vivo',
531
+ '.vivo' => 'video/vnd.vivo',
532
+ '.vmd' => 'application/vocaltec-media-desc',
533
+ '.vmf' => 'application/vocaltec-media-file',
534
+ '.voc' => 'audio/voc',
535
+ '.voc' => 'audio/x-voc',
536
+ '.vos' => 'video/vosaic',
537
+ '.vox' => 'audio/voxware',
538
+ '.vqe' => 'audio/x-twinvq-plugin',
539
+ '.vqf' => 'audio/x-twinvq',
540
+ '.vql' => 'audio/x-twinvq-plugin',
541
+ '.vrml' => 'application/x-vrml',
542
+ '.vrml' => 'model/vrml',
543
+ '.vrml' => 'x-world/x-vrml',
544
+ '.vrt' => 'x-world/x-vrt',
545
+ '.vsd' => 'application/x-visio',
546
+ '.vst' => 'application/x-visio',
547
+ '.vsw' => 'application/x-visio',
548
+ '.w' => ': application/wordperfect6.0',
549
+ '.w' => ': application/wordperfect6.1',
550
+ '.w' => ': application/msword',
551
+ '.war' => 'application/java-archive',
552
+ '.wav' => 'audio/wav',
553
+ '.wav' => 'audio/x-wav',
554
+ '.wb' => ' application/x-qpro',
555
+ '.wbmp' => 'image/vnd.wap.wbmp',
556
+ '.wbmp' => 'image/vnd.wap.wbmp',
557
+ '.wcm' => 'application/vnd.ms-works',
558
+ '.wdb' => 'application/vnd.ms-works',
559
+ '.web' => 'application/vnd.xara',
560
+ '.wiz' => 'application/msword',
561
+ '.wk' => ' application/x-123',
562
+ '.wks' => 'application/vnd.ms-works',
563
+ '.wmf' => 'application/x-msmetafile',
564
+ '.wmf' => 'windows/metafile',
565
+ '.wml' => 'text/vnd.wap.wml',
566
+ '.wmlc' => 'application/vnd.wap.wmlc',
567
+ '.wmls' => 'text/vnd.wap.wmlscript',
568
+ '.wmlsc' => 'application/vnd.wap.wmlscriptc',
569
+ '.wmv' => 'video/x-ms-wmv',
570
+ '.word' => 'application/msword',
571
+ '.wp' => ' application/wordperfect',
572
+ '.wp' => ' application/wordperfect',
573
+ '.wp' => 'application/wordperfect',
574
+ '.wpd' => 'application/wordperfect',
575
+ '.wps' => 'application/vnd.ms-works',
576
+ '.wq' => ' application/x-lotus',
577
+ '.wri' => 'application/mswrite',
578
+ '.wrl' => 'application/x-world',
579
+ '.wsc' => 'text/scriplet',
580
+ '.wsrc' => 'application/x-wais-source',
581
+ '.wtk' => 'application/x-wintalk',
582
+ '.x' => 'ng: image/png',
583
+ '.xaf' => 'x-world/x-vrml',
584
+ '.xbm' => 'image/xbm',
585
+ '.xdr' => 'video/x-amt-demorun',
586
+ '.xgz' => 'xgl/drawing',
587
+ '.xhtml' => 'application/xhtml+xml',
588
+ '.xif' => 'image/vnd.xiff',
589
+ '.xl' => 'application/excel',
590
+ '.xla' => 'application/excel',
591
+ '.xlb' => 'application/excel',
592
+ '.xlc' => 'application/excel',
593
+ '.xld' => 'application/excel',
594
+ '.xlk' => 'application/excel',
595
+ '.xll' => 'application/excel',
596
+ '.xlm' => 'application/excel',
597
+ '.xls' => 'application/excel',
598
+ '.xlt' => 'application/excel',
599
+ '.xlv' => 'application/excel',
600
+ '.xlw' => 'application/excel',
601
+ '.xm' => 'audio/xm',
602
+ '.xml' => 'text/xml',
603
+ '.xmz' => 'xgl/movie',
604
+ '.xof' => 'x-world/x-vrml',
605
+ '.xpi' => 'application/x-xpinstall',
606
+ '.xpix' => 'application/x-vnd.ls-xpix',
607
+ '.xpm' => 'image/x-xpixmap',
608
+ '.xpm' => 'image/xpm',
609
+ '.xsl' => 'application/xslt+xml',
610
+ '.xsr' => 'video/x-amt-showrun',
611
+ '.xwd' => 'image/x-xwd',
612
+ '.xwd' => 'image/x-xwindowdump',
613
+ '.xyz' => 'chemical/x-pdb',
614
+ '.z' => 'application/x-compressed',
615
+ '.zip' => 'application/zip',
616
+ '.zoo' => 'application/octet-stream',
617
+ '.zsh' => 'text/x-script.zsh'
618
+ }
619
+ end