Skip to content

Commit 7d88d14

Browse files
Kun Huangdbishop
Kun Huang
authored andcommittedJul 12, 2013
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
1 parent 65e5ef7 commit 7d88d14

File tree

2 files changed

+31
-3
lines changed

2 files changed

+31
-3
lines changed
 

‎swiftclient/client.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,17 @@ def quote(value, safe='/'):
7676
return value
7777

7878

79+
def validate_headers(headers):
80+
if headers:
81+
for key, value in headers.iteritems():
82+
if '\n' in value:
83+
raise InvalidHeadersException("%r header contained a "
84+
"newline" % key)
85+
if '\r' in value:
86+
raise InvalidHeadersException("%r header contained a "
87+
"carriage return" % key)
88+
89+
7990
def encode_utf8(value):
8091
if isinstance(value, unicode):
8192
value = value.encode('utf8')
@@ -91,6 +102,10 @@ def encode_utf8(value):
91102
from json import loads as json_loads
92103

93104

105+
class InvalidHeadersException(Exception):
106+
pass
107+
108+
94109
class ClientException(Exception):
95110

96111
def __init__(self, msg, http_scheme='', http_host='', http_port='',
@@ -187,6 +202,7 @@ def request_wrapper(func):
187202

188203
@wraps(func)
189204
def request_escaped(method, url, body=None, headers=None):
205+
validate_headers(headers)
190206
url = encode_utf8(url)
191207
if body:
192208
body = encode_utf8(body)
@@ -635,7 +651,7 @@ def put_container(url, token, container, headers=None, http_conn=None,
635651
headers = {}
636652
headers['X-Auth-Token'] = token
637653
if not 'content-length' in (k.lower() for k in headers):
638-
headers['Content-Length'] = 0
654+
headers['Content-Length'] = '0'
639655
conn.request(method, path, '', headers)
640656
resp = conn.getresponse()
641657
body = resp.read()
@@ -675,7 +691,7 @@ def post_container(url, token, container, headers, http_conn=None,
675691
method = 'POST'
676692
headers['X-Auth-Token'] = token
677693
if not 'content-length' in (k.lower() for k in headers):
678-
headers['Content-Length'] = 0
694+
headers['Content-Length'] = '0'
679695
conn.request(method, path, '', headers)
680696
resp = conn.getresponse()
681697
body = resp.read()

‎tests/test_swiftclient.py

+13-1
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,18 @@ def test_http_connection(self):
193193
url = 'ftp://www.test.com'
194194
self.assertRaises(c.ClientException, c.http_connection, url)
195195

196+
def test_validate_headers(self):
197+
headers = {'key': 'value'}
198+
self.assertEquals(c.validate_headers(headers), None)
199+
200+
headers = {'key': 'value1\nvalue2'}
201+
self.assertRaises(c.InvalidHeadersException, c.validate_headers,
202+
headers)
203+
204+
headers = {'key': 'value1\rvalue2'}
205+
self.assertRaises(c.InvalidHeadersException, c.validate_headers,
206+
headers)
207+
196208
# TODO: following tests are placeholders, need more tests, better coverage
197209

198210

@@ -595,7 +607,7 @@ def test_unicode_ok(self):
595607
u'\u5929\u7a7a\u4e2d\u7684\u4e4c\u4e91',
596608
u'\u5929\u7a7a\u4e2d\u7684\u4e4c\u4e91')
597609
headers = {'X-Header1': u'\u5929\u7a7a\u4e2d\u7684\u4e4c\u4e91',
598-
'X-2': 1, 'X-3': {'a': 'b'}, 'a-b': '.x:yz mn:kl:qr'}
610+
'X-2': '1', 'X-3': {'a': 'b'}, 'a-b': '.x:yz mn:kl:qr'}
599611

600612
resp = MockHttpResponse()
601613
conn[1].getresponse = resp.fake_response

0 commit comments

Comments
 (0)