Package ndg :: Package httpsclient :: Module https
[hide private]

Source Code for Module ndg.httpsclient.https

  1  """ndg_httpsclient HTTPS module containing PyOpenSSL implementation of 
  2  httplib.HTTPSConnection 
  3   
  4  PyOpenSSL utility to make a httplib-like interface suitable for use with  
  5  urllib2 
  6  """ 
  7  __author__ = "P J Kershaw (STFC)" 
  8  __date__ = "09/12/11" 
  9  __copyright__ = "(C) 2012 Science and Technology Facilities Council" 
 10  __license__ = "BSD - see LICENSE file in top-level directory" 
 11  __contact__ = "Philip.Kershaw@stfc.ac.uk" 
 12  __revision__ = '$Id$' 
 13  import logging 
 14  import socket 
 15  from httplib import HTTPS_PORT 
 16  from httplib import HTTPConnection 
 17  from urllib2 import AbstractHTTPHandler 
 18   
 19   
 20  from OpenSSL import SSL 
 21   
 22  from ndg.httpsclient.ssl_socket import SSLSocket 
 23   
 24  log = logging.getLogger(__name__) 
 25   
 26   
27 -class HTTPSConnection(HTTPConnection):
28 """This class allows communication via SSL using PyOpenSSL. 29 It is based on httplib.HTTPSConnection, modified to use PyOpenSSL. 30 31 Note: This uses the constructor inherited from HTTPConnection to allow it to 32 be used with httplib and HTTPSContextHandler. To use the class directly with 33 an SSL context set ssl_context after construction. 34 35 @cvar default_port: default port for this class (443) 36 @type default_port: int 37 @cvar default_ssl_method: default SSL method used if no SSL context is 38 explicitly set - defaults to version 2/3. 39 @type default_ssl_method: int 40 """ 41 default_port = HTTPS_PORT 42 default_ssl_method = SSL.SSLv23_METHOD 43
44 - def __init__(self, host, port=None, strict=None, 45 timeout=socket._GLOBAL_DEFAULT_TIMEOUT, ssl_context=None):
46 HTTPConnection.__init__(self, host, port, strict, timeout) 47 if not hasattr(self, 'ssl_context'): 48 self.ssl_context = None 49 50 if ssl_context is not None: 51 if not isinstance(ssl_context, SSL.Context): 52 raise TypeError('Expecting OpenSSL.SSL.Context type for "' 53 'ssl_context" keyword; got %r instead' % 54 ssl_context) 55 56 self.ssl_context = ssl_context
57
58 - def connect(self):
59 """Create SSL socket and connect to peer 60 """ 61 if getattr(self, 'ssl_context', None): 62 if not isinstance(self.ssl_context, SSL.Context): 63 raise TypeError('Expecting OpenSSL.SSL.Context type for "' 64 'ssl_context" attribute; got %r instead' % 65 self.ssl_context) 66 ssl_context = self.ssl_context 67 else: 68 ssl_context = SSL.Context(self.__class__.default_ssl_method) 69 70 sock = socket.create_connection((self.host, self.port), self.timeout) 71 72 # Tunnel if using a proxy - ONLY available for Python 2.6.2 and above 73 if getattr(self, '_tunnel_host', None): 74 self.sock = sock 75 self._tunnel() 76 77 self.sock = SSLSocket(ssl_context, sock) 78 79 # Go to client mode. 80 self.sock.set_connect_state()
81
82 - def close(self):
83 """Close socket and shut down SSL connection""" 84 self.sock.close()
85 86
87 -class HTTPSContextHandler(AbstractHTTPHandler):
88 '''HTTPS handler that allows a SSL context to be set for the SSL 89 connections. 90 ''' 91 https_request = AbstractHTTPHandler.do_request_ 92
93 - def __init__(self, ssl_context, debuglevel=0):
94 """ 95 @param ssl_context:SSL context 96 @type ssl_context: OpenSSL.SSL.Context 97 @param debuglevel: debug level for HTTPSHandler 98 @type debuglevel: int 99 """ 100 AbstractHTTPHandler.__init__(self, debuglevel) 101 102 if ssl_context is not None: 103 if not isinstance(ssl_context, SSL.Context): 104 raise TypeError('Expecting OpenSSL.SSL.Context type for "' 105 'ssl_context" keyword; got %r instead' % 106 ssl_context) 107 self.ssl_context = ssl_context 108 else: 109 self.ssl_context = SSL.Context(SSL.SSLv23_METHOD)
110
111 - def https_open(self, req):
112 """Opens HTTPS request 113 @param req: HTTP request 114 @return: HTTP Response object 115 """ 116 # Make a custom class extending HTTPSConnection, with the SSL context 117 # set as a class variable so that it is available to the connect method. 118 customHTTPSContextConnection = type('CustomHTTPSContextConnection', 119 (HTTPSConnection, object), 120 {'ssl_context': self.ssl_context}) 121 return self.do_open(customHTTPSContextConnection, req)
122