celluloid/reel — pull request #73 by adstage-david (2013-07-26 01:09:44+00:00)
Title: Pipelining Fix/Refactoring

Did some refactoring and made it so the request parser can handle pipelining. This closes #69 and #55 and makes #56 obsolete.

All of the specs pass, and I've run most of the examples and they all seem to work as well as they do on master (Rackup handler examples seem to be broken on master?)

Cleanup Changes:

* `Reel::Connection` delegates all of its work to `Reel::Request::Parser` (for socket reads) and Reel::Response::Writer (for socket writes).
* All reads/writes still go through the connection object, which makes sure the connection is in the proper state for the action and raises a `Reel::Connection::StateError` if not. No other objects know the parser/writer exist.
* `Reel::Request` and `Reel::Websocket` no longer require a direct link to the request parser - they are initialized with a Reel::RequestInfo object that includes the parsed request headers, url, method, http_version.
* `Reel::Response::Writer` knows how to render proper HTTP responses, but will send the socket to `Response#render` if that method exists (for the `StreamResponse` subclass) (there was a TODO about extracting this logic).

API Changes:

* `#read` can now only be called on the `Reel::Request`, not connection, since http_parser may accidentally consume bytes of multiple bodies, each `Reel::Request` keeps an internal buffer of bytes parsed but not yet pulled with #read. This buffer is read from before calling `@connection#readpartial`
* added `#<<` and `#write` to Reel::Request so you can call both `#read` and `#write` on the request itself.
* Removed #close from Reel::Request - since this should probably be called from the `Reel::Connection`.

Parser Details:

The `Reel::Request::Parser` maintains an internal buffer of incoming requests still reading (if body hasn't been read in yet), one currently awaiting response, and a queue of requests to be responded to after the current request is handled. The underlying http parser calls the callbacks on this class when bytes buffered to it add to headers or body.

`Reel::Request::Parser` has `#current_request`, which will return the current request being read/responded to, or block and read from the raw socket until a full set of headers has been discovered and the body is ready to read.