diff options
-rw-r--r-- | Rakefile | 2 | ||||
-rw-r--r-- | SPEC.rdoc | 22 |
2 files changed, 23 insertions, 1 deletions
@@ -78,7 +78,7 @@ file 'lib/rack/lint.rb' file "SPEC.rdoc" => 'lib/rack/lint.rb' do File.open("SPEC.rdoc", "wb") { |file| IO.foreach("lib/rack/lint.rb") { |line| - if line =~ /## (.*)/ + if line =~ /^\s*## ?(.*)/ file.puts $1 end } @@ -1,5 +1,6 @@ This specification aims to formalize the Rack protocol. You can (and should) use Rack::Lint to enforce it. + When you develop middleware, be sure to add a Lint before and after to catch all mistakes. = Rack applications @@ -14,6 +15,7 @@ and the *body*. The environment must be an unfrozen instance of Hash that includes CGI-like headers. The application is free to modify the environment. + The environment is required to include these variables (adopted from PEP333), except when they'd be empty, but see below. @@ -119,6 +121,7 @@ environment, too. The keys must contain at least one dot, and should be prefixed uniquely. The prefix <tt>rack.</tt> is reserved for use with the Rack core distribution and other accepted specifications and must not be used otherwise. + The environment must not contain the keys <tt>HTTP_CONTENT_TYPE</tt> or <tt>HTTP_CONTENT_LENGTH</tt> (use the versions without <tt>HTTP_</tt>). @@ -140,6 +143,7 @@ There are the following restrictions: <tt>SCRIPT_NAME</tt> is empty. <tt>SCRIPT_NAME</tt> never should be <tt>/</tt>, but instead be empty. === The Input Stream + The input stream is an IO-like object which contains the raw HTTP POST data. When applicable, its external encoding must be "ASCII-8BIT" and it @@ -149,14 +153,19 @@ The input stream must respond to +gets+, +each+, +read+ and +rewind+. or +nil+ on EOF. * +read+ behaves like IO#read. Its signature is <tt>read([length, [buffer]])</tt>. + If given, +length+ must be a non-negative Integer (>= 0) or +nil+, and +buffer+ must be a String and may not be nil. + If +length+ is given and not nil, then this method reads at most +length+ bytes from the input stream. + If +length+ is not given or nil, then this method reads all data until EOF. + When EOF is reached, this method returns nil if +length+ is given and not nil, or "" if +length+ is not given or is nil. + If +buffer+ is given, then the read data will be placed into +buffer+ instead of a newly created String object. * +each+ must be called without arguments and only yield Strings. @@ -178,16 +187,20 @@ The error stream must respond to +puts+, +write+ and +flush+. If rack.hijack? is true then rack.hijack must respond to #call. rack.hijack must return the io that will also be assigned (or is already present, in rack.hijack_io. + rack.hijack_io must respond to: <tt>read, write, read_nonblock, write_nonblock, flush, close, close_read, close_write, closed?</tt> + The semantics of these IO methods must be a best effort match to those of a normal ruby IO or Socket object, using standard arguments and raising standard exceptions. Servers are encouraged to simply pass on real IO objects, although it is recognized that this approach is not directly compatible with SPDY and HTTP 2.0. + IO provided in rack.hijack_io should preference the IO::WaitReadable and IO::WaitWritable APIs wherever supported. + There is a deliberate lack of full specification around rack.hijack_io, as semantics will change from server to server. Users are encouraged to utilize this API with a knowledge of their @@ -195,7 +208,9 @@ server choice, and servers may extend the functionality of hijack_io to provide additional features to users. The purpose of rack.hijack is for Rack to "get out of the way", as such, Rack only provides the minimum of specification and support. + If rack.hijack? is false, then rack.hijack should not be set. + If rack.hijack? is false, then rack.hijack_io should not be set. ==== Response (after headers) It is also possible to hijack a response after the status and headers @@ -204,6 +219,7 @@ In order to do this, an application may set the special header <tt>rack.hijack</tt> to an object that responds to <tt>call</tt> accepting an argument that conforms to the <tt>rack.hijack_io</tt> protocol. + After the headers have been sent, and this hijack callback has been called, the application is now responsible for the remaining lifecycle of the IO. The application is also responsible for maintaining HTTP @@ -212,8 +228,10 @@ applications will have wanted to specify the header Connection:close in HTTP/1.1, and not Connection:keep-alive, as there is no protocol for returning hijacked sockets to the web server. For that purpose, use the body streaming API instead (progressively yielding strings via each). + Servers must ignore the <tt>body</tt> part of the response tuple when the <tt>rack.hijack</tt> response API is in use. + The special response header <tt>rack.hijack</tt> must only be set if the request env has <tt>rack.hijack?</tt> <tt>true</tt>. ==== Conventions @@ -247,16 +265,20 @@ There must not be a <tt>Content-Length</tt> header when the === The Body The Body must respond to +each+ and must only yield String values. + The Body itself should not be an instance of String, as this will break in Ruby 1.9. + If the Body responds to +close+, it will be called after iteration. If the body is replaced by a middleware after action, the original body must be closed first, if it responds to close. + If the Body responds to +to_path+, it must return a String identifying the location of a file whose contents are identical to that produced by calling +each+; this may be used by the server as an alternative, possibly more efficient way to transport the response. + The Body commonly is an Array of Strings, the application instance itself, or a File-like object. == Thanks |