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) |