diff --git a/gerrit_util.py b/gerrit_util.py index 2c0267e884..7d4283558e 100755 --- a/gerrit_util.py +++ b/gerrit_util.py @@ -11,7 +11,7 @@ https://gerrit-review.googlesource.com/Documentation/rest-api.html import base64 import contextlib import cookielib -import httplib # Still used for its constants. +import httplib import json import logging import netrc @@ -27,7 +27,6 @@ import urlparse from cStringIO import StringIO import gclient_utils -from third_party import httplib2 LOGGER = logging.getLogger() TRY_LIMIT = 5 @@ -63,8 +62,10 @@ def _QueryString(param_dict, first_param=None): def GetConnectionClass(protocol=None): if protocol is None: protocol = GERRIT_PROTOCOL - if protocol in ('http', 'https'): - return httplib2.Http + if protocol == 'https': + return httplib.HTTPSConnection + elif protocol == 'http': + return httplib.HTTPConnection else: raise RuntimeError( "Don't know how to work with protocol '%s'" % protocol) @@ -228,11 +229,11 @@ class GceAuthenticator(Authenticator): def _test_is_gce(cls): # Based on https://cloud.google.com/compute/docs/metadata#runninggce try: - resp, _ = cls._get(cls._INFO_URL) + resp = cls._get(cls._INFO_URL) except socket.error: # Could not resolve URL. return False - return resp.get('metadata-flavor') == 'Google' + return resp.getheader('Metadata-Flavor', None) == 'Google' @staticmethod def _get(url, **kwargs): @@ -246,11 +247,12 @@ class GceAuthenticator(Authenticator): next_delay_sec *= 2 p = urlparse.urlparse(url) - c = GetConnectionClass(protocol=p.scheme)() - resp, contents = c.request(url, 'GET', **kwargs) + c = GetConnectionClass(protocol=p.scheme)(p.netloc) + c.request('GET', url, **kwargs) + resp = c.getresponse() LOGGER.debug('GET [%s] #%d/%d (%d)', url, i+1, TRY_LIMIT, resp.status) if resp.status < httplib.INTERNAL_SERVER_ERROR: - return (resp, contents) + return resp @classmethod def _get_token_dict(cls): @@ -259,10 +261,10 @@ class GceAuthenticator(Authenticator): if cls._token_expiration < time.time() - 25: return cls._token_cache - resp, contents = cls._get(cls._ACQUIRE_URL, headers=cls._ACQUIRE_HEADERS) + resp = cls._get(cls._ACQUIRE_URL, headers=cls._ACQUIRE_HEADERS) if resp.status != httplib.OK: return None - cls._token_cache = json.loads(contents) + cls._token_cache = json.load(resp) cls._token_expiration = cls._token_cache['expires_in'] + time.time() return cls._token_cache @@ -304,11 +306,12 @@ def CreateHttpConn(host, path, reqtype='GET', headers=None, body=None): conn = GetConnectionClass()(host) conn.req_host = host conn.req_params = { - 'uri': urlparse.urljoin('%s://%s' % (GERRIT_PROTOCOL, host), url), + 'url': url, 'method': reqtype, 'headers': headers, 'body': body, } + conn.request(**conn.req_params) return conn @@ -316,7 +319,7 @@ def ReadHttpResponse(conn, expect_status=200, ignore_404=True): """Reads an http response from a connection into a string buffer. Args: - conn: An Http object created by CreateHttpConn above. + conn: An HTTPSConnection or HTTPConnection created by CreateHttpConn, above. expect_status: Success is indicated by this status in the response. ignore_404: For many requests, gerrit-on-borg will return 404 if the request doesn't match the database contents. In most such cases, we @@ -326,10 +329,10 @@ def ReadHttpResponse(conn, expect_status=200, ignore_404=True): sleep_time = 0.5 for idx in range(TRY_LIMIT): - response, contents = conn.request(**conn.req_params) + response = conn.getresponse() # Check if this is an authentication issue. - www_authenticate = response.get('www-authenticate') + www_authenticate = response.getheader('www-authenticate') if (response.status in (httplib.UNAUTHORIZED, httplib.FOUND) and www_authenticate): auth_match = re.search('realm="([^"]+)"', www_authenticate, re.I) @@ -341,25 +344,31 @@ def ReadHttpResponse(conn, expect_status=200, ignore_404=True): # If response.status < 500 then the result is final; break retry loop. if response.status < 500: LOGGER.debug('got response %d for %s %s', response.status, - conn.req_params['method'], conn.req_params['uri']) + conn.req_params['method'], conn.req_params['url']) break # A status >=500 is assumed to be a possible transient error; retry. http_version = 'HTTP/%s' % ('1.1' if response.version == 11 else '1.0') LOGGER.warn('A transient error occurred while querying %s:\n' '%s %s %s\n' '%s %d %s', - conn.host, conn.req_params['method'], conn.req_params['uri'], + conn.host, conn.req_params['method'], conn.req_params['url'], http_version, http_version, response.status, response.reason) if TRY_LIMIT - idx > 1: LOGGER.warn('... will retry %d more times.', TRY_LIMIT - idx - 1) time.sleep(sleep_time) sleep_time = sleep_time * 2 + req_host = conn.req_host + req_params = conn.req_params + conn = GetConnectionClass()(req_host) + conn.req_host = req_host + conn.req_params = req_params + conn.request(**req_params) if ignore_404 and response.status == 404: return StringIO() if response.status != expect_status: - reason = '%s: %s' % (response.reason, contents) + reason = '%s: %s' % (response.reason, response.read()) raise GerritError(response.status, reason) - return StringIO(contents) + return StringIO(response.read()) def ReadHttpJsonResponse(conn, expect_status=200, ignore_404=True):