diff --git a/lib/sinatra.rb b/lib/sinatra.rb
index 796f2cf1..1b23d394 100644
--- a/lib/sinatra.rb
+++ b/lib/sinatra.rb
@@ -1,6 +1,15 @@
require "rubygems"
require "rack"
+require 'sinatra/mime_types'
+
+def silence_warnings
+ old_verbose, $VERBOSE = $VERBOSE, nil
+ yield
+ensure
+ $VERBOSE = old_verbose
+end
+
class String
def to_param
URI.escape(self)
@@ -87,7 +96,7 @@ module Sinatra
end
def config
- @config ||= @default_config
+ @config ||= @default_config.dup
end
def config=(c)
@@ -98,7 +107,9 @@ module Sinatra
@default_config ||= {
:run => true,
:raise_errors => false,
- :env => :development
+ :env => :development,
+ :root => File.dirname($0),
+ :default_static_mime_type => 'text/plain'
}
end
@@ -106,8 +117,23 @@ module Sinatra
routes[verb].eject { |r| r.match(path) } || routes[404]
end
+ def content_type_for(path)
+ ext = File.extname(path)[1..-1]
+ Sinatra.mime_types[ext] || config[:default_static_mime_type]
+ end
+
def call(env)
request = Rack::Request.new(env)
+
+ path = Sinatra.config[:root] + '/public' + request.path_info
+ if File.file?(path)
+ headers = {
+ 'Content-Type' => Array(content_type_for(path)),
+ 'Content-Length' => Array(File.size(path))
+ }
+ return [200, headers, File.read(path)]
+ end
+
response = Rack::Response.new
route = determine_route(
request.request_method.downcase.to_sym,
@@ -139,10 +165,12 @@ module Sinatra
end
class Route
-
+
URI_CHAR = '[^/?:,]'.freeze unless defined?(URI_CHAR)
PARAM = /:(#{URI_CHAR}+)/.freeze unless defined?(PARAM)
+ Result = Struct.new(:path, :block, :params, :default_status)
+
attr_reader :block, :path
def initialize(path, &b)
@@ -153,13 +181,12 @@ module Sinatra
"(#{URI_CHAR}+)"
end
@pattern = /^#{regex}$/
- @struct = Struct.new(:path, :block, :params, :default_status)
end
def match(path)
return nil unless path =~ @pattern
params = @param_keys.zip($~.captures.map(&:from_param)).to_hash
- @struct.new(@path, @block, params, 200)
+ Result.new(@path, @block, params, 200)
end
end
@@ -177,7 +204,7 @@ module Sinatra
end
end
-
+
end
def get(*paths, &b)
@@ -189,4 +216,8 @@ def error(*codes, &b)
codes.each { |code| Sinatra.define_error(code, &b) }
end
+def mime_type(content_type, *exts)
+ exts.each { |ext| Sinatra::MIME_TYPES.merge(ext.to_s, content_type) }
+end
+
Sinatra.setup_default_events!
diff --git a/lib/sinatra/mime_types.rb b/lib/sinatra/mime_types.rb
new file mode 100644
index 00000000..4b133385
--- /dev/null
+++ b/lib/sinatra/mime_types.rb
@@ -0,0 +1,256 @@
+module Sinatra
+
+ def mime_types
+
+ @default_mime_types ||= {
+ "csh"=>"application/x-csh",
+ "x_t"=>"model/vnd.parasolid.transmit.text",
+ "ksp"=>"application/vnd.kde.kspread",
+ "fsc"=>"application/vnd.fsc.weblaunch",
+ "vcs"=>"text/x-vcalendar",
+ "hvs"=>"application/vnd.yamaha.hv-script",
+ "seml"=>"application/vnd.sealed.eml",
+ "movie"=>"video/x-sgi-movie",
+ "plt"=>"application/vnd.hp-HPGL",
+ "wav"=>"audio/x-wav",
+ "3gpp"=>"audio/3gpp",
+ "eol"=>"audio/vnd.digital-winds",
+ "rtf"=>"application/rtf",
+ "kfo"=>"application/vnd.kde.kformula",
+ "rdf"=>"application/rdf+xml",
+ "rgb"=>"image/x-rgb",
+ "wpd"=>"application/vnd.wordperfect",
+ "sit"=>"application/x-stuffit",
+ "ogg"=>"application/ogg",
+ "pbm"=>"image/x-portable-bitmap",
+ "dwf"=>"x-drawing/dwf",
+ "smp3"=>"audio/vnd.sealedmedia.softseal.mpeg",
+ "html"=>"text/html",
+ "dwg"=>"image/vnd.dwg",
+ "see"=>"application/vnd.seemail",
+ "igs"=>"model/iges",
+ "siv"=>"application/sieve",
+ "jad"=>"text/vnd.sun.j2me.app-descriptor",
+ "wml"=>"text/vnd.wap.wml",
+ "ustar"=>"application/x-ustar",
+ "vis"=>"application/vnd.visionary",
+ "pkipath"=>"application/pkix-pkipath",
+ "ecelp4800"=>"audio/vnd.nuera.ecelp4800",
+ "ice"=>"x-conference/x-cooltalk",
+ "qcp"=>"audio/QCELP",
+ "ai"=>"application/postscript",
+ "sppt"=>"application/vnd.sealed.ppt",
+ "ltx"=>"application/x-latex",
+ "nim"=>"video/vnd.nokia.interleaved-multimedia",
+ "igx"=>"application/vnd.micrografx.igx",
+ "viv"=>"video/vnd.vivo",
+ "wpl"=>"application/vnd.ms-wpl",
+ "ami"=>"application/vnd.amiga.ami",
+ "tcl"=>"application/x-tcl",
+ "l16"=>"audio/L16",
+ "css"=>"text/css",
+ "vbk"=>"audio/vnd.nortel.vbk",
+ "pki"=>"application/pkixcmp",
+ "ras"=>"image/x-cmu-raster",
+ "jpeg"=>"image/jpeg",
+ "chrt"=>"application/vnd.kde.kchart",
+ "cil"=>"application/vnd.ms-artgalry",
+ "mxu"=>"video/vnd.mpegurl",
+ "xwd"=>"image/x-xwindowdump",
+ "kon"=>"application/vnd.kde.kontour",
+ "dgn"=>"image/x-vnd.dgn",
+ "csv"=>"text/csv",
+ "png"=>"image/png",
+ "xfdf"=>"application/vnd.adobe.xfdf",
+ "asf"=>"application/vnd.ms-asf",
+ "sxls"=>"application/vnd.sealed.xls",
+ "dl"=>"video/dl",
+ "karbon"=>"application/vnd.kde.karbon",
+ "ico"=>"image/vnd.microsoft.icon",
+ "sus"=>"application/vnd.sus-calendar",
+ "pdb"=>"x-chemical/x-pdb",
+ "wif"=>"application/watcherinfo+xml",
+ "ser"=>"application/x-java-serialized-object",
+ "mdi"=>"image/vnd.ms-modi",
+ "qt"=>"video/quicktime",
+ "rtx"=>"text/richtext",
+ "jar"=>"application/x-java-archive",
+ "rcprofile"=>"application/vnd.ipunplugged.rcprofile",
+ "tsv"=>"text/tab-separated-values",
+ "pnm"=>"image/x-portable-anymap",
+ "me"=>"application/x-troff-me",
+ "amr"=>"audio/AMR",
+ "wp5"=>"application/wordperfect5.1",
+ "gl"=>"video/gl",
+ "man"=>"application/x-troff-man",
+ "pdf"=>"application/pdf",
+ "pgb"=>"image/vnd.globalgraphics.pgb",
+ "au"=>"audio/basic",
+ "avi"=>"video/x-msvideo",
+ "wmlsc"=>"application/vnd.wap.wmlscriptc",
+ "wbxml"=>"application/vnd.wap.wbxml",
+ "saf"=>"application/vnd.yamaha.smaf-audio",
+ "gtar"=>"application/x-gtar",
+ "crl"=>"application/pkix-crl",
+ "pti"=>"application/vnd.pvi.ptid1",
+ "rdz"=>"application/vnd.data-vision.rdz",
+ "flo"=>"application/vnd.micrografx.flo",
+ "aif"=>"audio/x-aiff",
+ "qxd"=>"application/vnd.Quark.QuarkXPress",
+ "kne"=>"application/vnd.Kinar",
+ "rpm"=>"audio/x-pn-realaudio-plugin",
+ "lvp"=>"audio/vnd.lucent.voice",
+ "stml"=>"application/vnd.sealedmedia.softseal.html",
+ "sc"=>"application/vnd.ibm.secure-container",
+ "jnlp"=>"application/x-java-jnlp-file",
+ "smov"=>"video/vnd.sealedmedia.softseal.mov",
+ "dvi"=>"application/x-dvi",
+ "jisp"=>"application/vnd.jisp",
+ "wv"=>"application/vnd.wv.csp+wbxml",
+ "mseq"=>"application/vnd.mseq",
+ "mmf"=>"application/vnd.smaf",
+ "mpc"=>"application/vnd.mophun.certificate",
+ "stk"=>"application/hyperstudio",
+ "txd"=>"application/vnd.genomatix.tuxedo",
+ "ent"=>"application/vnd.nervana",
+ "hdf"=>"application/x-hdf",
+ "xml"=>"application/xml",
+ "mpga"=>"audio/mpeg",
+ "sh"=>"application/x-sh",
+ "pgm"=>"image/x-portable-graymap",
+ "lbd"=>"application/vnd.llamagraphics.life-balance.desktop",
+ "flw"=>"application/vnd.kde.kivio",
+ "si"=>"text/vnd.wap.si",
+ "zip"=>"application/zip",
+ "ecelp7470"=>"audio/vnd.nuera.ecelp7470",
+ "lbe"=>"application/vnd.llamagraphics.life-balance.exchange+xml",
+ "p10"=>"application/pkcs10",
+ "ief"=>"image/ief",
+ "doc"=>"application/msword",
+ "efif"=>"application/vnd.picsel",
+ "jpm"=>"image/jpm",
+ "gz"=>"application/x-gzip",
+ "xhtml"=>"application/xhtml+xml",
+ "irm"=>"application/vnd.ibm.rights-management",
+ "bcpio"=>"application/x-bcpio",
+ "mcd"=>"application/vnd.mcd",
+ "ecelp9600"=>"audio/vnd.nuera.ecelp9600",
+ "ms"=>"application/x-troff-ms",
+ "gif"=>"image/gif",
+ "kwd"=>"application/vnd.kde.kword",
+ "wrl"=>"model/vrml",
+ "sl"=>"text/vnd.wap.sl",
+ "xpm"=>"image/x-xpixmap",
+ "cer"=>"application/pkix-cert",
+ "mxmf"=>"audio/vnd.nokia.mobile-xmf",
+ "psb"=>"application/vnd.3gpp.pic-bw-small",
+ "cab"=>"application/vnd.ms-cab-compressed",
+ "rst"=>"text/prs.fallenstein.rst",
+ "p7m"=>"application/pkcs7-mime",
+ "spng"=>"image/vnd.sealed.png",
+ "mj2"=>"video/MJ2",
+ "wbmp"=>"image/vnd.wap.wbmp",
+ "irp"=>"application/vnd.irepository.package+xml",
+ "smht"=>"application/vnd.sealed.mht",
+ "msh"=>"model/mesh",
+ "htke"=>"application/vnd.kenameaapp",
+ "s11"=>"video/vnd.sealed.mpeg1",
+ "mpm"=>"application/vnd.blueice.multipass",
+ "mpn"=>"application/vnd.mophun.application",
+ "dfac"=>"application/vnd.dreamfactory",
+ "pvb"=>"application/vnd.3gpp.pic-bw-var",
+ "lrm"=>"application/vnd.ms-lrm",
+ "tiff"=>"image/tiff",
+ "jp2"=>"image/jp2",
+ "rpss"=>"application/vnd.nokia.radio-presets",
+ "wmlc"=>"application/vnd.wap.wmlc",
+ "rpst"=>"application/vnd.nokia.radio-preset",
+ "etx"=>"text/x-setext",
+ "bmp"=>"image/bmp",
+ "mpp"=>"application/vnd.ms-project",
+ "spf"=>"application/vnd.yamaha.smaf-phrase",
+ "3gp"=>"video/3gpp",
+ "mid"=>"audio/x-midi",
+ "hqx"=>"application/mac-binhex40",
+ "p7s"=>"application/pkcs7-signature",
+ "wbs"=>"application/vnd.criticaltools.wbs+xml",
+ "emm"=>"application/vnd.ibm.electronic-media",
+ "ppm"=>"image/x-portable-pixmap",
+ "texinfo"=>"application/x-texinfo",
+ "mp2"=>"video/mpeg",
+ "jpx"=>"image/jpx",
+ "evc"=>"audio/EVRC",
+ "mif"=>"application/x-mif",
+ "ra"=>"audio/x-realaudio",
+ "spdf"=>"application/vnd.sealedmedia.softseal.pdf",
+ "x_b"=>"model/vnd.parasolid.transmit.binary",
+ "class"=>"application/x-java-vm",
+ "txt"=>"text/plain",
+ "mp4"=>"video/vnd.objectvideo",
+ "hbci"=>"application/vnd.hbci",
+ "wqd"=>"application/vnd.wqd",
+ "vsc"=>"application/vnd.vidsoft.vidconference",
+ "mfm"=>"application/vnd.mfmp",
+ "sgml"=>"text/sgml",
+ "tex"=>"application/x-tex",
+ "curl"=>"application/vnd.curl",
+ "djvu"=>"image/vnd.djvu",
+ "cw"=>"application/prs.cww",
+ "vsd"=>"application/vnd.visio",
+ "tga"=>"image/targa",
+ "wtb"=>"application/vnd.webturbo",
+ "plb"=>"application/vnd.3gpp.pic-bw-large",
+ "t"=>"text/troff",
+ "les"=>"application/vnd.hhe.lesson-player",
+ "sms"=>"application/vnd.3gpp.sms",
+ "hvd"=>"application/vnd.yamaha.hv-dic",
+ "yaml"=>"text/x-yaml",
+ "ppt"=>"application/powerpoint",
+ "psp"=>"image/x-paintshoppro",
+ "sic"=>"application/vnd.wap.sic",
+ "cmc"=>"application/vnd.cosmocaller",
+ "vcf"=>"text/x-vcard",
+ "sjpg"=>"image/vnd.sealedmedia.softseal.jpg",
+ "sid"=>"audio/prs.sid",
+ "sv4cpio"=>"application/x-sv4cpio",
+ "sswf"=>"video/vnd.sealed.swf",
+ "cpio"=>"application/x-cpio",
+ "smv"=>"audio/SMV",
+ "wks"=>"application/vnd.lotus-1-2-3",
+ "sig"=>"application/pgp-signature",
+ "slc"=>"application/vnd.wap.slc",
+ "z"=>"application/x-compressed",
+ "rm"=>"audio/x-pn-realaudio",
+ "bin"=>"application/octet-stream",
+ "smpg"=>"video/vnd.sealed.mpeg4",
+ "wmls"=>"text/vnd.wap.wmlscript",
+ "atc"=>"application/vnd.acucorp",
+ "pfr"=>"application/font-tdpfr",
+ "plj"=>"audio/vnd.everad.plj",
+ "rnd"=>"application/prs.nprend",
+ "xls"=>"application/excel",
+ "sdoc"=>"application/vnd.sealed.doc",
+ "tar"=>"application/x-tar",
+ "oda"=>"application/oda",
+ "kia"=>"application/vnd.kidspiration",
+ "prc"=>"application/vnd.palm",
+ "sgif"=>"image/vnd.sealedmedia.softseal.gif",
+ "soc"=>"application/sgml-open-catalog",
+ "xyz"=>"x-chemical/x-xyz",
+ "awb"=>"audio/AMR-WB",
+ "xbm"=>"image/x-xbitmap",
+ "ccc"=>"text/vnd.net2phone.commcenter.command",
+ "xul"=>"application/vnd.mozilla.xul+xml",
+ "cdy"=>"application/vnd.cinderella",
+ "kpr"=>"application/vnd.kde.kpresenter",
+ "shar"=>"application/x-shar",
+ "src"=>"application/x-wais-source",
+ "hvp"=>"application/vnd.yamaha.hv-voice",
+ "nc"=>"application/netcdf",
+ "sv4crc"=>"application/x-sv4crc",
+ "js" => "text/javascript"
+ }
+
+ end
+
+end
diff --git a/lib/sinatra/test.rb b/lib/sinatra/test.rb
index 74143686..a3ed22b4 100644
--- a/lib/sinatra/test.rb
+++ b/lib/sinatra/test.rb
@@ -1,10 +1,6 @@
require 'test/unit'
require File.dirname(__FILE__) + "/test/methods"
-class Test::Unit::TestCase
- include Sinatra::Test::Methods
-end
-
-include Sinatra::Test::Methods
+Test::Unit::TestCase.send :include, Sinatra::Test::Methods
Sinatra.default_config[:raise_errors] = true
diff --git a/test/public/foo.foo b/test/public/foo.foo
new file mode 100644
index 00000000..ba0e162e
--- /dev/null
+++ b/test/public/foo.foo
@@ -0,0 +1 @@
+bar
\ No newline at end of file
diff --git a/test/public/foo.xml b/test/public/foo.xml
new file mode 100644
index 00000000..54181ed4
--- /dev/null
+++ b/test/public/foo.xml
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/test/public/test.js b/test/public/test.js
new file mode 100644
index 00000000..69a82a27
--- /dev/null
+++ b/test/public/test.js
@@ -0,0 +1 @@
+var i = 11;
\ No newline at end of file
diff --git a/test/public/xyz b/test/public/xyz
new file mode 100644
index 00000000..f2ba8f84
--- /dev/null
+++ b/test/public/xyz
@@ -0,0 +1 @@
+abc
\ No newline at end of file
diff --git a/test/static_test.rb b/test/static_test.rb
new file mode 100644
index 00000000..d8462fa0
--- /dev/null
+++ b/test/static_test.rb
@@ -0,0 +1,65 @@
+require File.dirname(__FILE__) + '/helper'
+
+context "Static" do
+
+ setup do
+ Sinatra.routes.clear
+ Sinatra.config = nil
+ Sinatra.setup_default_events!
+
+ Sinatra.config[:root] = File.dirname(__FILE__)
+ end
+
+ specify "sends files" do
+
+ get_it '/foo.xml'
+
+ should.be.ok
+ body.should.equal ''
+ headers.should.equal 'Content-Type' => 'application/xml',
+ 'Content-Length' => ''.size
+
+ end
+
+ specify "defaults to text/plain" do
+
+ get_it '/foo.foo'
+
+ should.be.ok
+ body.should.equal 'bar'
+ headers.should.equal 'Content-Type' => 'text/plain',
+ 'Content-Length' => 'bar'.size
+ end
+
+ specify "default to user definied type" do
+ Sinatra.config[:default_static_mime_type] = 'foo/bar'
+
+ get_it '/foo.foo'
+
+ should.be.ok
+ body.should.equal 'bar'
+ headers.should.equal 'Content-Type' => 'foo/bar',
+ 'Content-Length' => 'bar'.size
+ end
+
+ specify "handles files without ext" do
+ get_it '/xyz'
+
+ should.be.ok
+ body.should.equal 'abc'
+ headers.should.equal 'Content-Type' => 'text/plain',
+ 'Content-Length' => 'bar'.size
+ end
+
+ specify "should handle javascript correctly" do
+
+ get_it '/test.js'
+
+ should.be.ok
+ body.should.equal 'var i = 11;'
+ headers.should.equal 'Content-Type' => 'text/javascript',
+ 'Content-Length' => 'var i = 11;'.size
+
+ end
+
+end