diff --git a/glanceclient/common/http.py b/glanceclient/common/http.py index 7c8c0f4c..0564df62 100644 --- a/glanceclient/common/http.py +++ b/glanceclient/common/http.py @@ -18,6 +18,7 @@ import errno import hashlib import httplib import logging +import posixpath import socket import StringIO import struct @@ -190,7 +191,20 @@ class HTTPClient(object): try: if self.endpoint_path: - url = urlparse.urljoin(self.endpoint_path, url) + # NOTE(yuyangbj): this method _http_request could either be + # called by API layer, or be called recursively with + # redirection. For example, url would be '/v1/images/detail' + # from API layer, but url would be 'https://example.com:92/ + # v1/images/detail' from recursion. + # See bug #1230032 and bug #1208618. + if url is not None: + all_parts = urlparse.urlparse(url) + if not (all_parts.scheme and all_parts.netloc): + norm_parse = posixpath.normpath + url = norm_parse('/'.join([self.endpoint_path, url])) + else: + url = self.endpoint_path + conn_url = urlparse.urlsplit(url).geturl() # Note(flaper87): Ditto, headers / url # encoding to make httplib happy. diff --git a/tests/test_http.py b/tests/test_http.py index 81455468..8bc262d5 100644 --- a/tests/test_http.py +++ b/tests/test_http.py @@ -168,6 +168,34 @@ class TestClient(testtools.TestCase): resp, body = self.client.raw_request('GET', '/v1/images/detail') self.assertEqual(resp, fake) + def test_customized_path_raw_request(self): + """ + Verify the customized path being used for HTTP requests + reflects accurately + """ + + def check_request(method, path, **kwargs): + self.assertEqual(method, 'GET') + self.assertEqual(path, '/customized-path/v1/images/detail') + + # NOTE(yuyangbj): see bug 1230032 to get more info + endpoint = 'http://example.com:9292/customized-path' + client = http.HTTPClient(endpoint, token=u'abc123') + self.assertEqual(client.endpoint_path, '/customized-path') + + httplib.HTTPConnection.request( + mox.IgnoreArg(), + mox.IgnoreArg(), + headers=mox.IgnoreArg()).WithSideEffects(check_request) + + # fake the response returned by httplib + fake = utils.FakeResponse({}, StringIO.StringIO('Ok')) + httplib.HTTPConnection.getresponse().AndReturn(fake) + self.mock.ReplayAll() + + resp, body = client.raw_request('GET', '/v1/images/detail') + self.assertEqual(resp, fake) + def test_connection_refused_raw_request(self): """ Should receive a CommunicationError if connection refused.