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.

Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +377 -16
  3. data/CONTRIBUTING.md +144 -0
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +328 -0
  6. data/SPEC.rdoc +365 -0
  7. data/lib/rack/auth/abstract/handler.rb +3 -1
  8. data/lib/rack/auth/abstract/request.rb +2 -2
  9. data/lib/rack/auth/basic.rb +4 -7
  10. data/lib/rack/bad_request.rb +8 -0
  11. data/lib/rack/body_proxy.rb +34 -12
  12. data/lib/rack/builder.rb +162 -59
  13. data/lib/rack/cascade.rb +24 -10
  14. data/lib/rack/common_logger.rb +43 -28
  15. data/lib/rack/conditional_get.rb +30 -25
  16. data/lib/rack/constants.rb +66 -0
  17. data/lib/rack/content_length.rb +10 -16
  18. data/lib/rack/content_type.rb +9 -7
  19. data/lib/rack/deflater.rb +78 -50
  20. data/lib/rack/directory.rb +86 -63
  21. data/lib/rack/etag.rb +14 -22
  22. data/lib/rack/events.rb +18 -17
  23. data/lib/rack/files.rb +99 -61
  24. data/lib/rack/head.rb +8 -9
  25. data/lib/rack/headers.rb +238 -0
  26. data/lib/rack/lint.rb +868 -642
  27. data/lib/rack/lock.rb +2 -6
  28. data/lib/rack/logger.rb +3 -0
  29. data/lib/rack/media_type.rb +9 -4
  30. data/lib/rack/method_override.rb +6 -2
  31. data/lib/rack/mime.rb +14 -5
  32. data/lib/rack/mock.rb +1 -253
  33. data/lib/rack/mock_request.rb +171 -0
  34. data/lib/rack/mock_response.rb +124 -0
  35. data/lib/rack/multipart/generator.rb +15 -8
  36. data/lib/rack/multipart/parser.rb +238 -107
  37. data/lib/rack/multipart/uploaded_file.rb +17 -7
  38. data/lib/rack/multipart.rb +54 -42
  39. data/lib/rack/null_logger.rb +9 -0
  40. data/lib/rack/query_parser.rb +87 -105
  41. data/lib/rack/recursive.rb +3 -1
  42. data/lib/rack/reloader.rb +0 -4
  43. data/lib/rack/request.rb +366 -135
  44. data/lib/rack/response.rb +186 -68
  45. data/lib/rack/rewindable_input.rb +24 -6
  46. data/lib/rack/runtime.rb +8 -7
  47. data/lib/rack/sendfile.rb +29 -27
  48. data/lib/rack/show_exceptions.rb +27 -12
  49. data/lib/rack/show_status.rb +21 -13
  50. data/lib/rack/static.rb +19 -12
  51. data/lib/rack/tempfile_reaper.rb +14 -5
  52. data/lib/rack/urlmap.rb +5 -6
  53. data/lib/rack/utils.rb +274 -260
  54. data/lib/rack/version.rb +21 -0
  55. data/lib/rack.rb +18 -103
  56. metadata +25 -52
  57. data/README.rdoc +0 -262
  58. data/Rakefile +0 -123
  59. data/SPEC +0 -263
  60. data/bin/rackup +0 -5
  61. data/contrib/rack.png +0 -0
  62. data/contrib/rack.svg +0 -150
  63. data/contrib/rack_logo.svg +0 -164
  64. data/contrib/rdoc.css +0 -412
  65. data/example/lobster.ru +0 -6
  66. data/example/protectedlobster.rb +0 -16
  67. data/example/protectedlobster.ru +0 -10
  68. data/lib/rack/auth/digest/md5.rb +0 -131
  69. data/lib/rack/auth/digest/nonce.rb +0 -54
  70. data/lib/rack/auth/digest/params.rb +0 -54
  71. data/lib/rack/auth/digest/request.rb +0 -43
  72. data/lib/rack/chunked.rb +0 -92
  73. data/lib/rack/core_ext/regexp.rb +0 -14
  74. data/lib/rack/file.rb +0 -8
  75. data/lib/rack/handler/cgi.rb +0 -62
  76. data/lib/rack/handler/fastcgi.rb +0 -102
  77. data/lib/rack/handler/lsws.rb +0 -63
  78. data/lib/rack/handler/scgi.rb +0 -73
  79. data/lib/rack/handler/thin.rb +0 -38
  80. data/lib/rack/handler/webrick.rb +0 -122
  81. data/lib/rack/handler.rb +0 -104
  82. data/lib/rack/lobster.rb +0 -72
  83. data/lib/rack/server.rb +0 -467
  84. data/lib/rack/session/abstract/id.rb +0 -528
  85. data/lib/rack/session/cookie.rb +0 -205
  86. data/lib/rack/session/memcache.rb +0 -10
  87. data/lib/rack/session/pool.rb +0 -85
  88. data/rack.gemspec +0 -44
@@ -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
@@ -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
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'rack/files'
4
-
5
- module Rack
6
- warn "Rack::File is deprecated, please use Rack::Files instead."
7
- File = Files
8
- end
@@ -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
@@ -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
@@ -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
@@ -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