Author cananian
Recipients cananian, mhammond
Date 2008-08-23.13:44:54
SpamBayes Score 7.98207e-06
Marked as misclassified No
Message-id <1219499098.65.0.96713473507.issue3566@psf.upfronthosting.co.za>
In-reply-to
Content
FWIW, the following code works around the issue for me:

class HTTPConnection(httplib.HTTPConnection):
    def request(self, method, url, body=None, headers={}):
        # patch upstream to recv() after we send, so that a closed
        # connection is discovered here rather than later in
        # HTTPResponse._read_status()
        try:
            self._send_request(method, url, body, headers)
            b = self.sock.recv(1, socket.MSG_PEEK)
            if b == '':
                self.close()
                raise socket.error(32) # sender closed connection.
        except socket.error, v:
            # trap 'Broken pipe' if we're allowed to automatically reconnect
            if v[0] != 32 or not self.auto_open:
                raise
            # try one more time
            self._send_request(method, url, body, headers)

In general, attempting to read a byte of the response just to trigger
the broken pipe error is suboptimal; it doesn't accurately distinguish
the "closed before received request" case from the "closed just after
received request" case.  For idempotent methods like GET and HEAD, this
doesn't matter, but it does for POST, etc.

There ought to be a better way to force the underlying OS to give you
the current 'closed' status on a socket which doesn't require your
trying to send/receive bytes.  The fundamental issue here is that the
TCP spec, and Linux, allow the request send to succeed even if TCP FIN
has been received from the other side -- the receipt of FIN after the
response is received is always going to be a race to some degree.

All of which is why the HTTP pipelining specs encourage you *not* to use
pipelining for non-idempotent requests.  The above patch could be
tweaked to only perform the MSG_PEEK and retry if this is the second or
later pipelined request.  Then, following the HTTP recommendations and
always calling HttpConnection.close()/HttpConnection.connect() before
invoking "unsafe" requests like POST, would make the whole thing safe.
History
Date User Action Args
2008-08-23 13:44:58cananiansetrecipients: + cananian, mhammond
2008-08-23 13:44:58cananiansetmessageid: <1219499098.65.0.96713473507.issue3566@psf.upfronthosting.co.za>
2008-08-23 13:44:57cananianlinkissue3566 messages
2008-08-23 13:44:55cananiancreate