diff --git a/swift/common/bufferedhttp.py b/swift/common/bufferedhttp.py index 0fed79ed2e..e95b81bf8c 100644 --- a/swift/common/bufferedhttp.py +++ b/swift/common/bufferedhttp.py @@ -34,7 +34,7 @@ import socket import eventlet from eventlet.green.httplib import CONTINUE, HTTPConnection, HTTPMessage, \ HTTPResponse, HTTPSConnection, _UNKNOWN -from six.moves.urllib.parse import quote +from six.moves.urllib.parse import quote, parse_qsl, urlencode import six if six.PY2: @@ -292,6 +292,15 @@ def http_connect_raw(ipaddr, port, method, path, headers=None, else: conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port)) if query_string: + # Round trip to ensure proper quoting + if six.PY2: + query_string = urlencode(parse_qsl( + query_string, keep_blank_values=True)) + else: + query_string = urlencode( + parse_qsl(query_string, keep_blank_values=True, + encoding='latin1'), + encoding='latin1') path += '?' + query_string conn.path = path conn.putrequest(method, path, skip_host=(headers and 'Host' in headers)) diff --git a/test/unit/common/test_bufferedhttp.py b/test/unit/common/test_bufferedhttp.py index 7e0c9ec03e..38e62856cd 100644 --- a/test/unit/common/test_bufferedhttp.py +++ b/test/unit/common/test_bufferedhttp.py @@ -56,7 +56,8 @@ class TestBufferedHTTP(unittest.TestCase): b'RESPONSE') fp.flush() line = fp.readline() - path = b'/dev/' + expected_par + b'/path/..%25/?omg&no=%7f' + path = (b'/dev/' + expected_par + + b'/path/..%25/?omg=&no=%7F&%FF=%FF&no=%25ff') self.assertEqual( line, b'PUT ' + path + b' HTTP/1.1\r\n') @@ -83,7 +84,7 @@ class TestBufferedHTTP(unittest.TestCase): 'PUT', '/path/..%/', { 'content-length': 7, 'x-header': 'value'}, - query_string='omg&no=%7f') + query_string='omg&no=%7f&\xff=%ff&no=%25ff') conn.send(b'REQUEST\r\n') self.assertTrue(conn.sock.getsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY))