rack 1.0.0 → 1.0.1

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.

data/RDOX CHANGED
@@ -250,7 +250,6 @@
250
250
  * does conform to the Rack spec
251
251
  * should parse Accept-Encoding correctly
252
252
  * should provide ip information
253
- * memoizes itself to reduce the cost of repetitive initialization
254
253
  * should allow subclass request to be instantiated after parent request
255
254
  * should allow parent request to be instantiated after subclass request
256
255
 
@@ -379,6 +378,7 @@
379
378
 
380
379
  == Rack::Utils
381
380
  * should escape correctly
381
+ * should escape correctly for multibyte characters
382
382
  * should unescape correctly
383
383
  * should parse query strings correctly
384
384
  * should parse nested query strings correctly
@@ -393,6 +393,10 @@
393
393
  * should overwrite case insensitively and assume the new key's case
394
394
  * should be converted to real Hash
395
395
  * should convert Array values to Strings when converting to Hash
396
+ * should be able to delete the given key case-sensitively
397
+ * should be able to delete the given key case-insensitively
398
+ * should return the deleted value when #delete is called on an existing key
399
+ * should return nil when #delete is called on a non-existant key
396
400
 
397
401
  == Rack::Utils::Context
398
402
  * should set context correctly
@@ -405,6 +409,7 @@
405
409
  * should parse multipart upload with nested parameters
406
410
  * should parse multipart upload with binary file
407
411
  * should parse multipart upload with empty file
412
+ * should parse multipart upload with filename with semicolons
408
413
  * should not include file params if no file was selected
409
414
  * should parse IE multipart upload and clean up filename
410
415
  * rewinds input after parsing upload
@@ -420,4 +425,4 @@
420
425
  * should correctly set cookies
421
426
  * should provide a .run
422
427
 
423
- 330 specifications, 13 empty (1183 requirements), 0 failures
428
+ 335 specifications, 13 empty (1196 requirements), 0 failures
data/README CHANGED
@@ -272,6 +272,17 @@ run on port 11211) and memcache-client installed.
272
272
  * The Rakefile has been rewritten.
273
273
  * Many bugfixes and small improvements.
274
274
 
275
+ * October 18th, 2009: Eighth public release 1.0.1.
276
+ * Bump remainder of rack.versions.
277
+ * Support the pure Ruby FCGI implementation.
278
+ * Fix for form names containing "=": split first then unescape components
279
+ * Fixes the handling of the filename parameter with semicolons in names.
280
+ * Add anchor to nested params parsing regexp to prevent stack overflows
281
+ * Use more compatible gzip write api instead of "<<".
282
+ * Make sure that Reloader doesn't break when executed via ruby -e
283
+ * Make sure WEBrick respects the :Host option
284
+ * Many Ruby 1.9 fixes.
285
+
275
286
  == Contact
276
287
 
277
288
  Please mail bugs, suggestions and patches to
data/SPEC CHANGED
@@ -92,7 +92,9 @@ There are the following restrictions:
92
92
  <tt>SCRIPT_NAME</tt> never should be <tt>/</tt>, but instead be empty.
93
93
  === The Input Stream
94
94
  The input stream is an IO-like object which contains the raw HTTP
95
- POST data. If it is a file then it must be opened in binary mode.
95
+ POST data.
96
+ When applicable, its external encoding must be "ASCII-8BIT" and it
97
+ must be opened in binary mode, for Ruby 1.9 compatibility.
96
98
  The input stream must respond to +gets+, +each+, +read+ and +rewind+.
97
99
  * +gets+ must be called without arguments and return a string,
98
100
  or +nil+ on EOF.
@@ -60,7 +60,7 @@ module Rack
60
60
  @writer = block
61
61
  gzip =::Zlib::GzipWriter.new(self)
62
62
  gzip.mtime = @mtime
63
- @body.each { |part| gzip << part }
63
+ @body.each { |part| gzip.write(part) }
64
64
  @body.close if @body.respond_to?(:close)
65
65
  gzip.close
66
66
  @writer = nil
@@ -15,7 +15,7 @@ module Rack
15
15
 
16
16
  env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
17
17
 
18
- env.update({"rack.version" => [0,1],
18
+ env.update({"rack.version" => [1,0],
19
19
  "rack.input" => $stdin,
20
20
  "rack.errors" => $stderr,
21
21
 
@@ -3,13 +3,15 @@ require 'socket'
3
3
  require 'rack/content_length'
4
4
  require 'rack/rewindable_input'
5
5
 
6
- class FCGI::Stream
7
- alias _rack_read_without_buffer read
6
+ if defined? FCGI::Stream
7
+ class FCGI::Stream
8
+ alias _rack_read_without_buffer read
8
9
 
9
- def read(n, buffer=nil)
10
- buf = _rack_read_without_buffer n
11
- buffer.replace(buf.to_s) if buffer
12
- buf
10
+ def read(n, buffer=nil)
11
+ buf = _rack_read_without_buffer n
12
+ buffer.replace(buf.to_s) if buffer
13
+ buf
14
+ end
13
15
  end
14
16
  end
15
17
 
@@ -34,7 +36,7 @@ module Rack
34
36
 
35
37
  rack_input = RewindableInput.new(request.in)
36
38
 
37
- env.update({"rack.version" => [0,1],
39
+ env.update({"rack.version" => [1,0],
38
40
  "rack.input" => rack_input,
39
41
  "rack.errors" => request.err,
40
42
 
@@ -15,14 +15,19 @@ module Rack
15
15
  env = ENV.to_hash
16
16
  env.delete "HTTP_CONTENT_LENGTH"
17
17
  env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
18
- env.update({"rack.version" => [0,1],
19
- "rack.input" => StringIO.new($stdin.read.to_s),
20
- "rack.errors" => $stderr,
21
- "rack.multithread" => false,
22
- "rack.multiprocess" => true,
23
- "rack.run_once" => false,
24
- "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
25
- })
18
+
19
+ rack_input = RewindableInput.new($stdin.read.to_s)
20
+
21
+ env.update(
22
+ "rack.version" => [1,0],
23
+ "rack.input" => rack_input,
24
+ "rack.errors" => $stderr,
25
+ "rack.multithread" => false,
26
+ "rack.multiprocess" => true,
27
+ "rack.run_once" => false,
28
+ "rack.url_scheme" => ["yes", "on", "1"].include?(ENV["HTTPS"]) ? "https" : "http"
29
+ )
30
+
26
31
  env["QUERY_STRING"] ||= ""
27
32
  env["HTTP_VERSION"] ||= env["SERVER_PROTOCOL"]
28
33
  env["REQUEST_PATH"] ||= "/"
@@ -45,8 +45,11 @@ module Rack
45
45
 
46
46
  env["SCRIPT_NAME"] = "" if env["SCRIPT_NAME"] == "/"
47
47
 
48
- env.update({"rack.version" => [0,1],
49
- "rack.input" => request.body || StringIO.new(""),
48
+ rack_input = request.body || StringIO.new('')
49
+ rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
50
+
51
+ env.update({"rack.version" => [1,0],
52
+ "rack.input" => rack_input,
50
53
  "rack.errors" => $stderr,
51
54
 
52
55
  "rack.multithread" => true,
@@ -32,10 +32,13 @@ module Rack
32
32
  env["PATH_INFO"] = env["REQUEST_PATH"]
33
33
  env["QUERY_STRING"] ||= ""
34
34
  env["SCRIPT_NAME"] = ""
35
- env.update({"rack.version" => [0,1],
36
- "rack.input" => StringIO.new(input_body),
37
- "rack.errors" => $stderr,
38
35
 
36
+ rack_input = StringIO.new(input_body)
37
+ rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
38
+
39
+ env.update({"rack.version" => [1,0],
40
+ "rack.input" => rack_input,
41
+ "rack.errors" => $stderr,
39
42
  "rack.multithread" => true,
40
43
  "rack.multiprocess" => true,
41
44
  "rack.run_once" => false,
@@ -6,6 +6,7 @@ module Rack
6
6
  module Handler
7
7
  class WEBrick < ::WEBrick::HTTPServlet::AbstractServlet
8
8
  def self.run(app, options={})
9
+ options[:BindAddress] = options.delete(:Host) if options[:Host]
9
10
  server = ::WEBrick::HTTPServer.new(options)
10
11
  server.mount "/", Rack::Handler::WEBrick, app
11
12
  trap(:INT) { server.shutdown }
@@ -22,8 +23,11 @@ module Rack
22
23
  env = req.meta_vars
23
24
  env.delete_if { |k, v| v.nil? }
24
25
 
25
- env.update({"rack.version" => [0,1],
26
- "rack.input" => StringIO.new(req.body.to_s),
26
+ rack_input = StringIO.new(req.body.to_s)
27
+ rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
28
+
29
+ env.update({"rack.version" => [1,0],
30
+ "rack.input" => rack_input,
27
31
  "rack.errors" => $stderr,
28
32
 
29
33
  "rack.multithread" => true,
@@ -233,8 +233,17 @@ module Rack
233
233
  ## === The Input Stream
234
234
  ##
235
235
  ## The input stream is an IO-like object which contains the raw HTTP
236
- ## POST data. If it is a file then it must be opened in binary mode.
236
+ ## POST data.
237
237
  def check_input(input)
238
+ ## When applicable, its external encoding must be "ASCII-8BIT" and it
239
+ ## must be opened in binary mode, for Ruby 1.9 compatibility.
240
+ assert("rack.input #{input} does not have ASCII-8BIT as its external encoding") {
241
+ input.external_encoding.name == "ASCII-8BIT"
242
+ } if input.respond_to?(:external_encoding)
243
+ assert("rack.input #{input} is not opened in binary mode") {
244
+ input.binmode?
245
+ } if input.respond_to?(:binmode?)
246
+
238
247
  ## The input stream must respond to +gets+, +each+, +read+ and +rewind+.
239
248
  [:gets, :each, :read, :rewind].each { |method|
240
249
  assert("rack.input #{input} does not respond to ##{method}") {
@@ -40,7 +40,7 @@ module Rack
40
40
  end
41
41
 
42
42
  DEFAULT_ENV = {
43
- "rack.version" => [0,1],
43
+ "rack.version" => [1,0],
44
44
  "rack.input" => StringIO.new,
45
45
  "rack.errors" => StringIO.new,
46
46
  "rack.multithread" => true,
@@ -92,11 +92,14 @@ module Rack
92
92
 
93
93
  opts[:input] ||= ""
94
94
  if String === opts[:input]
95
- env["rack.input"] = StringIO.new(opts[:input])
95
+ rack_input = StringIO.new(opts[:input])
96
96
  else
97
- env["rack.input"] = opts[:input]
97
+ rack_input = opts[:input]
98
98
  end
99
99
 
100
+ rack_input.set_encoding(Encoding::BINARY) if rack_input.respond_to?(:set_encoding)
101
+ env['rack.input'] = rack_input
102
+
100
103
  env["CONTENT_LENGTH"] ||= env["rack.input"].length.to_s
101
104
 
102
105
  opts.each { |field, value|
@@ -70,7 +70,7 @@ module Rack
70
70
  next if file =~ /\.(so|bundle)$/ # cannot reload compiled files
71
71
 
72
72
  found, stat = figure_path(file, paths)
73
- next unless found and stat and mtime = stat.mtime
73
+ next unless found && stat && mtime = stat.mtime
74
74
 
75
75
  @cache[file] = found
76
76
 
@@ -87,7 +87,7 @@ module Rack
87
87
  found, stat = safe_stat(found)
88
88
  return found, stat if found
89
89
 
90
- paths.each do |possible_path|
90
+ paths.find do |possible_path|
91
91
  path = ::File.join(possible_path, file)
92
92
  found, stat = safe_stat(path)
93
93
  return ::File.expand_path(found), stat if found
@@ -17,14 +17,6 @@ module Rack
17
17
  # The environment of the request.
18
18
  attr_reader :env
19
19
 
20
- def self.new(env, *args)
21
- if self == Rack::Request
22
- env["rack.request"] ||= super
23
- else
24
- super
25
- end
26
- end
27
-
28
20
  def initialize(env)
29
21
  @env = env
30
22
  end
@@ -73,7 +65,7 @@ module Rack
73
65
 
74
66
  def host
75
67
  # Remove port number.
76
- (@env["HTTP_HOST"] || @env["SERVER_NAME"]).gsub(/:\d+\z/, '')
68
+ (@env["HTTP_HOST"] || @env["SERVER_NAME"]).to_s.gsub(/:\d+\z/, '')
77
69
  end
78
70
 
79
71
  def script_name=(s); @env["SCRIPT_NAME"] = s.to_s end
@@ -72,6 +72,8 @@ module Rack
72
72
  # access it because we have the file handle open.
73
73
  @rewindable_io = Tempfile.new('RackRewindableInput')
74
74
  @rewindable_io.chmod(0000)
75
+ @rewindable_io.set_encoding(Encoding::BINARY) if @rewindable_io.respond_to?(:set_encoding)
76
+ @rewindable_io.binmode
75
77
  if filesystem_has_posix_semantics?
76
78
  @rewindable_io.unlink
77
79
  @unlinked = true
@@ -1,3 +1,5 @@
1
+ # -*- encoding: binary -*-
2
+
1
3
  require 'set'
2
4
  require 'tempfile'
3
5
 
@@ -11,7 +13,7 @@ module Rack
11
13
  # version since it's faster. (Stolen from Camping).
12
14
  def escape(s)
13
15
  s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
14
- '%'+$1.unpack('H2'*$1.size).join('%').upcase
16
+ '%'+$1.unpack('H2'*bytesize($1)).join('%').upcase
15
17
  }.tr(' ', '+')
16
18
  end
17
19
  module_function :escape
@@ -24,16 +26,18 @@ module Rack
24
26
  end
25
27
  module_function :unescape
26
28
 
29
+ DEFAULT_SEP = /[&;] */n
30
+
27
31
  # Stolen from Mongrel, with some small modifications:
28
32
  # Parses a query string by breaking it up at the '&'
29
33
  # and ';' characters. You can also use this to parse
30
34
  # cookies by changing the characters used in the second
31
35
  # parameter (which defaults to '&;').
32
- def parse_query(qs, d = '&;')
36
+ def parse_query(qs, d = nil)
33
37
  params = {}
34
38
 
35
- (qs || '').split(/[#{d}] */n).each do |p|
36
- k, v = unescape(p).split('=', 2)
39
+ (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
40
+ k, v = p.split('=', 2).map { |x| unescape(x) }
37
41
 
38
42
  if cur = params[k]
39
43
  if cur.class == Array
@@ -50,10 +54,10 @@ module Rack
50
54
  end
51
55
  module_function :parse_query
52
56
 
53
- def parse_nested_query(qs, d = '&;')
57
+ def parse_nested_query(qs, d = nil)
54
58
  params = {}
55
59
 
56
- (qs || '').split(/[#{d}] */n).each do |p|
60
+ (qs || '').split(d ? /[#{d}] */n : DEFAULT_SEP).each do |p|
57
61
  k, v = unescape(p).split('=', 2)
58
62
  normalize_params(params, k, v)
59
63
  end
@@ -63,7 +67,7 @@ module Rack
63
67
  module_function :parse_nested_query
64
68
 
65
69
  def normalize_params(params, name, v = nil)
66
- name =~ %r([\[\]]*([^\[\]]+)\]*)
70
+ name =~ %r(\A[\[\]]*([^\[\]]+)\]*)
67
71
  k = $1 || ''
68
72
  after = $' || ''
69
73
 
@@ -99,7 +103,7 @@ module Rack
99
103
  if v.class == Array
100
104
  build_query(v.map { |x| [k, x] })
101
105
  else
102
- escape(k) + "=" + escape(v)
106
+ "#{escape(k)}=#{escape(v)}"
103
107
  end
104
108
  }.join("&")
105
109
  end
@@ -304,7 +308,7 @@ module Rack
304
308
  input = env['rack.input']
305
309
  input.rewind
306
310
 
307
- boundary_size = boundary.size + EOL.size
311
+ boundary_size = Utils.bytesize(boundary) + EOL.size
308
312
  bufsize = 16384
309
313
 
310
314
  content_length -= boundary_size
@@ -326,7 +330,7 @@ module Rack
326
330
  head = buf.slice!(0, i+2) # First \r\n
327
331
  buf.slice!(0, 2) # Second \r\n
328
332
 
329
- filename = head[/Content-Disposition:.* filename="?([^\";]*)"?/ni, 1]
333
+ filename = head[/Content-Disposition:.* filename=(?:"((?:\\.|[^\"])*)"|([^;\s]*))/ni, 1]
330
334
  content_type = head[/Content-Type: (.*)#{EOL}/ni, 1]
331
335
  name = head[/Content-Disposition:.*\s+name="?([^\";]*)"?/ni, 1] || head[/Content-ID:\s*([^#{EOL}]*)/ni, 1]
332
336
 
@@ -2,17 +2,17 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{rack}
5
- s.version = "1.0.0"
5
+ s.version = "1.0.1"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Christian Neukirchen"]
9
- s.date = %q{2009-04-25}
9
+ s.date = %q{2009-10-18}
10
10
  s.default_executable = %q{rackup}
11
11
  s.description = %q{Rack provides minimal, modular and adaptable interface for developing web applications in Ruby. By wrapping HTTP requests and responses in the simplest way possible, it unifies and distills the API for web servers, web frameworks, and software in between (the so-called middleware) into a single method call. Also see http://rack.rubyforge.org.}
12
12
  s.email = %q{chneukirchen@gmail.com}
13
13
  s.executables = ["rackup"]
14
14
  s.extra_rdoc_files = ["README", "SPEC", "RDOX", "KNOWN-ISSUES"]
15
- s.files = ["COPYING", "KNOWN-ISSUES", "README", "Rakefile", "bin/rackup", "contrib/rack_logo.svg", "example/lobster.ru", "example/protectedlobster.rb", "example/protectedlobster.ru", "lib/rack.rb", "lib/rack/adapter/camping.rb", "lib/rack/auth/abstract/handler.rb", "lib/rack/auth/abstract/request.rb", "lib/rack/auth/basic.rb", "lib/rack/auth/digest/md5.rb", "lib/rack/auth/digest/nonce.rb", "lib/rack/auth/digest/params.rb", "lib/rack/auth/digest/request.rb", "lib/rack/auth/openid.rb", "lib/rack/builder.rb", "lib/rack/cascade.rb", "lib/rack/chunked.rb", "lib/rack/commonlogger.rb", "lib/rack/conditionalget.rb", "lib/rack/content_length.rb", "lib/rack/content_type.rb", "lib/rack/deflater.rb", "lib/rack/directory.rb", "lib/rack/file.rb", "lib/rack/handler.rb", "lib/rack/handler/cgi.rb", "lib/rack/handler/evented_mongrel.rb", "lib/rack/handler/fastcgi.rb", "lib/rack/handler/lsws.rb", "lib/rack/handler/mongrel.rb", "lib/rack/handler/scgi.rb", "lib/rack/handler/swiftiplied_mongrel.rb", "lib/rack/handler/thin.rb", "lib/rack/handler/webrick.rb", "lib/rack/head.rb", "lib/rack/lint.rb", "lib/rack/lobster.rb", "lib/rack/lock.rb", "lib/rack/methodoverride.rb", "lib/rack/mime.rb", "lib/rack/mock.rb", "lib/rack/recursive.rb", "lib/rack/reloader.rb", "lib/rack/request.rb", "lib/rack/response.rb", "lib/rack/rewindable_input.rb", "lib/rack/session/abstract/id.rb", "lib/rack/session/cookie.rb", "lib/rack/session/memcache.rb", "lib/rack/session/pool.rb", "lib/rack/showexceptions.rb", "lib/rack/showstatus.rb", "lib/rack/static.rb", "lib/rack/urlmap.rb", "lib/rack/utils.rb", "test/cgi/lighttpd.conf", "test/cgi/test", "test/cgi/test.fcgi", "test/cgi/test.ru", "test/multipart/binary", "test/multipart/empty", "test/multipart/ie", "test/multipart/nested", "test/multipart/none", "test/multipart/text", "test/spec_rack_auth_basic.rb", "test/spec_rack_auth_digest.rb", "test/spec_rack_auth_openid.rb", "test/spec_rack_builder.rb", "test/spec_rack_camping.rb", "test/spec_rack_cascade.rb", "test/spec_rack_cgi.rb", "test/spec_rack_chunked.rb", "test/spec_rack_commonlogger.rb", "test/spec_rack_conditionalget.rb", "test/spec_rack_content_length.rb", "test/spec_rack_content_type.rb", "test/spec_rack_deflater.rb", "test/spec_rack_directory.rb", "test/spec_rack_fastcgi.rb", "test/spec_rack_file.rb", "test/spec_rack_handler.rb", "test/spec_rack_head.rb", "test/spec_rack_lint.rb", "test/spec_rack_lobster.rb", "test/spec_rack_lock.rb", "test/spec_rack_methodoverride.rb", "test/spec_rack_mock.rb", "test/spec_rack_mongrel.rb", "test/spec_rack_recursive.rb", "test/spec_rack_request.rb", "test/spec_rack_response.rb", "test/spec_rack_rewindable_input.rb", "test/spec_rack_session_cookie.rb", "test/spec_rack_session_memcache.rb", "test/spec_rack_session_pool.rb", "test/spec_rack_showexceptions.rb", "test/spec_rack_showstatus.rb", "test/spec_rack_static.rb", "test/spec_rack_thin.rb", "test/spec_rack_urlmap.rb", "test/spec_rack_utils.rb", "test/spec_rack_webrick.rb", "test/testrequest.rb", "test/unregistered_handler/rack/handler/unregistered.rb", "test/unregistered_handler/rack/handler/unregistered_long_one.rb", "SPEC", "RDOX", "rack.gemspec"]
15
+ s.files = ["COPYING", "KNOWN-ISSUES", "README", "Rakefile", "bin/rackup", "contrib/rack_logo.svg", "example/lobster.ru", "example/protectedlobster.rb", "example/protectedlobster.ru", "lib/rack.rb", "lib/rack/adapter/camping.rb", "lib/rack/auth/abstract/handler.rb", "lib/rack/auth/abstract/request.rb", "lib/rack/auth/basic.rb", "lib/rack/auth/digest/md5.rb", "lib/rack/auth/digest/nonce.rb", "lib/rack/auth/digest/params.rb", "lib/rack/auth/digest/request.rb", "lib/rack/auth/openid.rb", "lib/rack/builder.rb", "lib/rack/cascade.rb", "lib/rack/chunked.rb", "lib/rack/commonlogger.rb", "lib/rack/conditionalget.rb", "lib/rack/content_length.rb", "lib/rack/content_type.rb", "lib/rack/deflater.rb", "lib/rack/directory.rb", "lib/rack/file.rb", "lib/rack/handler.rb", "lib/rack/handler/cgi.rb", "lib/rack/handler/evented_mongrel.rb", "lib/rack/handler/fastcgi.rb", "lib/rack/handler/lsws.rb", "lib/rack/handler/mongrel.rb", "lib/rack/handler/scgi.rb", "lib/rack/handler/swiftiplied_mongrel.rb", "lib/rack/handler/thin.rb", "lib/rack/handler/webrick.rb", "lib/rack/head.rb", "lib/rack/lint.rb", "lib/rack/lobster.rb", "lib/rack/lock.rb", "lib/rack/methodoverride.rb", "lib/rack/mime.rb", "lib/rack/mock.rb", "lib/rack/recursive.rb", "lib/rack/reloader.rb", "lib/rack/request.rb", "lib/rack/response.rb", "lib/rack/rewindable_input.rb", "lib/rack/session/abstract/id.rb", "lib/rack/session/cookie.rb", "lib/rack/session/memcache.rb", "lib/rack/session/pool.rb", "lib/rack/showexceptions.rb", "lib/rack/showstatus.rb", "lib/rack/static.rb", "lib/rack/urlmap.rb", "lib/rack/utils.rb", "test/cgi/lighttpd.conf", "test/cgi/test", "test/cgi/test.fcgi", "test/cgi/test.ru", "test/multipart/binary", "test/multipart/empty", "test/multipart/ie", "test/multipart/nested", "test/multipart/none", "test/multipart/semicolon", "test/multipart/text", "test/spec_rack_auth_basic.rb", "test/spec_rack_auth_digest.rb", "test/spec_rack_auth_openid.rb", "test/spec_rack_builder.rb", "test/spec_rack_camping.rb", "test/spec_rack_cascade.rb", "test/spec_rack_cgi.rb", "test/spec_rack_chunked.rb", "test/spec_rack_commonlogger.rb", "test/spec_rack_conditionalget.rb", "test/spec_rack_content_length.rb", "test/spec_rack_content_type.rb", "test/spec_rack_deflater.rb", "test/spec_rack_directory.rb", "test/spec_rack_fastcgi.rb", "test/spec_rack_file.rb", "test/spec_rack_handler.rb", "test/spec_rack_head.rb", "test/spec_rack_lint.rb", "test/spec_rack_lobster.rb", "test/spec_rack_lock.rb", "test/spec_rack_methodoverride.rb", "test/spec_rack_mock.rb", "test/spec_rack_mongrel.rb", "test/spec_rack_recursive.rb", "test/spec_rack_request.rb", "test/spec_rack_response.rb", "test/spec_rack_rewindable_input.rb", "test/spec_rack_session_cookie.rb", "test/spec_rack_session_memcache.rb", "test/spec_rack_session_pool.rb", "test/spec_rack_showexceptions.rb", "test/spec_rack_showstatus.rb", "test/spec_rack_static.rb", "test/spec_rack_thin.rb", "test/spec_rack_urlmap.rb", "test/spec_rack_utils.rb", "test/spec_rack_webrick.rb", "test/testrequest.rb", "test/unregistered_handler/rack/handler/unregistered.rb", "test/unregistered_handler/rack/handler/unregistered_long_one.rb", "SPEC", "RDOX", "rack.gemspec"]
16
16
  s.has_rdoc = true
17
17
  s.homepage = %q{http://rack.rubyforge.org}
18
18
  s.require_paths = ["lib"]
@@ -0,0 +1,6 @@
1
+ --AaB03x
2
+ Content-Disposition: form-data; name="files"; filename="fi;le1.txt"
3
+ Content-Type: text/plain
4
+
5
+ contents
6
+ --AaB03x--
@@ -36,7 +36,7 @@ context "Rack::Handler::CGI" do
36
36
 
37
37
  specify "should have rack headers" do
38
38
  GET("/test")
39
- response["rack.version"].should.equal [0,1]
39
+ response["rack.version"].should.equal [1,0]
40
40
  response["rack.multithread"].should.be false
41
41
  response["rack.multiprocess"].should.be true
42
42
  response["rack.run_once"].should.be true
@@ -36,7 +36,7 @@ context "Rack::Handler::FastCGI" do
36
36
 
37
37
  specify "should have rack headers" do
38
38
  GET("/test.fcgi")
39
- response["rack.version"].should.equal [0,1]
39
+ response["rack.version"].should.equal [1,0]
40
40
  response["rack.multithread"].should.be false
41
41
  response["rack.multiprocess"].should.be true
42
42
  response["rack.run_once"].should.be false
@@ -110,6 +110,28 @@ context "Rack::Lint" do
110
110
  Rack::Lint.new(nil).call(env("rack.input" => ""))
111
111
  }.should.raise(Rack::Lint::LintError).
112
112
  message.should.match(/does not respond to #gets/)
113
+
114
+ lambda {
115
+ input = Object.new
116
+ def input.binmode?
117
+ false
118
+ end
119
+ Rack::Lint.new(nil).call(env("rack.input" => input))
120
+ }.should.raise(Rack::Lint::LintError).
121
+ message.should.match(/is not opened in binary mode/)
122
+
123
+ lambda {
124
+ input = Object.new
125
+ def input.external_encoding
126
+ result = Object.new
127
+ def result.name
128
+ "US-ASCII"
129
+ end
130
+ result
131
+ end
132
+ Rack::Lint.new(nil).call(env("rack.input" => input))
133
+ }.should.raise(Rack::Lint::LintError).
134
+ message.should.match(/does not have ASCII-8BIT as its external encoding/)
113
135
  end
114
136
 
115
137
  specify "notices error errors" do
@@ -130,7 +130,7 @@ context "Rack::MockResponse" do
130
130
  res.original_headers["Content-Type"].should.equal "text/yaml"
131
131
  res["Content-Type"].should.equal "text/yaml"
132
132
  res.content_type.should.equal "text/yaml"
133
- res.content_length.should.be 464 # needs change often.
133
+ res.content_length.should.be 401 # needs change often.
134
134
  res.location.should.be.nil
135
135
  end
136
136
 
@@ -41,7 +41,7 @@ context "Rack::Handler::Mongrel" do
41
41
 
42
42
  specify "should have rack headers" do
43
43
  GET("/test")
44
- response["rack.version"].should.equal [0,1]
44
+ response["rack.version"].should.equal [1,0]
45
45
  response["rack.multithread"].should.be true
46
46
  response["rack.multiprocess"].should.be false
47
47
  response["rack.run_once"].should.be false
@@ -37,6 +37,11 @@ context "Rack::Request" do
37
37
  req = Rack::Request.new \
38
38
  Rack::MockRequest.env_for("/", "SERVER_NAME" => "example.org:9292")
39
39
  req.host.should.equal "example.org"
40
+
41
+ env = Rack::MockRequest.env_for("/")
42
+ env.delete("SERVER_NAME")
43
+ req = Rack::Request.new(env)
44
+ req.host.should.equal ""
40
45
  end
41
46
 
42
47
  specify "can parse the query string" do
@@ -467,22 +472,6 @@ EOF
467
472
  res.body.should.equal '212.212.212.212'
468
473
  end
469
474
 
470
- specify "memoizes itself to reduce the cost of repetitive initialization" do
471
- env = Rack::MockRequest.env_for("http://example.com:8080/")
472
- env['rack.request'].should.be.nil
473
-
474
- req1 = Rack::Request.new(env)
475
- env['rack.request'].should.not.be.nil
476
- req1.should.equal env['rack.request']
477
-
478
- rack_request_object_id = env['rack.request'].object_id
479
-
480
- req2 = Rack::Request.new(env)
481
- env['rack.request'].should.not.be.nil
482
- rack_request_object_id.should.be.equal env['rack.request'].object_id
483
- req2.should.equal env['rack.request']
484
- end
485
-
486
475
  class MyRequest < Rack::Request
487
476
  def params
488
477
  {:foo => "bar"}
@@ -12,6 +12,15 @@ context "Rack::Utils" do
12
12
  should.equal "q1%212%22%27w%245%267%2Fz8%29%3F%5C"
13
13
  end
14
14
 
15
+ specify "should escape correctly for multibyte characters" do
16
+ matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
17
+ matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
18
+ Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
19
+ matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
20
+ matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
21
+ Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
22
+ end
23
+
15
24
  specify "should unescape correctly" do
16
25
  Rack::Utils.unescape("fo%3Co%3Ebar").should.equal "fo<o>bar"
17
26
  Rack::Utils.unescape("a+space").should.equal "a space"
@@ -28,6 +37,7 @@ context "Rack::Utils" do
28
37
  should.equal "foo" => "1", "bar" => "2"
29
38
  Rack::Utils.parse_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
30
39
  should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
40
+ Rack::Utils.parse_query("foo%3Dbaz=bar").should.equal "foo=baz" => "bar"
31
41
  end
32
42
 
33
43
  specify "should parse nested query strings correctly" do
@@ -180,6 +190,30 @@ context "Rack::Utils::HeaderHash" do
180
190
  h = Rack::Utils::HeaderHash.new("foo" => ["bar", "baz"])
181
191
  h.to_hash.should.equal({ "foo" => "bar\nbaz" })
182
192
  end
193
+
194
+ specify "should be able to delete the given key case-sensitively" do
195
+ h = Rack::Utils::HeaderHash.new("foo" => "bar")
196
+ h.delete("foo")
197
+ h["foo"].should.be.nil
198
+ h["FOO"].should.be.nil
199
+ end
200
+
201
+ specify "should be able to delete the given key case-insensitively" do
202
+ h = Rack::Utils::HeaderHash.new("foo" => "bar")
203
+ h.delete("FOO")
204
+ h["foo"].should.be.nil
205
+ h["FOO"].should.be.nil
206
+ end
207
+
208
+ specify "should return the deleted value when #delete is called on an existing key" do
209
+ h = Rack::Utils::HeaderHash.new("foo" => "bar")
210
+ h.delete("Foo").should.equal("bar")
211
+ end
212
+
213
+ specify "should return nil when #delete is called on a non-existant key" do
214
+ h = Rack::Utils::HeaderHash.new("foo" => "bar")
215
+ h.delete("Hello").should.be.nil
216
+ end
183
217
  end
184
218
 
185
219
  context "Rack::Utils::Context" do
@@ -295,6 +329,18 @@ context "Rack::Utils::Multipart" do
295
329
  params["files"][:tempfile].read.should.equal ""
296
330
  end
297
331
 
332
+ specify "should parse multipart upload with filename with semicolons" do
333
+ env = Rack::MockRequest.env_for("/", multipart_fixture(:semicolon))
334
+ params = Rack::Utils::Multipart.parse_multipart(env)
335
+ params["files"][:type].should.equal "text/plain"
336
+ params["files"][:filename].should.equal "fi;le1.txt"
337
+ params["files"][:head].should.equal "Content-Disposition: form-data; " +
338
+ "name=\"files\"; filename=\"fi;le1.txt\"\r\n" +
339
+ "Content-Type: text/plain\r\n"
340
+ params["files"][:name].should.equal "files"
341
+ params["files"][:tempfile].read.should.equal "contents"
342
+ end
343
+
298
344
  specify "should not include file params if no file was selected" do
299
345
  env = Rack::MockRequest.env_for("/", multipart_fixture(:none))
300
346
  params = Rack::Utils::Multipart.parse_multipart(env)
@@ -39,7 +39,7 @@ context "Rack::Handler::WEBrick" do
39
39
 
40
40
  specify "should have rack headers" do
41
41
  GET("/test")
42
- response["rack.version"].should.equal [0,1]
42
+ response["rack.version"].should.equal [1,0]
43
43
  response["rack.multithread"].should.be true
44
44
  response["rack.multiprocess"].should.be false
45
45
  response["rack.run_once"].should.be false
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christian Neukirchen
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-25 00:00:00 +02:00
12
+ date: 2009-10-18 00:00:00 +02:00
13
13
  default_executable: rackup
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -163,6 +163,7 @@ files:
163
163
  - test/multipart/ie
164
164
  - test/multipart/nested
165
165
  - test/multipart/none
166
+ - test/multipart/semicolon
166
167
  - test/multipart/text
167
168
  - test/spec_rack_auth_basic.rb
168
169
  - test/spec_rack_auth_digest.rb