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  import sys 
 16   
 17  if sys.version_info[0] > 2: 
 18      from http.client import HTTPS_PORT 
 19      from http.client import HTTPConnection 
 20   
 21      from urllib.request import AbstractHTTPHandler 
 22  else: 
 23      from httplib import HTTPS_PORT 
 24      from httplib import HTTPConnection 
 25   
 26      from urllib2 import AbstractHTTPHandler 
 27   
 28   
 29  from OpenSSL import SSL 
 30   
 31  from ndg.httpsclient.ssl_socket import SSLSocket 
 32   
 33  log = logging.getLogger(__name__) 
 34   
 35   
36 -class HTTPSConnection(HTTPConnection):
37 """This class allows communication via SSL using PyOpenSSL. 38 It is based on httplib.HTTPSConnection, modified to use PyOpenSSL. 39 40 Note: This uses the constructor inherited from HTTPConnection to allow it to 41 be used with httplib and HTTPSContextHandler. To use the class directly with 42 an SSL context set ssl_context after construction. 43 44 @cvar default_port: default port for this class (443) 45 @type default_port: int 46 @cvar default_ssl_method: default SSL method used if no SSL context is 47 explicitly set - defaults to version 2/3. 48 @type default_ssl_method: int 49 """ 50 default_port = HTTPS_PORT 51 default_ssl_method = SSL.SSLv23_METHOD 52
53 - def __init__(self, host, port=None, strict=None, 54 timeout=socket._GLOBAL_DEFAULT_TIMEOUT, ssl_context=None):
55 HTTPConnection.__init__(self, host, port, strict, timeout) 56 if not hasattr(self, 'ssl_context'): 57 self.ssl_context = None 58 59 if ssl_context is not None: 60 if not isinstance(ssl_context, SSL.Context): 61 raise TypeError('Expecting OpenSSL.SSL.Context type for "' 62 'ssl_context" keyword; got %r instead' % 63 ssl_context) 64 65 self.ssl_context = ssl_context
66
67 - def connect(self):
68 """Create SSL socket and connect to peer 69 """ 70 if getattr(self, 'ssl_context', None): 71 if not isinstance(self.ssl_context, SSL.Context): 72 raise TypeError('Expecting OpenSSL.SSL.Context type for "' 73 'ssl_context" attribute; got %r instead' % 74 self.ssl_context) 75 ssl_context = self.ssl_context 76 else: 77 ssl_context = SSL.Context(self.__class__.default_ssl_method) 78 79 sock = socket.create_connection((self.host, self.port), self.timeout) 80 81 # Tunnel if using a proxy - ONLY available for Python 2.6.2 and above 82 if getattr(self, '_tunnel_host', None): 83 self.sock = sock 84 self._tunnel() 85 86 self.sock = SSLSocket(ssl_context, sock) 87 88 # Go to client mode. 89 self.sock.set_connect_state()
90
91 - def close(self):
92 """Close socket and shut down SSL connection""" 93 if hasattr(self.sock, "close"): 94 self.sock.close()
95 96
97 -class HTTPSContextHandler(AbstractHTTPHandler):
98 '''HTTPS handler that allows a SSL context to be set for the SSL 99 connections. 100 ''' 101 https_request = AbstractHTTPHandler.do_request_ 102
103 - def __init__(self, ssl_context, debuglevel=0):
104 """ 105 @param ssl_context:SSL context 106 @type ssl_context: OpenSSL.SSL.Context 107 @param debuglevel: debug level for HTTPSHandler 108 @type debuglevel: int 109 """ 110 AbstractHTTPHandler.__init__(self, debuglevel) 111 112 if ssl_context is not None: 113 if not isinstance(ssl_context, SSL.Context): 114 raise TypeError('Expecting OpenSSL.SSL.Context type for "' 115 'ssl_context" keyword; got %r instead' % 116 ssl_context) 117 self.ssl_context = ssl_context 118 else: 119 self.ssl_context = SSL.Context(SSL.TLSv1_METHOD)
120
121 - def https_open(self, req):
122 """Opens HTTPS request 123 @param req: HTTP request 124 @return: HTTP Response object 125 """ 126 # Make a custom class extending HTTPSConnection, with the SSL context 127 # set as a class variable so that it is available to the connect method. 128 customHTTPSContextConnection = type('CustomHTTPSContextConnection', 129 (HTTPSConnection, object), 130 {'ssl_context': self.ssl_context}) 131 return self.do_open(customHTTPSContextConnection, req)
132