Refuse carriage return in header value
See bug #1188896. Comparing with Curl and Django, they both refuse carriage returns in header values, so the request() method on the HTTP(S)Connection instance returned by swiftclient.client.http_connection() will raise an InvalidHeadersException if any of the headers to be sent contain a newline. Drive-by fix for a couple of header values which were integers instead of strings (Content-Length getting set to zero). Fixes bug #1188896 Change-Id: Ic6afdb92882284f843aacb06d20f682ddcb47151
This commit is contained in:
parent
65e5ef7b81
commit
7d88d14def
@ -76,6 +76,17 @@ def quote(value, safe='/'):
|
||||
return value
|
||||
|
||||
|
||||
def validate_headers(headers):
|
||||
if headers:
|
||||
for key, value in headers.iteritems():
|
||||
if '\n' in value:
|
||||
raise InvalidHeadersException("%r header contained a "
|
||||
"newline" % key)
|
||||
if '\r' in value:
|
||||
raise InvalidHeadersException("%r header contained a "
|
||||
"carriage return" % key)
|
||||
|
||||
|
||||
def encode_utf8(value):
|
||||
if isinstance(value, unicode):
|
||||
value = value.encode('utf8')
|
||||
@ -91,6 +102,10 @@ except ImportError:
|
||||
from json import loads as json_loads
|
||||
|
||||
|
||||
class InvalidHeadersException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ClientException(Exception):
|
||||
|
||||
def __init__(self, msg, http_scheme='', http_host='', http_port='',
|
||||
@ -187,6 +202,7 @@ def http_connection(url, proxy=None, ssl_compression=True):
|
||||
|
||||
@wraps(func)
|
||||
def request_escaped(method, url, body=None, headers=None):
|
||||
validate_headers(headers)
|
||||
url = encode_utf8(url)
|
||||
if body:
|
||||
body = encode_utf8(body)
|
||||
@ -635,7 +651,7 @@ def put_container(url, token, container, headers=None, http_conn=None,
|
||||
headers = {}
|
||||
headers['X-Auth-Token'] = token
|
||||
if not 'content-length' in (k.lower() for k in headers):
|
||||
headers['Content-Length'] = 0
|
||||
headers['Content-Length'] = '0'
|
||||
conn.request(method, path, '', headers)
|
||||
resp = conn.getresponse()
|
||||
body = resp.read()
|
||||
@ -675,7 +691,7 @@ def post_container(url, token, container, headers, http_conn=None,
|
||||
method = 'POST'
|
||||
headers['X-Auth-Token'] = token
|
||||
if not 'content-length' in (k.lower() for k in headers):
|
||||
headers['Content-Length'] = 0
|
||||
headers['Content-Length'] = '0'
|
||||
conn.request(method, path, '', headers)
|
||||
resp = conn.getresponse()
|
||||
body = resp.read()
|
||||
|
@ -193,6 +193,18 @@ class TestHttpHelpers(MockHttpTest):
|
||||
url = 'ftp://www.test.com'
|
||||
self.assertRaises(c.ClientException, c.http_connection, url)
|
||||
|
||||
def test_validate_headers(self):
|
||||
headers = {'key': 'value'}
|
||||
self.assertEquals(c.validate_headers(headers), None)
|
||||
|
||||
headers = {'key': 'value1\nvalue2'}
|
||||
self.assertRaises(c.InvalidHeadersException, c.validate_headers,
|
||||
headers)
|
||||
|
||||
headers = {'key': 'value1\rvalue2'}
|
||||
self.assertRaises(c.InvalidHeadersException, c.validate_headers,
|
||||
headers)
|
||||
|
||||
# TODO: following tests are placeholders, need more tests, better coverage
|
||||
|
||||
|
||||
@ -595,7 +607,7 @@ class TestPostObject(MockHttpTest):
|
||||
u'\u5929\u7a7a\u4e2d\u7684\u4e4c\u4e91',
|
||||
u'\u5929\u7a7a\u4e2d\u7684\u4e4c\u4e91')
|
||||
headers = {'X-Header1': u'\u5929\u7a7a\u4e2d\u7684\u4e4c\u4e91',
|
||||
'X-2': 1, 'X-3': {'a': 'b'}, 'a-b': '.x:yz mn:kl:qr'}
|
||||
'X-2': '1', 'X-3': {'a': 'b'}, 'a-b': '.x:yz mn:kl:qr'}
|
||||
|
||||
resp = MockHttpResponse()
|
||||
conn[1].getresponse = resp.fake_response
|
||||
|
Loading…
x
Reference in New Issue
Block a user