GrahamDumpleton / mod_wsgi

Source code for Apache/mod_wsgi.
Apache License 2.0
1.03k stars 268 forks source link

Response chunking and daemon process crash or application exception. #42

Open GrahamDumpleton opened 10 years ago

GrahamDumpleton commented 10 years ago

If the daemon mode process crashes when yielding a chunked response by virtue of not setting a content length, or if either embedded or daemon mode is used and the WSGI application triggers an exception while yielding data, then the chunked response is being closed off with a final '0' chunk as if the response was complete rather than it leaving a hanging block with no '0' chunk.

This is possibly undesirable, but then it also isn't really known whether a client could even rely on absence of a '0' chunk to indicate that some sort of error occurred. This is because chunked transfer encoding is a hop by hop header and so a proxy can technically change the chunking due to buffering. It isn't known whether a proxy is required to preserve the absence of a '0' chunk so that a client is aware of it, or whether it is completely within its rights to add a '0' chunk with a subsequent loss of information.

Looking at the Apache HTTP proxy module it does try and ensure that not '0' chunk is added if the connection is broken:

        /* RFC 2616, Section 3.6.1
         *
         * If there is an EOS bucket, then prefix it with:
         *   1) the last-chunk marker ("0" CRLF)
         *   2) the trailer
         *   3) the end-of-chunked body CRLF
         *
         * We only do this if we have not seen an error bucket with
         * status HTTP_BAD_GATEWAY. We have memorized an
         * error bucket that we had seen in the filter context.
         * The error bucket with status HTTP_BAD_GATEWAY indicates that the
         * connection to the backend (mod_proxy) broke in the middle of the
         * response. In order to signal the client that something went wrong
         * we do not create the last-chunk marker and set c->keepalive to
         * AP_CONN_CLOSE in the core output filter.
         *
         * XXX: it would be nice to combine this with the end-of-chunk
         * marker above, but this is a bit more straight-forward for
         * now.
         */
        if (eos && !f->ctx) {
            /* XXX: (2) trailers ... does not yet exist */
            e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
                                           /* <trailers> */
                                           ASCII_CRLF, 5, c->bucket_alloc);
            APR_BUCKET_INSERT_BEFORE(eos, e);
        }

Other modules such as when proxying SCGI don't try and do this though and always add a EOS bucket after the bucket for the socket, meaning a client couldn't know if the connection was lost. For SCGI at least, this is because there is no chunking of data from SCGI process and so it couldn't know.

Right now have similar problem with responses from daemon mode as don't have any framing of data using chunked encoding or otherwise.

As to when an exception is raised, it looks like the EOS bucket will always be added automatically at the end of a request. The only thing one can appear to do is set r->eos_sent to true to fake out that EOS has already been sent. That should prevent automatic sending of EOS bucket and thus disable sending to '0' chunk if chunked transfer encoding on response.

GrahamDumpleton commented 9 years ago

This is fixed for embedded mode in 4.4.0. Still needs to be fixed for daemon, which is a lot more work.