[Twisted-Python] ssl.py/client.py patches to implement getSecurePage()
Clark C. Evans
cce at clarkevans.com
Tue Mar 25 17:19:22 MST 2003
Well, as per the last post, there seems to be a 'straight-forward'
version of twisted.web.client.getPage ; attached are two patches
which make code like below work.
from twisted.internet import reactor, ssl
from twisted.web import client
import urllib
def result(data): print data
if __name__ == '__main__':
reactor.callLater(5, reactor.stop)
# a very simple example
deferred = client.getSecurePage("https://localhost/some/path")
deferred.addCallback(result)
# a more complicated one
postdata = urllib.urlencode({'some': 'argument', 'another': 'arg'})
headers = {"Content-type":"application/x-www-form-urlencoded"}
deferred = client.getSecurePage("https://localhost:8443/some/path",
"POST", postdata, headers,
privateKeyFileName = "client.key",
certificateFileName = "client.crt",
serverCertificateFileName="server.crt")
deferred.addCallback(result)
reactor.run()
Best,
Clark
-------------- next part --------------
--- ssl.py.orig Tue Mar 25 13:44:40 2003
+++ ssl.py Tue Mar 25 15:32:15 2003
@@ -36,7 +36,7 @@
"""
# System imports
-from OpenSSL import SSL
+from OpenSSL import SSL, crypto
import socket
# sibling imports
@@ -55,20 +55,32 @@
"""Return a SSL.Context object. override in subclasses."""
raise NotImplementedError
+def dumpCertificate(cert, filetype = crypto.FILETYPE_PEM ):
+ ''' a helper to dump an incoming cert as a PEM '''
+ return crypto.dump_certificate(filetype, cert)
class DefaultOpenSSLContextFactory(ContextFactory):
def __init__(self, privateKeyFileName, certificateFileName,
- sslmethod=SSL.SSLv23_METHOD):
- self.privateKeyFileName = privateKeyFileName
+ sslmethod=SSL.SSLv23_METHOD, verifyCallback = None):
+ self.verifyCallback = (verifyCallback, )
+ self.privateKeyFileName = privateKeyFileName
self.certificateFileName = certificateFileName
self.sslmethod = sslmethod
self.cacheContext()
+
+ def verifyCertificate(self, conn, cert, errno, depth, retcode):
+ cb = self.verifyCallback[0]
+ if cb: return cb(cert)
+ return 1
+
def cacheContext(self):
ctx = SSL.Context(self.sslmethod)
ctx.use_certificate_file(self.certificateFileName)
ctx.use_privatekey_file(self.privateKeyFileName)
+ if self.verifyCallback[0]:
+ ctx.set_verify(SSL.VERIFY_PEER, self.verifyCertificate)
self._context = ctx
def __getstate__(self):
-------------- next part --------------
--- client.py.orig Tue Mar 25 18:10:28 2003
+++ client.py Tue Mar 25 18:55:08 2003
@@ -63,7 +63,8 @@
l = self.headers.get('location')
if not l:
self.handleStatusDefault()
- host, port, url = _parse(l[0])
+ https, host, port, url = _parse(l[0])
+ assert not https, "https redirects not implemented yet"
self.factory.host, self.factory.url = host, url
reactor.connectTCP(host, port, self.factory)
self.quietLoss = 1
@@ -105,7 +106,9 @@
protocol = HTTPPageGetter
- def __init__(self, host, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter"):
+ def __init__(self, host, url, method='GET', postdata=None,
+ headers=None, agent=None):
+ if agent is None: agent = "Twisted PageGetter"
if headers is not None:
self.headers = headers
if postdata is not None:
@@ -141,8 +144,10 @@
protocol = HTTPPageDownloader
value = None
- def __init__(self, host, url, fileName, method='GET', postdata=None, headers=None, agent="Twisted client"):
- HTTPClientFactory.__init__(self, host, url, method=method, postdata=postdata, headers=headers, agent=agent)
+ def __init__(self, host, url, fileName, method='GET', postdata=None,
+ headers=None, agent = None):
+ HTTPClientFactory.__init__(self, host, url, method,
+ postdata, headers, agent)
self.fileName = fileName
self.deferred = defer.Deferred()
self.waiting = 1
@@ -166,26 +171,59 @@
def _parse(url):
parsed = urlparse.urlparse(url)
url = urlparse.urlunparse(('','')+parsed[2:])
- host, port = parsed[1], 80
+ host = parsed[1]
+ if 'https' == parsed[0]:
+ https, port = 1, 443
+ else:
+ https, port = 0, 80
if ':' in host:
host, port = host.split(':')
port = int(port)
- return host, port, url
+ return https, host, port, url
-def getPage(url, *args, **kwargs):
+def getPage(url, method='GET', postdata=None, headers=None, agent = None):
'''download a web page
Download a page. Return a deferred, which will
callback with a page or errback with a description
of the error.
'''
- host, port, url = _parse(url)
- factory = HTTPClientFactory(host, url, *args, **kwargs)
+ https, host, port, path = _parse(url)
+ if https: return getSecurePage(url, method, postdata, headers, agent)
+ factory = HTTPClientFactory(host, path, method, postdata, headers, agent)
reactor.connectTCP(host, port, factory)
return factory.deferred
+try:
+ from twisted.internet import ssl
+ def getSecurePage(url, method='GET', postdata=None, headers=None,
+ agent = None,
+ privateKeyFileName = None, certificateFileName = None,
+ sslmethod=ssl.SSL.SSLv23_METHOD, verifyCallback = None,
+ serverCertificateFileName = None):
+ """ download a secure page """
+ https, host, port, path = _parse(url)
+ if serverCertificateFileName:
+ cert = file(serverCertificateFileName).read()
+ verifyCallback = lambda rhs: ssl.dumpCertificate(cert) == rhs
+ if verifyCallback or certificateFileName or privateKeyFileName:
+ context = ssl.DefaultOpenSSLContextFactory(
+ privateKeyFileName, certificateFileName,
+ sslmethod, verifyCallback)
+ context.isClient = 1
+ else:
+ context = ssl.ClientContextFactory()
+ factory = HTTPClientFactory(host, path, method, postdata, headers)
+ reactor.connectSSL(host, port, factory, context)
+ return factory.deferred
+except:
+ def getSecurePage(*args,**kwargs):
+ raise Exception("ssl not available")
+
def downloadPage(url, file, *args, **kwargs):
- host, port, url = _parse(url)
- factory = HTTPDownloader(host, url, file, *args, **kwargs)
+ https, host, port, path = _parse(url)
+ assert not https, "https is not yet implemented here"
+ factory = HTTPDownloader(host, path, file, *args, **kwargs)
reactor.connectTCP(host, port, factory)
return factory.deferred
+
More information about the Twisted-Python
mailing list