sinatra 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sinatra might be problematic. Click here for more details.
- data/CHANGELOG +1 -0
- data/LICENSE +22 -0
- data/Manifest +78 -1
- data/lib/sinatra.rb +12 -1
- data/sinatra.gemspec +7 -14
- data/vendor/rack/AUTHORS +7 -0
- data/vendor/rack/COPYING +18 -0
- data/vendor/rack/KNOWN-ISSUES +18 -0
- data/vendor/rack/README +242 -0
- data/vendor/rack/Rakefile +174 -0
- data/vendor/rack/bin/rackup +153 -0
- data/vendor/rack/contrib/rack_logo.svg +111 -0
- data/vendor/rack/example/lobster.ru +4 -0
- data/vendor/rack/example/protectedlobster.rb +14 -0
- data/vendor/rack/example/protectedlobster.ru +8 -0
- data/vendor/rack/lib/rack.rb +92 -0
- data/vendor/rack/lib/rack/adapter/camping.rb +22 -0
- data/vendor/rack/lib/rack/auth/abstract/handler.rb +28 -0
- data/vendor/rack/lib/rack/auth/abstract/request.rb +37 -0
- data/vendor/rack/lib/rack/auth/basic.rb +58 -0
- data/vendor/rack/lib/rack/auth/digest/md5.rb +124 -0
- data/vendor/rack/lib/rack/auth/digest/nonce.rb +51 -0
- data/vendor/rack/lib/rack/auth/digest/params.rb +55 -0
- data/vendor/rack/lib/rack/auth/digest/request.rb +40 -0
- data/vendor/rack/lib/rack/auth/openid.rb +116 -0
- data/vendor/rack/lib/rack/builder.rb +56 -0
- data/vendor/rack/lib/rack/cascade.rb +36 -0
- data/vendor/rack/lib/rack/commonlogger.rb +56 -0
- data/vendor/rack/lib/rack/file.rb +112 -0
- data/vendor/rack/lib/rack/handler/cgi.rb +57 -0
- data/vendor/rack/lib/rack/handler/fastcgi.rb +83 -0
- data/vendor/rack/lib/rack/handler/lsws.rb +52 -0
- data/vendor/rack/lib/rack/handler/mongrel.rb +78 -0
- data/vendor/rack/lib/rack/handler/scgi.rb +57 -0
- data/vendor/rack/lib/rack/handler/webrick.rb +57 -0
- data/vendor/rack/lib/rack/lint.rb +394 -0
- data/vendor/rack/lib/rack/lobster.rb +65 -0
- data/vendor/rack/lib/rack/mock.rb +160 -0
- data/vendor/rack/lib/rack/recursive.rb +57 -0
- data/vendor/rack/lib/rack/reloader.rb +64 -0
- data/vendor/rack/lib/rack/request.rb +197 -0
- data/vendor/rack/lib/rack/response.rb +166 -0
- data/vendor/rack/lib/rack/session/abstract/id.rb +126 -0
- data/vendor/rack/lib/rack/session/cookie.rb +71 -0
- data/vendor/rack/lib/rack/session/memcache.rb +83 -0
- data/vendor/rack/lib/rack/session/pool.rb +67 -0
- data/vendor/rack/lib/rack/showexceptions.rb +344 -0
- data/vendor/rack/lib/rack/showstatus.rb +103 -0
- data/vendor/rack/lib/rack/static.rb +38 -0
- data/vendor/rack/lib/rack/urlmap.rb +48 -0
- data/vendor/rack/lib/rack/utils.rb +240 -0
- data/vendor/rack/test/cgi/lighttpd.conf +20 -0
- data/vendor/rack/test/cgi/test +9 -0
- data/vendor/rack/test/cgi/test.fcgi +7 -0
- data/vendor/rack/test/cgi/test.ru +7 -0
- data/vendor/rack/test/spec_rack_auth_basic.rb +69 -0
- data/vendor/rack/test/spec_rack_auth_digest.rb +169 -0
- data/vendor/rack/test/spec_rack_builder.rb +50 -0
- data/vendor/rack/test/spec_rack_camping.rb +47 -0
- data/vendor/rack/test/spec_rack_cascade.rb +50 -0
- data/vendor/rack/test/spec_rack_cgi.rb +91 -0
- data/vendor/rack/test/spec_rack_commonlogger.rb +32 -0
- data/vendor/rack/test/spec_rack_fastcgi.rb +91 -0
- data/vendor/rack/test/spec_rack_file.rb +40 -0
- data/vendor/rack/test/spec_rack_lint.rb +317 -0
- data/vendor/rack/test/spec_rack_lobster.rb +45 -0
- data/vendor/rack/test/spec_rack_mock.rb +152 -0
- data/vendor/rack/test/spec_rack_mongrel.rb +165 -0
- data/vendor/rack/test/spec_rack_recursive.rb +77 -0
- data/vendor/rack/test/spec_rack_request.rb +384 -0
- data/vendor/rack/test/spec_rack_response.rb +167 -0
- data/vendor/rack/test/spec_rack_session_cookie.rb +49 -0
- data/vendor/rack/test/spec_rack_session_memcache.rb +100 -0
- data/vendor/rack/test/spec_rack_session_pool.rb +84 -0
- data/vendor/rack/test/spec_rack_showexceptions.rb +21 -0
- data/vendor/rack/test/spec_rack_showstatus.rb +71 -0
- data/vendor/rack/test/spec_rack_static.rb +37 -0
- data/vendor/rack/test/spec_rack_urlmap.rb +175 -0
- data/vendor/rack/test/spec_rack_utils.rb +57 -0
- data/vendor/rack/test/spec_rack_webrick.rb +106 -0
- data/vendor/rack/test/testrequest.rb +43 -0
- metadata +81 -4
- data/Rakefile +0 -24
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rack/auth/abstract/request'
|
2
|
+
require 'rack/auth/digest/params'
|
3
|
+
require 'rack/auth/digest/nonce'
|
4
|
+
|
5
|
+
module Rack
|
6
|
+
module Auth
|
7
|
+
module Digest
|
8
|
+
class Request < Auth::AbstractRequest
|
9
|
+
|
10
|
+
def method
|
11
|
+
@env['REQUEST_METHOD']
|
12
|
+
end
|
13
|
+
|
14
|
+
def digest?
|
15
|
+
:digest == scheme
|
16
|
+
end
|
17
|
+
|
18
|
+
def correct_uri?
|
19
|
+
@env['PATH_INFO'] == uri
|
20
|
+
end
|
21
|
+
|
22
|
+
def nonce
|
23
|
+
@nonce ||= Nonce.parse(params['nonce'])
|
24
|
+
end
|
25
|
+
|
26
|
+
def params
|
27
|
+
@params ||= Params.parse(parts.last)
|
28
|
+
end
|
29
|
+
|
30
|
+
def method_missing(sym)
|
31
|
+
if params.has_key? key = sym.to_s
|
32
|
+
return params[key]
|
33
|
+
end
|
34
|
+
super
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
# AUTHOR: blink <blinketje@gmail.com>; blink#ruby-lang@irc.freenode.net
|
2
|
+
|
3
|
+
gem_require 'ruby-openid', '~> 1.0.0' if defined? Gem
|
4
|
+
require 'rack/auth/abstract/handler'
|
5
|
+
require 'openid'
|
6
|
+
|
7
|
+
module Rack
|
8
|
+
module Auth
|
9
|
+
# Rack::Auth::OpenID provides a simple method for permitting openid
|
10
|
+
# based logins. It requires the ruby-openid lib from janrain to operate,
|
11
|
+
# as well as some method of session management of a Hash type.
|
12
|
+
#
|
13
|
+
# After a transaction, the response status object is stored in the
|
14
|
+
# environment at rack.auth.openid.status, which can be used in the
|
15
|
+
# followup block or in a wrapping application to accomplish
|
16
|
+
# additional data maniipulation.
|
17
|
+
#
|
18
|
+
# NOTE: Due to the amount of data that ruby-openid stores in the session,
|
19
|
+
# Rack::Session::Cookie may fault.
|
20
|
+
#
|
21
|
+
# A hash of data is stored in the session hash at the key of :openid.
|
22
|
+
# The fully canonicalized identity url is stored within at 'identity'.
|
23
|
+
# Extension data from 'openid.sreg.nickname' would be stored as
|
24
|
+
# { 'nickname' => value }.
|
25
|
+
#
|
26
|
+
# NOTE: To my knowledge there is no collision at this point from storage
|
27
|
+
# of this manner, if there is please let me know so I may adjust this app
|
28
|
+
# to cope.
|
29
|
+
# NOTE: This rack application is only compatible with the 1.x.x versions
|
30
|
+
# of the ruby-openid library. If rubygems is loaded at require time of
|
31
|
+
# this app, the specification will be made. If it is not then the 'openid'
|
32
|
+
# library will be required, and will fail if it is not compatible.
|
33
|
+
class OpenID < AbstractHandler
|
34
|
+
# Required for ruby-openid
|
35
|
+
OIDStore = ::OpenID::MemoryStore.new
|
36
|
+
|
37
|
+
# A Hash of options is taken as it's single initializing
|
38
|
+
# argument. String keys are taken to be openid protocol
|
39
|
+
# extension namespaces.
|
40
|
+
#
|
41
|
+
# For example: 'sreg' => { 'required' => # 'nickname' }
|
42
|
+
#
|
43
|
+
# Other keys are taken as options for Rack::Auth::OpenID, normally Symbols.
|
44
|
+
# Only :return is required. :trust is highly recommended to be set.
|
45
|
+
#
|
46
|
+
# * :return defines the url to return to after the client authenticates
|
47
|
+
# with the openid service provider. Should point to where this app is
|
48
|
+
# mounted. (ex: 'http://mysite.com/openid')
|
49
|
+
# * :trust defines the url identifying the site they are actually logging
|
50
|
+
# into. (ex: 'http://mysite.com/')
|
51
|
+
# * :session_key defines the key to the session hash in the env.
|
52
|
+
# (by default it uses 'rack.session')
|
53
|
+
def initialize(options={})
|
54
|
+
raise ArgumentError, 'No return url provided.' unless options[:return]
|
55
|
+
warn 'No trust url provided.' unless options[:trust]
|
56
|
+
options[:trust] ||= options[:return]
|
57
|
+
|
58
|
+
@options = {
|
59
|
+
:session_key => 'rack.session'
|
60
|
+
}.merge(options)
|
61
|
+
end
|
62
|
+
|
63
|
+
def call(env)
|
64
|
+
request = Rack::Request.new env
|
65
|
+
return no_session unless session = request.env[@options[:session_key]]
|
66
|
+
resp = if request.GET['openid.mode']
|
67
|
+
finish session, request.GET, env
|
68
|
+
elsif request.GET['openid_url']
|
69
|
+
check session, request.GET['openid_url'], env
|
70
|
+
else
|
71
|
+
bad_request
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def check(session, oid_url, env)
|
76
|
+
consumer = ::OpenID::Consumer.new session, OIDStore
|
77
|
+
oid = consumer.begin oid_url
|
78
|
+
return auth_fail unless oid.status == ::OpenID::SUCCESS
|
79
|
+
@options.each do |ns,s|
|
80
|
+
next unless ns.is_a? String
|
81
|
+
s.each {|k,v| oid.add_extension_arg(ns, k, v) }
|
82
|
+
end
|
83
|
+
r_url = @options.fetch :return do |k| request.url end
|
84
|
+
t_url = @options.fetch :trust
|
85
|
+
env['rack.auth.openid.status'] = oid
|
86
|
+
return 303, {'Location'=>oid.redirect_url( t_url, r_url )}, []
|
87
|
+
end
|
88
|
+
|
89
|
+
def finish(session, params, env)
|
90
|
+
consumer = ::OpenID::Consumer.new session, OIDStore
|
91
|
+
oid = consumer.complete params
|
92
|
+
return bad_login unless oid.status == ::OpenID::SUCCESS
|
93
|
+
session[:openid] = {'identity' => oid.identity_url}
|
94
|
+
@options.each do |ns,s|
|
95
|
+
next unless ns.is_a? String
|
96
|
+
oid.extension_response(ns).each{|k,v| session[k]=v }
|
97
|
+
end
|
98
|
+
env['rack.auth.openid.status'] = oid
|
99
|
+
return 303, {'Location'=>@options[:trust]}, []
|
100
|
+
end
|
101
|
+
|
102
|
+
def no_session
|
103
|
+
@options.
|
104
|
+
fetch :no_session, [500,{'Content-Type'=>'text/plain'},'No session available.']
|
105
|
+
end
|
106
|
+
def auth_fail
|
107
|
+
@options.
|
108
|
+
fetch :auth_fail, [500, {'Content-Type'=>'text/plain'},'Foreign server failure.']
|
109
|
+
end
|
110
|
+
def bad_login
|
111
|
+
@options.
|
112
|
+
fetch :bad_login, [401, {'Content-Type'=>'text/plain'},'Identification has failed.']
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Rack
|
2
|
+
# Rack::Builder implements a small DSL to iteratively construct Rack
|
3
|
+
# applications.
|
4
|
+
#
|
5
|
+
# Example:
|
6
|
+
#
|
7
|
+
# app = Rack::Builder.new {
|
8
|
+
# use Rack::CommonLogger
|
9
|
+
# use Rack::ShowExceptions
|
10
|
+
# map "/lobster" do
|
11
|
+
# use Rack::Lint
|
12
|
+
# run Rack::Lobster.new
|
13
|
+
# end
|
14
|
+
# }
|
15
|
+
#
|
16
|
+
# +use+ adds a middleware to the stack, +run+ dispatches to an application.
|
17
|
+
# You can use +map+ to construct a Rack::URLMap in a convenient way.
|
18
|
+
|
19
|
+
class Builder
|
20
|
+
def initialize(&block)
|
21
|
+
@ins = []
|
22
|
+
instance_eval(&block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def use(middleware, *args, &block)
|
26
|
+
@ins << if block_given?
|
27
|
+
lambda { |app| middleware.new(app, *args, &block) }
|
28
|
+
else
|
29
|
+
lambda { |app| middleware.new(app, *args) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def run(app)
|
34
|
+
@ins << app #lambda { |nothing| app }
|
35
|
+
end
|
36
|
+
|
37
|
+
def map(path, &block)
|
38
|
+
if @ins.last.kind_of? Hash
|
39
|
+
@ins.last[path] = Rack::Builder.new(&block).to_app
|
40
|
+
else
|
41
|
+
@ins << {}
|
42
|
+
map(path, &block)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_app
|
47
|
+
@ins[-1] = Rack::URLMap.new(@ins.last) if Hash === @ins.last
|
48
|
+
inner_app = @ins.last
|
49
|
+
@ins[0...-1].reverse.inject(inner_app) { |a, e| e.call(a) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def call(env)
|
53
|
+
to_app.call(env)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Rack
|
2
|
+
# Rack::Cascade tries an request on several apps, and returns the
|
3
|
+
# first response that is not 404 (or in a list of configurable
|
4
|
+
# status codes).
|
5
|
+
|
6
|
+
class Cascade
|
7
|
+
attr_reader :apps
|
8
|
+
|
9
|
+
def initialize(apps, catch=404)
|
10
|
+
@apps = apps
|
11
|
+
@catch = [*catch]
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(env)
|
15
|
+
status = headers = body = nil
|
16
|
+
raise ArgumentError, "empty cascade" if @apps.empty?
|
17
|
+
@apps.each { |app|
|
18
|
+
begin
|
19
|
+
status, headers, body = app.call(env)
|
20
|
+
break unless @catch.include?(status.to_i)
|
21
|
+
end
|
22
|
+
}
|
23
|
+
[status, headers, body]
|
24
|
+
end
|
25
|
+
|
26
|
+
def add app
|
27
|
+
@apps << app
|
28
|
+
end
|
29
|
+
|
30
|
+
def include? app
|
31
|
+
@apps.include? app
|
32
|
+
end
|
33
|
+
|
34
|
+
alias_method :<<, :add
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
module Rack
|
2
|
+
# Rack::CommonLogger forwards every request to an +app+ given, and
|
3
|
+
# logs a line in the Apache common log format to the +logger+, or
|
4
|
+
# rack.errors by default.
|
5
|
+
|
6
|
+
class CommonLogger
|
7
|
+
def initialize(app, logger=nil)
|
8
|
+
@app = app
|
9
|
+
@logger = logger
|
10
|
+
end
|
11
|
+
|
12
|
+
def call(env)
|
13
|
+
dup._call(env)
|
14
|
+
end
|
15
|
+
|
16
|
+
def _call(env)
|
17
|
+
@env = env
|
18
|
+
@logger ||= self
|
19
|
+
@time = Time.now
|
20
|
+
@status, @header, @body = @app.call(env)
|
21
|
+
[@status, @header, self]
|
22
|
+
end
|
23
|
+
|
24
|
+
# By default, log to rack.errors.
|
25
|
+
def <<(str)
|
26
|
+
@env["rack.errors"].write(str)
|
27
|
+
@env["rack.errors"].flush
|
28
|
+
end
|
29
|
+
|
30
|
+
def each
|
31
|
+
length = 0
|
32
|
+
@body.each { |part|
|
33
|
+
length += part.size
|
34
|
+
yield part
|
35
|
+
}
|
36
|
+
|
37
|
+
@now = Time.now
|
38
|
+
|
39
|
+
# Common Log Format: http://httpd.apache.org/docs/1.3/logs.html#common
|
40
|
+
# lilith.local - - [07/Aug/2006 23:58:02] "GET / HTTP/1.1" 500 -
|
41
|
+
# %{%s - %s [%s] "%s %s%s %s" %d %s\n} %
|
42
|
+
@logger << %{%s - %s [%s] "%s %s%s %s" %d %s %0.4f\n} %
|
43
|
+
[@env["REMOTE_ADDR"] || "-",
|
44
|
+
@env["REMOTE_USER"] || "-",
|
45
|
+
@now.strftime("%d/%b/%Y %H:%M:%S"),
|
46
|
+
@env["REQUEST_METHOD"],
|
47
|
+
@env["PATH_INFO"],
|
48
|
+
@env["QUERY_STRING"].empty? ? "" : "?"+@env["QUERY_STRING"],
|
49
|
+
@env["HTTP_VERSION"],
|
50
|
+
@status.to_s[0..3],
|
51
|
+
(length.zero? ? "-" : length.to_s),
|
52
|
+
@now - @time
|
53
|
+
]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'time'
|
2
|
+
|
3
|
+
module Rack
|
4
|
+
# Rack::File serves files below the +root+ given, according to the
|
5
|
+
# path info of the Rack request.
|
6
|
+
#
|
7
|
+
# Handlers can detect if bodies are a Rack::File, and use mechanisms
|
8
|
+
# like sendfile on the +path+.
|
9
|
+
|
10
|
+
class File
|
11
|
+
attr_accessor :root
|
12
|
+
attr_accessor :path
|
13
|
+
|
14
|
+
def initialize(root)
|
15
|
+
@root = root
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
dup._call(env)
|
20
|
+
end
|
21
|
+
|
22
|
+
F = ::File
|
23
|
+
|
24
|
+
def _call(env)
|
25
|
+
if env["PATH_INFO"].include? ".."
|
26
|
+
return [403, {"Content-Type" => "text/plain"}, ["Forbidden\n"]]
|
27
|
+
end
|
28
|
+
|
29
|
+
@path = F.join(@root, Utils.unescape(env["PATH_INFO"]))
|
30
|
+
ext = F.extname(@path)[1..-1]
|
31
|
+
|
32
|
+
if F.file?(@path) && F.readable?(@path)
|
33
|
+
[200, {
|
34
|
+
"Last-Modified" => F.mtime(@path).rfc822,
|
35
|
+
"Content-Type" => MIME_TYPES[ext] || "text/plain",
|
36
|
+
"Content-Length" => F.size(@path).to_s
|
37
|
+
}, self]
|
38
|
+
else
|
39
|
+
return [404, {"Content-Type" => "text/plain"},
|
40
|
+
["File not found: #{env["PATH_INFO"]}\n"]]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def each
|
45
|
+
F.open(@path, "rb") { |file|
|
46
|
+
while part = file.read(8192)
|
47
|
+
yield part
|
48
|
+
end
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
# :stopdoc:
|
53
|
+
# From WEBrick.
|
54
|
+
MIME_TYPES = {
|
55
|
+
"ai" => "application/postscript",
|
56
|
+
"asc" => "text/plain",
|
57
|
+
"avi" => "video/x-msvideo",
|
58
|
+
"bin" => "application/octet-stream",
|
59
|
+
"bmp" => "image/bmp",
|
60
|
+
"class" => "application/octet-stream",
|
61
|
+
"cer" => "application/pkix-cert",
|
62
|
+
"crl" => "application/pkix-crl",
|
63
|
+
"crt" => "application/x-x509-ca-cert",
|
64
|
+
#"crl" => "application/x-pkcs7-crl",
|
65
|
+
"css" => "text/css",
|
66
|
+
"dms" => "application/octet-stream",
|
67
|
+
"doc" => "application/msword",
|
68
|
+
"dvi" => "application/x-dvi",
|
69
|
+
"eps" => "application/postscript",
|
70
|
+
"etx" => "text/x-setext",
|
71
|
+
"exe" => "application/octet-stream",
|
72
|
+
"gif" => "image/gif",
|
73
|
+
"htm" => "text/html",
|
74
|
+
"html" => "text/html",
|
75
|
+
"jpe" => "image/jpeg",
|
76
|
+
"jpeg" => "image/jpeg",
|
77
|
+
"jpg" => "image/jpeg",
|
78
|
+
"js" => "text/javascript",
|
79
|
+
"lha" => "application/octet-stream",
|
80
|
+
"lzh" => "application/octet-stream",
|
81
|
+
"mov" => "video/quicktime",
|
82
|
+
"mpe" => "video/mpeg",
|
83
|
+
"mpeg" => "video/mpeg",
|
84
|
+
"mpg" => "video/mpeg",
|
85
|
+
"pbm" => "image/x-portable-bitmap",
|
86
|
+
"pdf" => "application/pdf",
|
87
|
+
"pgm" => "image/x-portable-graymap",
|
88
|
+
"png" => "image/png",
|
89
|
+
"pnm" => "image/x-portable-anymap",
|
90
|
+
"ppm" => "image/x-portable-pixmap",
|
91
|
+
"ppt" => "application/vnd.ms-powerpoint",
|
92
|
+
"ps" => "application/postscript",
|
93
|
+
"qt" => "video/quicktime",
|
94
|
+
"ras" => "image/x-cmu-raster",
|
95
|
+
"rb" => "text/plain",
|
96
|
+
"rd" => "text/plain",
|
97
|
+
"rtf" => "application/rtf",
|
98
|
+
"sgm" => "text/sgml",
|
99
|
+
"sgml" => "text/sgml",
|
100
|
+
"tif" => "image/tiff",
|
101
|
+
"tiff" => "image/tiff",
|
102
|
+
"txt" => "text/plain",
|
103
|
+
"xbm" => "image/x-xbitmap",
|
104
|
+
"xls" => "application/vnd.ms-excel",
|
105
|
+
"xml" => "text/xml",
|
106
|
+
"xpm" => "image/x-xpixmap",
|
107
|
+
"xwd" => "image/x-xwindowdump",
|
108
|
+
"zip" => "application/zip",
|
109
|
+
}
|
110
|
+
# :startdoc:
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Rack
|
2
|
+
module Handler
|
3
|
+
class CGI
|
4
|
+
def self.run(app, options=nil)
|
5
|
+
serve app
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.serve(app)
|
9
|
+
env = ENV.to_hash
|
10
|
+
env.delete "HTTP_CONTENT_LENGTH"
|
11
|
+
|
12
|
+
env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
|
13
|
+
|
14
|
+
env.update({"rack.version" => [0,1],
|
15
|
+
"rack.input" => STDIN,
|
16
|
+
"rack.errors" => STDERR,
|
17
|
+
|
18
|
+
"rack.multithread" => false,
|
19
|
+
"rack.multiprocess" => true,
|
20
|
+
"rack.run_once" => true,
|
21
|
+
|
22
|
+
"rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
|
23
|
+
})
|
24
|
+
|
25
|
+
env["QUERY_STRING"] ||= ""
|
26
|
+
env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
|
27
|
+
env["REQUEST_PATH"] ||= "/"
|
28
|
+
|
29
|
+
status, headers, body = app.call(env)
|
30
|
+
begin
|
31
|
+
send_headers status, headers
|
32
|
+
send_body body
|
33
|
+
ensure
|
34
|
+
body.close if body.respond_to? :close
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.send_headers(status, headers)
|
39
|
+
STDOUT.print "Status: #{status}\r\n"
|
40
|
+
headers.each { |k, vs|
|
41
|
+
vs.each { |v|
|
42
|
+
STDOUT.print "#{k}: #{v}\r\n"
|
43
|
+
}
|
44
|
+
}
|
45
|
+
STDOUT.print "\r\n"
|
46
|
+
STDOUT.flush
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.send_body(body)
|
50
|
+
body.each { |part|
|
51
|
+
STDOUT.print part
|
52
|
+
STDOUT.flush
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|