diff options
Diffstat (limited to 'Lib/httplib.py')
-rw-r--r-- | Lib/httplib.py | 216 |
1 files changed, 21 insertions, 195 deletions
diff --git a/Lib/httplib.py b/Lib/httplib.py index 9887540..a6ac4e3 100644 --- a/Lib/httplib.py +++ b/Lib/httplib.py @@ -72,7 +72,7 @@ import mimetools import socket from urlparse import urlsplit -__all__ = ["HTTPResponse", "HTTPConnection", "HTTPSConnection", +__all__ = ["HTTPResponse", "HTTPConnection", "HTTPException", "NotConnected", "UnknownProtocol", "UnknownTransferEncoding", "UnimplementedFileMode", "IncompleteRead", "InvalidURL", "ImproperConnectionState", @@ -964,207 +964,33 @@ class HTTPConnection: return response -# The next several classes are used to define FakeSocket, a socket-like -# interface to an SSL connection. - -# The primary complexity comes from faking a makefile() method. The -# standard socket makefile() implementation calls dup() on the socket -# file descriptor. As a consequence, clients can call close() on the -# parent socket and its makefile children in any order. The underlying -# socket isn't closed until they are all closed. - -# The implementation uses reference counting to keep the socket open -# until the last client calls close(). SharedSocket keeps track of -# the reference counting and SharedSocketClient provides an constructor -# and close() method that call incref() and decref() correctly. - -class SharedSocket: - - def __init__(self, sock): - self.sock = sock - self._refcnt = 0 - - def incref(self): - self._refcnt += 1 - - def decref(self): - self._refcnt -= 1 - assert self._refcnt >= 0 - if self._refcnt == 0: - self.sock.close() - - def __del__(self): - self.sock.close() - -class SharedSocketClient: - - def __init__(self, shared): - self._closed = 0 - self._shared = shared - self._shared.incref() - self._sock = shared.sock - - def close(self): - if not self._closed: - self._shared.decref() - self._closed = 1 - self._shared = None - -class SSLFile(SharedSocketClient): - """File-like object wrapping an SSL socket.""" - - BUFSIZE = 8192 - - def __init__(self, sock, ssl, bufsize=None): - SharedSocketClient.__init__(self, sock) - self._ssl = ssl - self._buf = b"" - self._bufsize = bufsize or self.__class__.BUFSIZE - - def _read(self): - buf = b"" - # put in a loop so that we retry on transient errors - while True: - try: - buf = self._ssl.read(self._bufsize) - except socket.sslerror as err: - err_type = err.args[0] - if (err_type == socket.SSL_ERROR_WANT_READ - or err_type == socket.SSL_ERROR_WANT_WRITE): - continue - if (err_type == socket.SSL_ERROR_ZERO_RETURN - or err_type == socket.SSL_ERROR_EOF): - break - raise - except socket.error as err: - err_type = err.args[0] - if err_type == errno.EINTR: - continue - if err_type == errno.EBADF: - # XXX socket was closed? - break - raise - else: - break - return buf - - def read(self, size=None): - L = [self._buf] - avail = len(self._buf) - while size is None or avail < size: - s = self._read() - if s == b"": - break - L.append(s) - avail += len(s) - all = b"".join(L) - if size is None: - self._buf = b"" - return all - else: - self._buf = all[size:] - return all[:size] - - def readline(self): - L = [self._buf] - self._buf = b"" - while 1: - i = L[-1].find("\n") - if i >= 0: - break - s = self._read() - if s == b"": - break - L.append(s) - if i == -1: - # loop exited because there is no more data - return b"".join(L) - else: - all = b"".join(L) - # XXX could do enough bookkeeping not to do a 2nd search - i = all.find("\n") + 1 - line = all[:i] - self._buf = all[i:] - return line - - def readlines(self, sizehint=0): - total = 0 - list = [] - while True: - line = self.readline() - if not line: - break - list.append(line) - total += len(line) - if sizehint and total >= sizehint: - break - return list - - def fileno(self): - return self._sock.fileno() - - def __iter__(self): - return self - - def __next__(self): - line = self.readline() - if not line: - raise StopIteration - return line - -class FakeSocket(SharedSocketClient): - - class _closedsocket: - def __getattr__(self, name): - raise error(9, 'Bad file descriptor') - - def __init__(self, sock, ssl): - sock = SharedSocket(sock) - SharedSocketClient.__init__(self, sock) - self._ssl = ssl - - def close(self): - SharedSocketClient.close(self) - self._sock = self.__class__._closedsocket() - - def makefile(self, mode, bufsize=None): - if mode != 'r' and mode != 'rb': - raise UnimplementedFileMode() - return SSLFile(self._shared, self._ssl, bufsize) - - def send(self, stuff, flags = 0): - return self._ssl.write(stuff) - - sendall = send - - def recv(self, len = 1024, flags = 0): - return self._ssl.read(len) - - def __getattr__(self, attr): - return getattr(self._sock, attr) +try: + import ssl +except ImportError: + pass +else: + class HTTPSConnection(HTTPConnection): + "This class allows communication via SSL." - def close(self): - SharedSocketClient.close(self) - self._ssl = None + default_port = HTTPS_PORT -class HTTPSConnection(HTTPConnection): - "This class allows communication via SSL." + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=None): + HTTPConnection.__init__(self, host, port, strict, timeout) + self.key_file = key_file + self.cert_file = cert_file - default_port = HTTPS_PORT + def connect(self): + "Connect to a host on a given (SSL) port." - def __init__(self, host, port=None, key_file=None, cert_file=None, - strict=None, timeout=None): - HTTPConnection.__init__(self, host, port, strict, timeout) - self.key_file = key_file - self.cert_file = cert_file + sock = socket.create_connection((self.host, self.port), self.timeout) + self.sock = ssl.sslsocket(sock, self.key_file, self.cert_file) - def connect(self): - "Connect to a host on a given (SSL) port." - sock = socket.create_connection((self.host, self.port), self.timeout) - ssl = socket.ssl(sock, self.key_file, self.cert_file) - self.sock = FakeSocket(sock, ssl) + def FakeSocket (sock, sslobj): + return sslobj + __all__.append("HTTPSConnection") class HTTPException(Exception): # Subclasses that define an __init__ must call Exception.__init__ |