rack 2.0.6 → 2.2.3

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 (190) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +694 -0
  3. data/CONTRIBUTING.md +136 -0
  4. data/{COPYING → MIT-LICENSE} +4 -2
  5. data/README.rdoc +152 -148
  6. data/Rakefile +37 -23
  7. data/{SPEC → SPEC.rdoc} +38 -10
  8. data/bin/rackup +1 -0
  9. data/example/lobster.ru +2 -0
  10. data/example/protectedlobster.rb +3 -1
  11. data/example/protectedlobster.ru +2 -0
  12. data/lib/rack.rb +67 -73
  13. data/lib/rack/auth/abstract/handler.rb +3 -1
  14. data/lib/rack/auth/abstract/request.rb +1 -1
  15. data/lib/rack/auth/basic.rb +7 -4
  16. data/lib/rack/auth/digest/md5.rb +13 -11
  17. data/lib/rack/auth/digest/nonce.rb +6 -3
  18. data/lib/rack/auth/digest/params.rb +4 -2
  19. data/lib/rack/auth/digest/request.rb +5 -3
  20. data/lib/rack/body_proxy.rb +15 -14
  21. data/lib/rack/builder.rb +116 -23
  22. data/lib/rack/cascade.rb +28 -12
  23. data/lib/rack/chunked.rb +68 -20
  24. data/lib/rack/common_logger.rb +33 -25
  25. data/lib/rack/conditional_get.rb +20 -16
  26. data/lib/rack/config.rb +2 -0
  27. data/lib/rack/content_length.rb +8 -7
  28. data/lib/rack/content_type.rb +5 -4
  29. data/lib/rack/core_ext/regexp.rb +14 -0
  30. data/lib/rack/deflater.rb +59 -34
  31. data/lib/rack/directory.rb +84 -64
  32. data/lib/rack/etag.rb +5 -4
  33. data/lib/rack/events.rb +19 -20
  34. data/lib/rack/file.rb +4 -173
  35. data/lib/rack/files.rb +218 -0
  36. data/lib/rack/handler.rb +7 -2
  37. data/lib/rack/handler/cgi.rb +2 -3
  38. data/lib/rack/handler/fastcgi.rb +4 -4
  39. data/lib/rack/handler/lsws.rb +3 -3
  40. data/lib/rack/handler/scgi.rb +9 -8
  41. data/lib/rack/handler/thin.rb +3 -3
  42. data/lib/rack/handler/webrick.rb +15 -6
  43. data/lib/rack/head.rb +1 -1
  44. data/lib/rack/lint.rb +71 -25
  45. data/lib/rack/lobster.rb +10 -10
  46. data/lib/rack/lock.rb +2 -1
  47. data/lib/rack/logger.rb +2 -0
  48. data/lib/rack/media_type.rb +10 -5
  49. data/lib/rack/method_override.rb +4 -2
  50. data/lib/rack/mime.rb +9 -1
  51. data/lib/rack/mock.rb +97 -20
  52. data/lib/rack/multipart.rb +6 -4
  53. data/lib/rack/multipart/generator.rb +17 -13
  54. data/lib/rack/multipart/parser.rb +57 -62
  55. data/lib/rack/multipart/uploaded_file.rb +15 -7
  56. data/lib/rack/null_logger.rb +2 -0
  57. data/lib/rack/query_parser.rb +53 -28
  58. data/lib/rack/recursive.rb +7 -5
  59. data/lib/rack/reloader.rb +8 -4
  60. data/lib/rack/request.rb +220 -61
  61. data/lib/rack/response.rb +127 -44
  62. data/lib/rack/rewindable_input.rb +4 -3
  63. data/lib/rack/runtime.rb +6 -4
  64. data/lib/rack/sendfile.rb +13 -9
  65. data/lib/rack/server.rb +95 -24
  66. data/lib/rack/session/abstract/id.rb +100 -22
  67. data/lib/rack/session/cookie.rb +22 -14
  68. data/lib/rack/session/memcache.rb +4 -87
  69. data/lib/rack/session/pool.rb +18 -9
  70. data/lib/rack/show_exceptions.rb +21 -17
  71. data/lib/rack/show_status.rb +9 -9
  72. data/lib/rack/static.rb +23 -11
  73. data/lib/rack/tempfile_reaper.rb +1 -1
  74. data/lib/rack/urlmap.rb +12 -6
  75. data/lib/rack/utils.rb +102 -109
  76. data/lib/rack/version.rb +29 -0
  77. data/rack.gemspec +40 -28
  78. metadata +39 -181
  79. data/HISTORY.md +0 -505
  80. data/test/builder/an_underscore_app.rb +0 -5
  81. data/test/builder/anything.rb +0 -5
  82. data/test/builder/comment.ru +0 -4
  83. data/test/builder/end.ru +0 -5
  84. data/test/builder/line.ru +0 -1
  85. data/test/builder/options.ru +0 -2
  86. data/test/cgi/assets/folder/test.js +0 -1
  87. data/test/cgi/assets/fonts/font.eot +0 -1
  88. data/test/cgi/assets/images/image.png +0 -1
  89. data/test/cgi/assets/index.html +0 -1
  90. data/test/cgi/assets/javascripts/app.js +0 -1
  91. data/test/cgi/assets/stylesheets/app.css +0 -1
  92. data/test/cgi/lighttpd.conf +0 -26
  93. data/test/cgi/rackup_stub.rb +0 -6
  94. data/test/cgi/sample_rackup.ru +0 -5
  95. data/test/cgi/test +0 -9
  96. data/test/cgi/test+directory/test+file +0 -1
  97. data/test/cgi/test.fcgi +0 -9
  98. data/test/cgi/test.gz +0 -0
  99. data/test/cgi/test.ru +0 -5
  100. data/test/gemloader.rb +0 -10
  101. data/test/helper.rb +0 -34
  102. data/test/multipart/bad_robots +0 -259
  103. data/test/multipart/binary +0 -0
  104. data/test/multipart/content_type_and_no_filename +0 -6
  105. data/test/multipart/empty +0 -10
  106. data/test/multipart/fail_16384_nofile +0 -814
  107. data/test/multipart/file1.txt +0 -1
  108. data/test/multipart/filename_and_modification_param +0 -7
  109. data/test/multipart/filename_and_no_name +0 -6
  110. data/test/multipart/filename_with_encoded_words +0 -7
  111. data/test/multipart/filename_with_escaped_quotes +0 -6
  112. data/test/multipart/filename_with_escaped_quotes_and_modification_param +0 -7
  113. data/test/multipart/filename_with_null_byte +0 -7
  114. data/test/multipart/filename_with_percent_escaped_quotes +0 -6
  115. data/test/multipart/filename_with_single_quote +0 -7
  116. data/test/multipart/filename_with_unescaped_percentages +0 -6
  117. data/test/multipart/filename_with_unescaped_percentages2 +0 -6
  118. data/test/multipart/filename_with_unescaped_percentages3 +0 -6
  119. data/test/multipart/filename_with_unescaped_quotes +0 -6
  120. data/test/multipart/ie +0 -6
  121. data/test/multipart/invalid_character +0 -6
  122. data/test/multipart/mixed_files +0 -21
  123. data/test/multipart/nested +0 -10
  124. data/test/multipart/none +0 -9
  125. data/test/multipart/quoted +0 -15
  126. data/test/multipart/rack-logo.png +0 -0
  127. data/test/multipart/semicolon +0 -6
  128. data/test/multipart/text +0 -15
  129. data/test/multipart/three_files_three_fields +0 -31
  130. data/test/multipart/unity3d_wwwform +0 -11
  131. data/test/multipart/webkit +0 -32
  132. data/test/rackup/config.ru +0 -31
  133. data/test/registering_handler/rack/handler/registering_myself.rb +0 -8
  134. data/test/spec_auth_basic.rb +0 -89
  135. data/test/spec_auth_digest.rb +0 -260
  136. data/test/spec_body_proxy.rb +0 -85
  137. data/test/spec_builder.rb +0 -233
  138. data/test/spec_cascade.rb +0 -63
  139. data/test/spec_cgi.rb +0 -84
  140. data/test/spec_chunked.rb +0 -103
  141. data/test/spec_common_logger.rb +0 -95
  142. data/test/spec_conditional_get.rb +0 -103
  143. data/test/spec_config.rb +0 -23
  144. data/test/spec_content_length.rb +0 -86
  145. data/test/spec_content_type.rb +0 -46
  146. data/test/spec_deflater.rb +0 -375
  147. data/test/spec_directory.rb +0 -148
  148. data/test/spec_etag.rb +0 -108
  149. data/test/spec_events.rb +0 -133
  150. data/test/spec_fastcgi.rb +0 -85
  151. data/test/spec_file.rb +0 -264
  152. data/test/spec_handler.rb +0 -57
  153. data/test/spec_head.rb +0 -46
  154. data/test/spec_lint.rb +0 -515
  155. data/test/spec_lobster.rb +0 -59
  156. data/test/spec_lock.rb +0 -204
  157. data/test/spec_logger.rb +0 -24
  158. data/test/spec_media_type.rb +0 -42
  159. data/test/spec_method_override.rb +0 -110
  160. data/test/spec_mime.rb +0 -51
  161. data/test/spec_mock.rb +0 -359
  162. data/test/spec_multipart.rb +0 -722
  163. data/test/spec_null_logger.rb +0 -21
  164. data/test/spec_recursive.rb +0 -75
  165. data/test/spec_request.rb +0 -1398
  166. data/test/spec_response.rb +0 -510
  167. data/test/spec_rewindable_input.rb +0 -128
  168. data/test/spec_runtime.rb +0 -50
  169. data/test/spec_sendfile.rb +0 -125
  170. data/test/spec_server.rb +0 -193
  171. data/test/spec_session_abstract_id.rb +0 -31
  172. data/test/spec_session_abstract_session_hash.rb +0 -45
  173. data/test/spec_session_cookie.rb +0 -442
  174. data/test/spec_session_memcache.rb +0 -320
  175. data/test/spec_session_pool.rb +0 -210
  176. data/test/spec_show_exceptions.rb +0 -93
  177. data/test/spec_show_status.rb +0 -104
  178. data/test/spec_static.rb +0 -184
  179. data/test/spec_tempfile_reaper.rb +0 -64
  180. data/test/spec_thin.rb +0 -96
  181. data/test/spec_urlmap.rb +0 -237
  182. data/test/spec_utils.rb +0 -742
  183. data/test/spec_version.rb +0 -11
  184. data/test/spec_webrick.rb +0 -206
  185. data/test/static/another/index.html +0 -1
  186. data/test/static/foo.html +0 -1
  187. data/test/static/index.html +0 -1
  188. data/test/testrequest.rb +0 -78
  189. data/test/unregistered_handler/rack/handler/unregistered.rb +0 -7
  190. data/test/unregistered_handler/rack/handler/unregistered_long_one.rb +0 -7
@@ -1,11 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'lsapi'
2
- require 'rack/content_length'
3
- require 'rack/rewindable_input'
4
4
 
5
5
  module Rack
6
6
  module Handler
7
7
  class LSWS
8
- def self.run(app, options=nil)
8
+ def self.run(app, **options)
9
9
  while LSAPI.accept != nil
10
10
  serve app
11
11
  end
@@ -1,19 +1,19 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'scgi'
2
4
  require 'stringio'
3
- require 'rack/content_length'
4
- require 'rack/chunked'
5
5
 
6
6
  module Rack
7
7
  module Handler
8
8
  class SCGI < ::SCGI::Processor
9
9
  attr_accessor :app
10
10
 
11
- def self.run(app, options=nil)
11
+ def self.run(app, **options)
12
12
  options[:Socket] = UNIXServer.new(options[:File]) if options[:File]
13
- new(options.merge(:app=>app,
14
- :host=>options[:Host],
15
- :port=>options[:Port],
16
- :socket=>options[:Socket])).listen
13
+ new(options.merge(app: app,
14
+ host: options[:Host],
15
+ port: options[:Port],
16
+ socket: options[:Socket])).listen
17
17
  end
18
18
 
19
19
  def self.valid_options
@@ -41,7 +41,8 @@ module Rack
41
41
  env[QUERY_STRING] ||= ""
42
42
  env[SCRIPT_NAME] = ""
43
43
 
44
- rack_input = StringIO.new(input_body, encoding: Encoding::BINARY)
44
+ rack_input = StringIO.new(input_body)
45
+ rack_input.set_encoding(Encoding::BINARY)
45
46
 
46
47
  env.update(
47
48
  RACK_VERSION => Rack::VERSION,
@@ -1,14 +1,14 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thin"
2
4
  require "thin/server"
3
5
  require "thin/logging"
4
6
  require "thin/backends/tcp_server"
5
- require "rack/content_length"
6
- require "rack/chunked"
7
7
 
8
8
  module Rack
9
9
  module Handler
10
10
  class Thin
11
- def self.run(app, options={})
11
+ def self.run(app, **options)
12
12
  environment = ENV['RACK_ENV'] || 'development'
13
13
  default_host = environment == 'development' ? 'localhost' : '0.0.0.0'
14
14
 
@@ -1,6 +1,7 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'webrick'
2
4
  require 'stringio'
3
- require 'rack/content_length'
4
5
 
5
6
  # This monkey patch allows for applications to perform their own chunking
6
7
  # through WEBrick::HTTPResponse if rack is set to true.
@@ -22,12 +23,18 @@ end
22
23
  module Rack
23
24
  module Handler
24
25
  class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
25
- def self.run(app, options={})
26
+ def self.run(app, **options)
26
27
  environment = ENV['RACK_ENV'] || 'development'
27
28
  default_host = environment == 'development' ? 'localhost' : nil
28
29
 
29
- options[:BindAddress] = options.delete(:Host) || default_host
30
+ if !options[:BindAddress] || options[:Host]
31
+ options[:BindAddress] = options.delete(:Host) || default_host
32
+ end
30
33
  options[:Port] ||= 8080
34
+ if options[:SSLEnable]
35
+ require 'webrick/https'
36
+ end
37
+
31
38
  @server = ::WEBrick::HTTPServer.new(options)
32
39
  @server.mount "/", Rack::Handler::WEBrick, app
33
40
  yield @server if block_given?
@@ -45,8 +52,10 @@ module Rack
45
52
  end
46
53
 
47
54
  def self.shutdown
48
- @server.shutdown
49
- @server = nil
55
+ if @server
56
+ @server.shutdown
57
+ @server = nil
58
+ end
50
59
  end
51
60
 
52
61
  def initialize(server, app)
@@ -79,7 +88,7 @@ module Rack
79
88
  env[QUERY_STRING] ||= ""
80
89
  unless env[PATH_INFO] == ""
81
90
  path, n = req.request_uri.path, env[SCRIPT_NAME].length
82
- env[PATH_INFO] = path[n, path.length-n]
91
+ env[PATH_INFO] = path[n, path.length - n]
83
92
  end
84
93
  env[REQUEST_PATH] ||= [env[SCRIPT_NAME], env[PATH_INFO]].join
85
94
 
@@ -1,4 +1,4 @@
1
- require 'rack/body_proxy'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Rack
4
4
  # Rack::Head returns an empty body for all HEAD requests. It leaves
@@ -1,4 +1,5 @@
1
- require 'rack/utils'
1
+ # frozen_string_literal: true
2
+
2
3
  require 'forwardable'
3
4
 
4
5
  module Rack
@@ -33,7 +34,7 @@ module Rack
33
34
 
34
35
  ## A Rack application is a Ruby object (not a class) that
35
36
  ## responds to +call+.
36
- def call(env=nil)
37
+ def call(env = nil)
37
38
  dup._call(env)
38
39
  end
39
40
 
@@ -46,13 +47,24 @@ module Rack
46
47
  env[RACK_ERRORS] = ErrorWrapper.new(env[RACK_ERRORS])
47
48
 
48
49
  ## and returns an Array of exactly three values:
49
- status, headers, @body = @app.call(env)
50
+ ary = @app.call(env)
51
+ assert("response #{ary.inspect} is not an Array , but #{ary.class}") {
52
+ ary.kind_of? Array
53
+ }
54
+ assert("response array #{ary.inspect} has #{ary.size} elements instead of 3") {
55
+ ary.size == 3
56
+ }
57
+
58
+ status, headers, @body = ary
50
59
  ## The *status*,
51
60
  check_status status
52
61
  ## the *headers*,
53
62
  check_headers headers
54
63
 
55
- check_hijack_response headers, env
64
+ hijack_proc = check_hijack_response headers, env
65
+ if hijack_proc && headers.is_a?(Hash)
66
+ headers[RACK_HIJACK] = hijack_proc
67
+ end
56
68
 
57
69
  ## and the *body*.
58
70
  check_content_type status, headers
@@ -63,12 +75,15 @@ module Rack
63
75
 
64
76
  ## == The Environment
65
77
  def check_env(env)
66
- ## The environment must be an instance of Hash that includes
78
+ ## The environment must be an unfrozen instance of Hash that includes
67
79
  ## CGI-like headers. The application is free to modify the
68
80
  ## environment.
69
81
  assert("env #{env.inspect} is not a Hash, but #{env.class}") {
70
82
  env.kind_of? Hash
71
83
  }
84
+ assert("env should not be frozen, but is") {
85
+ !env.frozen?
86
+ }
72
87
 
73
88
  ##
74
89
  ## The environment is required to include these variables
@@ -102,17 +117,19 @@ module Rack
102
117
  ## follows the <tt>?</tt>, if any. May be
103
118
  ## empty, but is always required!
104
119
 
105
- ## <tt>SERVER_NAME</tt>, <tt>SERVER_PORT</tt>::
106
- ## When combined with <tt>SCRIPT_NAME</tt> and
120
+ ## <tt>SERVER_NAME</tt>:: When combined with <tt>SCRIPT_NAME</tt> and
107
121
  ## <tt>PATH_INFO</tt>, these variables can be
108
122
  ## used to complete the URL. Note, however,
109
123
  ## that <tt>HTTP_HOST</tt>, if present,
110
124
  ## should be used in preference to
111
125
  ## <tt>SERVER_NAME</tt> for reconstructing
112
126
  ## the request URL.
113
- ## <tt>SERVER_NAME</tt> and <tt>SERVER_PORT</tt>
114
- ## can never be empty strings, and so
115
- ## are always required.
127
+ ## <tt>SERVER_NAME</tt> can never be an empty
128
+ ## string, and so is always required.
129
+
130
+ ## <tt>SERVER_PORT</tt>:: An optional +Integer+ which is the port the
131
+ ## server is running on. Should be specified if
132
+ ## the server is running on a non-standard port.
116
133
 
117
134
  ## <tt>HTTP_</tt> Variables:: Variables corresponding to the
118
135
  ## client-supplied HTTP request
@@ -123,9 +140,8 @@ module Rack
123
140
  ## the presence or absence of the
124
141
  ## appropriate HTTP header in the
125
142
  ## request. See
126
- ## <a href="https://tools.ietf.org/html/rfc3875#section-4.1.18">
127
- ## RFC3875 section 4.1.18</a> for
128
- ## specific behavior.
143
+ ## {RFC3875 section 4.1.18}[https://tools.ietf.org/html/rfc3875#section-4.1.18]
144
+ ## for specific behavior.
129
145
 
130
146
  ## In addition to this, the Rack environment must include these
131
147
  ## Rack-specific variables:
@@ -197,6 +213,11 @@ module Rack
197
213
  assert("session #{session.inspect} must respond to clear") {
198
214
  session.respond_to?(:clear)
199
215
  }
216
+
217
+ ## to_hash (returning unfrozen Hash instance);
218
+ assert("session #{session.inspect} must respond to to_hash and return unfrozen Hash instance") {
219
+ session.respond_to?(:to_hash) && session.to_hash.kind_of?(Hash) && !session.to_hash.frozen?
220
+ }
200
221
  end
201
222
 
202
223
  ## <tt>rack.logger</tt>:: A common object interface for logging messages.
@@ -252,28 +273,49 @@ module Rack
252
273
  ## accepted specifications and must not be used otherwise.
253
274
  ##
254
275
 
255
- %w[REQUEST_METHOD SERVER_NAME SERVER_PORT
256
- QUERY_STRING
276
+ %w[REQUEST_METHOD SERVER_NAME QUERY_STRING
257
277
  rack.version rack.input rack.errors
258
278
  rack.multithread rack.multiprocess rack.run_once].each { |header|
259
279
  assert("env missing required key #{header}") { env.include? header }
260
280
  }
261
281
 
282
+ ## The <tt>SERVER_PORT</tt> must be an Integer if set.
283
+ assert("env[SERVER_PORT] is not an Integer") do
284
+ server_port = env["SERVER_PORT"]
285
+ server_port.nil? || (Integer(server_port) rescue false)
286
+ end
287
+
288
+ ## The <tt>SERVER_NAME</tt> must be a valid authority as defined by RFC7540.
289
+ assert("#{env[SERVER_NAME]} must be a valid authority") do
290
+ URI.parse("http://#{env[SERVER_NAME]}/") rescue false
291
+ end
292
+
293
+ ## The <tt>HTTP_HOST</tt> must be a valid authority as defined by RFC7540.
294
+ assert("#{env[HTTP_HOST]} must be a valid authority") do
295
+ URI.parse("http://#{env[HTTP_HOST]}/") rescue false
296
+ end
297
+
262
298
  ## The environment must not contain the keys
263
299
  ## <tt>HTTP_CONTENT_TYPE</tt> or <tt>HTTP_CONTENT_LENGTH</tt>
264
300
  ## (use the versions without <tt>HTTP_</tt>).
265
301
  %w[HTTP_CONTENT_TYPE HTTP_CONTENT_LENGTH].each { |header|
266
- assert("env contains #{header}, must use #{header[5,-1]}") {
302
+ assert("env contains #{header}, must use #{header[5, -1]}") {
267
303
  not env.include? header
268
304
  }
269
305
  }
270
306
 
271
307
  ## The CGI keys (named without a period) must have String values.
308
+ ## If the string values for CGI keys contain non-ASCII characters,
309
+ ## they should use ASCII-8BIT encoding.
272
310
  env.each { |key, value|
273
311
  next if key.include? "." # Skip extensions
274
312
  assert("env variable #{key} has non-string value #{value.inspect}") {
275
313
  value.kind_of? String
276
314
  }
315
+ next if value.encoding == Encoding::ASCII_8BIT
316
+ assert("env variable #{key} has value containing non-ASCII characters and has non-ASCII-8BIT encoding #{value.inspect} encoding: #{value.encoding}") {
317
+ value.b !~ /[\x80-\xff]/n
318
+ }
277
319
  }
278
320
 
279
321
  ## There are the following restrictions:
@@ -336,7 +378,7 @@ module Rack
336
378
  ## When applicable, its external encoding must be "ASCII-8BIT" and it
337
379
  ## must be opened in binary mode, for Ruby 1.9 compatibility.
338
380
  assert("rack.input #{input} does not have ASCII-8BIT as its external encoding") {
339
- input.external_encoding.name == "ASCII-8BIT"
381
+ input.external_encoding == Encoding::ASCII_8BIT
340
382
  } if input.respond_to?(:external_encoding)
341
383
  assert("rack.input #{input} is not opened in binary mode") {
342
384
  input.binmode?
@@ -568,7 +610,7 @@ module Rack
568
610
 
569
611
  # this check uses headers like a hash, but the spec only requires
570
612
  # headers respond to #each
571
- headers = Rack::Utils::HeaderHash.new(headers)
613
+ headers = Rack::Utils::HeaderHash[headers]
572
614
 
573
615
  ## In order to do this, an application may set the special header
574
616
  ## <tt>rack.hijack</tt> to an object that responds to <tt>call</tt>
@@ -592,7 +634,7 @@ module Rack
592
634
  headers[RACK_HIJACK].respond_to? :call
593
635
  }
594
636
  original_hijack = headers[RACK_HIJACK]
595
- headers[RACK_HIJACK] = proc do |io|
637
+ proc do |io|
596
638
  original_hijack.call HijackWrapper.new(io)
597
639
  end
598
640
  else
@@ -602,6 +644,8 @@ module Rack
602
644
  assert('rack.hijack header must not be present if server does not support hijacking') {
603
645
  headers[RACK_HIJACK].nil?
604
646
  }
647
+
648
+ nil
605
649
  end
606
650
  end
607
651
  ## ==== Conventions
@@ -626,15 +670,17 @@ module Rack
626
670
  assert("headers object should respond to #each, but doesn't (got #{header.class} as headers)") {
627
671
  header.respond_to? :each
628
672
  }
629
- header.each { |key, value|
630
- ## Special headers starting "rack." are for communicating with the
631
- ## server, and must not be sent back to the client.
632
- next if key =~ /^rack\..+$/
633
673
 
674
+ header.each { |key, value|
634
675
  ## The header keys must be Strings.
635
676
  assert("header key must be a string, was #{key.class}") {
636
677
  key.kind_of? String
637
678
  }
679
+
680
+ ## Special headers starting "rack." are for communicating with the
681
+ ## server, and must not be sent back to the client.
682
+ next if key =~ /^rack\..+$/
683
+
638
684
  ## The header must not contain a +Status+ key.
639
685
  assert("header must not contain Status") { key.downcase != "status" }
640
686
  ## The header must conform to RFC7230 token specification, i.e. cannot
@@ -662,7 +708,7 @@ module Rack
662
708
  ## 204 or 304.
663
709
  if key.downcase == "content-type"
664
710
  assert("Content-Type header found in #{status} response, not allowed") {
665
- not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
711
+ not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i
666
712
  }
667
713
  return
668
714
  end
@@ -676,7 +722,7 @@ module Rack
676
722
  ## There must not be a <tt>Content-Length</tt> header when the
677
723
  ## +Status+ is 1xx, 204 or 304.
678
724
  assert("Content-Length header found in #{status} response, not allowed") {
679
- not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.include? status.to_i
725
+ not Rack::Utils::STATUS_WITH_NO_ENTITY_BODY.key? status.to_i
680
726
  }
681
727
  @content_length = value
682
728
  end
@@ -1,7 +1,6 @@
1
- require 'zlib'
1
+ # frozen_string_literal: true
2
2
 
3
- require 'rack/request'
4
- require 'rack/response'
3
+ require 'zlib'
5
4
 
6
5
  module Rack
7
6
  # Paste has a Pony, Rack has a Lobster!
@@ -25,8 +24,8 @@ module Rack
25
24
  content = ["<title>Lobstericious!</title>",
26
25
  "<pre>", lobster, "</pre>",
27
26
  "<a href='#{href}'>flip!</a>"]
28
- length = content.inject(0) { |a,e| a+e.size }.to_s
29
- [200, {CONTENT_TYPE => "text/html", CONTENT_LENGTH => length}, content]
27
+ length = content.inject(0) { |a, e| a + e.size }.to_s
28
+ [200, { CONTENT_TYPE => "text/html", CONTENT_LENGTH => length }, content]
30
29
  }
31
30
 
32
31
  def call(env)
@@ -37,8 +36,8 @@ module Rack
37
36
  gsub('\\', 'TEMP').
38
37
  gsub('/', '\\').
39
38
  gsub('TEMP', '/').
40
- gsub('{','}').
41
- gsub('(',')')
39
+ gsub('{', '}').
40
+ gsub('(', ')')
42
41
  end.join("\n")
43
42
  href = "?flip=right"
44
43
  elsif req.GET["flip"] == "crash"
@@ -62,9 +61,10 @@ module Rack
62
61
  end
63
62
 
64
63
  if $0 == __FILE__
65
- require 'rack'
66
- require 'rack/show_exceptions'
64
+ # :nocov:
65
+ require_relative '../rack'
67
66
  Rack::Server.start(
68
- :app => Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), :Port => 9292
67
+ app: Rack::ShowExceptions.new(Rack::Lint.new(Rack::Lobster.new)), Port: 9292
69
68
  )
69
+ # :nocov:
70
70
  end
@@ -1,5 +1,6 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'thread'
2
- require 'rack/body_proxy'
3
4
 
4
5
  module Rack
5
6
  # Rack::Lock locks every request inside a mutex, so that every request
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
 
3
5
  module Rack
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Rack
2
4
  # Rack::MediaType parse media type and parameters out of content_type string
3
5
 
@@ -13,7 +15,7 @@ module Rack
13
15
  # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7
14
16
  def type(content_type)
15
17
  return nil unless content_type
16
- content_type.split(SPLIT_PATTERN, 2).first.downcase
18
+ content_type.split(SPLIT_PATTERN, 2).first.tap &:downcase!
17
19
  end
18
20
 
19
21
  # The media type parameters provided in CONTENT_TYPE as a Hash, or
@@ -23,15 +25,18 @@ module Rack
23
25
  # { 'charset' => 'utf-8' }
24
26
  def params(content_type)
25
27
  return {} if content_type.nil?
26
- Hash[*content_type.split(SPLIT_PATTERN)[1..-1].
27
- collect { |s| s.split('=', 2) }.
28
- map { |k,v| [k.downcase, strip_doublequotes(v)] }.flatten]
28
+
29
+ content_type.split(SPLIT_PATTERN)[1..-1].each_with_object({}) do |s, hsh|
30
+ k, v = s.split('=', 2)
31
+
32
+ hsh[k.tap(&:downcase!)] = strip_doublequotes(v)
33
+ end
29
34
  end
30
35
 
31
36
  private
32
37
 
33
38
  def strip_doublequotes(str)
34
- (str[0] == ?" && str[-1] == ?") ? str[1..-2] : str
39
+ (str.start_with?('"') && str.end_with?('"')) ? str[1..-2] : str
35
40
  end
36
41
  end
37
42
  end