rack 1.3.0 → 1.3.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.

@@ -337,6 +337,21 @@ run on port 11211) and memcache-client installed.
337
337
  * Cookies respect renew
338
338
  * Session middleware uses SecureRandom.hex
339
339
 
340
+ * May 22nd, 2011: Fourteenth public release 1.2.3
341
+ * Pulled in relevant bug fixes from 1.3
342
+ * Fixed 1.8.6 support
343
+
344
+ * July 13, 2011: Fifteenth public release 1.3.1
345
+ * Fix 1.9.1 support
346
+ * Fix JRuby support
347
+ * Properly handle $KCODE in Rack::Utils.escape
348
+ * Make method_missing/respond_to behavior consistent for Rack::Lock,
349
+ Rack::Auth::Digest::Request and Rack::Multipart::UploadedFile
350
+ * Reenable passing rack.session to session middleware
351
+ * Rack::CommonLogger handles streaming responses correctly
352
+ * Rack::MockResponse calls close on the body object
353
+ * Fix a DOS vector from MRI stdlib backport
354
+
340
355
  == Contact
341
356
 
342
357
  Please post bugs, suggestions and patches to
@@ -361,6 +376,8 @@ The Rack Core Team, consisting of
361
376
  * Michael Fellinger (manveru)
362
377
  * Ryan Tomayko (rtomayko)
363
378
  * Scytrin dai Kinthra (scytrin)
379
+ * Aaron Patterson (tenderlove)
380
+ * Konstantin Haase (rkh)
364
381
 
365
382
  would like to thank:
366
383
 
data/Rakefile CHANGED
@@ -86,9 +86,9 @@ end
86
86
 
87
87
  desc "Generate RDoc documentation"
88
88
  task :rdoc => ["SPEC"] do
89
- sh(*%w{rdoc --line-numbers --main README
89
+ sh(*%w{rdoc --line-numbers --main README.rdoc
90
90
  --title 'Rack\ Documentation' --charset utf-8 -U -o doc} +
91
- %w{README KNOWN-ISSUES SPEC} +
91
+ %w{README.rdoc KNOWN-ISSUES SPEC} +
92
92
  Dir["lib/**/*.rb"])
93
93
  end
94
94
 
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" encoding="UTF-8" standalone="no"?>
2
- <!-- Created with Inkscape (http://www.inkscape.org/)
2
+ <!-- Created with Inkscape (http://www.inkscape.org/)
3
3
  by Armin Ronacher (mitsuhiko), MIT-licensed.
4
4
  -->
5
5
  <svg
@@ -24,6 +24,7 @@ module Rack
24
24
  end
25
25
 
26
26
  autoload :Builder, "rack/builder"
27
+ autoload :BodyProxy, "rack/body_proxy"
27
28
  autoload :Cascade, "rack/cascade"
28
29
  autoload :Chunked, "rack/chunked"
29
30
  autoload :CommonLogger, "rack/commonlogger"
@@ -24,7 +24,7 @@ module Rack
24
24
  def initialize(app, realm=nil, opaque=nil, &authenticator)
25
25
  @passwords_hashed = nil
26
26
  if opaque.nil? and realm.respond_to? :values_at
27
- realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed
27
+ realm, opaque, @passwords_hashed = realm.values_at :realm, :opaque, :passwords_hashed
28
28
  end
29
29
  super(app, realm, &authenticator)
30
30
  @opaque = opaque
@@ -6,7 +6,6 @@ module Rack
6
6
  module Auth
7
7
  module Digest
8
8
  class Request < Auth::AbstractRequest
9
-
10
9
  def method
11
10
  @env['rack.methodoverride.original_method'] || @env['REQUEST_METHOD']
12
11
  end
@@ -27,13 +26,15 @@ module Rack
27
26
  @params ||= Params.parse(parts.last)
28
27
  end
29
28
 
30
- def method_missing(sym)
31
- if params.has_key? key = sym.to_s
32
- return params[key]
33
- end
34
- super
29
+ def respond_to?(sym, *)
30
+ super or params.has_key? sym.to_s
35
31
  end
36
32
 
33
+ def method_missing(sym, *args)
34
+ return super unless params.has_key?(key = sym.to_s)
35
+ return params[key] if args.size == 0
36
+ raise ArgumentError, "wrong number of arguments (#{args.size} for 0)"
37
+ end
37
38
  end
38
39
  end
39
40
  end
@@ -20,20 +20,26 @@ module URI
20
20
  #
21
21
  # See URI.decode_www_form_component, URI.encode_www_form
22
22
  def self.encode_www_form_component(str)
23
- if TBLENCWWWCOMP_.empty?
24
- tbl = {}
25
- 256.times do |i|
26
- tbl[i.chr] = '%%%02X' % i
27
- end
28
- tbl[' '] = '+'
29
- begin
30
- TBLENCWWWCOMP_.replace(tbl)
31
- TBLENCWWWCOMP_.freeze
32
- rescue
23
+ if RUBY_VERSION < "1.9" && $KCODE =~ /u/i
24
+ str.gsub(/([^ a-zA-Z0-9_.-]+)/) do
25
+ '%' + $1.unpack('H2' * Rack::Utils.bytesize($1)).join('%').upcase
26
+ end.tr(' ', '+')
27
+ else
28
+ if TBLENCWWWCOMP_.empty?
29
+ tbl = {}
30
+ 256.times do |i|
31
+ tbl[i.chr] = '%%%02X' % i
32
+ end
33
+ tbl[' '] = '+'
34
+ begin
35
+ TBLENCWWWCOMP_.replace(tbl)
36
+ TBLENCWWWCOMP_.freeze
37
+ rescue
38
+ end
33
39
  end
40
+ str = str.to_s
41
+ str.gsub(/[^*\-.0-9A-Z_a-z]/) {|m| TBLENCWWWCOMP_[m]}
34
42
  end
35
- str = str.to_s
36
- str.gsub(/[^*\-.0-9A-Z_a-z]/) {|m| TBLENCWWWCOMP_[m]}
37
43
  end
38
44
 
39
45
  # Decode given +str+ of URL-encoded form data.
@@ -58,7 +64,7 @@ module URI
58
64
  rescue
59
65
  end
60
66
  end
61
- raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%[0-9a-fA-F]{2}|[^%]+)*\z/ =~ str
67
+ raise ArgumentError, "invalid %-encoding (#{str})" unless /\A(?:%[0-9a-fA-F]{2}|[^%])*\z/ =~ str
62
68
  str.gsub(/\+|%[0-9a-fA-F]{2}/) {|m| TBLDECWWWCOMP_[m]}
63
69
  end
64
70
  end
@@ -0,0 +1,29 @@
1
+ module Rack
2
+ class BodyProxy
3
+ def initialize(body, &block)
4
+ @body, @block, @closed = body, block, false
5
+ end
6
+
7
+ def respond_to?(*args)
8
+ super or @body.respond_to?(*args)
9
+ end
10
+
11
+ def close
12
+ raise IOError, "closed stream" if @closed
13
+ begin
14
+ @body.close if @body.respond_to? :close
15
+ ensure
16
+ @block.call
17
+ @closed = true
18
+ end
19
+ end
20
+
21
+ def closed?
22
+ @closed
23
+ end
24
+
25
+ def method_missing(*args, &block)
26
+ @body.__send__(*args, &block)
27
+ end
28
+ end
29
+ end
@@ -113,7 +113,7 @@ module Rack
113
113
  # end
114
114
  # end
115
115
  #
116
- # This example includes a piece of middleware which will run before requests hit +Heartbeat+.
116
+ # This example includes a piece of middleware which will run before requests hit +Heartbeat+.
117
117
  #
118
118
  def map(path, &block)
119
119
  if @ins.last.kind_of? Hash
@@ -1,3 +1,5 @@
1
+ require 'rack/body_proxy'
2
+
1
3
  module Rack
2
4
  # Rack::CommonLogger forwards every request to an +app+ given, and
3
5
  # logs a line in the Apache common log format to the +logger+, or
@@ -17,7 +19,7 @@ module Rack
17
19
  began_at = Time.now
18
20
  status, header, body = @app.call(env)
19
21
  header = Utils::HeaderHash.new(header)
20
- log(env, status, header, began_at)
22
+ body = BodyProxy.new(body) { log(env, status, header, began_at) }
21
23
  [status, header, body]
22
24
  end
23
25
 
@@ -9,7 +9,7 @@ module Rack
9
9
  #
10
10
  # On initialization, you can pass two parameters: a Cache-Control directive
11
11
  # used when Etag is absent and a directive when it is present. The first
12
- # defaults to nil, while the second defaults to "max-age=0, privaute, must-revalidate"
12
+ # defaults to nil, while the second defaults to "max-age=0, private, must-revalidate"
13
13
  class ETag
14
14
  DEFAULT_CACHE_CONTROL = "max-age=0, private, must-revalidate".freeze
15
15
 
@@ -28,7 +28,8 @@ module Rack
28
28
  end
29
29
 
30
30
  unless headers['Cache-Control']
31
- headers['Cache-Control'] = digest ? @cache_control : @no_cache_control
31
+ headers['Cache-Control'] =
32
+ (digest ? @cache_control : @no_cache_control) || []
32
33
  end
33
34
 
34
35
  [status, headers, body]
@@ -28,7 +28,7 @@ module Rack
28
28
  serve request, app
29
29
  }
30
30
  end
31
-
31
+
32
32
  def self.valid_options
33
33
  {
34
34
  "Host=HOST" => "Hostname to listen on (default: localhost)",
@@ -15,7 +15,7 @@ module Rack
15
15
  :port=>options[:Port],
16
16
  :socket=>options[:Socket])).listen
17
17
  end
18
-
18
+
19
19
  def self.valid_options
20
20
  {
21
21
  "Host=HOST" => "Hostname to listen on (default: localhost)",
@@ -12,7 +12,7 @@ module Rack
12
12
  yield @server if block_given?
13
13
  @server.start
14
14
  end
15
-
15
+
16
16
  def self.valid_options
17
17
  {
18
18
  "Host=HOST" => "Hostname to listen on (default: localhost)",
@@ -1,27 +1,8 @@
1
1
  require 'thread'
2
+ require 'rack/body_proxy'
2
3
 
3
4
  module Rack
4
5
  class Lock
5
- class Proxy < Struct.new(:target, :mutex) # :nodoc:
6
- def each
7
- target.each { |x| yield x }
8
- end
9
-
10
- def close
11
- target.close if target.respond_to?(:close)
12
- ensure
13
- mutex.unlock
14
- end
15
-
16
- def to_path
17
- target.to_path
18
- end
19
-
20
- def respond_to?(sym)
21
- sym.to_sym == :close || target.respond_to?(sym)
22
- end
23
- end
24
-
25
6
  FLAG = 'rack.multithread'.freeze
26
7
 
27
8
  def initialize(app, mutex = Mutex.new)
@@ -32,7 +13,7 @@ module Rack
32
13
  old, env[FLAG] = env[FLAG], false
33
14
  @mutex.lock
34
15
  response = @app.call(env)
35
- response[2] = Proxy.new(response[2], @mutex)
16
+ response[2] = BodyProxy.new(response[2]) { @mutex.unlock }
36
17
  response
37
18
  rescue Exception
38
19
  @mutex.unlock
@@ -68,7 +68,10 @@ module Rack
68
68
  end
69
69
 
70
70
  errors = env["rack.errors"]
71
- MockResponse.new(*(app.call(env) + [errors]))
71
+ status, headers, body = app.call(env)
72
+ MockResponse.new(status, headers, body, errors)
73
+ ensure
74
+ body.close if body.respond_to?(:close)
72
75
  end
73
76
 
74
77
  # Return the Rack environment used for a request to +uri+.
@@ -68,7 +68,7 @@ module Rack
68
68
  h
69
69
  end
70
70
  end
71
-
71
+
72
72
  def content_for_tempfile(io, file, name)
73
73
  <<-EOF
74
74
  --#{MULTIPART_BOUNDARY}\r
@@ -15,7 +15,7 @@ module Rack
15
15
  fast_forward_to_first_boundary
16
16
 
17
17
  loop do
18
- head, filename, content_type, name, body =
18
+ head, filename, content_type, name, body =
19
19
  get_current_head_and_filename_and_content_type_and_name_and_body
20
20
 
21
21
  # Save the rest.
@@ -22,6 +22,10 @@ module Rack
22
22
  end
23
23
  alias_method :local_path, :path
24
24
 
25
+ def respond_to?(*args)
26
+ super or @tempfile.respond_to?(*args)
27
+ end
28
+
25
29
  def method_missing(method_name, *args, &block) #:nodoc:
26
30
  @tempfile.__send__(method_name, *args, &block)
27
31
  end
@@ -47,10 +47,9 @@ module Rack
47
47
  # }
48
48
  #
49
49
  # Note that the X-Sendfile-Type header must be set exactly as shown above. The
50
- # X-Accel-Mapping header should specify the by the location on the file system,
51
- # followed by an equals sign (=), followed name of the private URL pattern
52
- # that it maps to. The middleware performs a simple substitution on the
53
- # resulting path.
50
+ # X-Accel-Mapping header should specify the internal URI path, followed by an
51
+ # equals sign (=), followed name of the location in the file system that it maps
52
+ # to. The middleware performs a simple substitution on the resulting path.
54
53
  #
55
54
  # See Also: http://wiki.codemongers.com/NginxXSendfile
56
55
  #
@@ -47,11 +47,11 @@ module Rack
47
47
  opts.on("-p", "--port PORT", "use PORT (default: 9292)") { |port|
48
48
  options[:Port] = port
49
49
  }
50
-
50
+
51
51
  opts.on("-O", "--option NAME[=VALUE]", "pass VALUE to the server as option NAME. If no VALUE, sets it to true. Run '#{$0} -s SERVER -h' to get a list of options for SERVER") { |name|
52
52
  name, value = name.split('=', 2)
53
53
  value = true if value.nil?
54
- options[name.to_sym] = value
54
+ options[name.to_sym] = value
55
55
  }
56
56
 
57
57
  opts.on("-E", "--env ENVIRONMENT", "use ENVIRONMENT for defaults (default: development)") { |e|
@@ -72,7 +72,7 @@ module Rack
72
72
  opts.on_tail("-h", "-?", "--help", "Show this message") do
73
73
  puts opts
74
74
  puts handler_opts(options)
75
-
75
+
76
76
  exit
77
77
  end
78
78
 
@@ -92,7 +92,7 @@ module Rack
92
92
  options[:config] = args.last if args.last
93
93
  options
94
94
  end
95
-
95
+
96
96
  def handler_opts(options)
97
97
  begin
98
98
  info = []
@@ -100,7 +100,7 @@ module Rack
100
100
  if server && server.respond_to?(:valid_options)
101
101
  info << ""
102
102
  info << "Server-specific options for #{server.name}:"
103
-
103
+
104
104
  has_options = false
105
105
  server.valid_options.each do |name, description|
106
106
  next if name.to_s.match(/^(Host|Port)[^a-zA-Z]/) # ignore handler's host and port options, we do our own.
@@ -214,7 +214,7 @@ module Rack
214
214
  else
215
215
  "%0#{@sid_length}x" % Kernel.rand(2**@sidbits - 1)
216
216
  end
217
- rescue NotImpelentedError
217
+ rescue NotImplementedError
218
218
  generate_sid(false)
219
219
  end
220
220
 
@@ -222,8 +222,10 @@ module Rack
222
222
  # metadata into 'rack.session.options'.
223
223
 
224
224
  def prepare_session(env)
225
- env[ENV_SESSION_KEY] = SessionHash.new(self, env)
225
+ session_was = env[ENV_SESSION_KEY]
226
+ env[ENV_SESSION_KEY] = SessionHash.new(self, env)
226
227
  env[ENV_SESSION_OPTIONS_KEY] = OptionsHash.new(self, env, @default_options)
228
+ env[ENV_SESSION_KEY].merge! session_was if session_was
227
229
  end
228
230
 
229
231
  # Extracts the session id from provided cookies and passes it and the
@@ -1,12 +1,12 @@
1
1
  # -*- encoding: binary -*-
2
-
3
2
  require 'fileutils'
4
3
  require 'set'
5
4
  require 'tempfile'
6
-
7
5
  require 'rack/multipart'
8
6
 
9
- if RUBY_VERSION[/^\d+\.\d+/] == '1.8'
7
+ major, minor, patch = RUBY_VERSION.split('.').map { |v| v.to_i }
8
+
9
+ if (major == 1 && minor < 9) || (major == 1 && minor == 9 && patch < 2)
10
10
  # pull in backports
11
11
  require 'rack/backports/uri/common'
12
12
  else
@@ -351,9 +351,9 @@ module Rack
351
351
  end
352
352
 
353
353
  def to_hash
354
- Hash[*map do |k, v|
355
- [k, v.respond_to?(:to_ary) ? v.to_ary.join("\n") : v]
356
- end.flatten]
354
+ hash = {}
355
+ each { |k,v| hash[k] = v }
356
+ hash
357
357
  end
358
358
 
359
359
  def [](k)
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "rack"
3
- s.version = "1.3.0"
3
+ s.version = "1.3.1"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.summary = "a modular Ruby webserver interface"
6
6
 
@@ -15,11 +15,11 @@ Also see http://rack.rubyforge.org.
15
15
  EOF
16
16
 
17
17
  s.files = Dir['{bin/*,contrib/*,example/*,lib/**/*,test/**/*}'] +
18
- %w(COPYING KNOWN-ISSUES rack.gemspec Rakefile README SPEC)
18
+ %w(COPYING KNOWN-ISSUES rack.gemspec Rakefile README.rdoc SPEC)
19
19
  s.bindir = 'bin'
20
20
  s.executables << 'rackup'
21
21
  s.require_path = 'lib'
22
- s.extra_rdoc_files = ['README', 'KNOWN-ISSUES']
22
+ s.extra_rdoc_files = ['README.rdoc', 'KNOWN-ISSUES']
23
23
  s.test_files = Dir['test/spec_*.rb']
24
24
 
25
25
  s.author = 'Christian Neukirchen'
@@ -0,0 +1,43 @@
1
+ require 'rack/body_proxy'
2
+
3
+ describe Rack::BodyProxy do
4
+ should 'call each on the wrapped body' do
5
+ called = false
6
+ proxy = Rack::BodyProxy.new(['foo']) { }
7
+ proxy.each do |str|
8
+ called = true
9
+ str.should.equal 'foo'
10
+ end
11
+ called.should.equal true
12
+ end
13
+
14
+ should 'call close on the wrapped body' do
15
+ body = StringIO.new
16
+ proxy = Rack::BodyProxy.new(body) { }
17
+ proxy.close
18
+ body.should.be.closed
19
+ end
20
+
21
+ should 'only call close on the wrapped body if it responds to close' do
22
+ body = []
23
+ proxy = Rack::BodyProxy.new(body) { }
24
+ proc { proxy.close }.should.not.raise
25
+ end
26
+
27
+ should 'call the passed block on close' do
28
+ called = false
29
+ proxy = Rack::BodyProxy.new([]) { called = true }
30
+ called.should.equal false
31
+ proxy.close
32
+ called.should.equal true
33
+ end
34
+
35
+ should 'not close more than one time' do
36
+ count = 0
37
+ proxy = Rack::BodyProxy.new([]) { count += 1; raise "Block invoked more than 1 time!" if count > 1 }
38
+ proxy.close
39
+ lambda {
40
+ proxy.close
41
+ }.should.raise(IOError)
42
+ end
43
+ end
@@ -1,5 +1,6 @@
1
1
  require 'yaml'
2
2
  require 'rack/mock'
3
+ require 'stringio'
3
4
 
4
5
  app = lambda { |env|
5
6
  req = Rack::Request.new(env)
@@ -183,6 +184,15 @@ describe Rack::MockRequest do
183
184
  get("https://bla.example.org:9292/meh/foo?bar", :lint => true)
184
185
  }.should.not.raise(Rack::Lint::LintError)
185
186
  end
187
+
188
+ should "call close on the original body object" do
189
+ called = false
190
+ body = Rack::BodyProxy.new(['hi']) { called = true }
191
+ capp = proc { |e| [200, {'Content-Type' => 'text/plain '}, body] }
192
+ called.should.equal false
193
+ Rack::MockRequest.new(capp).get('/', :lint => true)
194
+ called.should.equal true
195
+ end
186
196
  end
187
197
 
188
198
  describe Rack::MockResponse do
@@ -233,6 +243,14 @@ describe Rack::MockResponse do
233
243
  res.errors.should.include "foo"
234
244
  end
235
245
 
246
+ should "allow calling body.close afterwards" do
247
+ # this is exactly what rack-test does
248
+ body = StringIO.new("hi")
249
+ res = Rack::MockResponse.new(200, {}, body)
250
+ body.close if body.respond_to?(:close)
251
+ res.body.should == 'hi'
252
+ end
253
+
236
254
  should "optionally make Rack errors fatal" do
237
255
  lambda {
238
256
  Rack::MockRequest.new(app).get("/?error=foo", :fatal => true)
@@ -1,5 +1,6 @@
1
1
  require 'set'
2
2
  require 'rack/response'
3
+ require 'stringio'
3
4
 
4
5
  describe Rack::Response do
5
6
  should "have sensible default values" do
@@ -243,4 +244,10 @@ describe Rack::Response do
243
244
  res.headers["Content-Length"].should.equal "8"
244
245
  end
245
246
 
247
+ it "calls close on #body" do
248
+ res = Rack::Response.new
249
+ res.body = StringIO.new
250
+ res.close
251
+ res.body.should.be.closed
252
+ end
246
253
  end
@@ -207,4 +207,10 @@ describe Rack::Session::Cookie do
207
207
  res = Rack::MockRequest.new(app).get("/")
208
208
  res.body.should.match(/Base64::Marshal/)
209
209
  end
210
+
211
+ it "allows passing in a hash with session data from middleware in front" do
212
+ app = Rack::Session::Cookie.new(session_id)
213
+ res = Rack::MockRequest.new(app).get("/", 'rack.session' => {:foo => 'bar'})
214
+ res.body.should.match(/foo/)
215
+ end
210
216
  end
@@ -1,5 +1,4 @@
1
1
  # -*- encoding: utf-8 -*-
2
-
3
2
  require 'rack/utils'
4
3
  require 'rack/mock'
5
4
 
@@ -20,6 +19,28 @@ describe Rack::Utils do
20
19
  Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
21
20
  end
22
21
 
22
+ if RUBY_VERSION[/^\d+\.\d+/] == '1.8'
23
+ should "escape correctly for multibyte characters if $KCODE is set to 'U'" do
24
+ default_kcode, $KCODE = $KCODE, 'U'
25
+
26
+ matz_name = "\xE3\x81\xBE\xE3\x81\xA4\xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsumoto
27
+ matz_name.force_encoding("UTF-8") if matz_name.respond_to? :force_encoding
28
+ Rack::Utils.escape(matz_name).should.equal '%E3%81%BE%E3%81%A4%E3%82%82%E3%81%A8'
29
+ matz_name_sep = "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0] # Matsu moto
30
+ matz_name_sep.force_encoding("UTF-8") if matz_name_sep.respond_to? :force_encoding
31
+ Rack::Utils.escape(matz_name_sep).should.equal '%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8'
32
+
33
+ $KCODE = default_kcode
34
+ end
35
+
36
+ should "unescape multibyte characters correctly if $KCODE is set to 'U'" do
37
+ default_kcode, $KCODE = $KCODE, 'U'
38
+ Rack::Utils.unescape('%E3%81%BE%E3%81%A4+%E3%82%82%E3%81%A8').should.equal(
39
+ "\xE3\x81\xBE\xE3\x81\xA4 \xE3\x82\x82\xE3\x81\xA8".unpack("a*")[0])
40
+ $KCODE = default_kcode
41
+ end
42
+ end
43
+
23
44
  if "".respond_to?(:encode)
24
45
  should "escape non-UTF8 strings" do
25
46
  Rack::Utils.escape("ø".encode("ISO-8859-1")).should.equal "%F8"
@@ -76,7 +97,7 @@ describe Rack::Utils do
76
97
  should.equal "foo" => "bar", "baz" => ""
77
98
  Rack::Utils.parse_nested_query("my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F").
78
99
  should.equal "my weird field" => "q1!2\"'w$5&7/z8)?"
79
-
100
+
80
101
  Rack::Utils.parse_nested_query("a=b&pid%3D1234=1023").
81
102
  should.equal "pid=1234" => "1023", "a" => "b"
82
103
 
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rack
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 25
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 3
9
- - 0
10
- version: 1.3.0
9
+ - 1
10
+ version: 1.3.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Christian Neukirchen
@@ -15,8 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-05-22 00:00:00 -07:00
19
- default_executable:
18
+ date: 2011-07-13 00:00:00 Z
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
22
21
  name: bacon
@@ -117,7 +116,7 @@ executables:
117
116
  extensions: []
118
117
 
119
118
  extra_rdoc_files:
120
- - README
119
+ - README.rdoc
121
120
  - KNOWN-ISSUES
122
121
  files:
123
122
  - bin/rackup
@@ -133,6 +132,7 @@ files:
133
132
  - lib/rack/auth/digest/params.rb
134
133
  - lib/rack/auth/digest/request.rb
135
134
  - lib/rack/backports/uri/common.rb
135
+ - lib/rack/body_proxy.rb
136
136
  - lib/rack/builder.rb
137
137
  - lib/rack/cascade.rb
138
138
  - lib/rack/chunked.rb
@@ -219,6 +219,7 @@ files:
219
219
  - test/registering_handler/rack/handler/registering_myself.rb
220
220
  - test/spec_auth_basic.rb
221
221
  - test/spec_auth_digest.rb
222
+ - test/spec_body_proxy.rb
222
223
  - test/spec_builder.rb
223
224
  - test/spec_cascade.rb
224
225
  - test/spec_cgi.rb
@@ -269,9 +270,8 @@ files:
269
270
  - KNOWN-ISSUES
270
271
  - rack.gemspec
271
272
  - Rakefile
272
- - README
273
+ - README.rdoc
273
274
  - SPEC
274
- has_rdoc: true
275
275
  homepage: http://rack.rubyforge.org
276
276
  licenses: []
277
277
 
@@ -301,13 +301,14 @@ required_rubygems_version: !ruby/object:Gem::Requirement
301
301
  requirements: []
302
302
 
303
303
  rubyforge_project: rack
304
- rubygems_version: 1.5.2
304
+ rubygems_version: 1.8.5
305
305
  signing_key:
306
306
  specification_version: 3
307
307
  summary: a modular Ruby webserver interface
308
308
  test_files:
309
309
  - test/spec_auth_basic.rb
310
310
  - test/spec_auth_digest.rb
311
+ - test/spec_body_proxy.rb
311
312
  - test/spec_builder.rb
312
313
  - test/spec_cascade.rb
313
314
  - test/spec_cgi.rb