rack 1.6.0.beta → 1.6.0.beta2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rack might be problematic. Click here for more details.

Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/SPEC +3 -3
  3. data/lib/rack.rb +10 -0
  4. data/lib/rack/auth/abstract/handler.rb +4 -4
  5. data/lib/rack/auth/digest/request.rb +1 -1
  6. data/lib/rack/cascade.rb +1 -1
  7. data/lib/rack/chunked.rb +2 -2
  8. data/lib/rack/commonlogger.rb +4 -4
  9. data/lib/rack/conditionalget.rb +3 -3
  10. data/lib/rack/content_length.rb +2 -2
  11. data/lib/rack/content_type.rb +1 -1
  12. data/lib/rack/deflater.rb +4 -5
  13. data/lib/rack/directory.rb +5 -5
  14. data/lib/rack/etag.rb +7 -6
  15. data/lib/rack/file.rb +32 -14
  16. data/lib/rack/handler.rb +1 -1
  17. data/lib/rack/handler/cgi.rb +1 -1
  18. data/lib/rack/handler/fastcgi.rb +1 -1
  19. data/lib/rack/handler/lsws.rb +1 -1
  20. data/lib/rack/handler/mongrel.rb +1 -1
  21. data/lib/rack/handler/scgi.rb +2 -2
  22. data/lib/rack/handler/webrick.rb +6 -4
  23. data/lib/rack/head.rb +1 -1
  24. data/lib/rack/lint.rb +30 -16
  25. data/lib/rack/lobster.rb +2 -2
  26. data/lib/rack/methodoverride.rb +3 -3
  27. data/lib/rack/mock.rb +7 -7
  28. data/lib/rack/multipart/parser.rb +21 -7
  29. data/lib/rack/recursive.rb +6 -5
  30. data/lib/rack/request.rb +6 -6
  31. data/lib/rack/response.rb +8 -6
  32. data/lib/rack/runtime.rb +2 -1
  33. data/lib/rack/sendfile.rb +2 -2
  34. data/lib/rack/server.rb +7 -10
  35. data/lib/rack/showexceptions.rb +2 -2
  36. data/lib/rack/showstatus.rb +3 -3
  37. data/lib/rack/static.rb +1 -1
  38. data/lib/rack/urlmap.rb +2 -2
  39. data/lib/rack/utils.rb +14 -10
  40. data/rack.gemspec +1 -1
  41. data/test/spec_body_proxy.rb +16 -0
  42. data/test/spec_lint.rb +20 -9
  43. data/test/spec_multipart.rb +38 -16
  44. data/test/spec_request.rb +17 -0
  45. data/test/spec_server.rb +22 -13
  46. metadata +2 -2
@@ -12,7 +12,7 @@ class Head
12
12
  def call(env)
13
13
  status, headers, body = @app.call(env)
14
14
 
15
- if env["REQUEST_METHOD"] == "HEAD"
15
+ if env[REQUEST_METHOD] == HEAD
16
16
  [
17
17
  status, headers, Rack::BodyProxy.new([]) do
18
18
  body.close if body.respond_to? :close
@@ -57,7 +57,7 @@ module Rack
57
57
  ## and the *body*.
58
58
  check_content_type status, headers
59
59
  check_content_length status, headers
60
- @head_request = env["REQUEST_METHOD"] == "HEAD"
60
+ @head_request = env[REQUEST_METHOD] == "HEAD"
61
61
  [status, headers, self]
62
62
  end
63
63
 
@@ -228,6 +228,23 @@ module Rack
228
228
  }
229
229
  end
230
230
 
231
+ ## <tt>rack.multipart.buffer_size</tt>:: An Integer hint to the multipart parser as to what chunk size to use for reads and writes.
232
+ if bufsize = env['rack.multipart.buffer_size']
233
+ assert("rack.multipart.buffer_size must be an Integer > 0 if specified") {
234
+ bufsize.is_a?(Integer) && bufsize > 0
235
+ }
236
+ end
237
+
238
+ ## <tt>rack.multipart.tempfile_factory</tt>:: An object responding to #call with two arguments, the filename and content_type given for the multipart form field, and returning an IO-like object that responds to #<< and optionally #rewind. This factory will be used to instantiate the tempfile for each multipart form file upload field, rather than the default class of Tempfile.
239
+ if tempfile_factory = env['rack.multipart.tempfile_factory']
240
+ assert("rack.multipart.tempfile_factory must respond to #call") { tempfile_factory.respond_to?(:call) }
241
+ env['rack.multipart.tempfile_factory'] = lambda do |filename, content_type|
242
+ io = tempfile_factory.call(filename, content_type)
243
+ assert("rack.multipart.tempfile_factory return value must respond to #<<") { io.respond_to?(:<<) }
244
+ io
245
+ end
246
+ end
247
+
231
248
  ## The server or the application can store their own data in the
232
249
  ## environment, too. The keys must contain at least one dot,
233
250
  ## and should be prefixed uniquely. The prefix <tt>rack.</tt>
@@ -278,7 +295,7 @@ module Rack
278
295
  check_hijack env
279
296
 
280
297
  ## * The <tt>REQUEST_METHOD</tt> must be a valid token.
281
- assert("REQUEST_METHOD unknown: #{env["REQUEST_METHOD"]}") {
298
+ assert("REQUEST_METHOD unknown: #{env[REQUEST_METHOD]}") {
282
299
  env["REQUEST_METHOD"] =~ /\A[0-9A-Za-z!\#$%&'*+.^_`|~-]+\z/
283
300
  }
284
301
 
@@ -510,20 +527,20 @@ module Rack
510
527
  ## already present, in rack.hijack_io.
511
528
  io = original_hijack.call
512
529
  HijackWrapper.new(io)
513
- ##
530
+ ##
514
531
  ## rack.hijack_io must respond to:
515
532
  ## <tt>read, write, read_nonblock, write_nonblock, flush, close,
516
533
  ## close_read, close_write, closed?</tt>
517
- ##
534
+ ##
518
535
  ## The semantics of these IO methods must be a best effort match to
519
536
  ## those of a normal ruby IO or Socket object, using standard
520
537
  ## arguments and raising standard exceptions. Servers are encouraged
521
538
  ## to simply pass on real IO objects, although it is recognized that
522
539
  ## this approach is not directly compatible with SPDY and HTTP 2.0.
523
- ##
540
+ ##
524
541
  ## IO provided in rack.hijack_io should preference the
525
542
  ## IO::WaitReadable and IO::WaitWritable APIs wherever supported.
526
- ##
543
+ ##
527
544
  ## There is a deliberate lack of full specification around
528
545
  ## rack.hijack_io, as semantics will change from server to server.
529
546
  ## Users are encouraged to utilize this API with a knowledge of their
@@ -535,10 +552,10 @@ module Rack
535
552
  io
536
553
  end
537
554
  else
538
- ##
555
+ ##
539
556
  ## If rack.hijack? is false, then rack.hijack should not be set.
540
557
  assert("rack.hijack? is false, but rack.hijack is present") { env['rack.hijack'].nil? }
541
- ##
558
+ ##
542
559
  ## If rack.hijack? is false, then rack.hijack_io should not be set.
543
560
  assert("rack.hijack? is false, but rack.hijack_io is present") { env['rack.hijack_io'].nil? }
544
561
  end
@@ -557,7 +574,7 @@ module Rack
557
574
  ## <tt>rack.hijack</tt> to an object that responds to <tt>call</tt>
558
575
  ## accepting an argument that conforms to the <tt>rack.hijack_io</tt>
559
576
  ## protocol.
560
- ##
577
+ ##
561
578
  ## After the headers have been sent, and this hijack callback has been
562
579
  ## called, the application is now responsible for the remaining lifecycle
563
580
  ## of the IO. The application is also responsible for maintaining HTTP
@@ -566,7 +583,7 @@ module Rack
566
583
  ## HTTP/1.1, and not Connection:keep-alive, as there is no protocol for
567
584
  ## returning hijacked sockets to the web server. For that purpose, use the
568
585
  ## body streaming API instead (progressively yielding strings via each).
569
- ##
586
+ ##
570
587
  ## Servers must ignore the <tt>body</tt> part of the response tuple when
571
588
  ## the <tt>rack.hijack</tt> response API is in use.
572
589
 
@@ -579,7 +596,7 @@ module Rack
579
596
  original_hijack.call HijackWrapper.new(io)
580
597
  end
581
598
  else
582
- ##
599
+ ##
583
600
  ## The special response header <tt>rack.hijack</tt> must only be set
584
601
  ## if the request env has <tt>rack.hijack?</tt> <tt>true</tt>.
585
602
  assert('rack.hijack header must not be present if server does not support hijacking') {
@@ -622,11 +639,8 @@ module Rack
622
639
  assert("header must not contain Status") { key.downcase != "status" }
623
640
  ## contain keys with <tt>:</tt> or newlines in their name,
624
641
  assert("header names must not contain : or \\n") { key !~ /[:\n]/ }
625
- ## contain keys names that end in <tt>-</tt> or <tt>_</tt>,
626
- assert("header names must not end in - or _") { key !~ /[-_]\z/ }
627
- ## but only contain keys that consist of
628
- ## letters, digits, <tt>_</tt> or <tt>-</tt> and start with a letter.
629
- assert("invalid header name: #{key}") { key =~ /\A[a-zA-Z][a-zA-Z0-9_-]*\z/ }
642
+ ## The header must match the token rule according to RFC 2616
643
+ assert("invalid header name: #{key}") { key =~ /\A[\!#\$%&'\*\+-.0-9A-Z\^_`a-z\|~]+\z/ }
630
644
 
631
645
  ## The values of the header must be Strings,
632
646
  assert("a header value must be a String, but the value of " +
@@ -12,7 +12,7 @@ module Rack
12
12
  I8jyiTlhTcYXkekJAzTyYN6E08A+dk8voBkAVTJQ==".delete("\n ").unpack("m*")[0])
13
13
 
14
14
  LambdaLobster = lambda { |env|
15
- if env["QUERY_STRING"].include?("flip")
15
+ if env[QUERY_STRING].include?("flip")
16
16
  lobster = LobsterString.split("\n").
17
17
  map { |line| line.ljust(42).reverse }.
18
18
  join("\n")
@@ -26,7 +26,7 @@ module Rack
26
26
  "<pre>", lobster, "</pre>",
27
27
  "<a href='#{href}'>flip!</a>"]
28
28
  length = content.inject(0) { |a,e| a+e.size }.to_s
29
- [200, {"Content-Type" => "text/html", "Content-Length" => length}, content]
29
+ [200, {CONTENT_TYPE => "text/html", CONTENT_LENGTH => length}, content]
30
30
  }
31
31
 
32
32
  def call(env)
@@ -11,11 +11,11 @@ module Rack
11
11
  end
12
12
 
13
13
  def call(env)
14
- if allowed_methods.include?(env["REQUEST_METHOD"])
14
+ if allowed_methods.include?(env[REQUEST_METHOD])
15
15
  method = method_override(env)
16
16
  if HTTP_METHODS.include?(method)
17
- env["rack.methodoverride.original_method"] = env["REQUEST_METHOD"]
18
- env["REQUEST_METHOD"] = method
17
+ env["rack.methodoverride.original_method"] = env[REQUEST_METHOD]
18
+ env[REQUEST_METHOD] = method
19
19
  end
20
20
  end
21
21
 
@@ -91,15 +91,15 @@ module Rack
91
91
 
92
92
  env = DEFAULT_ENV.dup
93
93
 
94
- env["REQUEST_METHOD"] = opts[:method] ? opts[:method].to_s.upcase : "GET"
94
+ env[REQUEST_METHOD] = opts[:method] ? opts[:method].to_s.upcase : "GET"
95
95
  env["SERVER_NAME"] = uri.host || "example.org"
96
96
  env["SERVER_PORT"] = uri.port ? uri.port.to_s : "80"
97
- env["QUERY_STRING"] = uri.query.to_s
98
- env["PATH_INFO"] = (!uri.path || uri.path.empty?) ? "/" : uri.path
97
+ env[QUERY_STRING] = uri.query.to_s
98
+ env[PATH_INFO] = (!uri.path || uri.path.empty?) ? "/" : uri.path
99
99
  env["rack.url_scheme"] = uri.scheme || "http"
100
100
  env["HTTPS"] = env["rack.url_scheme"] == "https" ? "on" : "off"
101
101
 
102
- env["SCRIPT_NAME"] = opts[:script_name] || ""
102
+ env[SCRIPT_NAME] = opts[:script_name] || ""
103
103
 
104
104
  if opts[:fatal]
105
105
  env["rack.errors"] = FatalWarner.new
@@ -108,10 +108,10 @@ module Rack
108
108
  end
109
109
 
110
110
  if params = opts[:params]
111
- if env["REQUEST_METHOD"] == "GET"
111
+ if env[REQUEST_METHOD] == "GET"
112
112
  params = Utils.parse_nested_query(params) if params.is_a?(String)
113
- params.update(Utils.parse_nested_query(env["QUERY_STRING"]))
114
- env["QUERY_STRING"] = Utils.build_nested_query(params)
113
+ params.update(Utils.parse_nested_query(env[QUERY_STRING]))
114
+ env[QUERY_STRING] = Utils.build_nested_query(params)
115
115
  elsif !opts.has_key?(:input)
116
116
  opts["CONTENT_TYPE"] = "application/x-www-form-urlencoded"
117
117
  if params.is_a?(Hash)
@@ -2,6 +2,8 @@ require 'rack/utils'
2
2
 
3
3
  module Rack
4
4
  module Multipart
5
+ class MultipartPartLimitError < Errno::EMFILE; end
6
+
5
7
  class Parser
6
8
  BUFSIZE = 16384
7
9
 
@@ -16,10 +18,14 @@ module Rack
16
18
  content_length = env['CONTENT_LENGTH']
17
19
  content_length = content_length.to_i if content_length
18
20
 
19
- new($1, io, content_length, env)
21
+ tempfile = env['rack.multipart.tempfile_factory'] ||
22
+ lambda { |filename, content_type| Tempfile.new(["RackMultipart", ::File.extname(filename)]) }
23
+ bufsize = env['rack.multipart.buffer_size'] || BUFSIZE
24
+
25
+ new($1, io, content_length, env, tempfile, bufsize)
20
26
  end
21
27
 
22
- def initialize(boundary, io, content_length, env)
28
+ def initialize(boundary, io, content_length, env, tempfile, bufsize)
23
29
  @buf = ""
24
30
 
25
31
  if @buf.respond_to? :force_encoding
@@ -32,6 +38,8 @@ module Rack
32
38
  @content_length = content_length
33
39
  @boundary_size = Utils.bytesize(@boundary) + EOL.size
34
40
  @env = env
41
+ @tempfile = tempfile
42
+ @bufsize = bufsize
35
43
 
36
44
  if @content_length
37
45
  @content_length -= @boundary_size
@@ -44,7 +52,13 @@ module Rack
44
52
  def parse
45
53
  fast_forward_to_first_boundary
46
54
 
55
+ opened_files = 0
47
56
  loop do
57
+ if Utils.multipart_part_limit > 0
58
+ raise MultipartPartLimitError, 'Maximum file multiparts in content reached' if opened_files >= Utils.multipart_part_limit
59
+ opened_files += 1
60
+ end
61
+
48
62
  head, filename, content_type, name, body =
49
63
  get_current_head_and_filename_and_content_type_and_name_and_body
50
64
 
@@ -78,7 +92,7 @@ module Rack
78
92
 
79
93
  def fast_forward_to_first_boundary
80
94
  loop do
81
- content = @io.read(BUFSIZE)
95
+ content = @io.read(@bufsize)
82
96
  raise EOFError, "bad content body" unless content
83
97
  @buf << content
84
98
 
@@ -87,7 +101,7 @@ module Rack
87
101
  return if read_buffer == full_boundary
88
102
  end
89
103
 
90
- raise EOFError, "bad content body" if Utils.bytesize(@buf) >= BUFSIZE
104
+ raise EOFError, "bad content body" if Utils.bytesize(@buf) >= @bufsize
91
105
  end
92
106
  end
93
107
 
@@ -117,7 +131,7 @@ module Rack
117
131
  end
118
132
 
119
133
  if filename
120
- (@env['rack.tempfiles'] ||= []) << body = Tempfile.new("RackMultipart")
134
+ (@env['rack.tempfiles'] ||= []) << body = @tempfile.call(filename, content_type)
121
135
  body.binmode if body.respond_to?(:binmode)
122
136
  end
123
137
 
@@ -129,7 +143,7 @@ module Rack
129
143
  body << @buf.slice!(0, @buf.size - (@boundary_size+4))
130
144
  end
131
145
 
132
- content = @io.read(@content_length && BUFSIZE >= @content_length ? @content_length : BUFSIZE)
146
+ content = @io.read(@content_length && @bufsize >= @content_length ? @content_length : @bufsize)
133
147
  raise EOFError, "bad content body" if content.nil? || content.empty?
134
148
 
135
149
  @buf << content
@@ -214,7 +228,7 @@ module Rack
214
228
  # filename is blank which means no file has been selected
215
229
  return
216
230
  elsif filename
217
- body.rewind
231
+ body.rewind if body.respond_to?(:rewind)
218
232
 
219
233
  # Take the basename of the upload's original filename.
220
234
  # This handles the full Windows paths given by Internet Explorer
@@ -14,8 +14,8 @@ module Rack
14
14
  @url = URI(url)
15
15
  @env = env
16
16
 
17
- @env["PATH_INFO"] = @url.path
18
- @env["QUERY_STRING"] = @url.query if @url.query
17
+ @env[PATH_INFO] = @url.path
18
+ @env[QUERY_STRING] = @url.query if @url.query
19
19
  @env["HTTP_HOST"] = @url.host if @url.host
20
20
  @env["HTTP_PORT"] = @url.port if @url.port
21
21
  @env["rack.url_scheme"] = @url.scheme if @url.scheme
@@ -39,7 +39,7 @@ module Rack
39
39
  end
40
40
 
41
41
  def _call(env)
42
- @script_name = env["SCRIPT_NAME"]
42
+ @script_name = env[SCRIPT_NAME]
43
43
  @app.call(env.merge('rack.recursive.include' => method(:include)))
44
44
  rescue ForwardRequest => req
45
45
  call(env.merge(req.env))
@@ -51,8 +51,9 @@ module Rack
51
51
  raise ArgumentError, "can only include below #{@script_name}, not #{path}"
52
52
  end
53
53
 
54
- env = env.merge("PATH_INFO" => path, "SCRIPT_NAME" => @script_name,
55
- "REQUEST_METHOD" => "GET",
54
+ env = env.merge(PATH_INFO => path,
55
+ SCRIPT_NAME => @script_name,
56
+ REQUEST_METHOD => "GET",
56
57
  "CONTENT_LENGTH" => "0", "CONTENT_TYPE" => "",
57
58
  "rack.input" => StringIO.new(""))
58
59
  @app.call(env)
@@ -18,10 +18,10 @@ module Rack
18
18
  end
19
19
 
20
20
  def body; @env["rack.input"] end
21
- def script_name; @env["SCRIPT_NAME"].to_s end
22
- def path_info; @env["PATH_INFO"].to_s end
21
+ def script_name; @env[SCRIPT_NAME].to_s end
22
+ def path_info; @env[PATH_INFO].to_s end
23
23
  def request_method; @env["REQUEST_METHOD"] end
24
- def query_string; @env["QUERY_STRING"].to_s end
24
+ def query_string; @env[QUERY_STRING].to_s end
25
25
  def content_length; @env['CONTENT_LENGTH'] end
26
26
 
27
27
  def content_type
@@ -116,10 +116,10 @@ module Rack
116
116
  def delete?; request_method == "DELETE" end
117
117
 
118
118
  # Checks the HTTP request method (or verb) to see if it was of type GET
119
- def get?; request_method == "GET" end
119
+ def get?; request_method == GET end
120
120
 
121
121
  # Checks the HTTP request method (or verb) to see if it was of type HEAD
122
- def head?; request_method == "HEAD" end
122
+ def head?; request_method == HEAD end
123
123
 
124
124
  # Checks the HTTP request method (or verb) to see if it was of type OPTIONS
125
125
  def options?; request_method == "OPTIONS" end
@@ -173,7 +173,7 @@ module Rack
173
173
  # Content-Type header is provided and the request_method is POST.
174
174
  def form_data?
175
175
  type = media_type
176
- meth = env["rack.methodoverride.original_method"] || env['REQUEST_METHOD']
176
+ meth = env["rack.methodoverride.original_method"] || env[REQUEST_METHOD]
177
177
  (meth == 'POST' && type.nil?) || FORM_DATA_MEDIA_TYPES.include?(type)
178
178
  end
179
179
 
@@ -20,11 +20,13 @@ module Rack
20
20
  class Response
21
21
  attr_accessor :length
22
22
 
23
+ CHUNKED = 'chunked'.freeze
24
+ TRANSFER_ENCODING = 'Transfer-Encoding'.freeze
23
25
  def initialize(body=[], status=200, header={})
24
26
  @status = status.to_i
25
27
  @header = Utils::HeaderHash.new.merge(header)
26
28
 
27
- @chunked = "chunked" == @header['Transfer-Encoding']
29
+ @chunked = CHUNKED == @header[TRANSFER_ENCODING]
28
30
  @writer = lambda { |x| @body << x }
29
31
  @block = nil
30
32
  @length = 0
@@ -72,8 +74,8 @@ module Rack
72
74
  @block = block
73
75
 
74
76
  if [204, 205, 304].include?(status.to_i)
75
- header.delete "Content-Type"
76
- header.delete "Content-Length"
77
+ header.delete CONTENT_TYPE
78
+ header.delete CONTENT_LENGTH
77
79
  close
78
80
  [status.to_i, header, []]
79
81
  else
@@ -98,7 +100,7 @@ module Rack
98
100
  @length += Rack::Utils.bytesize(s) unless @chunked
99
101
  @writer.call s
100
102
 
101
- header["Content-Length"] = @length.to_s unless @chunked
103
+ header[CONTENT_LENGTH] = @length.to_s unless @chunked
102
104
  str
103
105
  end
104
106
 
@@ -142,11 +144,11 @@ module Rack
142
144
  end
143
145
 
144
146
  def content_type
145
- headers["Content-Type"]
147
+ headers[CONTENT_TYPE]
146
148
  end
147
149
 
148
150
  def content_length
149
- cl = headers["Content-Length"]
151
+ cl = headers[CONTENT_LENGTH]
150
152
  cl ? cl.to_i : cl
151
153
  end
152
154
 
@@ -12,13 +12,14 @@ module Rack
12
12
  @header_name << "-#{name}" if name
13
13
  end
14
14
 
15
+ FORMAT_STRING = "%0.6f"
15
16
  def call(env)
16
17
  start_time = Time.now
17
18
  status, headers, body = @app.call(env)
18
19
  request_time = Time.now - start_time
19
20
 
20
21
  if !headers.has_key?(@header_name)
21
- headers[@header_name] = "%0.6f" % request_time
22
+ headers[@header_name] = FORMAT_STRING % request_time
22
23
  end
23
24
 
24
25
  [status, headers, body]
@@ -116,7 +116,7 @@ module Rack
116
116
  when 'X-Accel-Redirect'
117
117
  path = F.expand_path(body.to_path)
118
118
  if url = map_accel_path(env, path)
119
- headers['Content-Length'] = '0'
119
+ headers[CONTENT_LENGTH] = '0'
120
120
  headers[type] = url
121
121
  obody = body
122
122
  body = Rack::BodyProxy.new([]) do
@@ -127,7 +127,7 @@ module Rack
127
127
  end
128
128
  when 'X-Sendfile', 'X-Lighttpd-Send-File'
129
129
  path = F.expand_path(body.to_path)
130
- headers['Content-Length'] = '0'
130
+ headers[CONTENT_LENGTH] = '0'
131
131
  headers[type] = path
132
132
  obody = body
133
133
  body = Rack::BodyProxy.new([]) do
@@ -235,17 +235,15 @@ module Rack
235
235
  m
236
236
  end
237
237
 
238
- # Aliased for backwards-compatibility
239
- alias :middleware :default_middleware_by_environment
238
+ def middleware
239
+ default_middleware_by_environment
240
+ end
240
241
  end
241
242
 
242
- def default_middleware_by_environment
243
- self.class.default_middleware_by_environment
243
+ def middleware
244
+ self.class.middleware
244
245
  end
245
246
 
246
- # Aliased for backwards-compatibility
247
- alias :middleware :default_middleware_by_environment
248
-
249
247
  def start &blk
250
248
  if options[:warn]
251
249
  $-w = true
@@ -312,7 +310,7 @@ module Rack
312
310
 
313
311
  # Don't evaluate CGI ISINDEX parameters.
314
312
  # http://www.meb.uni-bonn.de/docs/cgi/cl.html
315
- args.clear if ENV.include?("REQUEST_METHOD")
313
+ args.clear if ENV.include?(REQUEST_METHOD)
316
314
 
317
315
  options.merge! opt_parser.parse!(args)
318
316
  options[:config] = ::File.expand_path(options[:config])
@@ -325,8 +323,7 @@ module Rack
325
323
  end
326
324
 
327
325
  def build_app(app)
328
- middlewares = default_middleware_by_environment[options[:environment]]
329
- middlewares.reverse_each do |middleware|
326
+ middleware[options[:environment]].reverse_each do |middleware|
330
327
  middleware = middleware.call(self) if middleware.respond_to?(:call)
331
328
  next unless middleware
332
329
  klass, *args = middleware