supernovus/perl6-http-easy — Issue #1: recv() is not guaranteed to work the way it is used in this module
Author: bbkr
Created: 2012-01-28 01:20:29+00:00
State: open

# Problem

Handler may get random $.body content from following P5 client code.

```perl
use IO::Socket;
my $sock = IO::Socket::INET->new(PeerAddr=>"localhost",PeerPort=>8080,Proto=>"tcp") or die;
print $sock "POST / HTTP/1.0\\r\nContent-Length: 5r\n\r\n";
print $sock "Hello" ;
```

Sometimes $.body will be present, sometimes not - depending on race condition between client sending to socket and HTTP::Easy consuming from it. If recv() consumed headers before client send body then recv() won't see body and fetch it.

Try this on laggy network or put "sleep 1" before "Hello" is passed,

# Solution

Decompose request fetch

* socket.get() status line
* socket.get() headers, parse them on-the fly, stop on empty line
* how many bytes are left? easy to tell

RFC HTTP 1.0 says
The presence of an entity body in a
request is signaled by the inclusion of a Content-Length header field
in the request message headers. HTTP/1.0 requests containing an
entity body must include a valid Content-Length header field.

So easy deal here, just socket.read( $content_length ).decode() octets.

RFC HTTP 1.1 says
For compatibility with HTTP/1.0 applications, HTTP/1.1 requests containing
a message-body MUST include a valid Content-Length header field
unless the server is known to be HTTP/1.1 compliant.

And this one gets ugly in one case because

If a message is received with both a
Transfer-Encoding header field and a Content-Length header field,
the latter MUST be ignored.

Since implementing 1.1 toys such as chunked Transfer-Encoding is way beyond reasonable time I would suggest just to socket.recv in this ugly case (it won't be worse than it is now). In other cases precise amount of octets can be received as in HTTP 1.0.