get.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. import cookielib
  2. import httplib
  3. import logging
  4. from optparse import OptionParser
  5. import os
  6. import urllib2
  7. import urlparse
  8. from OpenSSL import SSL
  9. from urllib2pyopenssl.urllib2_build_opener import urllib2_build_opener
  10. from urllib2pyopenssl.https import HTTPSContextHandler
  11. import urllib2pyopenssl.ssl_context_util as ssl_context_util
  12. from urllib2pyopenssl.ssl_peer_verification import ServerSSLCertVerification
  13. def fetch_from_url(url, config):
  14. """Returns data retrieved from a URL.
  15. @param url - URL to attempt to open
  16. @param config - configuration
  17. @return data retrieved from URL or None
  18. """
  19. (return_code, return_message, response) = open_url(url, config)
  20. if return_code and return_code == httplib.OK:
  21. return_data = response.read()
  22. response.close()
  23. return return_data
  24. else:
  25. raise Exception(return_message)
  26. def fetch_from_url_to_file(url, config, output_file):
  27. """Writes data retrieved from a URL to a file.
  28. @param url - URL to attempt to open
  29. @param config - configuration
  30. @param output_file - output file
  31. @return tuple (
  32. returned HTTP status code or 0 if an error occurred
  33. returned message
  34. boolean indicating whether access was successful
  35. )
  36. """
  37. (return_code, return_message, response) = open_url(url, config)
  38. if return_code == httplib.OK:
  39. return_data = response.read()
  40. response.close()
  41. outfile = open(output_file, "w")
  42. outfile.write(return_data)
  43. outfile.close()
  44. return (return_code, return_message, (return_code == httplib.OK))
  45. def open_url(url, config):
  46. """Attempts to open a connection to a specified URL.
  47. @param url - URL to attempt to open
  48. @param config - configuration
  49. @return tuple (
  50. returned HTTP status code or 0 if an error occurred
  51. returned message or error description
  52. response object
  53. )
  54. """
  55. debuglevel = 1 if config.debug else 0
  56. # Set up handlers for URL opener.
  57. cj = cookielib.CookieJar()
  58. cookie_handler = urllib2.HTTPCookieProcessor(cj)
  59. handlers = [cookie_handler]
  60. if config.debug:
  61. http_handler = urllib2.HTTPHandler(debuglevel=debuglevel)
  62. https_handler = HTTPSContextHandler(config.ssl_context, debuglevel=debuglevel)
  63. handlers.extend([http_handler, https_handler])
  64. # Explicitly remove proxy handling if the host is one listed in the value of the no_proxy
  65. # environment variable because urllib2 does use proxy settings set via http_proxy and
  66. # https_proxy, but does not take the no_proxy value into account.
  67. if not _should_use_proxy(url):
  68. handlers.append(urllib2.ProxyHandler({}))
  69. if config.debug:
  70. print "Not using proxy"
  71. opener = urllib2_build_opener(config.ssl_context, *handlers)
  72. # Open the URL and check the response.
  73. return_code = 0
  74. return_message = ''
  75. response = None
  76. try:
  77. response = opener.open(url)
  78. if response.url == url:
  79. return_message = response.msg
  80. return_code = response.code
  81. else:
  82. return_message = ('Redirected (%s %s)' % (response.code, response.url))
  83. if config.debug:
  84. for index, cookie in enumerate(cj):
  85. print index, ' : ', cookie
  86. except urllib2.HTTPError, exc:
  87. return_code = exc.code
  88. return_message = ("Error: %s" % exc.msg)
  89. if config.debug:
  90. print exc.code, exc.msg
  91. except Exception, exc:
  92. return_message = ("Error: %s" % exc.__str__())
  93. if config.debug:
  94. print exc.__class__, exc.__str__()
  95. return (return_code, return_message, response)
  96. def _should_use_proxy(url):
  97. """Determines whether a proxy should be used to open a connection to the specified URL, based on
  98. the value of the no_proxy environment variable.
  99. @param url - URL string
  100. """
  101. no_proxy = os.environ.get('no_proxy', '')
  102. urlObj = urlparse.urlparse(url)
  103. for np in [h.strip() for h in no_proxy.split(',')]:
  104. if urlObj.hostname == np:
  105. return False
  106. return True
  107. class Configuration(object):
  108. """Checker configuration.
  109. """
  110. def __init__(self, ssl_context, debug):
  111. """
  112. @param key_file - file containing the user's private key
  113. @param cert_file - file containing the user's certificate
  114. @param debug - if True, output debugging information
  115. """
  116. self.ssl_context = ssl_context
  117. self.debug = debug
  118. def main():
  119. '''Utility to fetch data using HTTP or HTTPS GET from a specified URL.
  120. '''
  121. parser = OptionParser(usage="%prog [options] url")
  122. parser.add_option("-k", "--private-key", dest="key_file", metavar="FILE",
  123. default=None,
  124. help="Private key file.")
  125. parser.add_option("-c", "--certificate", dest="cert_file", metavar="FILE",
  126. default=os.path.expanduser("~/credentials.pem"),
  127. help="Certificate file.")
  128. parser.add_option("-t", "--ca-certificate-dir", dest="ca_dir", metavar="PATH",
  129. default=None,
  130. help="Trusted CA certificate file directory.")
  131. parser.add_option("-d", "--debug", action="store_true", dest="debug", default=False,
  132. help="Print debug information.")
  133. parser.add_option("-f", "--fetch", dest="output_file", metavar="FILE",
  134. default=None, help="Output file.")
  135. parser.add_option("-v", "--verify-peer", action="store_true", dest="verify_peer", default=False,
  136. help="Verify peer certificate.")
  137. (options, args) = parser.parse_args()
  138. if len(args) != 1:
  139. parser.error("Incorrect number of arguments")
  140. url = args[0]
  141. # If a private key file is not specified, the key is assumed to be stored in the certificate file.
  142. ssl_context = ssl_context_util.make_ssl_context(
  143. options.key_file if options.key_file and os.path.exists(options.key_file) else None,
  144. options.cert_file if options.cert_file and os.path.exists(options.cert_file) else None,
  145. None,
  146. options.ca_dir if options.ca_dir and os.path.exists(options.ca_dir) else None,
  147. options.verify_peer, url)
  148. config = Configuration(ssl_context, options.debug)
  149. if options.output_file:
  150. (return_code, return_message, success) = fetch_from_url_to_file(url, config,
  151. options.output_file)
  152. print return_code, return_message
  153. else:
  154. data = fetch_from_url(url, config)
  155. print data
  156. if __name__=='__main__':
  157. logging.basicConfig()
  158. main()