patternpythonMinor
Subclass of socket with optional TLS
Viewed 0 times
withtlssubclassoptionalsocket
Problem
import ssl
from socket import socket
class testsock(socket):
def __init__(self, tls=True):
super(testsock, self).__init__()
self.connect(('192.168.0.1', 443))
if tls:
self = ssl.wrap_socket(self) # Ugly "handover"
testsock(tls=True)This code works, it's the second ugliest bodge I've done as of today.
But it works with the behavior I desire, that
.send() and .close() etc are "intact".However, if I ever try to add any other values to my custom class
testsock those will effectively be gone, since I replace self with whatever wrap_socket spits out.I could use something that looks like this:
class testsock():
def __init__(self, tls=True):
self.s = socket()
...
self.s = ssl.wrap_socket(self.s)
def send(self, data):
self.s.send(data)But that goes against the elegance of inheriting the socket object and not having to create all the functions you'd expect out of a ordinary socket. (I know, lazy programming, but it looks cleaner without all the definitions).
I could probably iterate over all the
.__dict__ or inspect.getmembers() functions and replace them with the matching available items from wrap_socket, but that would also cause for concerns later on, but it would look something like:for name, obj in inspect.getmembers(self):
print(name, obj)It would yield something like:
close >I'm not sure how I'd get
socket from this, obj.__class__.__name__ doesn't yield this. If I could some how get socket from the object I would know that it's a socket() bound method, and replace the corresponding method from wrap_socket() return.I've heard of metaclass programming, and I'm having a go at it.
But my question is, out of all the options - Which would be the best according to the community?
Would it be possible to inline-replace the inherited socket object with whatever
ssl.wrap_socket returns?Solution
You don't need a class here, a simple function will do:
Returned objects are either plain sockets or ssl sockets but they share some common behaviour (like
In case you wish to be able to extend it better, you can still use the socket as an attribute on a custom class and expose the
But you don't need it for now.
import ssl
from socket import socket
def testsock(tls=True):
sock = socket()
sock.connect(('192.168.0.1', 443))
if tls:
sock = ssl.wrap_socket(sock)
return sock
testsock(tls=True)Returned objects are either plain sockets or ssl sockets but they share some common behaviour (like
send or recv). If you need to add attributes, you can do that before the return statement.In case you wish to be able to extend it better, you can still use the socket as an attribute on a custom class and expose the
socket API through __getattr__:class TestSock(object):
def __init__(self, tls=True):
sock = socket()
sock.connect(('192.168.0.1', 443))
if tls:
sock = ssl.wrap_socket(sock)
self.socket = sock
# other attributes
def __getattr__(self, attribute_name):
"""Defer unknown behaviour to the socket"""
return getattr(self.socket, attribute_name)
# other methodsBut you don't need it for now.
Code Snippets
import ssl
from socket import socket
def testsock(tls=True):
sock = socket()
sock.connect(('192.168.0.1', 443))
if tls:
sock = ssl.wrap_socket(sock)
return sock
testsock(tls=True)class TestSock(object):
def __init__(self, tls=True):
sock = socket()
sock.connect(('192.168.0.1', 443))
if tls:
sock = ssl.wrap_socket(sock)
self.socket = sock
# other attributes
def __getattr__(self, attribute_name):
"""Defer unknown behaviour to the socket"""
return getattr(self.socket, attribute_name)
# other methodsContext
StackExchange Code Review Q#153035, answer score: 4
Revisions (0)
No revisions yet.