gevent.http.HTTPServer API suggests streaming, but instead buffers entire requests and responses
Question: The APIs offered by `gevent.http.HTTPServer` would seem to support streaming
in both directions. The request object does not offer the request body as a
simple string, but instead provides an `.input_buffer` attribute that is a
Python iterable, while in the other direction the data for a response can be
delivered as chunks with the three calls:

    
    
    request.send_reply_start(200, 'OK')
    request.send_reply_chunk(...)  # as many times as you wish
    request.send_reply_end()
    

But I must have something mis-configured, because despite this wonderfully
unbuffered API, my request handler is not getting called until the _last_
chunk of request POST data has finally arrived, and in the other direction I
am not seeing _any_ headers arrive on my client socket until the server
reaches `.send_reply_end()`. Is there some switch that I have to throw or some
configuration setting that I have to manipulate in order to turn off buffering
and see requests and send responses as they arrive, like gevent supports with
raw sockets through its `StreamServer`?

My application needs to supports single-file uploads and downloads that may be
bigger than RAM, which will require this buffering to be turned off.

Here are a simple server and client written with gevent that should show you
this behavior:

    
    
    # srv.py
    
    import gevent.http
    
    M100 = 100 * 1024 * 1024
    
    def main():
        print 'Serving on 8088...'
        gevent.http.HTTPServer(('0.0.0.0', 8088), handle).serve_forever()
    
    def handle(request):
        print 'Is request chunked?', request.chunked
        for item in request.input_buffer:
            print 'received body segment of length', len(item), 'bytes'
        request.add_output_header('Content-Type', 'application/octet-stream')
        request.send_reply_start(200, 'OK')
        for i in range(5):
            print 'sending chunk', i
            request.send_reply_chunk(M100 * 'x')
        request.send_reply_end()
    
    if __name__ == '__main__':
        main()
    

And:

    
    
    # cli.py
    
    import requests
    import time
    
    M100 = 100 * 1024 * 1024
    
    def gen():
        for i in range(5):
            print 'sending chunk', i
            yield M100 * 'x'
            time.sleep(1)
    
    if __name__ == '__main__':
        r = requests.post('http://localhost:8088/', data=gen(), stream=True)
        for block in r.iter_content(M100):
            print 'received', len(block), 'bytes from download'
    

Thanks for any guidance!


Answer: **Requests to the server:** Looking at the source code, it looks like the
server's handler function is not called until the request is complete,
regardless of whether or not it is sent in a chunked fashion. So you're out of
luck there.

**Server responses:** The server response can be sent in a streaming fashion,
but you need to voluntarily yield control in the handler thread for this to
work (e.g. by calling `gevent.sleep()` after each chunk).

Unfortunately, `gevent` does not seem to provide a way to wait for a given
chunk to finish sending before starting on the next chunk, so if you generate
data faster than it can be sent you may run into memory issues.

* * *

Note that the above information refers to `gevent<1.0`, which uses the
`libevent` library, and is not applicable to more recent versions of `gevent`.
The current version of `gevent` no longer includes an `http` module so the
question is moot.

