harbor 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Rakefile +76 -0
- data/bin/harbor +7 -0
- data/lib/harbor.rb +17 -0
- data/lib/harbor/accessor_injector.rb +30 -0
- data/lib/harbor/application.rb +172 -0
- data/lib/harbor/auth/basic.rb +51 -0
- data/lib/harbor/block_io.rb +63 -0
- data/lib/harbor/cache.rb +90 -0
- data/lib/harbor/cache/disk.rb +99 -0
- data/lib/harbor/cache/item.rb +48 -0
- data/lib/harbor/cache/memory.rb +35 -0
- data/lib/harbor/cascade.rb +75 -0
- data/lib/harbor/console.rb +34 -0
- data/lib/harbor/container.rb +134 -0
- data/lib/harbor/contrib/debug.rb +236 -0
- data/lib/harbor/contrib/session/data_mapper.rb +74 -0
- data/lib/harbor/daemon.rb +105 -0
- data/lib/harbor/errors.rb +49 -0
- data/lib/harbor/events.rb +45 -0
- data/lib/harbor/exception_notifier.rb +59 -0
- data/lib/harbor/file.rb +66 -0
- data/lib/harbor/file_store.rb +69 -0
- data/lib/harbor/file_store/file.rb +100 -0
- data/lib/harbor/file_store/local.rb +71 -0
- data/lib/harbor/file_store/mosso.rb +154 -0
- data/lib/harbor/file_store/mosso/private.rb +8 -0
- data/lib/harbor/generator.rb +56 -0
- data/lib/harbor/generator/help.rb +34 -0
- data/lib/harbor/generator/setup.rb +82 -0
- data/lib/harbor/generator/skeletons/basic/config.ru.skel +21 -0
- data/lib/harbor/generator/skeletons/basic/lib/appname.rb.skel +49 -0
- data/lib/harbor/generator/skeletons/basic/lib/appname/controllers/home.rb +9 -0
- data/lib/harbor/generator/skeletons/basic/lib/appname/views/home/index.html.erb.skel +23 -0
- data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/application.html.erb.skel +48 -0
- data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/exception.html.erb.skel +13 -0
- data/lib/harbor/generator/skeletons/basic/lib/appname/views/layouts/login.html.erb.skel +11 -0
- data/lib/harbor/generator/skeletons/basic/log/development.log +0 -0
- data/lib/harbor/hooks.rb +105 -0
- data/lib/harbor/json_cookies.rb +37 -0
- data/lib/harbor/layouts.rb +61 -0
- data/lib/harbor/locale.rb +50 -0
- data/lib/harbor/locales.txt +22 -0
- data/lib/harbor/logging.rb +39 -0
- data/lib/harbor/logging/appenders/email.rb +84 -0
- data/lib/harbor/logging/request_logger.rb +34 -0
- data/lib/harbor/mail_servers/abstract.rb +12 -0
- data/lib/harbor/mail_servers/sendmail.rb +19 -0
- data/lib/harbor/mail_servers/smtp.rb +25 -0
- data/lib/harbor/mail_servers/test.rb +17 -0
- data/lib/harbor/mailer.rb +96 -0
- data/lib/harbor/messages.rb +17 -0
- data/lib/harbor/mime.rb +206 -0
- data/lib/harbor/plugin.rb +52 -0
- data/lib/harbor/plugin_list.rb +38 -0
- data/lib/harbor/request.rb +138 -0
- data/lib/harbor/response.rb +281 -0
- data/lib/harbor/router.rb +112 -0
- data/lib/harbor/script.rb +155 -0
- data/lib/harbor/session.rb +75 -0
- data/lib/harbor/session/abstract.rb +27 -0
- data/lib/harbor/session/cookie.rb +17 -0
- data/lib/harbor/shellwords.rb +26 -0
- data/lib/harbor/test/mailer.rb +10 -0
- data/lib/harbor/test/request.rb +28 -0
- data/lib/harbor/test/response.rb +17 -0
- data/lib/harbor/test/session.rb +11 -0
- data/lib/harbor/test/test.rb +22 -0
- data/lib/harbor/version.rb +3 -0
- data/lib/harbor/view.rb +89 -0
- data/lib/harbor/view_context.rb +134 -0
- data/lib/harbor/view_context/helpers.rb +7 -0
- data/lib/harbor/view_context/helpers/cache.rb +77 -0
- data/lib/harbor/view_context/helpers/form.rb +34 -0
- data/lib/harbor/view_context/helpers/html.rb +26 -0
- data/lib/harbor/view_context/helpers/text.rb +120 -0
- data/lib/harbor/view_context/helpers/url.rb +11 -0
- data/lib/harbor/xml_view.rb +57 -0
- data/lib/harbor/zipped_io.rb +203 -0
- data/lib/vendor/cloudfiles-1.3.0/cloudfiles.rb +77 -0
- data/lib/vendor/cloudfiles-1.3.0/cloudfiles/authentication.rb +46 -0
- data/lib/vendor/cloudfiles-1.3.0/cloudfiles/connection.rb +280 -0
- data/lib/vendor/cloudfiles-1.3.0/cloudfiles/container.rb +260 -0
- data/lib/vendor/cloudfiles-1.3.0/cloudfiles/storage_object.rb +253 -0
- metadata +155 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
gem "logging"
|
2
|
+
require "logging"
|
3
|
+
require Pathname(__FILE__).dirname + "logging/request_logger"
|
4
|
+
|
5
|
+
Logging.configure do
|
6
|
+
|
7
|
+
logger 'root' do
|
8
|
+
level :debug
|
9
|
+
appenders 'app'
|
10
|
+
end
|
11
|
+
|
12
|
+
logger 'request' do
|
13
|
+
additive false
|
14
|
+
level :info
|
15
|
+
appenders 'request'
|
16
|
+
end
|
17
|
+
|
18
|
+
logger 'error' do
|
19
|
+
additive false
|
20
|
+
level :error
|
21
|
+
appenders 'error'
|
22
|
+
end
|
23
|
+
|
24
|
+
appender 'app' do
|
25
|
+
type 'File'
|
26
|
+
filename 'log/app.log'
|
27
|
+
end
|
28
|
+
|
29
|
+
appender 'request' do
|
30
|
+
type 'File'
|
31
|
+
filename 'log/request.log'
|
32
|
+
end
|
33
|
+
|
34
|
+
appender 'error' do
|
35
|
+
type 'File'
|
36
|
+
filename 'log/error.log'
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Harbor
|
2
|
+
module LogAppenders
|
3
|
+
|
4
|
+
class Email < Logging::Appender
|
5
|
+
|
6
|
+
attr_accessor :duplicate_subject_delivery_threshold
|
7
|
+
|
8
|
+
def initialize(container, from, *addresses)
|
9
|
+
@container = container
|
10
|
+
@from = from
|
11
|
+
@addresses = addresses
|
12
|
+
@tracked_subjects = []
|
13
|
+
|
14
|
+
# Deliver emails with exact-match subjects only every 10 Minutes
|
15
|
+
@duplicate_subject_delivery_threshold = 60 * 10
|
16
|
+
|
17
|
+
super("exception_notifier", :level => :error)
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(event)
|
21
|
+
unless @level > event.level
|
22
|
+
flush_expired_subjects
|
23
|
+
|
24
|
+
data = event.data
|
25
|
+
subject = data.split($/, 2)[0]
|
26
|
+
|
27
|
+
if tracked_subject = @tracked_subjects.detect { |tracked_subject| tracked_subject.subject == subject }
|
28
|
+
tracked_subject.occurances << Time.now
|
29
|
+
|
30
|
+
# Don't send the email if we've already sent one within the time threshold
|
31
|
+
return false if (Time.now - tracked_subject.sent_at) < @duplicate_subject_delivery_threshold
|
32
|
+
else
|
33
|
+
tracked_subject = TrackedSubject.new(subject)
|
34
|
+
tracked_subject.occurances << Time.now
|
35
|
+
|
36
|
+
@tracked_subjects << tracked_subject
|
37
|
+
end
|
38
|
+
|
39
|
+
mailer = @container.get(:mailer)
|
40
|
+
mailer.from = @from
|
41
|
+
mailer.to = @addresses
|
42
|
+
|
43
|
+
data << "\n(from: #{`hostname`.chomp}, PID: #{Process.pid})"
|
44
|
+
|
45
|
+
mailer.subject = "[ERROR] #{subject}"
|
46
|
+
mailer["x_priority"] = "1 (Highest)"
|
47
|
+
mailer["x_msmail_priority"] = "High"
|
48
|
+
mailer.text = if tracked_subject.occurances.size > 1
|
49
|
+
"Repeated #{tracked_subject.occurances.size} times since #{tracked_subject.sent_at.strftime('%Y-%m-%d %R%z')}\n\n#{data}"
|
50
|
+
else
|
51
|
+
data
|
52
|
+
end
|
53
|
+
mailer.send!
|
54
|
+
|
55
|
+
tracked_subject.occurances.clear
|
56
|
+
tracked_subject.sent_at = Time.now
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
##
|
63
|
+
# Flushes items from the @tracked_subjects array when they are no longer useful
|
64
|
+
##
|
65
|
+
def flush_expired_subjects
|
66
|
+
@tracked_subjects.reject! do |tracked_subject|
|
67
|
+
tracked_subject.occurances.empty? && (Time.now - tracked_subject.sent_at) >= @duplicate_subject_delivery_threshold
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
class Email::TrackedSubject
|
74
|
+
attr_accessor :sent_at
|
75
|
+
attr_reader :subject, :occurances
|
76
|
+
|
77
|
+
def initialize(subject)
|
78
|
+
@subject = subject
|
79
|
+
@occurances = []
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Harbor
|
2
|
+
class RequestLogger
|
3
|
+
##
|
4
|
+
# Logs requests and their params the configured request logger.
|
5
|
+
#
|
6
|
+
# Format:
|
7
|
+
#
|
8
|
+
# #application #time #duration #ip #method #uri #status #params
|
9
|
+
# [PhotoManagement] [04-02-2009 @ 14:22:40] [0.12s] [64.134.226.23] [GET] /products (200) {"order" => "desc"}
|
10
|
+
##
|
11
|
+
def self.info(request, response, start_time, end_time)
|
12
|
+
case
|
13
|
+
when response.status >= 500 then status = "\033[0;31m#{response.status}\033[0m" # prints the status value in red
|
14
|
+
when response.status >= 400 then status = "\033[0;33m#{response.status}\033[0m" # prints the status value in yellow
|
15
|
+
else status = "\033[0;32m#{response.status}\033[0m" # prints the status value in green
|
16
|
+
end
|
17
|
+
|
18
|
+
message = "[#{self.class}] [#{start_time.strftime('%m-%d-%Y @ %H:%M:%S')}] [#{"%2.2fs" % (end_time - start_time)}] [#{request.remote_ip}] [#{request.request_method}] #{request.path_info} (#{status})"
|
19
|
+
message << "\t #{request.params.inspect}" unless request.params.empty?
|
20
|
+
message << "\n"
|
21
|
+
|
22
|
+
if (request_logger = Logging::Logger["request"]).info?
|
23
|
+
request_logger << message
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.error(exception, request, response, trace)
|
28
|
+
Logging::Logger['error'] << trace
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Harbor::Application.register_event(:request_complete) { |*args| Harbor::RequestLogger.info(*args) }
|
34
|
+
Harbor::Application.register_event(:exception) { |*args| Harbor::RequestLogger.error(*args) }
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Harbor
|
2
|
+
module MailServers
|
3
|
+
class Abstract
|
4
|
+
def initialize(config = {})
|
5
|
+
end
|
6
|
+
|
7
|
+
def deliver(message_or_messages)
|
8
|
+
raise NotImplementedError.new("Classes extending #{self.class.name} must implement #deliver(message_or_messages).")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Harbor
|
2
|
+
module MailServers
|
3
|
+
class Sendmail < Abstract
|
4
|
+
def initialize(config = {})
|
5
|
+
@sendmail = config[:sendmail] || `which sendmail`.chomp
|
6
|
+
end
|
7
|
+
|
8
|
+
def deliver(message_or_messages)
|
9
|
+
messages = Array === message_or_messages ? message_or_messages : [message_or_messages]
|
10
|
+
|
11
|
+
messages.each do |message|
|
12
|
+
sendmail = ::IO.popen("#{@sendmail} -i -t", "w+")
|
13
|
+
sendmail.puts message.to_s
|
14
|
+
sendmail.close
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "net/smtp"
|
2
|
+
|
3
|
+
module Harbor
|
4
|
+
module MailServers
|
5
|
+
class SmtpServer < Abstract
|
6
|
+
def initialize(config = {})
|
7
|
+
@config = {}
|
8
|
+
raise ArgumentError("You must provide the :address to your SMTP server in the SmtpServer config.") unless config.has_key?(:address)
|
9
|
+
|
10
|
+
@config[:address] = config[:address]
|
11
|
+
@config[:port] = config.fetch(:port, 25)
|
12
|
+
end
|
13
|
+
|
14
|
+
def deliver(message_or_messages)
|
15
|
+
messages = Array === message_or_messages ? message_or_messages : [message_or_messages]
|
16
|
+
|
17
|
+
Net::SMTP.start(@config[:address], @config[:port]) do |smtp|
|
18
|
+
messages.each do |message|
|
19
|
+
smtp.send_message(message.to_s, message.from, message.to)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Harbor
|
2
|
+
module MailServers
|
3
|
+
class Test < Abstract
|
4
|
+
attr_accessor :messages
|
5
|
+
|
6
|
+
def initialize(config = {})
|
7
|
+
self.messages = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def deliver(message_or_messages)
|
11
|
+
messages = Array === message_or_messages ? message_or_messages : [message_or_messages]
|
12
|
+
|
13
|
+
messages.push(*messages)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require "cgi"
|
2
|
+
|
3
|
+
gem "mail_builder"
|
4
|
+
require "mail_builder"
|
5
|
+
|
6
|
+
require Pathname(__FILE__).dirname + "mail_servers/abstract"
|
7
|
+
require Pathname(__FILE__).dirname + "mail_servers/sendmail"
|
8
|
+
require Pathname(__FILE__).dirname + "mail_servers/smtp"
|
9
|
+
require Pathname(__FILE__).dirname + "mail_servers/test"
|
10
|
+
|
11
|
+
module Harbor
|
12
|
+
class Mailer < MailBuilder
|
13
|
+
|
14
|
+
def self.layout=(layout)
|
15
|
+
@@layout = layout
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.layout
|
19
|
+
@@layout rescue nil
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.host=(host)
|
23
|
+
@@host = host
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.host
|
27
|
+
@@host rescue "www.example.com"
|
28
|
+
end
|
29
|
+
|
30
|
+
attr_accessor :mail_server
|
31
|
+
|
32
|
+
def initialize(*args)
|
33
|
+
super
|
34
|
+
|
35
|
+
@layout = self.class.layout
|
36
|
+
@host = self.class.host
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# We want to automatically assign the value of @mailer to self whenever
|
41
|
+
# a view is passed to the mailer object. This lets us use, for instance,
|
42
|
+
# the envelope_id to track click-through's and bounces using the same
|
43
|
+
# identifier.
|
44
|
+
#
|
45
|
+
%w(html= text=).each do |method|
|
46
|
+
define_method(method) do |value|
|
47
|
+
if value.is_a?(Harbor::View)
|
48
|
+
value.context.merge(:mailer => self)
|
49
|
+
end
|
50
|
+
|
51
|
+
if @layout && layout = @layout.dup
|
52
|
+
layout.sub!(/(\.html\.erb$)|$/, ".txt.erb") if method == "text="
|
53
|
+
value = Harbor::View.new(layout, :content => value, :mailer => self)
|
54
|
+
end
|
55
|
+
|
56
|
+
super(value)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def host
|
61
|
+
@host
|
62
|
+
end
|
63
|
+
|
64
|
+
##
|
65
|
+
# Tokenizes urls in the email body by replacing them with the mail_server_url
|
66
|
+
# provided. The message's envelope_id and a base64 encoded version of the original
|
67
|
+
# url are passed to the URL provided.
|
68
|
+
#
|
69
|
+
# mailer.html = 'Please visit <a href="http://example.com">our site</a> for details.'
|
70
|
+
# mailer.tokenize_urls!("http://example.com/.m/%s?redirect=%s")
|
71
|
+
# mailer.html # => "Please visit <a href=\"http://example.com/.m/%2AF%2Ch2Gtn.ny1poJnnvvCeSMZA?redirect=aHR0cDovL2V4YW1wbGUuY29t%0A\">our site</a> for details."
|
72
|
+
##
|
73
|
+
def tokenize_urls!(mail_server_url)
|
74
|
+
mail_server_url = "http://#{mail_server_url}" unless mail_server_url =~ /^http/
|
75
|
+
|
76
|
+
[:@html, :@text].each do |ivar|
|
77
|
+
if content = instance_variable_get(ivar)
|
78
|
+
new_content = content.to_s.gsub(/(https?:\/\/.+?(?=[" <]|$))(\W*)(.{4}|$)/) do |url|
|
79
|
+
# Don't tokenize the inner text of a link
|
80
|
+
if $3 == '</a>'
|
81
|
+
url
|
82
|
+
else
|
83
|
+
(mail_server_url % [CGI.escape(envelope_id), CGI.escape([$1].pack("m"))]) + $2 + $3
|
84
|
+
end
|
85
|
+
end
|
86
|
+
instance_variable_set(ivar, new_content)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def send!
|
92
|
+
mail_server.deliver(self)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
end
|
data/lib/harbor/mime.rb
ADDED
@@ -0,0 +1,206 @@
|
|
1
|
+
module Harbor
|
2
|
+
# Copyright (c) 2007, 2008, 2009 Christian Neukirchen <purl.org/net/chneukirchen>
|
3
|
+
# This file originated from the Rack project, which can be found at rack.rubyforge.org
|
4
|
+
module Mime
|
5
|
+
# Returns String with mime type if found, otherwise use +fallback+.
|
6
|
+
# +ext+ should be filename extension in the '.ext' format that
|
7
|
+
# File.extname(file) returns.
|
8
|
+
# +fallback+ may be any object
|
9
|
+
#
|
10
|
+
# Also see the documentation for MIME_TYPES
|
11
|
+
#
|
12
|
+
# Usage:
|
13
|
+
# Harbor::Mime.mime_type('.foo')
|
14
|
+
#
|
15
|
+
# This is a shortcut for:
|
16
|
+
# Harbor::Mime::MIME_TYPES.fetch('.foo', 'application/octet-stream')
|
17
|
+
|
18
|
+
def mime_type(ext, fallback='application/octet-stream')
|
19
|
+
MIME_TYPES.fetch(ext, fallback)
|
20
|
+
end
|
21
|
+
module_function :mime_type
|
22
|
+
|
23
|
+
# List of most common mime-types, selected various sources
|
24
|
+
# according to their usefulness in a webserving scope for Ruby
|
25
|
+
# users.
|
26
|
+
#
|
27
|
+
# To amend this list with your local mime.types list you can use:
|
28
|
+
#
|
29
|
+
# require 'webrick/httputils'
|
30
|
+
# list = WEBrick::HTTPUtils.load_mime_types('/etc/mime.types')
|
31
|
+
# Harbor::Mime::MIME_TYPES.merge!(list)
|
32
|
+
#
|
33
|
+
# To add the list mongrel provides, use:
|
34
|
+
#
|
35
|
+
# require 'mongrel/handlers'
|
36
|
+
# Harbor::Mime::MIME_TYPES.merge!(Mongrel::DirHandler::MIME_TYPES)
|
37
|
+
|
38
|
+
MIME_TYPES = {
|
39
|
+
".3gp" => "video/3gpp",
|
40
|
+
".a" => "application/octet-stream",
|
41
|
+
".ai" => "application/postscript",
|
42
|
+
".aif" => "audio/x-aiff",
|
43
|
+
".aiff" => "audio/x-aiff",
|
44
|
+
".asc" => "application/pgp-signature",
|
45
|
+
".asf" => "video/x-ms-asf",
|
46
|
+
".asm" => "text/x-asm",
|
47
|
+
".asx" => "video/x-ms-asf",
|
48
|
+
".atom" => "application/atom+xml",
|
49
|
+
".au" => "audio/basic",
|
50
|
+
".avi" => "video/x-msvideo",
|
51
|
+
".bat" => "application/x-msdownload",
|
52
|
+
".bin" => "application/octet-stream",
|
53
|
+
".bmp" => "image/bmp",
|
54
|
+
".bz2" => "application/x-bzip2",
|
55
|
+
".c" => "text/x-c",
|
56
|
+
".cab" => "application/vnd.ms-cab-compressed",
|
57
|
+
".cc" => "text/x-c",
|
58
|
+
".chm" => "application/vnd.ms-htmlhelp",
|
59
|
+
".class" => "application/octet-stream",
|
60
|
+
".com" => "application/x-msdownload",
|
61
|
+
".conf" => "text/plain",
|
62
|
+
".cpp" => "text/x-c",
|
63
|
+
".crt" => "application/x-x509-ca-cert",
|
64
|
+
".css" => "text/css",
|
65
|
+
".csv" => "text/csv",
|
66
|
+
".cxx" => "text/x-c",
|
67
|
+
".deb" => "application/x-debian-package",
|
68
|
+
".der" => "application/x-x509-ca-cert",
|
69
|
+
".diff" => "text/x-diff",
|
70
|
+
".djv" => "image/vnd.djvu",
|
71
|
+
".djvu" => "image/vnd.djvu",
|
72
|
+
".dll" => "application/x-msdownload",
|
73
|
+
".dmg" => "application/octet-stream",
|
74
|
+
".doc" => "application/msword",
|
75
|
+
".dot" => "application/msword",
|
76
|
+
".dtd" => "application/xml-dtd",
|
77
|
+
".dvi" => "application/x-dvi",
|
78
|
+
".ear" => "application/java-archive",
|
79
|
+
".eml" => "message/rfc822",
|
80
|
+
".eps" => "application/postscript",
|
81
|
+
".exe" => "application/x-msdownload",
|
82
|
+
".f" => "text/x-fortran",
|
83
|
+
".f77" => "text/x-fortran",
|
84
|
+
".f90" => "text/x-fortran",
|
85
|
+
".flv" => "video/x-flv",
|
86
|
+
".for" => "text/x-fortran",
|
87
|
+
".gem" => "application/octet-stream",
|
88
|
+
".gemspec" => "text/x-script.ruby",
|
89
|
+
".gif" => "image/gif",
|
90
|
+
".gz" => "application/x-gzip",
|
91
|
+
".h" => "text/x-c",
|
92
|
+
".hh" => "text/x-c",
|
93
|
+
".htm" => "text/html",
|
94
|
+
".html" => "text/html",
|
95
|
+
".ico" => "image/vnd.microsoft.icon",
|
96
|
+
".ics" => "text/calendar",
|
97
|
+
".ifb" => "text/calendar",
|
98
|
+
".iso" => "application/octet-stream",
|
99
|
+
".jar" => "application/java-archive",
|
100
|
+
".java" => "text/x-java-source",
|
101
|
+
".jnlp" => "application/x-java-jnlp-file",
|
102
|
+
".jpeg" => "image/jpeg",
|
103
|
+
".jpg" => "image/jpeg",
|
104
|
+
".js" => "application/javascript",
|
105
|
+
".json" => "application/json",
|
106
|
+
".log" => "text/plain",
|
107
|
+
".m3u" => "audio/x-mpegurl",
|
108
|
+
".m4v" => "video/mp4",
|
109
|
+
".man" => "text/troff",
|
110
|
+
".mathml" => "application/mathml+xml",
|
111
|
+
".mbox" => "application/mbox",
|
112
|
+
".mdoc" => "text/troff",
|
113
|
+
".me" => "text/troff",
|
114
|
+
".mid" => "audio/midi",
|
115
|
+
".midi" => "audio/midi",
|
116
|
+
".mime" => "message/rfc822",
|
117
|
+
".mml" => "application/mathml+xml",
|
118
|
+
".mng" => "video/x-mng",
|
119
|
+
".mov" => "video/quicktime",
|
120
|
+
".mp3" => "audio/mpeg",
|
121
|
+
".mp4" => "video/mp4",
|
122
|
+
".mp4v" => "video/mp4",
|
123
|
+
".mpeg" => "video/mpeg",
|
124
|
+
".mpg" => "video/mpeg",
|
125
|
+
".ms" => "text/troff",
|
126
|
+
".msi" => "application/x-msdownload",
|
127
|
+
".odp" => "application/vnd.oasis.opendocument.presentation",
|
128
|
+
".ods" => "application/vnd.oasis.opendocument.spreadsheet",
|
129
|
+
".odt" => "application/vnd.oasis.opendocument.text",
|
130
|
+
".ogg" => "application/ogg",
|
131
|
+
".p" => "text/x-pascal",
|
132
|
+
".pas" => "text/x-pascal",
|
133
|
+
".pbm" => "image/x-portable-bitmap",
|
134
|
+
".pdf" => "application/pdf",
|
135
|
+
".pem" => "application/x-x509-ca-cert",
|
136
|
+
".pgm" => "image/x-portable-graymap",
|
137
|
+
".pgp" => "application/pgp-encrypted",
|
138
|
+
".pkg" => "application/octet-stream",
|
139
|
+
".pl" => "text/x-script.perl",
|
140
|
+
".pm" => "text/x-script.perl-module",
|
141
|
+
".png" => "image/png",
|
142
|
+
".pnm" => "image/x-portable-anymap",
|
143
|
+
".ppm" => "image/x-portable-pixmap",
|
144
|
+
".pps" => "application/vnd.ms-powerpoint",
|
145
|
+
".ppt" => "application/vnd.ms-powerpoint",
|
146
|
+
".ps" => "application/postscript",
|
147
|
+
".psd" => "image/vnd.adobe.photoshop",
|
148
|
+
".py" => "text/x-script.python",
|
149
|
+
".qt" => "video/quicktime",
|
150
|
+
".ra" => "audio/x-pn-realaudio",
|
151
|
+
".rake" => "text/x-script.ruby",
|
152
|
+
".ram" => "audio/x-pn-realaudio",
|
153
|
+
".rar" => "application/x-rar-compressed",
|
154
|
+
".rb" => "text/x-script.ruby",
|
155
|
+
".rdf" => "application/rdf+xml",
|
156
|
+
".roff" => "text/troff",
|
157
|
+
".rpm" => "application/x-redhat-package-manager",
|
158
|
+
".rss" => "application/rss+xml",
|
159
|
+
".rtf" => "application/rtf",
|
160
|
+
".ru" => "text/x-script.ruby",
|
161
|
+
".s" => "text/x-asm",
|
162
|
+
".sgm" => "text/sgml",
|
163
|
+
".sgml" => "text/sgml",
|
164
|
+
".sh" => "application/x-sh",
|
165
|
+
".sig" => "application/pgp-signature",
|
166
|
+
".snd" => "audio/basic",
|
167
|
+
".so" => "application/octet-stream",
|
168
|
+
".svg" => "image/svg+xml",
|
169
|
+
".svgz" => "image/svg+xml",
|
170
|
+
".swf" => "application/x-shockwave-flash",
|
171
|
+
".t" => "text/troff",
|
172
|
+
".tar" => "application/x-tar",
|
173
|
+
".tbz" => "application/x-bzip-compressed-tar",
|
174
|
+
".tcl" => "application/x-tcl",
|
175
|
+
".tex" => "application/x-tex",
|
176
|
+
".texi" => "application/x-texinfo",
|
177
|
+
".texinfo" => "application/x-texinfo",
|
178
|
+
".text" => "text/plain",
|
179
|
+
".tif" => "image/tiff",
|
180
|
+
".tiff" => "image/tiff",
|
181
|
+
".torrent" => "application/x-bittorrent",
|
182
|
+
".tr" => "text/troff",
|
183
|
+
".txt" => "text/plain",
|
184
|
+
".vcf" => "text/x-vcard",
|
185
|
+
".vcs" => "text/x-vcalendar",
|
186
|
+
".vrml" => "model/vrml",
|
187
|
+
".war" => "application/java-archive",
|
188
|
+
".wav" => "audio/x-wav",
|
189
|
+
".wma" => "audio/x-ms-wma",
|
190
|
+
".wmv" => "video/x-ms-wmv",
|
191
|
+
".wmx" => "video/x-ms-wmx",
|
192
|
+
".wrl" => "model/vrml",
|
193
|
+
".wsdl" => "application/wsdl+xml",
|
194
|
+
".xbm" => "image/x-xbitmap",
|
195
|
+
".xhtml" => "application/xhtml+xml",
|
196
|
+
".xls" => "application/vnd.ms-excel",
|
197
|
+
".xml" => "application/xml",
|
198
|
+
".xpm" => "image/x-xpixmap",
|
199
|
+
".xsl" => "application/xml",
|
200
|
+
".xslt" => "application/xslt+xml",
|
201
|
+
".yaml" => "text/yaml",
|
202
|
+
".yml" => "text/yaml",
|
203
|
+
".zip" => "application/zip",
|
204
|
+
}
|
205
|
+
end
|
206
|
+
end
|