Moved GreenSSLObject into eventlet.green.socket, cleaned up imports slightly, removed PyOpenSSL dependency -- it will warn you if you need to install it.

This commit is contained in:
Ryan Williams
2009-11-24 12:59:42 -05:00
parent 8e27d09a32
commit 5d72de3d03
6 changed files with 91 additions and 103 deletions

View File

@@ -9,10 +9,8 @@ except AttributeError:
pass pass
from eventlet.api import get_hub from eventlet.api import get_hub
from eventlet.util import wrap_ssl_obj
from eventlet.greenio import GreenSocket as socket from eventlet.greenio import GreenSocket as socket
from eventlet.greenio import GreenSSL as _GreenSSL from eventlet.greenio import SSL as _SSL
from eventlet.greenio import GreenSSLObject as _GreenSSLObject
def fromfd(*args): def fromfd(*args):
return socket(__socket.fromfd(*args)) return socket(__socket.fromfd(*args))
@@ -78,5 +76,73 @@ def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT):
raise error, msg raise error, msg
def ssl(sock, certificate=None, private_key=None): def _convert_to_sslerror(ex):
return wrap_ssl_obj(sock, certificate, private_key) """ Transliterates SSL.SysCallErrors to socket.sslerrors"""
return socket.sslerror((ex[0], ex[1]))
class GreenSSLObject(object):
""" Wrapper object around the SSLObjects returned by socket.ssl, which have a
slightly different interface from SSL.Connection objects. """
def __init__(self, green_ssl_obj):
""" Should only be called by a 'green' socket.ssl """
self.connection = green_ssl_obj
try:
# if it's already connected, do the handshake
self.connection.getpeername()
except:
pass
else:
try:
self.connection.do_handshake()
except _SSL.SysCallError, e:
raise _convert_to_sslerror(e)
def read(self, n=None):
"""If n is provided, read n bytes from the SSL connection, otherwise read
until EOF. The return value is a string of the bytes read."""
if n is None:
# don't support this until someone needs it
raise NotImplementedError("GreenSSLObject does not support "\
" unlimited reads until we hear of someone needing to use them.")
else:
try:
return self.connection.read(n)
except _SSL.ZeroReturnError:
return ''
except _SSL.SysCallError, e:
raise _convert_to_sslerror(e)
def write(self, s):
"""Writes the string s to the on the object's SSL connection.
The return value is the number of bytes written. """
try:
return self.connection.write(s)
except _SSL.SysCallError, e:
raise _convert_to_sslerror(e)
def server(self):
""" Returns a string describing the server's certificate. Useful for debugging
purposes; do not parse the content of this string because its format can't be
parsed unambiguously. """
return str(self.connection.get_peer_certificate().get_subject())
def issuer(self):
"""Returns a string describing the issuer of the server's certificate. Useful
for debugging purposes; do not parse the content of this string because its
format can't be parsed unambiguously."""
return str(self.connection.get_peer_certificate().get_issuer())
try:
from eventlet.green import ssl
def ssl(sock, certificate=None, private_key=None):
warnings.warn("socket.ssl() is deprecated. Use ssl.wrap_socket() instead.",
DeprecationWarning, stacklevel=2)
return ssl.sslwrap_simple(sock, keyfile, certfile)
except ImportError:
def ssl(sock, certificate=None, private_key=None):
from eventlet import util
wrapped = util.wrap_ssl(sock, certificate, private_key)
return GreenSSLObject(wrapped)

View File

@@ -8,7 +8,7 @@ import time
from eventlet.api import trampoline, getcurrent from eventlet.api import trampoline, getcurrent
from thread import get_ident from thread import get_ident
from eventlet.greenio import set_nonblocking, GreenSocket, GreenSSLObject, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS from eventlet.greenio import set_nonblocking, GreenSocket, SOCKET_CLOSED, CONNECT_ERR, CONNECT_SUCCESS
orig_socket = __import__('socket') orig_socket = __import__('socket')
socket = orig_socket.socket socket = orig_socket.socket
@@ -290,6 +290,7 @@ def sslwrap_simple(sock, keyfile=None, certfile=None):
"""A replacement for the old socket.ssl function. Designed """A replacement for the old socket.ssl function. Designed
for compability with Python 2.5 and earlier. Will disappear in for compability with Python 2.5 and earlier. Will disappear in
Python 3.0.""" Python 3.0."""
from eventlet.green.socket import GreenSSLObject
ssl_sock = GreenSSLSocket(sock, 0, keyfile, certfile, CERT_NONE, ssl_sock = GreenSSLSocket(sock, 0, keyfile, certfile, CERT_NONE,
PROTOCOL_SSLv23, None) PROTOCOL_SSLv23, None)
return GreenSSLObject(ssl_sock) return GreenSSLObject(ssl_sock)

View File

@@ -1,6 +1,4 @@
from eventlet.api import trampoline, get_hub from eventlet.api import trampoline, get_hub
from eventlet import util
BUFFER_SIZE = 4096 BUFFER_SIZE = 4096
@@ -712,67 +710,3 @@ def shutdown_safe(sock):
if e[0] != errno.ENOTCONN: if e[0] != errno.ENOTCONN:
raise raise
def _convert_to_sslerror(ex):
""" Transliterates SSL.SysCallErrors to socket.sslerrors"""
return socket.sslerror((ex[0], ex[1]))
class GreenSSLObject(object):
""" Wrapper object around the SSLObjects returned by socket.ssl, which have a
slightly different interface from SSL.Connection objects. """
def __init__(self, green_ssl_obj):
""" Should only be called by a 'green' socket.ssl """
try:
from eventlet.green.ssl import GreenSSLSocket
except ImportError:
class GreenSSLSocket(object):
pass
assert isinstance(green_ssl_obj, (GreenSSL, GreenSSLSocket))
self.connection = green_ssl_obj
try:
# if it's already connected, do the handshake
self.connection.getpeername()
except:
pass
else:
try:
self.connection.do_handshake()
except SSL.SysCallError, e:
raise _convert_to_sslerror(e)
def read(self, n=None):
"""If n is provided, read n bytes from the SSL connection, otherwise read
until EOF. The return value is a string of the bytes read."""
if n is None:
# don't support this until someone needs it
raise NotImplementedError("GreenSSLObject does not support "\
" unlimited reads until we hear of someone needing to use them.")
else:
try:
return self.connection.read(n)
except SSL.ZeroReturnError:
return ''
except SSL.SysCallError, e:
raise _convert_to_sslerror(e)
def write(self, s):
"""Writes the string s to the on the object's SSL connection.
The return value is the number of bytes written. """
try:
return self.connection.write(s)
except SSL.SysCallError, e:
raise _convert_to_sslerror(e)
def server(self):
""" Returns a string describing the server's certificate. Useful for debugging
purposes; do not parse the content of this string because its format can't be
parsed unambiguously. """
return str(self.connection.get_peer_certificate().get_subject())
def issuer(self):
"""Returns a string describing the issuer of the server's certificate. Useful
for debugging purposes; do not parse the content of this string because its
format can't be parsed unambiguously."""
return str(self.connection.get_peer_certificate().get_issuer())

View File

@@ -3,6 +3,8 @@ import select
import socket import socket
import errno import errno
from eventlet import greenio
def g_log(*args): def g_log(*args):
import sys import sys
from eventlet.support import greenlets as greenlet from eventlet.support import greenlets as greenlet
@@ -37,27 +39,21 @@ def tcp_socket():
try: try:
# if ssl is available, use eventlet.green.ssl for our ssl implementation # if ssl is available, use eventlet.green.ssl for our ssl implementation
import ssl as _ssl from eventlet.green import ssl
def wrap_ssl(sock, certificate=None, private_key=None, server_side=False): def wrap_ssl(sock, certificate=None, private_key=None, server_side=False):
from eventlet.green import ssl
return ssl.wrap_socket(sock, return ssl.wrap_socket(sock,
keyfile=private_key, certfile=certificate, keyfile=private_key, certfile=certificate,
server_side=server_side, cert_reqs=ssl.CERT_NONE, server_side=server_side, cert_reqs=ssl.CERT_NONE,
ssl_version=ssl.PROTOCOL_SSLv23, ca_certs=None, ssl_version=ssl.PROTOCOL_SSLv23, ca_certs=None,
do_handshake_on_connect=True, do_handshake_on_connect=True,
suppress_ragged_eofs=True) suppress_ragged_eofs=True)
def wrap_ssl_obj(sock, certificate=None, private_key=None):
from eventlet import ssl
warnings.warn("socket.ssl() is deprecated. Use ssl.wrap_socket() instead.",
DeprecationWarning, stacklevel=2)
return ssl.sslwrap_simple(sock, keyfile, certfile)
except ImportError: except ImportError:
# if ssl is not available, use PyOpenSSL # if ssl is not available, use PyOpenSSL
def wrap_ssl(sock, certificate=None, private_key=None, server_side=False): def wrap_ssl(sock, certificate=None, private_key=None, server_side=False):
from OpenSSL import SSL try:
from eventlet import greenio from OpenSSL import SSL
except ImportError:
raise ImportError("To use SSL with Eventlet, you must install PyOpenSSL or use Python 2.6 or later.")
context = SSL.Context(SSL.SSLv23_METHOD) context = SSL.Context(SSL.SSLv23_METHOD)
if certificate is not None: if certificate is not None:
context.use_certificate_file(certificate) context.use_certificate_file(certificate)
@@ -72,25 +68,15 @@ except ImportError:
connection.set_connect_state() connection.set_connect_state()
return greenio.GreenSSL(connection) return greenio.GreenSSL(connection)
def wrap_ssl_obj(sock, certificate=None, private_key=None):
""" For 100% compatibility with the socket module, this wraps and handshakes an
open connection, returning a SSLObject."""
from eventlet import greenio
wrapped = wrap_ssl(sock, certificate, private_key)
return greenio.GreenSSLObject(wrapped)
socket_already_wrapped = False socket_already_wrapped = False
def wrap_socket_with_coroutine_socket(use_thread_pool=True): def wrap_socket_with_coroutine_socket(use_thread_pool=True):
global socket_already_wrapped global socket_already_wrapped
if socket_already_wrapped: if socket_already_wrapped:
return return
def new_socket(*args, **kw): import eventlet.green.socket
from eventlet import greenio socket.socket = eventlet.green.socket.socket
return greenio.GreenSocket(__original_socket__(*args, **kw)) socket.ssl = eventlet.green.socket.ssl
socket.socket = new_socket
socket.ssl = wrap_ssl_obj
try: try:
import ssl as _ssl import ssl as _ssl
from eventlet.green import ssl from eventlet.green import ssl
@@ -115,7 +101,6 @@ def wrap_socket_with_coroutine_socket(use_thread_pool=True):
if __original_fromfd__ is not None: if __original_fromfd__ is not None:
def new_fromfd(*args, **kw): def new_fromfd(*args, **kw):
from eventlet import greenio
return greenio.GreenSocket(__original_fromfd__(*args, **kw)) return greenio.GreenSocket(__original_fromfd__(*args, **kw))
socket.fromfd = new_fromfd socket.fromfd = new_fromfd
@@ -136,7 +121,6 @@ def wrap_pipes_with_coroutine_pipes():
if pipes_already_wrapped: if pipes_already_wrapped:
return return
def new_fdopen(*args, **kw): def new_fdopen(*args, **kw):
from eventlet import greenio
return greenio.GreenPipe(__original_fdopen__(*args, **kw)) return greenio.GreenPipe(__original_fdopen__(*args, **kw))
def new_read(fd, *args, **kw): def new_read(fd, *args, **kw):
from eventlet import api from eventlet import api

View File

@@ -6,8 +6,7 @@ from eventlet import __version__
import sys import sys
requirements = [] requirements = []
for flag, req in [('--without-greenlet','greenlet >= 0.2'), for flag, req in [('--without-greenlet','greenlet >= 0.2')]:
('--without-pyopenssl', 'pyopenssl')]:
if flag in sys.argv: if flag in sys.argv:
sys.argv.remove(flag) sys.argv.remove(flag)
else: else:

View File

@@ -1,6 +1,7 @@
from tests import skipped, LimitedTestCase, skip_with_libevent, TestIsTakingTooLong from tests import skipped, LimitedTestCase, skip_with_libevent, TestIsTakingTooLong
from unittest import main from unittest import main
from eventlet import api, util, coros, proc, greenio from eventlet import api, util, coros, proc, greenio
from eventlet.green.socket import GreenSSLObject
import os import os
import socket import socket
import sys import sys
@@ -282,7 +283,7 @@ class SSLTest(LimitedTestCase):
self.private_key_file) self.private_key_file)
killer = api.spawn(serve, listener) killer = api.spawn(serve, listener)
client = util.wrap_ssl(api.connect_tcp(('localhost', listener.getsockname()[1]))) client = util.wrap_ssl(api.connect_tcp(('localhost', listener.getsockname()[1])))
client = greenio.GreenSSLObject(client) client = GreenSSLObject(client)
self.assertEquals(client.read(1024), 'content') self.assertEquals(client.read(1024), 'content')
self.assertEquals(client.read(1024), '') self.assertEquals(client.read(1024), '')
@@ -290,7 +291,10 @@ class SSLTest(LimitedTestCase):
def serve(listener): def serve(listener):
sock, addr = listener.accept() sock, addr = listener.accept()
stuff = sock.read(8192) stuff = sock.read(8192)
empt = sock.read(8192) try:
self.assertEquals("", sock.read(8192))
except greenio.SSL.ZeroReturnError:
pass
sock = api.ssl_listener(('127.0.0.1', 0), self.certificate_file, self.private_key_file) sock = api.ssl_listener(('127.0.0.1', 0), self.certificate_file, self.private_key_file)
server_coro = coros.execute(serve, sock) server_coro = coros.execute(serve, sock)