rack 3.0.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.
data/lib/rack/builder.rb CHANGED
@@ -2,6 +2,9 @@
2
2
 
3
3
  require_relative 'urlmap'
4
4
 
5
+ module Rack; end
6
+ Rack::BUILDER_TOPLEVEL_BINDING = ->(builder){builder.instance_eval{binding}}
7
+
5
8
  module Rack
6
9
  # Rack::Builder provides a domain-specific language (DSL) to construct Rack
7
10
  # applications. It is primarily used to parse +config.ru+ files which
@@ -10,26 +13,23 @@ module Rack
10
13
  #
11
14
  # Example:
12
15
  #
13
- # require 'rack/lobster'
14
- # app = Rack::Builder.new do
15
- # use Rack::CommonLogger
16
- # use Rack::ShowExceptions
17
- # map "/lobster" do
18
- # use Rack::Lint
19
- # run Rack::Lobster.new
20
- # end
21
- # end
16
+ # app = Rack::Builder.new do
17
+ # use Rack::CommonLogger
18
+ # map "/ok" do
19
+ # run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] }
20
+ # end
21
+ # end
22
22
  #
23
- # run app
23
+ # run app
24
24
  #
25
25
  # Or
26
26
  #
27
- # app = Rack::Builder.app do
28
- # use Rack::CommonLogger
29
- # run lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['OK']] }
30
- # end
27
+ # app = Rack::Builder.app do
28
+ # use Rack::CommonLogger
29
+ # run lambda { |env| [200, {'content-type' => 'text/plain'}, ['OK']] }
30
+ # end
31
31
  #
32
- # run app
32
+ # run app
33
33
  #
34
34
  # +use+ adds middleware to the stack, +run+ dispatches to an application.
35
35
  # You can use +map+ to construct a Rack::URLMap in a convenient way.
@@ -56,15 +56,15 @@ module Rack
56
56
  # Rack::Builder.parse_file('app.rb')
57
57
  # # requires app.rb, which can be anywhere in Ruby's
58
58
  # # load path. After requiring, assumes App constant
59
- # # contains Rack application
59
+ # # is a Rack application
60
60
  #
61
61
  # Rack::Builder.parse_file('./my_app.rb')
62
62
  # # requires ./my_app.rb, which should be in the
63
63
  # # process's current directory. After requiring,
64
- # # assumes MyApp constant contains Rack application
65
- def self.parse_file(path)
64
+ # # assumes MyApp constant is a Rack application
65
+ def self.parse_file(path, **options)
66
66
  if path.end_with?('.ru')
67
- return self.load_file(path)
67
+ return self.load_file(path, **options)
68
68
  else
69
69
  require path
70
70
  return Object.const_get(::File.basename(path, '.rb').split('_').map(&:capitalize).join(''))
@@ -84,7 +84,7 @@ module Rack
84
84
  # use Rack::ContentLength
85
85
  # require './app.rb'
86
86
  # run App
87
- def self.load_file(path)
87
+ def self.load_file(path, **options)
88
88
  config = ::File.read(path)
89
89
  config.slice!(/\A#{UTF_8_BOM}/) if config.encoding == Encoding::UTF_8
90
90
 
@@ -94,16 +94,18 @@ module Rack
94
94
 
95
95
  config.sub!(/^__END__\n.*\Z/m, '')
96
96
 
97
- return new_from_string(config, path)
97
+ return new_from_string(config, path, **options)
98
98
  end
99
99
 
100
100
  # Evaluate the given +builder_script+ string in the context of
101
101
  # a Rack::Builder block, returning a Rack application.
102
- def self.new_from_string(builder_script, file = "(rackup)")
102
+ def self.new_from_string(builder_script, path = "(rackup)", **options)
103
+ builder = self.new(**options)
104
+
103
105
  # We want to build a variant of TOPLEVEL_BINDING with self as a Rack::Builder instance.
104
106
  # We cannot use instance_eval(String) as that would resolve constants differently.
105
- binding, builder = TOPLEVEL_BINDING.eval('Rack::Builder.new.instance_eval { [binding, self] }')
106
- eval builder_script, binding, file
107
+ binding = BUILDER_TOPLEVEL_BINDING.call(builder)
108
+ eval(builder_script, binding, path)
107
109
 
108
110
  return builder.to_app
109
111
  end
@@ -111,16 +113,24 @@ module Rack
111
113
  # Initialize a new Rack::Builder instance. +default_app+ specifies the
112
114
  # default application if +run+ is not called later. If a block
113
115
  # is given, it is evaluated in the context of the instance.
114
- def initialize(default_app = nil, &block)
116
+ def initialize(default_app = nil, **options, &block)
115
117
  @use = []
116
118
  @map = nil
117
119
  @run = default_app
118
120
  @warmup = nil
119
121
  @freeze_app = false
122
+ @options = options
120
123
 
121
124
  instance_eval(&block) if block_given?
122
125
  end
123
126
 
127
+ # Any options provided to the Rack::Builder instance at initialization.
128
+ # These options can be server-specific. Some general options are:
129
+ #
130
+ # * +:isolation+: One of +process+, +thread+ or +fiber+. The execution
131
+ # isolation model to use.
132
+ attr :options
133
+
124
134
  # Create a new Rack::Builder instance and return the Rack application
125
135
  # generated from it.
126
136
  def self.app(default_app = nil, &block)
@@ -180,15 +190,6 @@ module Rack
180
190
  #
181
191
  # run Heartbeat.new
182
192
  #
183
- # It could also be a module:
184
- #
185
- # module HelloWorld
186
- # def call(env)
187
- # [200, { "content-type" => "text/plain" }, ["Hello World"]]
188
- # end
189
- # end
190
- #
191
- # run HelloWorld
192
193
  def run(app = nil, &block)
193
194
  raise ArgumentError, "Both app and block given!" if app && block_given?
194
195
 
@@ -213,21 +214,35 @@ module Rack
213
214
  # the Rack application specified by run inside the block. Other requests will be sent to the
214
215
  # default application specified by run outside the block.
215
216
  #
216
- # Rack::Builder.app do
217
+ # class App
218
+ # def call(env)
219
+ # [200, {'content-type' => 'text/plain'}, ["Hello World"]]
220
+ # end
221
+ # end
222
+ #
223
+ # class Heartbeat
224
+ # def call(env)
225
+ # [200, { "content-type" => "text/plain" }, ["OK"]]
226
+ # end
227
+ # end
228
+ #
229
+ # app = Rack::Builder.app do
217
230
  # map '/heartbeat' do
218
- # run Heartbeat
231
+ # run Heartbeat.new
219
232
  # end
220
- # run App
233
+ # run App.new
221
234
  # end
222
235
  #
236
+ # run app
237
+ #
223
238
  # The +use+ method can also be used inside the block to specify middleware to run under a specific path:
224
239
  #
225
- # Rack::Builder.app do
240
+ # app = Rack::Builder.app do
226
241
  # map '/heartbeat' do
227
242
  # use Middleware
228
- # run Heartbeat
243
+ # run Heartbeat.new
229
244
  # end
230
- # run App
245
+ # run App.new
231
246
  # end
232
247
  #
233
248
  # This example includes a piece of middleware which will run before +/heartbeat+ requests hit +Heartbeat+.
data/lib/rack/cascade.rb CHANGED
@@ -9,9 +9,6 @@ module Rack
9
9
  # status codes, return the last response.
10
10
 
11
11
  class Cascade
12
- # deprecated, no longer used
13
- NotFound = [404, { CONTENT_TYPE => "text/plain" }, []]
14
-
15
12
  # An array of applications to try in order.
16
13
  attr_reader :apps
17
14
 
@@ -14,7 +14,7 @@ module Rack
14
14
  SERVER_NAME = 'SERVER_NAME'
15
15
  SERVER_PORT = 'SERVER_PORT'
16
16
  HTTP_COOKIE = 'HTTP_COOKIE'
17
-
17
+
18
18
  # Response Header Keys
19
19
  CACHE_CONTROL = 'cache-control'
20
20
  CONTENT_LENGTH = 'content-length'
@@ -22,7 +22,6 @@ module Rack
22
22
  ETAG = 'etag'
23
23
  EXPIRES = 'expires'
24
24
  SET_COOKIE = 'set-cookie'
25
- TRANSFER_ENCODING = 'transfer-encoding'
26
25
 
27
26
  # HTTP method verbs
28
27
  GET = 'GET'
@@ -32,6 +31,7 @@ module Rack
32
31
  DELETE = 'DELETE'
33
32
  HEAD = 'HEAD'
34
33
  OPTIONS = 'OPTIONS'
34
+ CONNECT = 'CONNECT'
35
35
  LINK = 'LINK'
36
36
  UNLINK = 'UNLINK'
37
37
  TRACE = 'TRACE'
@@ -39,6 +39,7 @@ module Rack
39
39
  # Rack environment variables
40
40
  RACK_VERSION = 'rack.version'
41
41
  RACK_TEMPFILES = 'rack.tempfiles'
42
+ RACK_EARLY_HINTS = 'rack.early_hints'
42
43
  RACK_ERRORS = 'rack.errors'
43
44
  RACK_LOGGER = 'rack.logger'
44
45
  RACK_INPUT = 'rack.input'
@@ -54,7 +55,9 @@ module Rack
54
55
  RACK_RESPONSE_FINISHED = 'rack.response_finished'
55
56
  RACK_REQUEST_FORM_INPUT = 'rack.request.form_input'
56
57
  RACK_REQUEST_FORM_HASH = 'rack.request.form_hash'
58
+ RACK_REQUEST_FORM_PAIRS = 'rack.request.form_pairs'
57
59
  RACK_REQUEST_FORM_VARS = 'rack.request.form_vars'
60
+ RACK_REQUEST_FORM_ERROR = 'rack.request.form_error'
58
61
  RACK_REQUEST_COOKIE_HASH = 'rack.request.cookie_hash'
59
62
  RACK_REQUEST_COOKIE_STRING = 'rack.request.cookie_string'
60
63
  RACK_REQUEST_QUERY_HASH = 'rack.request.query_hash'
@@ -21,7 +21,6 @@ module Rack
21
21
 
22
22
  if !STATUS_WITH_NO_ENTITY_BODY.key?(status.to_i) &&
23
23
  !headers[CONTENT_LENGTH] &&
24
- !headers[TRANSFER_ENCODING] &&
25
24
  body.respond_to?(:to_ary)
26
25
 
27
26
  response[2] = body = body.to_ary
data/lib/rack/headers.rb CHANGED
@@ -1,9 +1,93 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  # Rack::Headers is a Hash subclass that downcases all keys. It's designed
3
5
  # to be used by rack applications that don't implement the Rack 3 SPEC
4
6
  # (by using non-lowercase response header keys), automatically handling
5
7
  # the downcasing of keys.
6
8
  class Headers < Hash
9
+ KNOWN_HEADERS = {}
10
+ %w(
11
+ Accept-CH
12
+ Accept-Patch
13
+ Accept-Ranges
14
+ Access-Control-Allow-Credentials
15
+ Access-Control-Allow-Headers
16
+ Access-Control-Allow-Methods
17
+ Access-Control-Allow-Origin
18
+ Access-Control-Expose-Headers
19
+ Access-Control-Max-Age
20
+ Age
21
+ Allow
22
+ Alt-Svc
23
+ Cache-Control
24
+ Connection
25
+ Content-Disposition
26
+ Content-Encoding
27
+ Content-Language
28
+ Content-Length
29
+ Content-Location
30
+ Content-MD5
31
+ Content-Range
32
+ Content-Security-Policy
33
+ Content-Security-Policy-Report-Only
34
+ Content-Type
35
+ Date
36
+ Delta-Base
37
+ ETag
38
+ Expect-CT
39
+ Expires
40
+ Feature-Policy
41
+ IM
42
+ Last-Modified
43
+ Link
44
+ Location
45
+ NEL
46
+ P3P
47
+ Permissions-Policy
48
+ Pragma
49
+ Preference-Applied
50
+ Proxy-Authenticate
51
+ Public-Key-Pins
52
+ Referrer-Policy
53
+ Refresh
54
+ Report-To
55
+ Retry-After
56
+ Server
57
+ Set-Cookie
58
+ Status
59
+ Strict-Transport-Security
60
+ Timing-Allow-Origin
61
+ Tk
62
+ Trailer
63
+ Transfer-Encoding
64
+ Upgrade
65
+ Vary
66
+ Via
67
+ WWW-Authenticate
68
+ Warning
69
+ X-Cascade
70
+ X-Content-Duration
71
+ X-Content-Security-Policy
72
+ X-Content-Type-Options
73
+ X-Correlation-ID
74
+ X-Correlation-Id
75
+ X-Download-Options
76
+ X-Frame-Options
77
+ X-Permitted-Cross-Domain-Policies
78
+ X-Powered-By
79
+ X-Redirect-By
80
+ X-Request-ID
81
+ X-Request-Id
82
+ X-Runtime
83
+ X-UA-Compatible
84
+ X-WebKit-CS
85
+ X-XSS-Protection
86
+ ).each do |str|
87
+ downcased = str.downcase.freeze
88
+ KNOWN_HEADERS[str] = KNOWN_HEADERS[downcased] = downcased
89
+ end
90
+
7
91
  def self.[](*items)
8
92
  if items.length % 2 != 0
9
93
  if items.length == 1 && items.first.is_a?(Hash)
@@ -28,10 +112,10 @@ module Rack
28
112
  end
29
113
 
30
114
  def []=(key, value)
31
- super(key.downcase.freeze, value)
115
+ super(KNOWN_HEADERS[key] || key.downcase.freeze, value)
32
116
  end
33
117
  alias store []=
34
-
118
+
35
119
  def assoc(key)
36
120
  super(downcase_key(key))
37
121
  end
@@ -43,7 +127,7 @@ module Rack
43
127
  def delete(key)
44
128
  super(downcase_key(key))
45
129
  end
46
-
130
+
47
131
  def dig(key, *a)
48
132
  super(downcase_key(key), *a)
49
133
  end
@@ -52,7 +136,7 @@ module Rack
52
136
  key = downcase_key(key)
53
137
  super
54
138
  end
55
-
139
+
56
140
  def fetch_values(*a)
57
141
  super(*a.map!{|key| downcase_key(key)})
58
142
  end
@@ -63,34 +147,34 @@ module Rack
63
147
  alias include? has_key?
64
148
  alias key? has_key?
65
149
  alias member? has_key?
66
-
150
+
67
151
  def invert
68
152
  hash = self.class.new
69
153
  each{|key, value| hash[value] = key}
70
154
  hash
71
155
  end
72
-
156
+
73
157
  def merge(hash, &block)
74
158
  dup.merge!(hash, &block)
75
159
  end
76
-
160
+
77
161
  def reject(&block)
78
162
  hash = dup
79
163
  hash.reject!(&block)
80
164
  hash
81
165
  end
82
-
166
+
83
167
  def replace(hash)
84
168
  clear
85
169
  update(hash)
86
170
  end
87
-
171
+
88
172
  def select(&block)
89
173
  hash = dup
90
174
  hash.select!(&block)
91
175
  hash
92
176
  end
93
-
177
+
94
178
  def to_proc
95
179
  lambda{|x| self[x]}
96
180
  end
@@ -100,10 +184,10 @@ module Rack
100
184
  end
101
185
 
102
186
  def update(hash, &block)
103
- hash.each do |key, value|
187
+ hash.each do |key, value|
104
188
  self[key] = if block_given? && include?(key)
105
189
  block.call(key, self[key], value)
106
- else
190
+ else
107
191
  value
108
192
  end
109
193
  end
@@ -114,7 +198,7 @@ module Rack
114
198
  def values_at(*keys)
115
199
  keys.map{|key| self[key]}
116
200
  end
117
-
201
+
118
202
  # :nocov:
119
203
  if RUBY_VERSION >= '2.5'
120
204
  # :nocov:
@@ -148,7 +232,7 @@ module Rack
148
232
  private
149
233
 
150
234
  def downcase_key(key)
151
- key.is_a?(String) ? key.downcase : key
235
+ key.is_a?(String) ? KNOWN_HEADERS[key] || key.downcase : key
152
236
  end
153
237
  end
154
238
  end