| Index: third_party/requests/packages/urllib3/contrib/pyopenssl.py
|
| diff --git a/third_party/requests/packages/urllib3/contrib/pyopenssl.py b/third_party/requests/packages/urllib3/contrib/pyopenssl.py
|
| index 5c4c6d8d31052b88426dd83aaf50ccea33f51126..d43bcd60977e4bd8ee9b0a9ebff908893fbd0492 100644
|
| --- a/third_party/requests/packages/urllib3/contrib/pyopenssl.py
|
| +++ b/third_party/requests/packages/urllib3/contrib/pyopenssl.py
|
| @@ -20,13 +20,13 @@ Now you can use :mod:`urllib3` as you normally would, and it will support SNI
|
| when the required modules are installed.
|
| '''
|
|
|
| -from ndg.httpsclient.ssl_peer_verification import (ServerSSLCertVerification,
|
| - SUBJ_ALT_NAME_SUPPORT)
|
| +from ndg.httpsclient.ssl_peer_verification import SUBJ_ALT_NAME_SUPPORT
|
| from ndg.httpsclient.subj_alt_name import SubjectAltName
|
| import OpenSSL.SSL
|
| from pyasn1.codec.der import decoder as der_decoder
|
| from socket import _fileobject
|
| import ssl
|
| +from cStringIO import StringIO
|
|
|
| from .. import connectionpool
|
| from .. import util
|
| @@ -99,6 +99,172 @@ def get_subj_alt_name(peer_cert):
|
| return dns_name
|
|
|
|
|
| +class fileobject(_fileobject):
|
| +
|
| + def read(self, size=-1):
|
| + # Use max, disallow tiny reads in a loop as they are very inefficient.
|
| + # We never leave read() with any leftover data from a new recv() call
|
| + # in our internal buffer.
|
| + rbufsize = max(self._rbufsize, self.default_bufsize)
|
| + # Our use of StringIO rather than lists of string objects returned by
|
| + # recv() minimizes memory usage and fragmentation that occurs when
|
| + # rbufsize is large compared to the typical return value of recv().
|
| + buf = self._rbuf
|
| + buf.seek(0, 2) # seek end
|
| + if size < 0:
|
| + # Read until EOF
|
| + self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
|
| + while True:
|
| + try:
|
| + data = self._sock.recv(rbufsize)
|
| + except OpenSSL.SSL.WantReadError:
|
| + continue
|
| + if not data:
|
| + break
|
| + buf.write(data)
|
| + return buf.getvalue()
|
| + else:
|
| + # Read until size bytes or EOF seen, whichever comes first
|
| + buf_len = buf.tell()
|
| + if buf_len >= size:
|
| + # Already have size bytes in our buffer? Extract and return.
|
| + buf.seek(0)
|
| + rv = buf.read(size)
|
| + self._rbuf = StringIO()
|
| + self._rbuf.write(buf.read())
|
| + return rv
|
| +
|
| + self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
|
| + while True:
|
| + left = size - buf_len
|
| + # recv() will malloc the amount of memory given as its
|
| + # parameter even though it often returns much less data
|
| + # than that. The returned data string is short lived
|
| + # as we copy it into a StringIO and free it. This avoids
|
| + # fragmentation issues on many platforms.
|
| + try:
|
| + data = self._sock.recv(left)
|
| + except OpenSSL.SSL.WantReadError:
|
| + continue
|
| + if not data:
|
| + break
|
| + n = len(data)
|
| + if n == size and not buf_len:
|
| + # Shortcut. Avoid buffer data copies when:
|
| + # - We have no data in our buffer.
|
| + # AND
|
| + # - Our call to recv returned exactly the
|
| + # number of bytes we were asked to read.
|
| + return data
|
| + if n == left:
|
| + buf.write(data)
|
| + del data # explicit free
|
| + break
|
| + assert n <= left, "recv(%d) returned %d bytes" % (left, n)
|
| + buf.write(data)
|
| + buf_len += n
|
| + del data # explicit free
|
| + #assert buf_len == buf.tell()
|
| + return buf.getvalue()
|
| +
|
| + def readline(self, size=-1):
|
| + buf = self._rbuf
|
| + buf.seek(0, 2) # seek end
|
| + if buf.tell() > 0:
|
| + # check if we already have it in our buffer
|
| + buf.seek(0)
|
| + bline = buf.readline(size)
|
| + if bline.endswith('\n') or len(bline) == size:
|
| + self._rbuf = StringIO()
|
| + self._rbuf.write(buf.read())
|
| + return bline
|
| + del bline
|
| + if size < 0:
|
| + # Read until \n or EOF, whichever comes first
|
| + if self._rbufsize <= 1:
|
| + # Speed up unbuffered case
|
| + buf.seek(0)
|
| + buffers = [buf.read()]
|
| + self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
|
| + data = None
|
| + recv = self._sock.recv
|
| + while True:
|
| + try:
|
| + while data != "\n":
|
| + data = recv(1)
|
| + if not data:
|
| + break
|
| + buffers.append(data)
|
| + except OpenSSL.SSL.WantReadError:
|
| + continue
|
| + break
|
| + return "".join(buffers)
|
| +
|
| + buf.seek(0, 2) # seek end
|
| + self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
|
| + while True:
|
| + try:
|
| + data = self._sock.recv(self._rbufsize)
|
| + except OpenSSL.SSL.WantReadError:
|
| + continue
|
| + if not data:
|
| + break
|
| + nl = data.find('\n')
|
| + if nl >= 0:
|
| + nl += 1
|
| + buf.write(data[:nl])
|
| + self._rbuf.write(data[nl:])
|
| + del data
|
| + break
|
| + buf.write(data)
|
| + return buf.getvalue()
|
| + else:
|
| + # Read until size bytes or \n or EOF seen, whichever comes first
|
| + buf.seek(0, 2) # seek end
|
| + buf_len = buf.tell()
|
| + if buf_len >= size:
|
| + buf.seek(0)
|
| + rv = buf.read(size)
|
| + self._rbuf = StringIO()
|
| + self._rbuf.write(buf.read())
|
| + return rv
|
| + self._rbuf = StringIO() # reset _rbuf. we consume it via buf.
|
| + while True:
|
| + try:
|
| + data = self._sock.recv(self._rbufsize)
|
| + except OpenSSL.SSL.WantReadError:
|
| + continue
|
| + if not data:
|
| + break
|
| + left = size - buf_len
|
| + # did we just receive a newline?
|
| + nl = data.find('\n', 0, left)
|
| + if nl >= 0:
|
| + nl += 1
|
| + # save the excess data to _rbuf
|
| + self._rbuf.write(data[nl:])
|
| + if buf_len:
|
| + buf.write(data[:nl])
|
| + break
|
| + else:
|
| + # Shortcut. Avoid data copy through buf when returning
|
| + # a substring of our first recv().
|
| + return data[:nl]
|
| + n = len(data)
|
| + if n == size and not buf_len:
|
| + # Shortcut. Avoid data copy through buf when
|
| + # returning exactly all of our first recv().
|
| + return data
|
| + if n >= left:
|
| + buf.write(data[:left])
|
| + self._rbuf.write(data[left:])
|
| + break
|
| + buf.write(data)
|
| + buf_len += n
|
| + #assert buf_len == buf.tell()
|
| + return buf.getvalue()
|
| +
|
| +
|
| class WrappedSocket(object):
|
| '''API-compatibility wrapper for Python OpenSSL's Connection-class.'''
|
|
|
| @@ -106,8 +272,11 @@ class WrappedSocket(object):
|
| self.connection = connection
|
| self.socket = socket
|
|
|
| + def fileno(self):
|
| + return self.socket.fileno()
|
| +
|
| def makefile(self, mode, bufsize=-1):
|
| - return _fileobject(self.connection, mode, bufsize)
|
| + return fileobject(self.connection, mode, bufsize)
|
|
|
| def settimeout(self, timeout):
|
| return self.socket.settimeout(timeout)
|
| @@ -115,10 +284,14 @@ class WrappedSocket(object):
|
| def sendall(self, data):
|
| return self.connection.sendall(data)
|
|
|
| + def close(self):
|
| + return self.connection.shutdown()
|
| +
|
| def getpeercert(self, binary_form=False):
|
| x509 = self.connection.get_peer_certificate()
|
| +
|
| if not x509:
|
| - raise ssl.SSLError('')
|
| + return x509
|
|
|
| if binary_form:
|
| return OpenSSL.crypto.dump_certificate(
|
| @@ -159,9 +332,13 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
|
| cnx = OpenSSL.SSL.Connection(ctx, sock)
|
| cnx.set_tlsext_host_name(server_hostname)
|
| cnx.set_connect_state()
|
| - try:
|
| - cnx.do_handshake()
|
| - except OpenSSL.SSL.Error as e:
|
| - raise ssl.SSLError('bad handshake', e)
|
| + while True:
|
| + try:
|
| + cnx.do_handshake()
|
| + except OpenSSL.SSL.WantReadError:
|
| + continue
|
| + except OpenSSL.SSL.Error as e:
|
| + raise ssl.SSLError('bad handshake', e)
|
| + break
|
|
|
| return WrappedSocket(cnx, sock)
|
|
|