1414from optparse import OptionParser
1515import os
1616import urllib2
17- from urllib2 import HTTPHandler , HTTPCookieProcessor
17+ from urllib2 import (HTTPHandler , HTTPCookieProcessor ,
18+ HTTPBasicAuthHandler , HTTPPasswordMgrWithDefaultRealm )
1819
1920import urlparse
2021
@@ -126,6 +127,8 @@ def open_url(url, config, data=None, handlers=None):
126127 @type config: Configuration
127128 @param data: HTTP POST data
128129 @type data: str
130+ @param handlers: list of custom urllib2 handlers to add to the request
131+ @type handlers: iterable
129132 @return: tuple (
130133 returned HTTP status code or 0 if an error occurred
131134 returned message or error description
@@ -154,6 +157,15 @@ def open_url(url, config, data=None, handlers=None):
154157 https_handler = HTTPSContextHandler (config .ssl_context ,
155158 debuglevel = debuglevel )
156159 handlers .extend ([http_handler , https_handler ])
160+
161+ if config .http_basicauth :
162+ # currently only supports http basic auth
163+ auth_handler = HTTPBasicAuthHandler (HTTPPasswordMgrWithDefaultRealm ())
164+ auth_handler .add_password (realm = None , uri = url ,
165+ user = config .httpauth [0 ],
166+ passwd = config .httpauth [1 ])
167+ handlers .append (auth_handler )
168+
157169
158170 # Explicitly remove proxy handling if the host is one listed in the value of
159171 # the no_proxy environment variable because urllib2 does use proxy settings
@@ -167,13 +179,18 @@ def open_url(url, config, data=None, handlers=None):
167179 log .debug ("Configuring proxies: %s" % config .proxies )
168180
169181 opener = build_opener (* handlers , ssl_context = config .ssl_context )
182+
183+ headers = config .headers
184+ if headers is None :
185+ headers = {}
186+ request = urllib2 .Request (url , data , headers )
170187
171188 # Open the URL and check the response.
172189 return_code = 0
173190 return_message = ''
174191 response = None
175192 try :
176- response = opener .open (url , data )
193+ response = opener .open (request )
177194 return_message = response .msg
178195 return_code = response .code
179196 if log .isEnabledFor (logging .DEBUG ):
@@ -231,7 +248,7 @@ class Configuration(object):
231248 """Connection configuration.
232249 """
233250 def __init__ (self , ssl_context , debug = False , proxies = None , no_proxy = None ,
234- cookie = None ):
251+ cookie = None , http_basicauth = None , headers = None ):
235252 """
236253 @param ssl_context: SSL context to use with this configuration
237254 @type ssl_context: OpenSSL.SSL.Context
@@ -243,12 +260,18 @@ def __init__(self, ssl_context, debug=False, proxies=None, no_proxy=None,
243260 @type no_proxy: basestring
244261 @param cookie: cookies to set for request
245262 @type cookie: cookielib.CookieJar
263+ @param http_basicauth: http authentication, or None
264+ @type http_basicauth: tuple of (username,password)
265+ @param headers: http headers
266+ @type headers: dict
246267 """
247268 self .ssl_context = ssl_context
248269 self .debug = debug
249270 self .proxies = proxies
250271 self .no_proxy = no_proxy
251272 self .cookie = cookie
273+ self .http_basicauth = http_basicauth
274+ self .headers = headers
252275
253276
254277def main ():
@@ -276,6 +299,12 @@ def main():
276299 parser .add_option ("-n" , "--no-verify-peer" , action = "store_true" ,
277300 dest = "no_verify_peer" , default = False ,
278301 help = "Skip verification of peer certificate." )
302+ parser .add_option ("-a" , "--basicauth" , dest = "auth" , metavar = "USER:PASSWD" ,
303+ default = None ,
304+ help = "HTTP authentication credentials" )
305+ parser .add_option ("--header" , action = "append" , dest = "headers" ,
306+ metavar = "HEADER: VALUE" ,
307+ help = "Add HTTP header to request" )
279308 (options , args ) = parser .parse_args ()
280309 if len (args ) != 1 :
281310 parser .error ("Incorrect number of arguments" )
@@ -309,6 +338,17 @@ def main():
309338 else :
310339 data = None
311340
341+ if options .basicauth :
342+ http_basicauth = options .auth .split (':' , 1 )
343+ else :
344+ http_basicauth = None
345+
346+ headers = {}
347+ if options .headers :
348+ for h in options .headers :
349+ key , val = h .split (':' , 1 )
350+ headers [key .strip ()] = val .lstrip ()
351+
312352 # If a private key file is not specified, the key is assumed to be stored in
313353 # the certificate file.
314354 ssl_context = ssl_context_util .make_ssl_context (key_file ,
@@ -318,9 +358,13 @@ def main():
318358 verify_peer ,
319359 url )
320360
321- config = Configuration (ssl_context , options .debug )
361+ config = Configuration (ssl_context ,
362+ options .debug ,
363+ http_basicauth = http_basicauth ,
364+ headers = headers )
322365 if options .output_file :
323- return_code , return_message = fetch_from_url_to_file (url ,
366+ return_code , return_message = fetch_from_url_to_file (
367+ url ,
324368 config ,
325369 options .output_file ,
326370 data )[:2 ]
0 commit comments