Repository: sanic-org/sanic

Issue:
Streaming Response Chunked Encoding Incomplete Read Error
The new `stream` method works with the [demo example](http://sanic.readthedocs.io/en/latest/sanic/streaming.html), but if I try to stream larger chunks of data (e.g. 10 bytes) I get a ChunkedEncodingError / broken connection / Incomplete Read on the client.

I confirmed this on both latest master 62ebcba64 and when the feature was introduced at 19592e8eea.

Here is a slightly modified test demo server to reproduce the problem:
```
from sanic import Sanic
from sanic.response import stream

app = Sanic(__name__)

@app.route("/")
async def test(request):
    async def sample_streaming_fn(response):
        response.write('foo,bat,baz,')
        response.write('bar')

    return stream(sample_streaming_fn, content_type='text/csv')

app.run(host="0.0.0.0", port=8000, workers=1)
```

Start this test server with:
```
$ docker run --rm -it -v `pwd`:/app -p 8000:8000 ubergarm/sanic-alpine /app/test.py
2017-04-04 17:27:49,501: INFO: Goin' Fast @ http://0.0.0.0:8000
2017-04-04 17:27:49,503: INFO: Starting worker [1]
```

Test with `curl`:
```
$ curl -v localhost:8000
* Rebuilt URL to: localhost:8000/
*   Trying ::1...
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Keep-Alive: 60
< Transfer-Encoding: chunked
< Content-Type: text/csv
<
foo,bat,baz,
3
* Malformed encoding found in chunked-encoding
* Closing connection 0
curl: (56) Malformed encoding found in chunked-encoding
```

Test with `httpie`:
```
$ http -v localhost:8000
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8000
User-Agent: HTTPie/0.9.4



HTTP/1.1 200 OK
Content-Type: text/csv
Keep-Alive: 60
Transfer-Encoding: chunked


http: error: ChunkedEncodingError: ('Connection broken: IncompleteRead(2 bytes read)', IncompleteRead(2 bytes read))
```
Streaming Response Chunked Encoding Incomplete Read Error
The new `stream` method works with the [demo example](http://sanic.readthedocs.io/en/latest/sanic/streaming.html), but if I try to stream larger chunks of data (e.g. 10 bytes) I get a ChunkedEncodingError / broken connection / Incomplete Read on the client.

I confirmed this on both latest master 62ebcba64 and when the feature was introduced at 19592e8eea.

Here is a slightly modified test demo server to reproduce the problem:
```
from sanic import Sanic
from sanic.response import stream

app = Sanic(__name__)

@app.route("/")
async def test(request):
    async def sample_streaming_fn(response):
        response.write('foo,bat,baz,')
        response.write('bar')

    return stream(sample_streaming_fn, content_type='text/csv')

app.run(host="0.0.0.0", port=8000, workers=1)
```

Start this test server with:
```
$ docker run --rm -it -v `pwd`:/app -p 8000:8000 ubergarm/sanic-alpine /app/test.py
2017-04-04 17:27:49,501: INFO: Goin' Fast @ http://0.0.0.0:8000
2017-04-04 17:27:49,503: INFO: Starting worker [1]
```

Test with `curl`:
```
$ curl -v localhost:8000
* Rebuilt URL to: localhost:8000/
*   Trying ::1...
* Connected to localhost (::1) port 8000 (#0)
> GET / HTTP/1.1
> Host: localhost:8000
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Keep-Alive: 60
< Transfer-Encoding: chunked
< Content-Type: text/csv
<
foo,bat,baz,
3
* Malformed encoding found in chunked-encoding
* Closing connection 0
curl: (56) Malformed encoding found in chunked-encoding
```

Test with `httpie`:
```
$ http -v localhost:8000
GET / HTTP/1.1
Accept: */*
Accept-Encoding: gzip, deflate
Connection: keep-alive
Host: localhost:8000
User-Agent: HTTPie/0.9.4



HTTP/1.1 200 OK
Content-Type: text/csv
Keep-Alive: 60
Transfer-Encoding: chunked


http: error: ChunkedEncodingError: ('Connection broken: IncompleteRead(2 bytes read)', IncompleteRead(2 bytes read))
```


Discussion:

Resolving patch:
diff --git a/sanic/response.py b/sanic/response.py
--- a/sanic/response.py
+++ b/sanic/response.py
@@ -129,7 +129,7 @@ def write(self, data):
             data = self._encode_body(data)
 
         self.transport.write(
-            b"%b\r\n%b\r\n" % (str(len(data)).encode(), data))
+            b"%x\r\n%b\r\n" % (len(data), data))
 
     async def stream(
             self, version="1.1", keep_alive=False, keep_alive_timeout=None):


Test patch: