From faf71a1c2c5596c60b4f9e631b4c282c31cc9f3f Mon Sep 17 00:00:00 2001 From: Gustavo Carneiro Date: Fri, 18 May 2018 14:00:19 +0100 Subject: [PATCH] Don't throw away port number when parsing the Forwarded header #3009 --- CHANGES/3009.bugfix | 1 + aiohttp/web_request.py | 6 ++++-- tests/test_web_request.py | 14 ++++++++++++++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 CHANGES/3009.bugfix diff --git a/CHANGES/3009.bugfix b/CHANGES/3009.bugfix new file mode 100644 index 00000000000..c2e8e953df6 --- /dev/null +++ b/CHANGES/3009.bugfix @@ -0,0 +1 @@ +When parsing the Forwarded header, the optional port number is now preserved. diff --git a/aiohttp/web_request.py b/aiohttp/web_request.py index 17e9e43771d..06a93007fd9 100644 --- a/aiohttp/web_request.py +++ b/aiohttp/web_request.py @@ -52,7 +52,7 @@ class FileField: qdtext=_QDTEXT, quoted_pair=_QUOTED_PAIR) _FORWARDED_PAIR = ( - r'({token})=({token}|{quoted_string})'.format( + r'({token})=({token}|{quoted_string})(:\d{{1,4}})?'.format( token=_TOKEN, quoted_string=_QUOTED_STRING)) @@ -247,11 +247,13 @@ def forwarded(self): # bad syntax here, skip to next comma pos = field_value.find(',', pos) else: - (name, value) = match.groups() + (name, value, port) = match.groups() if value[0] == '"': # quoted string: remove quotes and unescape value = _QUOTED_PAIR_REPLACE_RE.sub(r'\1', value[1:-1]) + if port: + value += port elem[name.lower()] = value pos += len(match.group(0)) need_separator = True diff --git a/tests/test_web_request.py b/tests/test_web_request.py index 00c32655672..6c77b2def50 100644 --- a/tests/test_web_request.py +++ b/tests/test_web_request.py @@ -296,6 +296,20 @@ def test_single_forwarded_header(): assert req.forwarded[0]['proto'] == 'identifier' +def test_forwarded_host_with_port(): + header = 'for=1.2.3.4:1234' + req = make_mocked_request('GET', '/', + headers=CIMultiDict({'Forwarded': header})) + assert req.forwarded == ({'for': "1.2.3.4:1234"},) + + +def test_forwarded_quoted_host_with_port(): + header = 'for="[2001:db8:cafe::17]:1234"' + req = make_mocked_request('GET', '/', + headers=CIMultiDict({'Forwarded': header})) + assert req.forwarded == ({'for': "[2001:db8:cafe::17]:1234"},) + + def test_single_forwarded_header_camelcase(): header = 'bY=identifier;fOr=identifier;HOst=identifier;pRoTO=identifier' req = make_mocked_request('GET', '/',