rack 2.1.0 → 3.1.0
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.
Potentially problematic release.
This version of rack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +377 -16
- data/CONTRIBUTING.md +144 -0
- data/MIT-LICENSE +1 -1
- data/README.md +328 -0
- data/SPEC.rdoc +365 -0
- data/lib/rack/auth/abstract/handler.rb +3 -1
- data/lib/rack/auth/abstract/request.rb +2 -2
- data/lib/rack/auth/basic.rb +4 -7
- data/lib/rack/bad_request.rb +8 -0
- data/lib/rack/body_proxy.rb +34 -12
- data/lib/rack/builder.rb +162 -59
- data/lib/rack/cascade.rb +24 -10
- data/lib/rack/common_logger.rb +43 -28
- data/lib/rack/conditional_get.rb +30 -25
- data/lib/rack/constants.rb +66 -0
- data/lib/rack/content_length.rb +10 -16
- data/lib/rack/content_type.rb +9 -7
- data/lib/rack/deflater.rb +78 -50
- data/lib/rack/directory.rb +86 -63
- data/lib/rack/etag.rb +14 -22
- data/lib/rack/events.rb +18 -17
- data/lib/rack/files.rb +99 -61
- data/lib/rack/head.rb +8 -9
- data/lib/rack/headers.rb +238 -0
- data/lib/rack/lint.rb +868 -642
- data/lib/rack/lock.rb +2 -6
- data/lib/rack/logger.rb +3 -0
- data/lib/rack/media_type.rb +9 -4
- data/lib/rack/method_override.rb +6 -2
- data/lib/rack/mime.rb +14 -5
- data/lib/rack/mock.rb +1 -253
- data/lib/rack/mock_request.rb +171 -0
- data/lib/rack/mock_response.rb +124 -0
- data/lib/rack/multipart/generator.rb +15 -8
- data/lib/rack/multipart/parser.rb +238 -107
- data/lib/rack/multipart/uploaded_file.rb +17 -7
- data/lib/rack/multipart.rb +54 -42
- data/lib/rack/null_logger.rb +9 -0
- data/lib/rack/query_parser.rb +87 -105
- data/lib/rack/recursive.rb +3 -1
- data/lib/rack/reloader.rb +0 -4
- data/lib/rack/request.rb +366 -135
- data/lib/rack/response.rb +186 -68
- data/lib/rack/rewindable_input.rb +24 -6
- data/lib/rack/runtime.rb +8 -7
- data/lib/rack/sendfile.rb +29 -27
- data/lib/rack/show_exceptions.rb +27 -12
- data/lib/rack/show_status.rb +21 -13
- data/lib/rack/static.rb +19 -12
- data/lib/rack/tempfile_reaper.rb +14 -5
- data/lib/rack/urlmap.rb +5 -6
- data/lib/rack/utils.rb +274 -260
- data/lib/rack/version.rb +21 -0
- data/lib/rack.rb +18 -103
- metadata +25 -52
- data/README.rdoc +0 -262
- data/Rakefile +0 -123
- data/SPEC +0 -263
- data/bin/rackup +0 -5
- data/contrib/rack.png +0 -0
- data/contrib/rack.svg +0 -150
- data/contrib/rack_logo.svg +0 -164
- data/contrib/rdoc.css +0 -412
- data/example/lobster.ru +0 -6
- data/example/protectedlobster.rb +0 -16
- data/example/protectedlobster.ru +0 -10
- data/lib/rack/auth/digest/md5.rb +0 -131
- data/lib/rack/auth/digest/nonce.rb +0 -54
- data/lib/rack/auth/digest/params.rb +0 -54
- data/lib/rack/auth/digest/request.rb +0 -43
- data/lib/rack/chunked.rb +0 -92
- data/lib/rack/core_ext/regexp.rb +0 -14
- data/lib/rack/file.rb +0 -8
- data/lib/rack/handler/cgi.rb +0 -62
- data/lib/rack/handler/fastcgi.rb +0 -102
- data/lib/rack/handler/lsws.rb +0 -63
- data/lib/rack/handler/scgi.rb +0 -73
- data/lib/rack/handler/thin.rb +0 -38
- data/lib/rack/handler/webrick.rb +0 -122
- data/lib/rack/handler.rb +0 -104
- data/lib/rack/lobster.rb +0 -72
- data/lib/rack/server.rb +0 -467
- data/lib/rack/session/abstract/id.rb +0 -528
- data/lib/rack/session/cookie.rb +0 -205
- data/lib/rack/session/memcache.rb +0 -10
- data/lib/rack/session/pool.rb +0 -85
- data/rack.gemspec +0 -44
data/lib/rack/auth/digest/md5.rb
DELETED
@@ -1,131 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rack/auth/abstract/handler'
|
4
|
-
require 'rack/auth/digest/request'
|
5
|
-
require 'rack/auth/digest/params'
|
6
|
-
require 'rack/auth/digest/nonce'
|
7
|
-
require 'digest/md5'
|
8
|
-
|
9
|
-
module Rack
|
10
|
-
module Auth
|
11
|
-
module Digest
|
12
|
-
# Rack::Auth::Digest::MD5 implements the MD5 algorithm version of
|
13
|
-
# HTTP Digest Authentication, as per RFC 2617.
|
14
|
-
#
|
15
|
-
# Initialize with the [Rack] application that you want protecting,
|
16
|
-
# and a block that looks up a plaintext password for a given username.
|
17
|
-
#
|
18
|
-
# +opaque+ needs to be set to a constant base64/hexadecimal string.
|
19
|
-
#
|
20
|
-
class MD5 < AbstractHandler
|
21
|
-
|
22
|
-
attr_accessor :opaque
|
23
|
-
|
24
|
-
attr_writer :passwords_hashed
|
25
|
-
|
26
|
-
def initialize(app, realm = nil, opaque = nil, &authenticator)
|
27
|
-
@passwords_hashed = nil
|
28
|
-
if opaque.nil? and realm.respond_to? :values_at
|
29
|
-
realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed
|
30
|
-
end
|
31
|
-
super(app, realm, &authenticator)
|
32
|
-
@opaque = opaque
|
33
|
-
end
|
34
|
-
|
35
|
-
def passwords_hashed?
|
36
|
-
!!@passwords_hashed
|
37
|
-
end
|
38
|
-
|
39
|
-
def call(env)
|
40
|
-
auth = Request.new(env)
|
41
|
-
|
42
|
-
unless auth.provided?
|
43
|
-
return unauthorized
|
44
|
-
end
|
45
|
-
|
46
|
-
if !auth.digest? || !auth.correct_uri? || !valid_qop?(auth)
|
47
|
-
return bad_request
|
48
|
-
end
|
49
|
-
|
50
|
-
if valid?(auth)
|
51
|
-
if auth.nonce.stale?
|
52
|
-
return unauthorized(challenge(stale: true))
|
53
|
-
else
|
54
|
-
env['REMOTE_USER'] = auth.username
|
55
|
-
|
56
|
-
return @app.call(env)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
unauthorized
|
61
|
-
end
|
62
|
-
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
QOP = 'auth'
|
67
|
-
|
68
|
-
def params(hash = {})
|
69
|
-
Params.new do |params|
|
70
|
-
params['realm'] = realm
|
71
|
-
params['nonce'] = Nonce.new.to_s
|
72
|
-
params['opaque'] = H(opaque)
|
73
|
-
params['qop'] = QOP
|
74
|
-
|
75
|
-
hash.each { |k, v| params[k] = v }
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def challenge(hash = {})
|
80
|
-
"Digest #{params(hash)}"
|
81
|
-
end
|
82
|
-
|
83
|
-
def valid?(auth)
|
84
|
-
valid_opaque?(auth) && valid_nonce?(auth) && valid_digest?(auth)
|
85
|
-
end
|
86
|
-
|
87
|
-
def valid_qop?(auth)
|
88
|
-
QOP == auth.qop
|
89
|
-
end
|
90
|
-
|
91
|
-
def valid_opaque?(auth)
|
92
|
-
H(opaque) == auth.opaque
|
93
|
-
end
|
94
|
-
|
95
|
-
def valid_nonce?(auth)
|
96
|
-
auth.nonce.valid?
|
97
|
-
end
|
98
|
-
|
99
|
-
def valid_digest?(auth)
|
100
|
-
pw = @authenticator.call(auth.username)
|
101
|
-
pw && Rack::Utils.secure_compare(digest(auth, pw), auth.response)
|
102
|
-
end
|
103
|
-
|
104
|
-
def md5(data)
|
105
|
-
::Digest::MD5.hexdigest(data)
|
106
|
-
end
|
107
|
-
|
108
|
-
alias :H :md5
|
109
|
-
|
110
|
-
def KD(secret, data)
|
111
|
-
H "#{secret}:#{data}"
|
112
|
-
end
|
113
|
-
|
114
|
-
def A1(auth, password)
|
115
|
-
"#{auth.username}:#{auth.realm}:#{password}"
|
116
|
-
end
|
117
|
-
|
118
|
-
def A2(auth)
|
119
|
-
"#{auth.method}:#{auth.uri}"
|
120
|
-
end
|
121
|
-
|
122
|
-
def digest(auth, password)
|
123
|
-
password_hash = passwords_hashed? ? password : H(A1(auth, password))
|
124
|
-
|
125
|
-
KD password_hash, "#{auth.nonce}:#{auth.nc}:#{auth.cnonce}:#{QOP}:#{H A2(auth)}"
|
126
|
-
end
|
127
|
-
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'digest/md5'
|
4
|
-
require 'base64'
|
5
|
-
|
6
|
-
module Rack
|
7
|
-
module Auth
|
8
|
-
module Digest
|
9
|
-
# Rack::Auth::Digest::Nonce is the default nonce generator for the
|
10
|
-
# Rack::Auth::Digest::MD5 authentication handler.
|
11
|
-
#
|
12
|
-
# +private_key+ needs to set to a constant string.
|
13
|
-
#
|
14
|
-
# +time_limit+ can be optionally set to an integer (number of seconds),
|
15
|
-
# to limit the validity of the generated nonces.
|
16
|
-
|
17
|
-
class Nonce
|
18
|
-
|
19
|
-
class << self
|
20
|
-
attr_accessor :private_key, :time_limit
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.parse(string)
|
24
|
-
new(*Base64.decode64(string).split(' ', 2))
|
25
|
-
end
|
26
|
-
|
27
|
-
def initialize(timestamp = Time.now, given_digest = nil)
|
28
|
-
@timestamp, @given_digest = timestamp.to_i, given_digest
|
29
|
-
end
|
30
|
-
|
31
|
-
def to_s
|
32
|
-
Base64.encode64("#{@timestamp} #{digest}").strip
|
33
|
-
end
|
34
|
-
|
35
|
-
def digest
|
36
|
-
::Digest::MD5.hexdigest("#{@timestamp}:#{self.class.private_key}")
|
37
|
-
end
|
38
|
-
|
39
|
-
def valid?
|
40
|
-
digest == @given_digest
|
41
|
-
end
|
42
|
-
|
43
|
-
def stale?
|
44
|
-
!self.class.time_limit.nil? && (Time.now.to_i - @timestamp) > self.class.time_limit
|
45
|
-
end
|
46
|
-
|
47
|
-
def fresh?
|
48
|
-
!stale?
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,54 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Rack
|
4
|
-
module Auth
|
5
|
-
module Digest
|
6
|
-
class Params < Hash
|
7
|
-
|
8
|
-
def self.parse(str)
|
9
|
-
Params[*split_header_value(str).map do |param|
|
10
|
-
k, v = param.split('=', 2)
|
11
|
-
[k, dequote(v)]
|
12
|
-
end.flatten]
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.dequote(str) # From WEBrick::HTTPUtils
|
16
|
-
ret = (/\A"(.*)"\Z/ =~ str) ? $1 : str.dup
|
17
|
-
ret.gsub!(/\\(.)/, "\\1")
|
18
|
-
ret
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.split_header_value(str)
|
22
|
-
str.scan(/\w+\=(?:"[^\"]+"|[^,]+)/n)
|
23
|
-
end
|
24
|
-
|
25
|
-
def initialize
|
26
|
-
super()
|
27
|
-
|
28
|
-
yield self if block_given?
|
29
|
-
end
|
30
|
-
|
31
|
-
def [](k)
|
32
|
-
super k.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
def []=(k, v)
|
36
|
-
super k.to_s, v.to_s
|
37
|
-
end
|
38
|
-
|
39
|
-
UNQUOTED = ['nc', 'stale']
|
40
|
-
|
41
|
-
def to_s
|
42
|
-
map do |k, v|
|
43
|
-
"#{k}=#{(UNQUOTED.include?(k) ? v.to_s : quote(v))}"
|
44
|
-
end.join(', ')
|
45
|
-
end
|
46
|
-
|
47
|
-
def quote(str) # From WEBrick::HTTPUtils
|
48
|
-
'"' + str.gsub(/[\\\"]/o, "\\\1") + '"'
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rack/auth/abstract/request'
|
4
|
-
require 'rack/auth/digest/params'
|
5
|
-
require 'rack/auth/digest/nonce'
|
6
|
-
|
7
|
-
module Rack
|
8
|
-
module Auth
|
9
|
-
module Digest
|
10
|
-
class Request < Auth::AbstractRequest
|
11
|
-
def method
|
12
|
-
@env[RACK_METHODOVERRIDE_ORIGINAL_METHOD] || @env[REQUEST_METHOD]
|
13
|
-
end
|
14
|
-
|
15
|
-
def digest?
|
16
|
-
"digest" == scheme
|
17
|
-
end
|
18
|
-
|
19
|
-
def correct_uri?
|
20
|
-
request.fullpath == uri
|
21
|
-
end
|
22
|
-
|
23
|
-
def nonce
|
24
|
-
@nonce ||= Nonce.parse(params['nonce'])
|
25
|
-
end
|
26
|
-
|
27
|
-
def params
|
28
|
-
@params ||= Params.parse(parts.last)
|
29
|
-
end
|
30
|
-
|
31
|
-
def respond_to?(sym, *)
|
32
|
-
super or params.has_key? sym.to_s
|
33
|
-
end
|
34
|
-
|
35
|
-
def method_missing(sym, *args)
|
36
|
-
return super unless params.has_key?(key = sym.to_s)
|
37
|
-
return params[key] if args.size == 0
|
38
|
-
raise ArgumentError, "wrong number of arguments (#{args.size} for 0)"
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/rack/chunked.rb
DELETED
@@ -1,92 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rack/utils'
|
4
|
-
|
5
|
-
module Rack
|
6
|
-
|
7
|
-
# Middleware that applies chunked transfer encoding to response bodies
|
8
|
-
# when the response does not include a Content-Length header.
|
9
|
-
class Chunked
|
10
|
-
include Rack::Utils
|
11
|
-
|
12
|
-
# A body wrapper that emits chunked responses
|
13
|
-
class Body
|
14
|
-
TERM = "\r\n"
|
15
|
-
TAIL = "0#{TERM}"
|
16
|
-
|
17
|
-
include Rack::Utils
|
18
|
-
|
19
|
-
def initialize(body)
|
20
|
-
@body = body
|
21
|
-
end
|
22
|
-
|
23
|
-
def each(&block)
|
24
|
-
term = TERM
|
25
|
-
@body.each do |chunk|
|
26
|
-
size = chunk.bytesize
|
27
|
-
next if size == 0
|
28
|
-
|
29
|
-
chunk = chunk.b
|
30
|
-
yield [size.to_s(16), term, chunk, term].join
|
31
|
-
end
|
32
|
-
yield TAIL
|
33
|
-
insert_trailers(&block)
|
34
|
-
yield TERM
|
35
|
-
end
|
36
|
-
|
37
|
-
def close
|
38
|
-
@body.close if @body.respond_to?(:close)
|
39
|
-
end
|
40
|
-
|
41
|
-
private
|
42
|
-
|
43
|
-
def insert_trailers(&block)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class TrailerBody < Body
|
48
|
-
private
|
49
|
-
|
50
|
-
def insert_trailers(&block)
|
51
|
-
@body.trailers.each_pair do |k, v|
|
52
|
-
yield "#{k}: #{v}\r\n"
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def initialize(app)
|
58
|
-
@app = app
|
59
|
-
end
|
60
|
-
|
61
|
-
# pre-HTTP/1.0 (informally "HTTP/0.9") HTTP requests did not have
|
62
|
-
# a version (nor response headers)
|
63
|
-
def chunkable_version?(ver)
|
64
|
-
case ver
|
65
|
-
when 'HTTP/1.0', nil, 'HTTP/0.9'
|
66
|
-
false
|
67
|
-
else
|
68
|
-
true
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def call(env)
|
73
|
-
status, headers, body = @app.call(env)
|
74
|
-
headers = HeaderHash.new(headers)
|
75
|
-
|
76
|
-
if ! chunkable_version?(env[SERVER_PROTOCOL]) ||
|
77
|
-
STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) ||
|
78
|
-
headers[CONTENT_LENGTH] ||
|
79
|
-
headers[TRANSFER_ENCODING]
|
80
|
-
[status, headers, body]
|
81
|
-
else
|
82
|
-
headers.delete(CONTENT_LENGTH)
|
83
|
-
headers[TRANSFER_ENCODING] = 'chunked'
|
84
|
-
if headers['Trailer']
|
85
|
-
[status, headers, TrailerBody.new(body)]
|
86
|
-
else
|
87
|
-
[status, headers, Body.new(body)]
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
data/lib/rack/core_ext/regexp.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Regexp has `match?` since Ruby 2.4
|
4
|
-
# so to support Ruby < 2.4 we need to define this method
|
5
|
-
|
6
|
-
module Rack
|
7
|
-
module RegexpExtensions
|
8
|
-
refine Regexp do
|
9
|
-
def match?(string, pos = 0)
|
10
|
-
!!match(string, pos)
|
11
|
-
end
|
12
|
-
end unless //.respond_to?(:match?)
|
13
|
-
end
|
14
|
-
end
|
data/lib/rack/file.rb
DELETED
data/lib/rack/handler/cgi.rb
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'rack/content_length'
|
4
|
-
require 'rack/rewindable_input'
|
5
|
-
|
6
|
-
module Rack
|
7
|
-
module Handler
|
8
|
-
class CGI
|
9
|
-
def self.run(app, options = nil)
|
10
|
-
$stdin.binmode
|
11
|
-
serve app
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.serve(app)
|
15
|
-
env = ENV.to_hash
|
16
|
-
env.delete "HTTP_CONTENT_LENGTH"
|
17
|
-
|
18
|
-
env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
|
19
|
-
|
20
|
-
env.update(
|
21
|
-
RACK_VERSION => Rack::VERSION,
|
22
|
-
RACK_INPUT => Rack::RewindableInput.new($stdin),
|
23
|
-
RACK_ERRORS => $stderr,
|
24
|
-
RACK_MULTITHREAD => false,
|
25
|
-
RACK_MULTIPROCESS => true,
|
26
|
-
RACK_RUNONCE => true,
|
27
|
-
RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http"
|
28
|
-
)
|
29
|
-
|
30
|
-
env[QUERY_STRING] ||= ""
|
31
|
-
env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
|
32
|
-
env[REQUEST_PATH] ||= "/"
|
33
|
-
|
34
|
-
status, headers, body = app.call(env)
|
35
|
-
begin
|
36
|
-
send_headers status, headers
|
37
|
-
send_body body
|
38
|
-
ensure
|
39
|
-
body.close if body.respond_to? :close
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.send_headers(status, headers)
|
44
|
-
$stdout.print "Status: #{status}\r\n"
|
45
|
-
headers.each { |k, vs|
|
46
|
-
vs.split("\n").each { |v|
|
47
|
-
$stdout.print "#{k}: #{v}\r\n"
|
48
|
-
}
|
49
|
-
}
|
50
|
-
$stdout.print "\r\n"
|
51
|
-
$stdout.flush
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.send_body(body)
|
55
|
-
body.each { |part|
|
56
|
-
$stdout.print part
|
57
|
-
$stdout.flush
|
58
|
-
}
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
data/lib/rack/handler/fastcgi.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'fcgi'
|
4
|
-
require 'socket'
|
5
|
-
require 'rack/content_length'
|
6
|
-
require 'rack/rewindable_input'
|
7
|
-
|
8
|
-
if defined? FCGI::Stream
|
9
|
-
class FCGI::Stream
|
10
|
-
alias _rack_read_without_buffer read
|
11
|
-
|
12
|
-
def read(n, buffer = nil)
|
13
|
-
buf = _rack_read_without_buffer n
|
14
|
-
buffer.replace(buf.to_s) if buffer
|
15
|
-
buf
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
module Rack
|
21
|
-
module Handler
|
22
|
-
class FastCGI
|
23
|
-
def self.run(app, options = {})
|
24
|
-
if options[:File]
|
25
|
-
STDIN.reopen(UNIXServer.new(options[:File]))
|
26
|
-
elsif options[:Port]
|
27
|
-
STDIN.reopen(TCPServer.new(options[:Host], options[:Port]))
|
28
|
-
end
|
29
|
-
FCGI.each { |request|
|
30
|
-
serve request, app
|
31
|
-
}
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.valid_options
|
35
|
-
environment = ENV['RACK_ENV'] || 'development'
|
36
|
-
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
37
|
-
|
38
|
-
{
|
39
|
-
"Host=HOST" => "Hostname to listen on (default: #{default_host})",
|
40
|
-
"Port=PORT" => "Port to listen on (default: 8080)",
|
41
|
-
"File=PATH" => "Creates a Domain socket at PATH instead of a TCP socket. Ignores Host and Port if set.",
|
42
|
-
}
|
43
|
-
end
|
44
|
-
|
45
|
-
def self.serve(request, app)
|
46
|
-
env = request.env
|
47
|
-
env.delete "HTTP_CONTENT_LENGTH"
|
48
|
-
|
49
|
-
env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
|
50
|
-
|
51
|
-
rack_input = RewindableInput.new(request.in)
|
52
|
-
|
53
|
-
env.update(
|
54
|
-
RACK_VERSION => Rack::VERSION,
|
55
|
-
RACK_INPUT => rack_input,
|
56
|
-
RACK_ERRORS => request.err,
|
57
|
-
RACK_MULTITHREAD => false,
|
58
|
-
RACK_MULTIPROCESS => true,
|
59
|
-
RACK_RUNONCE => false,
|
60
|
-
RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http"
|
61
|
-
)
|
62
|
-
|
63
|
-
env[QUERY_STRING] ||= ""
|
64
|
-
env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
|
65
|
-
env[REQUEST_PATH] ||= "/"
|
66
|
-
env.delete "CONTENT_TYPE" if env["CONTENT_TYPE"] == ""
|
67
|
-
env.delete "CONTENT_LENGTH" if env["CONTENT_LENGTH"] == ""
|
68
|
-
|
69
|
-
begin
|
70
|
-
status, headers, body = app.call(env)
|
71
|
-
begin
|
72
|
-
send_headers request.out, status, headers
|
73
|
-
send_body request.out, body
|
74
|
-
ensure
|
75
|
-
body.close if body.respond_to? :close
|
76
|
-
end
|
77
|
-
ensure
|
78
|
-
rack_input.close
|
79
|
-
request.finish
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def self.send_headers(out, status, headers)
|
84
|
-
out.print "Status: #{status}\r\n"
|
85
|
-
headers.each { |k, vs|
|
86
|
-
vs.split("\n").each { |v|
|
87
|
-
out.print "#{k}: #{v}\r\n"
|
88
|
-
}
|
89
|
-
}
|
90
|
-
out.print "\r\n"
|
91
|
-
out.flush
|
92
|
-
end
|
93
|
-
|
94
|
-
def self.send_body(out, body)
|
95
|
-
body.each { |part|
|
96
|
-
out.print part
|
97
|
-
out.flush
|
98
|
-
}
|
99
|
-
end
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
data/lib/rack/handler/lsws.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'lsapi'
|
4
|
-
require 'rack/content_length'
|
5
|
-
require 'rack/rewindable_input'
|
6
|
-
|
7
|
-
module Rack
|
8
|
-
module Handler
|
9
|
-
class LSWS
|
10
|
-
def self.run(app, options = nil)
|
11
|
-
while LSAPI.accept != nil
|
12
|
-
serve app
|
13
|
-
end
|
14
|
-
end
|
15
|
-
def self.serve(app)
|
16
|
-
env = ENV.to_hash
|
17
|
-
env.delete "HTTP_CONTENT_LENGTH"
|
18
|
-
env[SCRIPT_NAME] = "" if env[SCRIPT_NAME] == "/"
|
19
|
-
|
20
|
-
rack_input = RewindableInput.new($stdin.read.to_s)
|
21
|
-
|
22
|
-
env.update(
|
23
|
-
RACK_VERSION => Rack::VERSION,
|
24
|
-
RACK_INPUT => rack_input,
|
25
|
-
RACK_ERRORS => $stderr,
|
26
|
-
RACK_MULTITHREAD => false,
|
27
|
-
RACK_MULTIPROCESS => true,
|
28
|
-
RACK_RUNONCE => false,
|
29
|
-
RACK_URL_SCHEME => ["yes", "on", "1"].include?(ENV[HTTPS]) ? "https" : "http"
|
30
|
-
)
|
31
|
-
|
32
|
-
env[QUERY_STRING] ||= ""
|
33
|
-
env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
|
34
|
-
env[REQUEST_PATH] ||= "/"
|
35
|
-
status, headers, body = app.call(env)
|
36
|
-
begin
|
37
|
-
send_headers status, headers
|
38
|
-
send_body body
|
39
|
-
ensure
|
40
|
-
body.close if body.respond_to? :close
|
41
|
-
end
|
42
|
-
ensure
|
43
|
-
rack_input.close
|
44
|
-
end
|
45
|
-
def self.send_headers(status, headers)
|
46
|
-
print "Status: #{status}\r\n"
|
47
|
-
headers.each { |k, vs|
|
48
|
-
vs.split("\n").each { |v|
|
49
|
-
print "#{k}: #{v}\r\n"
|
50
|
-
}
|
51
|
-
}
|
52
|
-
print "\r\n"
|
53
|
-
STDOUT.flush
|
54
|
-
end
|
55
|
-
def self.send_body(body)
|
56
|
-
body.each { |part|
|
57
|
-
print part
|
58
|
-
STDOUT.flush
|
59
|
-
}
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
data/lib/rack/handler/scgi.rb
DELETED
@@ -1,73 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'scgi'
|
4
|
-
require 'stringio'
|
5
|
-
require 'rack/content_length'
|
6
|
-
require 'rack/chunked'
|
7
|
-
|
8
|
-
module Rack
|
9
|
-
module Handler
|
10
|
-
class SCGI < ::SCGI::Processor
|
11
|
-
attr_accessor :app
|
12
|
-
|
13
|
-
def self.run(app, options = nil)
|
14
|
-
options[:Socket] = UNIXServer.new(options[:File]) if options[:File]
|
15
|
-
new(options.merge(app: app,
|
16
|
-
host: options[:Host],
|
17
|
-
port: options[:Port],
|
18
|
-
socket: options[:Socket])).listen
|
19
|
-
end
|
20
|
-
|
21
|
-
def self.valid_options
|
22
|
-
environment = ENV['RACK_ENV'] || 'development'
|
23
|
-
default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
|
24
|
-
|
25
|
-
{
|
26
|
-
"Host=HOST" => "Hostname to listen on (default: #{default_host})",
|
27
|
-
"Port=PORT" => "Port to listen on (default: 8080)",
|
28
|
-
}
|
29
|
-
end
|
30
|
-
|
31
|
-
def initialize(settings = {})
|
32
|
-
@app = settings[:app]
|
33
|
-
super(settings)
|
34
|
-
end
|
35
|
-
|
36
|
-
def process_request(request, input_body, socket)
|
37
|
-
env = Hash[request]
|
38
|
-
env.delete "HTTP_CONTENT_TYPE"
|
39
|
-
env.delete "HTTP_CONTENT_LENGTH"
|
40
|
-
env[REQUEST_PATH], env[QUERY_STRING] = env["REQUEST_URI"].split('?', 2)
|
41
|
-
env[HTTP_VERSION] ||= env[SERVER_PROTOCOL]
|
42
|
-
env[PATH_INFO] = env[REQUEST_PATH]
|
43
|
-
env[QUERY_STRING] ||= ""
|
44
|
-
env[SCRIPT_NAME] = ""
|
45
|
-
|
46
|
-
rack_input = StringIO.new(input_body)
|
47
|
-
rack_input.set_encoding(Encoding::BINARY)
|
48
|
-
|
49
|
-
env.update(
|
50
|
-
RACK_VERSION => Rack::VERSION,
|
51
|
-
RACK_INPUT => rack_input,
|
52
|
-
RACK_ERRORS => $stderr,
|
53
|
-
RACK_MULTITHREAD => true,
|
54
|
-
RACK_MULTIPROCESS => true,
|
55
|
-
RACK_RUNONCE => false,
|
56
|
-
RACK_URL_SCHEME => ["yes", "on", "1"].include?(env[HTTPS]) ? "https" : "http"
|
57
|
-
)
|
58
|
-
|
59
|
-
status, headers, body = app.call(env)
|
60
|
-
begin
|
61
|
-
socket.write("Status: #{status}\r\n")
|
62
|
-
headers.each do |k, vs|
|
63
|
-
vs.split("\n").each { |v| socket.write("#{k}: #{v}\r\n")}
|
64
|
-
end
|
65
|
-
socket.write("\r\n")
|
66
|
-
body.each {|s| socket.write(s)}
|
67
|
-
ensure
|
68
|
-
body.close if body.respond_to? :close
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|