Ticket #6782: tls.patch

File tls.patch, 5.6 KB (added by Andy Lutomirski, 7 years ago)

Partial fix

  • twisted/protocols/tls.py

     
    3737
    3838from __future__ import division, absolute_import
    3939
    40 from OpenSSL.SSL import Error, ZeroReturnError, WantReadError
     40from OpenSSL.SSL import Error, ZeroReturnError, WantReadError, WantWriteError
    4141from OpenSSL.SSL import TLSv1_METHOD, Context, Connection
    4242
    4343try:
     
    316316        # Now that we ourselves have a transport (initialized by the
    317317        # ProtocolWrapper.makeConnection call above), kick off the TLS
    318318        # handshake.
    319         try:
    320             self._tlsConnection.do_handshake()
    321         except WantReadError:
    322             # This is the expected case - there's no data in the connection's
    323             # input buffer yet, so it won't be able to complete the whole
    324             # handshake now.  If this is the speak-first side of the
    325             # connection, then some bytes will be in the send buffer now; flush
    326             # them.
    327             self._flushSendBIO()
     319        self.__tryHandshake()
    328320
    329321
     322    def __tryHandshake(self):
     323        """
     324        Attempts to handshake.  OpenSSL wants us to keep trying to
     325        handshake until either it works or fails (as opposed to needing
     326        to do I/O).
     327        """
     328        while True:
     329            try:
     330                self._tlsConnection.do_handshake()
     331            except WantReadError:
     332                self._flushSendBIO()  # do_handshake may have queued up a send
     333                return
     334            except WantWriteError:
     335                self._flushSendBIO()
     336                # And try again immediately
     337            except Error as e:
     338                self._handshakeDone = True
     339                self._tlsShutdownFinished(Failure())
     340                return
     341            else:
     342                self._handshakeDone = True
     343                return
     344
     345
    330346    def _flushSendBIO(self):
    331347        """
    332348        Read any bytes out of the send BIO and write them to the underlying
     
    336352            bytes = self._tlsConnection.bio_read(2 ** 15)
    337353        except WantReadError:
    338354            # There may be nothing in the send BIO right now.
    339             pass
    340         else:
    341             self.transport.write(bytes)
     355            return
    342356
     357        self.transport.write(bytes)
     358        # XXX: This could unblock a recv call, so we should call
     359        # self._tlsConnection.recv.  It should also probably loop.
     360        # (The OpenSSL BIO interface sucks.)
    343361
     362
    344363    def _flushReceiveBIO(self):
    345364        """
    346365        Try to receive any application-level bytes which are now available
     
    358377                bytes = self._tlsConnection.recv(2 ** 15)
    359378            except WantReadError:
    360379                # The newly received bytes might not have been enough to produce
    361                 # any application data.
     380                # any application data or finish a handshake.
    362381                break
    363382            except ZeroReturnError:
    364383                # TLS has shut down and no more TLS data will be received over
     
    368387                # will get called with reason from underlying transport:
    369388                self._tlsShutdownFinished(None)
    370389            except Error as e:
    371                 # Something went pretty wrong.  For example, this might be a
    372                 # handshake failure (because there were no shared ciphers, because
    373                 # a certificate failed to verify, etc).  TLS can no longer proceed.
    374 
    375                 # Squash EOF in violation of protocol into ConnectionLost; we
    376                 # create Failure before calling _flushSendBio so that no new
    377                 # exception will get thrown in the interim.
     390                # Something went pretty wrong.  Squash EOF in violation of
     391                # protocol into ConnectionLost; we create Failure before calling
     392                # _flushSendBio so that no new exception will get thrown in the
     393                # interim.
    378394                if e.args[0] == -1 and e.args[1] == 'Unexpected EOF':
    379395                    failure = Failure(CONNECTION_LOST)
    380396                else:
     
    383399                self._flushSendBIO()
    384400                self._tlsShutdownFinished(failure)
    385401            else:
    386                 # If we got application bytes, the handshake must be done by
    387                 # now.  Keep track of this to control error reporting later.
    388                 self._handshakeDone = True
    389402                ProtocolWrapper.dataReceived(self, bytes)
    390403
    391404        # The received bytes might have generated a response which needs to be
    392         # sent now.  For example, the handshake involves several round-trip
    393         # exchanges without ever producing application-bytes.
     405        # sent now.  This is most likely to occur during renegotiation.
    394406        self._flushSendBIO()
    395407
    396408
     
    402414        """
    403415        self._tlsConnection.bio_write(bytes)
    404416
     417        if not self._handshakeDone:
     418            self.__tryHandshake()
     419
    405420        if self._writeBlockedOnRead:
    406421            # A read just happened, so we might not be blocked anymore.  Try to
    407422            # flush all the pending application bytes.
  • twisted/web/topfiles/6768.feature

     
     1twisted.web.proxy.ProxyClient (and all of its users in twisted.web.proxy) will now close HTTP connections that they initiate if the incoming connection to the proxy dies before receiving a response.
     2 No newline at end of file