Hello community, here is the log from the commit of package python-httplib2 for openSUSE:Factory checked in at 2020-04-09 23:14:19 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-httplib2 (Old) and /work/SRC/openSUSE:Factory/.python-httplib2.new.3248 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-httplib2" Thu Apr 9 23:14:19 2020 rev:45 rq:791798 version:0.17.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-httplib2/python-httplib2.changes 2019-11-04 17:04:44.780154718 +0100 +++ /work/SRC/openSUSE:Factory/.python-httplib2.new.3248/python-httplib2.changes 2020-04-09 23:14:20.522205905 +0200 @@ -1,0 +2,14 @@ +Mon Apr 6 14:02:25 UTC 2020 - Marketa Calabkova <mcalabk...@suse.com> + +- Update to 0.17.1 + * python3: no_proxy was not checked with https + * feature: Http().redirect_codes set, works after follow(_all)_redirects check + This allows one line workaround for old gcloud library that uses 308 + response without redirect semantics. + * IMPORTANT cache invalidation change, fix 307 keep method, add 308 Redirects + * proxy: username/password as str compatible with pysocks + * python2: regression in connect() error handling + * add support for password protected certificate files + * feature: Http.close() to clean persistent connections and sensitive data + +------------------------------------------------------------------- Old: ---- httplib2-0.14.0.tar.gz New: ---- httplib2-0.17.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-httplib2.spec ++++++ --- /var/tmp/diff_new_pack.MrWjrw/_old 2020-04-09 23:14:21.166206277 +0200 +++ /var/tmp/diff_new_pack.MrWjrw/_new 2020-04-09 23:14:21.170206280 +0200 @@ -1,7 +1,7 @@ # # spec file for package python-httplib2 # -# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany. +# Copyright (c) 2020 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -20,7 +20,7 @@ # Tests require network connection %bcond_with tests Name: python-httplib2 -Version: 0.14.0 +Version: 0.17.1 Release: 0 Summary: A Python HTTP client library License: MIT AND Apache-2.0 AND (MPL-1.1 OR GPL-2.0-or-later OR LGPL-2.1-or-later) ++++++ httplib2-0.14.0.tar.gz -> httplib2-0.17.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httplib2-0.14.0/PKG-INFO new/httplib2-0.17.1/PKG-INFO --- old/httplib2-0.14.0/PKG-INFO 2019-09-27 06:52:00.000000000 +0200 +++ new/httplib2-0.17.1/PKG-INFO 2020-04-02 20:28:49.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: httplib2 -Version: 0.14.0 +Version: 0.17.1 Summary: A comprehensive HTTP client library. Home-page: https://github.com/httplib2/httplib2 Author: Joe Gregorio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httplib2-0.14.0/python2/httplib2/__init__.py new/httplib2-0.17.1/python2/httplib2/__init__.py --- old/httplib2-0.14.0/python2/httplib2/__init__.py 2019-09-27 06:51:36.000000000 +0200 +++ new/httplib2-0.17.1/python2/httplib2/__init__.py 2020-04-02 20:28:24.000000000 +0200 @@ -19,7 +19,7 @@ "Alex Yu", ] __license__ = "MIT" -__version__ = '0.14.0' +__version__ = '0.17.1' import base64 import calendar @@ -76,7 +76,7 @@ def _ssl_wrap_socket( - sock, key_file, cert_file, disable_validation, ca_certs, ssl_version, hostname + sock, key_file, cert_file, disable_validation, ca_certs, ssl_version, hostname, key_password ): if disable_validation: cert_reqs = ssl.CERT_NONE @@ -90,11 +90,16 @@ context.verify_mode = cert_reqs context.check_hostname = cert_reqs != ssl.CERT_NONE if cert_file: - context.load_cert_chain(cert_file, key_file) + if key_password: + context.load_cert_chain(cert_file, key_file, key_password) + else: + context.load_cert_chain(cert_file, key_file) if ca_certs: context.load_verify_locations(ca_certs) return context.wrap_socket(sock, server_hostname=hostname) else: + if key_password: + raise NotSupportedOnThisPlatform("Certificate with password is not supported.") return ssl.wrap_socket( sock, keyfile=key_file, @@ -106,7 +111,7 @@ def _ssl_wrap_socket_unsupported( - sock, key_file, cert_file, disable_validation, ca_certs, ssl_version, hostname + sock, key_file, cert_file, disable_validation, ca_certs, ssl_version, hostname, key_password ): if not disable_validation: raise CertificateValidationUnsupported( @@ -114,6 +119,8 @@ "the ssl module installed. To avoid this error, install " "the ssl module, or explicity disable validation." ) + if key_password: + raise NotSupportedOnThisPlatform("Certificate with password is not supported.") ssl_sock = socket.ssl(sock, key_file, cert_file) return httplib.FakeSocket(sock, ssl_sock) @@ -284,6 +291,12 @@ "upgrade", ] +# https://tools.ietf.org/html/rfc7231#section-8.1.3 +SAFE_METHODS = ("GET", "HEAD") # TODO add "OPTIONS", "TRACE" + +# To change, assign to `Http().redirect_codes` +REDIRECT_CODES = frozenset((300, 301, 302, 303, 307, 308)) + def _get_end2end_headers(response): hopbyhop = list(HOP_BY_HOP) @@ -978,8 +991,13 @@ class KeyCerts(Credentials): """Identical to Credentials except that name/password are mapped to key/cert.""" + def add(self, key, cert, domain, password): + self.credentials.append((domain.lower(), key, cert, password)) - pass + def iter(self, domain): + for (cdomain, key, cert, password) in self.credentials: + if cdomain == "" or domain == cdomain: + yield (key, cert, password) class AllHosts(object): @@ -1150,7 +1168,6 @@ raise ProxiesUnavailableError( "Proxy support missing but proxy use was requested!" ) - msg = "getaddrinfo returns an empty list" if self.proxy_info and self.proxy_info.isgood(): use_proxy = True proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers = ( @@ -1165,6 +1182,8 @@ host = self.host port = self.port + socket_err = None + for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM): af, socktype, proto, canonname, sa = res try: @@ -1206,7 +1225,8 @@ self.sock.connect((self.host, self.port) + sa[2:]) else: self.sock.connect(sa) - except socket.error as msg: + except socket.error as e: + socket_err = e if self.debuglevel > 0: print("connect fail: (%s, %s)" % (self.host, self.port)) if use_proxy: @@ -1229,7 +1249,7 @@ continue break if not self.sock: - raise socket.error(msg) + raise socket_err or socket.error("getaddrinfo returns an empty list") class HTTPSConnectionWithTimeout(httplib.HTTPSConnection): @@ -1253,10 +1273,19 @@ ca_certs=None, disable_ssl_certificate_validation=False, ssl_version=None, + key_password=None, ): - httplib.HTTPSConnection.__init__( - self, host, port=port, key_file=key_file, cert_file=cert_file, strict=strict - ) + if key_password: + httplib.HTTPSConnection.__init__(self, host, port=port, strict=strict) + self._context.load_cert_chain(cert_file, key_file, key_password) + self.key_file = key_file + self.cert_file = cert_file + self.key_password = key_password + else: + httplib.HTTPSConnection.__init__( + self, host, port=port, key_file=key_file, cert_file=cert_file, strict=strict + ) + self.key_password = None self.timeout = timeout self.proxy_info = proxy_info if ca_certs is None: @@ -1317,7 +1346,6 @@ def connect(self): "Connect to a host on a given (SSL) port." - msg = "getaddrinfo returns an empty list" if self.proxy_info and self.proxy_info.isgood(): use_proxy = True proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers = ( @@ -1332,6 +1360,8 @@ host = self.host port = self.port + socket_err = None + address_info = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM) for family, socktype, proto, canonname, sockaddr in address_info: try: @@ -1366,6 +1396,7 @@ self.ca_certs, self.ssl_version, self.host, + self.key_password, ) if self.debuglevel > 0: print("connect: (%s, %s)" % (self.host, self.port)) @@ -1413,7 +1444,8 @@ raise except (socket.timeout, socket.gaierror): raise - except socket.error as msg: + except socket.error as e: + socket_err = e if self.debuglevel > 0: print("connect fail: (%s, %s)" % (self.host, self.port)) if use_proxy: @@ -1436,7 +1468,7 @@ continue break if not self.sock: - raise socket.error(msg) + raise socket_err or socket.error("getaddrinfo returns an empty list") SCHEME_TO_CONNECTION = { @@ -1515,7 +1547,10 @@ ca_certs=None, disable_ssl_certificate_validation=False, ssl_version=None, + key_password=None, ): + if key_password: + raise NotSupportedOnThisPlatform("Certificate with password is not supported.") httplib.HTTPSConnection.__init__( self, host, @@ -1632,10 +1667,14 @@ # If set to False then no redirects are followed, even safe ones. self.follow_redirects = True + self.redirect_codes = REDIRECT_CODES + # Which HTTP methods do we apply optimistic concurrency to, i.e. # which methods get an "if-match:" etag header added to them. self.optimistic_concurrency_methods = ["PUT", "PATCH"] + self.safe_methods = list(SAFE_METHODS) + # If 'follow_redirects' is True, and this is set to True then # all redirecs are followed, including unsafe ones. self.follow_all_redirects = False @@ -1649,6 +1688,16 @@ # Keep Authorization: headers on a redirect. self.forward_authorization_headers = False + def close(self): + """Close persistent connections, clear sensitive data. + Not thread-safe, requires external synchronization against concurrent requests. + """ + existing, self.connections = self.connections, {} + for _, c in existing.iteritems(): + c.close() + self.certificates.clear() + self.clear_credentials() + def __getstate__(self): state_dict = copy.copy(self.__dict__) # In case request is augmented by some foreign object such as @@ -1680,10 +1729,10 @@ any time a request requires authentication.""" self.credentials.add(name, password, domain) - def add_certificate(self, key, cert, domain): + def add_certificate(self, key, cert, domain, password=None): """Add a key and cert that will be used any time a request requires authentication.""" - self.certificates.add(key, cert, domain) + self.certificates.add(key, cert, domain, password) def clear_credentials(self): """Remove all the names and passwords @@ -1819,10 +1868,10 @@ if ( self.follow_all_redirects - or (method in ["GET", "HEAD"]) - or response.status == 303 + or method in self.safe_methods + or response.status in (303, 308) ): - if self.follow_redirects and response.status in [300, 301, 302, 303, 307]: + if self.follow_redirects and response.status in self.redirect_codes: # Pick out the location header and basically start from the beginning # remembering first to strip the ETag header and decrement our 'depth' if redirections: @@ -1842,7 +1891,7 @@ response["location"] = urlparse.urljoin( absolute_uri, location ) - if response.status == 301 and method in ["GET", "HEAD"]: + if response.status == 308 or (response.status == 301 and method in self.safe_methods): response["-x-permanent-redirect-url"] = response["location"] if "content-location" not in response: response["content-location"] = absolute_uri @@ -1879,7 +1928,7 @@ response, content, ) - elif response.status in [200, 203] and method in ["GET", "HEAD"]: + elif response.status in [200, 203] and method in self.safe_methods: # Don't cache 206's since we aren't going to handle byte range requests if "content-location" not in response: response["content-location"] = absolute_uri @@ -1925,7 +1974,7 @@ a string that contains the response entity body. """ conn_key = '' - + try: if headers is None: headers = {} @@ -1958,6 +2007,7 @@ ca_certs=self.ca_certs, disable_ssl_certificate_validation=self.disable_ssl_certificate_validation, ssl_version=self.ssl_version, + key_password=certs[0][2], ) else: conn = self.connections[conn_key] = connection_type( @@ -1978,6 +2028,7 @@ headers["accept-encoding"] = "gzip, deflate" info = email.Message.Message() + cachekey = None cached_value = None if self.cache: cachekey = defrag_uri.encode("utf-8") @@ -1998,8 +2049,6 @@ self.cache.delete(cachekey) cachekey = None cached_value = None - else: - cachekey = None if ( method in self.optimistic_concurrency_methods @@ -2011,13 +2060,15 @@ # http://www.w3.org/1999/04/Editing/ headers["if-match"] = info["etag"] - if method not in ["GET", "HEAD"] and self.cache and cachekey: - # RFC 2616 Section 13.10 + # https://tools.ietf.org/html/rfc7234 + # A cache MUST invalidate the effective Request URI as well as [...] Location and Content-Location + # when a non-error status code is received in response to an unsafe request method. + if self.cache and cachekey and method not in self.safe_methods: self.cache.delete(cachekey) # Check the vary header in the cache to see if this request # matches what varies in the cache. - if method in ["GET", "HEAD"] and "vary" in info: + if method in self.safe_methods and "vary" in info: vary = info["vary"] vary_headers = vary.lower().replace(" ", "").split(",") for header in vary_headers: @@ -2028,11 +2079,14 @@ break if ( - cached_value - and method in ["GET", "HEAD"] - and self.cache + self.cache + and cached_value + and (method in self.safe_methods or info["status"] == "308") and "range" not in headers ): + redirect_method = method + if info["status"] not in ("307", "308"): + redirect_method = "GET" if "-x-permanent-redirect-url" in info: # Should cached permanent redirects be counted in our redirection count? For now, yes. if redirections <= 0: @@ -2043,7 +2097,7 @@ ) (response, new_content) = self.request( info["-x-permanent-redirect-url"], - method="GET", + method=redirect_method, headers=headers, redirections=redirections - 1, ) @@ -2140,7 +2194,7 @@ conn = self.connections.pop(conn_key, None) if conn: conn.close() - + if self.force_exception_to_status_code: if isinstance(e, HttpLib2ErrorWithResponse): response = e.response diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httplib2-0.14.0/python2/httplib2/socks.py new/httplib2-0.17.1/python2/httplib2/socks.py --- old/httplib2-0.14.0/python2/httplib2/socks.py 2019-09-27 06:51:36.000000000 +0200 +++ new/httplib2-0.17.1/python2/httplib2/socks.py 2020-04-02 20:28:24.000000000 +0200 @@ -238,7 +238,15 @@ headers - Additional or modified headers for the proxy connect request. """ - self.__proxy = (proxytype, addr, port, rdns, username, password, headers) + self.__proxy = ( + proxytype, + addr, + port, + rdns, + username.encode() if username else None, + password.encode() if password else None, + headers, + ) def __negotiatesocks5(self, destaddr, destport): """__negotiatesocks5(self,destaddr,destport) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httplib2-0.14.0/python3/httplib2/__init__.py new/httplib2-0.17.1/python3/httplib2/__init__.py --- old/httplib2-0.14.0/python3/httplib2/__init__.py 2019-09-27 06:51:36.000000000 +0200 +++ new/httplib2-0.17.1/python3/httplib2/__init__.py 2020-04-02 20:28:24.000000000 +0200 @@ -15,7 +15,7 @@ "Alex Yu", ] __license__ = "MIT" -__version__ = '0.14.0' +__version__ = '0.17.1' import base64 import calendar @@ -161,6 +161,13 @@ "upgrade", ] +# https://tools.ietf.org/html/rfc7231#section-8.1.3 +SAFE_METHODS = ("GET", "HEAD", "OPTIONS", "TRACE") + +# To change, assign to `Http().redirect_codes` +REDIRECT_CODES = frozenset((300, 301, 302, 303, 307, 308)) + + from httplib2 import certs CA_CERTS = certs.where() @@ -175,7 +182,7 @@ def _build_ssl_context( disable_ssl_certificate_validation, ca_certs, cert_file=None, key_file=None, - maximum_version=None, minimum_version=None, + maximum_version=None, minimum_version=None, key_password=None, ): if not hasattr(ssl, "SSLContext"): raise RuntimeError("httplib2 requires Python 3.2+ for ssl.SSLContext") @@ -207,7 +214,7 @@ context.load_verify_locations(ca_certs) if cert_file: - context.load_cert_chain(cert_file, key_file) + context.load_cert_chain(cert_file, key_file, key_password) return context @@ -315,7 +322,7 @@ # Whether to use a strict mode to parse WWW-Authenticate headers # Might lead to bad results in case of ill-formed header value, # so disabled by default, falling back to relaxed parsing. -# Set to true to turn on, usefull for testing servers. +# Set to true to turn on, useful for testing servers. USE_WWW_AUTH_STRICT_PARSING = 0 # In regex below: @@ -959,8 +966,13 @@ class KeyCerts(Credentials): """Identical to Credentials except that name/password are mapped to key/cert.""" + def add(self, key, cert, domain, password): + self.credentials.append((domain.lower(), key, cert, password)) - pass + def iter(self, domain): + for (cdomain, key, cert, password) in self.credentials: + if cdomain == "" or domain == cdomain: + yield (key, cert, password) class AllHosts(object): @@ -999,10 +1011,10 @@ proxy_headers: Additional or modified headers for the proxy connect request. """ - if isinstance(proxy_user, str): - proxy_user = proxy_user.encode() - if isinstance(proxy_pass, str): - proxy_pass = proxy_pass.encode() + if isinstance(proxy_user, bytes): + proxy_user = proxy_user.decode() + if isinstance(proxy_pass, bytes): + proxy_pass = proxy_pass.decode() self.proxy_type, self.proxy_host, self.proxy_port, self.proxy_rdns, self.proxy_user, self.proxy_pass, self.proxy_headers = ( proxy_type, proxy_host, @@ -1245,6 +1257,7 @@ disable_ssl_certificate_validation=False, tls_maximum_version=None, tls_minimum_version=None, + key_password=None, ): self.disable_ssl_certificate_validation = disable_ssl_certificate_validation @@ -1257,19 +1270,21 @@ context = _build_ssl_context( self.disable_ssl_certificate_validation, self.ca_certs, cert_file, key_file, maximum_version=tls_maximum_version, minimum_version=tls_minimum_version, + key_password=key_password, ) super(HTTPSConnectionWithTimeout, self).__init__( host, port=port, - key_file=key_file, - cert_file=cert_file, timeout=timeout, context=context, ) + self.key_file = key_file + self.cert_file = cert_file + self.key_password = key_password def connect(self): """Connect to a host on a given (SSL) port.""" - if self.proxy_info and self.proxy_info.isgood(): + if self.proxy_info and self.proxy_info.isgood() and self.proxy_info.applies_to(self.host): use_proxy = True proxy_type, proxy_host, proxy_port, proxy_rdns, proxy_user, proxy_pass, proxy_headers = ( self.proxy_info.astuple() @@ -1459,10 +1474,14 @@ # If set to False then no redirects are followed, even safe ones. self.follow_redirects = True + self.redirect_codes = REDIRECT_CODES + # Which HTTP methods do we apply optimistic concurrency to, i.e. # which methods get an "if-match:" etag header added to them. self.optimistic_concurrency_methods = ["PUT", "PATCH"] + self.safe_methods = list(SAFE_METHODS) + # If 'follow_redirects' is True, and this is set to True then # all redirecs are followed, including unsafe ones. self.follow_all_redirects = False @@ -1476,6 +1495,16 @@ # Keep Authorization: headers on a redirect. self.forward_authorization_headers = False + def close(self): + """Close persistent connections, clear sensitive data. + Not thread-safe, requires external synchronization against concurrent requests. + """ + existing, self.connections = self.connections, {} + for _, c in existing.items(): + c.close() + self.certificates.clear() + self.clear_credentials() + def __getstate__(self): state_dict = copy.copy(self.__dict__) # In case request is augmented by some foreign object such as @@ -1507,10 +1536,10 @@ any time a request requires authentication.""" self.credentials.add(name, password, domain) - def add_certificate(self, key, cert, domain): + def add_certificate(self, key, cert, domain, password=None): """Add a key and cert that will be used any time a request requires authentication.""" - self.certificates.add(key, cert, domain) + self.certificates.add(key, cert, domain, password) def clear_credentials(self): """Remove all the names and passwords @@ -1645,10 +1674,10 @@ if ( self.follow_all_redirects - or (method in ["GET", "HEAD"]) - or response.status == 303 + or method in self.safe_methods + or response.status in (303, 308) ): - if self.follow_redirects and response.status in [300, 301, 302, 303, 307]: + if self.follow_redirects and response.status in self.redirect_codes: # Pick out the location header and basically start from the beginning # remembering first to strip the ETag header and decrement our 'depth' if redirections: @@ -1668,7 +1697,7 @@ response["location"] = urllib.parse.urljoin( absolute_uri, location ) - if response.status == 301 and method in ["GET", "HEAD"]: + if response.status == 308 or (response.status == 301 and (method in self.safe_methods)): response["-x-permanent-redirect-url"] = response["location"] if "content-location" not in response: response["content-location"] = absolute_uri @@ -1705,7 +1734,7 @@ response, content, ) - elif response.status in [200, 203] and method in ["GET", "HEAD"]: + elif response.status in [200, 203] and method in self.safe_methods: # Don't cache 206's since we aren't going to handle byte range requests if "content-location" not in response: response["content-location"] = absolute_uri @@ -1782,6 +1811,7 @@ disable_ssl_certificate_validation=self.disable_ssl_certificate_validation, tls_maximum_version=self.tls_maximum_version, tls_minimum_version=self.tls_minimum_version, + key_password=certs[0][2], ) else: conn = self.connections[conn_key] = connection_type( @@ -1803,6 +1833,7 @@ headers["accept-encoding"] = "gzip, deflate" info = email.message.Message() + cachekey = None cached_value = None if self.cache: cachekey = defrag_uri @@ -1820,8 +1851,6 @@ self.cache.delete(cachekey) cachekey = None cached_value = None - else: - cachekey = None if ( method in self.optimistic_concurrency_methods @@ -1833,13 +1862,15 @@ # http://www.w3.org/1999/04/Editing/ headers["if-match"] = info["etag"] - if method not in ["GET", "HEAD"] and self.cache and cachekey: - # RFC 2616 Section 13.10 + # https://tools.ietf.org/html/rfc7234 + # A cache MUST invalidate the effective Request URI as well as [...] Location and Content-Location + # when a non-error status code is received in response to an unsafe request method. + if self.cache and cachekey and method not in self.safe_methods: self.cache.delete(cachekey) # Check the vary header in the cache to see if this request # matches what varies in the cache. - if method in ["GET", "HEAD"] and "vary" in info: + if method in self.safe_methods and "vary" in info: vary = info["vary"] vary_headers = vary.lower().replace(" ", "").split(",") for header in vary_headers: @@ -1850,11 +1881,14 @@ break if ( - cached_value - and method in ["GET", "HEAD"] - and self.cache + self.cache + and cached_value + and (method in self.safe_methods or info["status"] == "308") and "range" not in headers ): + redirect_method = method + if info["status"] not in ("307", "308"): + redirect_method = "GET" if "-x-permanent-redirect-url" in info: # Should cached permanent redirects be counted in our redirection count? For now, yes. if redirections <= 0: @@ -1865,7 +1899,7 @@ ) (response, new_content) = self.request( info["-x-permanent-redirect-url"], - method="GET", + method=redirect_method, headers=headers, redirections=redirections - 1, ) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httplib2-0.14.0/python3/httplib2/socks.py new/httplib2-0.17.1/python3/httplib2/socks.py --- old/httplib2-0.14.0/python3/httplib2/socks.py 2019-09-27 06:51:36.000000000 +0200 +++ new/httplib2-0.17.1/python3/httplib2/socks.py 2020-04-02 20:28:24.000000000 +0200 @@ -238,7 +238,15 @@ headers - Additional or modified headers for the proxy connect request. """ - self.__proxy = (proxytype, addr, port, rdns, username, password, headers) + self.__proxy = ( + proxytype, + addr, + port, + rdns, + username.encode() if username else None, + password.encode() if password else None, + headers, + ) def __negotiatesocks5(self, destaddr, destport): """__negotiatesocks5(self,destaddr,destport) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httplib2-0.14.0/python3/httplib2.egg-info/PKG-INFO new/httplib2-0.17.1/python3/httplib2.egg-info/PKG-INFO --- old/httplib2-0.14.0/python3/httplib2.egg-info/PKG-INFO 2019-09-27 06:52:00.000000000 +0200 +++ new/httplib2-0.17.1/python3/httplib2.egg-info/PKG-INFO 2020-04-02 20:28:48.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: httplib2 -Version: 0.14.0 +Version: 0.17.1 Summary: A comprehensive HTTP client library. Home-page: https://github.com/httplib2/httplib2 Author: Joe Gregorio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/httplib2-0.14.0/setup.py new/httplib2-0.17.1/setup.py --- old/httplib2-0.14.0/setup.py 2019-09-27 06:51:36.000000000 +0200 +++ new/httplib2-0.17.1/setup.py 2020-04-02 20:28:24.000000000 +0200 @@ -4,7 +4,7 @@ import sys pkgdir = {"": "python%s" % sys.version_info[0]} -VERSION = '0.14.0' +VERSION = '0.17.1' # `python setup.py test` uses existing Python environment, no virtualenv, no pip.