Permalink
Browse files

Update Rack specification: require rack.input to be rewindable.

  • Loading branch information...
1 parent 6dad8ac commit 8ff87d4a55cb7b9b5016e72b13aec647104c037a @FooBarWidget FooBarWidget committed Apr 14, 2009
Showing with 39 additions and 6 deletions.
  1. +19 −6 lib/rack/lint.rb
  2. +20 −0 test/spec_rack_lint.rb
View
@@ -206,8 +206,8 @@ def check_env(env)
## The input stream is an IO-like object which contains the raw HTTP
## POST data. If it is a file then it must be opened in binary mode.
def check_input(input)
- ## The input stream must respond to +gets+, +each+ and +read+.
- [:gets, :each, :read].each { |method|
+ ## The input stream must respond to +gets+, +each+, +read+ and +rewind+.
+ [:gets, :each, :read, :rewind].each { |method|
assert("rack.input #{input} does not respond to ##{method}") {
input.respond_to? method
}
@@ -225,10 +225,6 @@ def size
@input.size
end
- def rewind
- @input.rewind
- end
-
## * +gets+ must be called without arguments and return a string,
## or +nil+ on EOF.
def gets(*args)
@@ -268,6 +264,23 @@ def each(*args)
yield line
}
end
+
+ ## * +rewind+ must be called without arguments. It rewinds the input
+ ## stream back to the beginning. It must not raise Errno::ESPIPE:
+ ## that is, it may not be a pipe or a socket. Therefore, handler
+ ## developers must buffer the input data into some rewindable object
+ ## if the underlying input stream is not rewindable.
+ def rewind(*args)
+ assert("rack.input#rewind called with arguments") { args.size == 0 }
+ assert("rack.input#rewind raised Errno::ESPIPE") {
+ begin
+ @input.rewind
+ true
+ rescue Errno::ESPIPE
+ false
+ end
+ }
+ end
## * +close+ must never be called on the input stream.
def close(*args)
View
@@ -266,6 +266,14 @@ def env(*args)
}.should.raise(Rack::Lint::LintError).
message.should.match(/read called with non-integer argument/)
+ lambda {
+ Rack::Lint.new(lambda { |env|
+ env["rack.input"].rewind(0)
+ [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
+ }).call(env({}))
+ }.should.raise(Rack::Lint::LintError).
+ message.should.match(/rewind called with arguments/)
+
weirdio = Object.new
class << weirdio
def gets
@@ -280,6 +288,10 @@ def each
yield 23
yield 42
end
+
+ def rewind
+ raise Errno::ESPIPE, "Errno::ESPIPE"
+ end
end
lambda {
@@ -306,6 +318,14 @@ def each
}.should.raise(Rack::Lint::LintError).
message.should.match(/read didn't return a String/)
+ lambda {
+ Rack::Lint.new(lambda { |env|
+ env["rack.input"].rewind
+ [201, {"Content-type" => "text/plain", "Content-length" => "0"}, []]
+ }).call(env("rack.input" => weirdio))
+ }.should.raise(Rack::Lint::LintError).
+ message.should.match(/rewind raised Errno::ESPIPE/)
+
lambda {
Rack::Lint.new(lambda { |env|

0 comments on commit 8ff87d4

Please sign in to comment.