diff --git a/code/client/munkilib/fetch.py b/code/client/munkilib/fetch.py index c243afcc5..9bf7cf5eb 100644 --- a/code/client/munkilib/fetch.py +++ b/code/client/munkilib/fetch.py @@ -99,22 +99,27 @@ class GurlError(Exception): """General exception for gurl errors""" pass + class HTTPError(Exception): """General exception for http/https errors""" pass + class MunkiDownloadError(Exception): """Base exception for download errors""" pass + class GurlDownloadError(MunkiDownloadError): """Gurl failed to download the item""" pass + class FileCopyError(MunkiDownloadError): """Download failed because of file copy errors.""" pass + class PackageVerificationError(MunkiDownloadError): """Package failed verification""" pass @@ -184,9 +189,13 @@ def get_url(url, destinationpath, cache_data = gurl_obj.get_stored_headers() del gurl_obj + # only works with NSURLSession (10.9 and newer) + ignore_system_proxy = munkicommon.pref('IgnoreSystemProxies') + options = {'url': url, 'file': tempdownloadpath, 'follow_redirects': follow_redirects, + 'ignore_system_proxy': ignore_system_proxy, 'can_resume': resume, 'additional_headers': header_dict_from_list(custom_headers), 'download_only_if_changed': onlyifnewer, @@ -236,13 +245,13 @@ def get_url(url, destinationpath, # safely kill the connection then re-raise connection.cancel() raise - except Exception, err: # too general, I know + except Exception, err: # too general, I know # Let us out! ... Safely! Unexpectedly quit dialogs are annoying... connection.cancel() # Re-raise the error as a GurlError raise GurlError(-1, str(err)) - if connection.error != None: + if connection.error is not None: # Gurl returned an error munkicommon.display_detail( 'Download error %s: %s', connection.error.code(), @@ -257,7 +266,7 @@ def get_url(url, destinationpath, raise GurlError(connection.error.code(), connection.error.localizedDescription()) - if connection.response != None: + if connection.response is not None: munkicommon.display_debug1('Status: %s', connection.status) munkicommon.display_debug1('Headers: %s', connection.headers) if connection.redirection != []: @@ -286,6 +295,7 @@ def get_url(url, destinationpath, raise HTTPError(connection.status, connection.headers.get('http_result_description', '')) + def getResourceIfChangedAtomically(url, destinationpath, custom_headers=None, @@ -328,9 +338,9 @@ def getResourceIfChangedAtomically(url, munkicommon.log('Cached payload does not match hash in catalog, ' 'will check if changed and redownload: %s' % destinationpath) - #continue with normal if-modified-since/etag update methods. + # continue with normal if-modified-since/etag update methods. - if follow_redirects != True: + if follow_redirects is not True: # If we haven't explicitly said to follow redirect, # the preference decides follow_redirects = munkicommon.pref('FollowHTTPRedirects') @@ -552,4 +562,3 @@ def verifySoftwarePackageIntegrity(file_path, item_hash, always_hash=False): 'illegal value: %s' % munkicommon.pref('PackageVerificationMode')) return (False, chash) - diff --git a/code/client/munkilib/gurl.py b/code/client/munkilib/gurl.py index 71bfb79ff..a0d63ea63 100644 --- a/code/client/munkilib/gurl.py +++ b/code/client/munkilib/gurl.py @@ -33,17 +33,19 @@ # PyLint cannot properly find names inside Cocoa libraries, so issues bogus # No name 'Foo' in module 'Bar' warnings. Disable them. # pylint: disable=E0611 -from Foundation import NSBundle, \ - NSRunLoop, NSDate, \ - NSObject, NSURL, NSURLConnection, \ - NSMutableURLRequest, \ - NSURLRequestReloadIgnoringLocalCacheData, \ - NSURLResponseUnknownLength, \ - NSLog, \ - NSURLCredential, NSURLCredentialPersistenceNone, \ - NSPropertyListSerialization, \ - NSPropertyListMutableContainersAndLeaves, \ - NSPropertyListXMLFormat_v1_0 + +from CFNetwork import kCFNetworkProxiesHTTPSEnable, kCFNetworkProxiesHTTPEnable + +from Foundation import (NSBundle, NSRunLoop, NSDate, + NSObject, NSURL, NSURLConnection, + NSMutableURLRequest, + NSURLRequestReloadIgnoringLocalCacheData, + NSURLResponseUnknownLength, + NSLog, + NSURLCredential, NSURLCredentialPersistenceNone, + NSPropertyListSerialization, + NSPropertyListMutableContainersAndLeaves, + NSPropertyListXMLFormat_v1_0) try: from Foundation import NSURLSession, NSURLSessionConfiguration @@ -176,6 +178,7 @@ def initWithOptions_(self, options): return self.follow_redirects = options.get('follow_redirects', False) + self.ignore_system_proxy = options.get('ignore_system_proxy', False) self.destination_path = options.get('file') self.can_resume = options.get('can_resume', False) self.url = options.get('url') @@ -244,6 +247,13 @@ def start(self): if NSURLSESSION_AVAILABLE: configuration = \ NSURLSessionConfiguration.defaultSessionConfiguration() + + # optional: ignore system http/https proxies (10.9+ only) + if self.ignore_system_proxy is True: + configuration.setConnectionProxyDictionary_( + {kCFNetworkProxiesHTTPEnable: False, + kCFNetworkProxiesHTTPSEnable: False}) + # set minumum supported TLS protocol (defaults to TLS1) configuration.setTLSMinimumSupportedProtocol_( self.minimum_tls_protocol) @@ -466,7 +476,7 @@ def connection_didReceiveResponse_(self, connection, response): def handleRedirect_newRequest_withCompletionHandler_( self, response, request, completionHandler): '''Handle the redirect request''' - if response == None: + if response is None: # the request has changed the NSURLRequest in order to standardize # its format, for example, changing a request for # http://www.apple.com to http://www.apple.com/. This occurs because @@ -493,7 +503,7 @@ def handleRedirect_newRequest_withCompletionHandler_( newParsedURL = urlparse(newURL) # This code was largely based on the work of Andreas Fuchs # (https://github.com/munki/munki/pull/465) - if self.follow_redirects == True or self.follow_redirects == 'all': + if self.follow_redirects is True or self.follow_redirects == 'all': # Allow the redirect self.log('Allowing redirect to: %s' % newURL) if completionHandler: