pocoproject / poco

The POCO C++ Libraries are powerful cross-platform C++ libraries for building network- and internet-based applications that run on desktop, server, mobile, IoT, and embedded systems.
https://pocoproject.org
Other
8.4k stars 2.16k forks source link

HTTPServerResponse flushes its stream too late #337

Closed madmaxoft closed 10 years ago

madmaxoft commented 10 years ago

In our HTTP server application we need to commit changes to the DB only after we are sure that the client has received data. There is currently no way to do this - the server sends the last chunk of data in the HTTPServerRequest destructor and there's no way to attach a callback to be called after this destructor is called.

We'd like to use code similar to the following:

class CRequestHandler :
    public Poco::Net::HTTPRequestHandler
{
    virtual void handleRequest(HTTPServerRequest & request, HTTPServerResponse & response) override
    {
        // Read DB, create a response based on the DB
        response.sendBuffer(...);
        // Commit the changes in the DB
        //  ... but the response hasn't been fully sent yet!
    }
} ;

Since HTTPServerResponse::sendBuffer() assumes that no further sending will occur for the response, our situation would be solved easily if it flushed the underlying stream as its last operation, or at least if the function returned the stream object so that it could be flushed manually by our code.

jmansion commented 10 years ago

On 27/11/2013 13:16, Mattes D wrote:

In our HTTP server application we need to commit changes to the DB only after we are sure that the client has received data. There is currently no way to do this - the server sends the last chunk of data in the HTTPServerRequest destructor and there's no way to attach a callback to be called after this destructor is called.

Flushing the buffer doesn't tell you that the client received the data either - the only way you can know that is to receive a positive acknowledgement back from it.

madmaxoft commented 10 years ago

I believe flushing the stream does that - since it will send the data over the socket, which will fail if the socket aborts. Isn't that the whole point of using TCP?

jmansion commented 10 years ago

On 27/11/2013 20:59, Mattes D wrote:

I believe flushing the stream does that - since it will send the data over the socket, which will fail if the socket aborts. Isn't that the whole point of using TCP?

— Reply to this email directly or view it on GitHub https://github.com/pocoproject/poco/issues/337#issuecomment-29419641.

No, flushing the stream does not do that. Flushing will queue the data to be sent. It tells you nothing about whether the peer receives it.
There is buffering in your host's network buffers, on the card, in switches and routers, and in the peer's host.

TCP means that if you receive packet n from the stack, then you also already received packet n-1, and that you got all of it/them (after reassembly).

madmaxoft commented 10 years ago

Then we need the possibility to wait for the connection close confirmation, somehow.

obiltschnig commented 10 years ago

There's no good way to implement this behavior with the current design. You could try to obtain the underlying socket and call shutdownSend() on it, but only if you're not using chunked transfer encoding.