On 13 Jan 2017, at 08:48, Nathaniel Smith <njs@pobox.com> wrote:
The potentially-useful idea I took from this subthread was: right now we have an interface with a bunch of getter/setter methods. Would it make sense to *replace* that with something more declarative, like a single method that takes configuration data in some sort of standard format? Something very non-clever and simple, like, a dict? That seems like it might both simplify the interface (e.g. the sni callback can return one of these dicts instead of trying to specify OpenSSL's context switcheroo weirdness; if the new dict tries to change options that this particular implementation doesn't allow to be changed, then it's free to error out) and be more flexible (e.g. people could write validation routines that take one of these dicts and raise an error or not -- having a standard format enables this but also makes it not our problem).
Hmm. I am extremely unsure. At the risk of sounding facetious, these two solutions are *basically* isomorphic to one another: that is, an object with a bunch of getters/setters is basically a dict, it’s just not something you can shove arbitrary data into. That’s my main reason for preferring an object to a dict: I want to eliminate a whole class of bugs that comes from accidentally doing `config[’ssl_version_minimum’] = TLSv1_1` instead of `config[‘tls_version_minimum’] = TLSv1_1`. Put another way, the dict approach either requires that we override __setitem__ to validate all keys, or that we allow typo-based errors where people accidentally get the default. The second is terrifying, so we’d have to do the first, and at that point we’re basically just writing an object. ;) I think the actual key here is that the “Context” object should not be confused with an *actual* Context object from the backing library. That is, a ClientContext() for OpenSSL does not need to compose onto it a SSL_CTX from OpenSSL. It is quite reasonable for the ClientContext to just be a bucket of data that manufactures SSL_CTX objects when wrap_socket is called. I don’t see why validation routines couldn’t run on Context objects directly. You could even do this: class ClientValidationContext(ClientContext): def validate(self): “””Checks internal state and returns whether or not the context meets your criteria””” pass Essentially, because all code operates on the abstract objects, one of the things you can do for validation is insert a *validating* implementation of the abstract object. It’s exactly like a test fake, but for validation. Does that make any sense, or have I not had enough coffee yet? Cory