Skip to content

Commit b8ce8fb

Browse files
committed
Merge pull request #573 from redixin/fix-wsgi-env-building
Fix wsgi environment building
2 parents 52f2f0e + eb54e6c commit b8ce8fb

File tree

2 files changed

+59
-64
lines changed

2 files changed

+59
-64
lines changed

aiohttp/wsgi.py

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from urllib.parse import urlsplit
1515

1616
import aiohttp
17-
from aiohttp import server, helpers, hdrs
17+
from aiohttp import server, hdrs
1818

1919
__all__ = ('WSGIServerHttpProtocol',)
2020

@@ -63,16 +63,11 @@ def create_wsgi_environ(self, message, payload):
6363
'SERVER_PROTOCOL': 'HTTP/%s.%s' % message.version
6464
}
6565

66-
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
67-
# may not qualify the remote addr:
68-
# http://www.ietf.org/rfc/rfc3875
69-
forward = self.transport.get_extra_info('addr', '127.0.0.1')
7066
script_name = self.SCRIPT_NAME
71-
server = forward
7267

7368
for hdr_name, hdr_value in message.headers.items():
74-
if hdr_name == 'HOST':
75-
server = hdr_value
69+
if hdr_name == 'AUTHORIZATION':
70+
continue
7671
elif hdr_name == 'SCRIPT_NAME':
7772
script_name = hdr_value
7873
elif hdr_name == 'CONTENT-TYPE':
@@ -88,17 +83,23 @@ def create_wsgi_environ(self, message, payload):
8883

8984
environ[key] = hdr_value
9085

91-
remote = helpers.parse_remote_addr(forward)
86+
# authors should be aware that REMOTE_HOST and REMOTE_ADDR
87+
# may not qualify the remote addr
88+
# also SERVER_PORT variable MUST be set to the TCP/IP port number on
89+
# which this request is received from the client.
90+
# http://www.ietf.org/rfc/rfc3875
91+
92+
remote = self.transport.get_extra_info('peername')
9293
environ['REMOTE_ADDR'] = remote[0]
9394
environ['REMOTE_PORT'] = remote[1]
9495

95-
if isinstance(server, str):
96-
server = server.split(':')
97-
if len(server) == 1:
98-
server.append('80' if url_scheme == 'http' else '443')
99-
100-
environ['SERVER_NAME'] = server[0]
101-
environ['SERVER_PORT'] = str(server[1])
96+
sockname = self.transport.get_extra_info('sockname')
97+
environ['SERVER_PORT'] = str(sockname[1])
98+
host = message.headers.get("HOST", None)
99+
if host:
100+
environ['SERVER_NAME'] = host.split(":")[0]
101+
else:
102+
environ['SERVER_NAME'] = sockname[0]
102103

103104
path_info = uri_parts.path
104105
if script_name:

tests/test_wsgi.py

Lines changed: 42 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,10 @@ def setUp(self):
2222
self.writer = unittest.mock.Mock()
2323
self.writer.drain.return_value = ()
2424
self.transport = unittest.mock.Mock()
25-
self.transport.get_extra_info.return_value = '127.0.0.1'
25+
self.transport.get_extra_info.side_effect = [('1.2.3.4', 1234),
26+
('2.3.4.5', 80)]
2627

27-
self.headers = multidict.MultiDict()
28+
self.headers = multidict.MultiDict({"HOST": "python.org"})
2829
self.message = protocol.RawRequestMessage(
2930
'GET', '/path', (1, 0), self.headers, True, 'deflate')
3031
self.payload = aiohttp.FlowControlDataQueue(self.reader)
@@ -63,64 +64,40 @@ def test_environ(self):
6364

6465
def test_environ_headers(self):
6566
self.headers.extend(
66-
(('HOST', 'python.org'),
67-
('SCRIPT_NAME', 'script'),
67+
(('SCRIPT_NAME', 'script'),
6868
('CONTENT-TYPE', 'text/plain'),
6969
('CONTENT-LENGTH', '209'),
7070
('X_TEST', '123'),
7171
('X_TEST', '456')))
72-
environ = self._make_one(is_ssl=True)
72+
environ = self._make_one()
7373
self.assertEqual(environ['CONTENT_TYPE'], 'text/plain')
7474
self.assertEqual(environ['CONTENT_LENGTH'], '209')
7575
self.assertEqual(environ['HTTP_X_TEST'], '123,456')
7676
self.assertEqual(environ['SCRIPT_NAME'], 'script')
7777
self.assertEqual(environ['SERVER_NAME'], 'python.org')
78-
self.assertEqual(environ['SERVER_PORT'], '443')
79-
80-
def test_environ_host_header(self):
81-
self.headers.add('HOST', 'python.org')
82-
environ = self._make_one()
83-
84-
self.assertEqual(environ['HTTP_HOST'], 'python.org')
85-
self.assertEqual(environ['SERVER_NAME'], 'python.org')
8678
self.assertEqual(environ['SERVER_PORT'], '80')
87-
self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.0')
88-
89-
def test_environ_host_port_header(self):
90-
self.message = protocol.RawRequestMessage(
91-
'GET', '/path', (1, 1), self.headers, True, 'deflate')
92-
self.headers.add('HOST', 'python.org:443')
93-
environ = self._make_one()
94-
95-
self.assertEqual(environ['HTTP_HOST'], 'python.org:443')
96-
self.assertEqual(environ['SERVER_NAME'], 'python.org')
97-
self.assertEqual(environ['SERVER_PORT'], '443')
98-
self.assertEqual(environ['SERVER_PROTOCOL'], 'HTTP/1.1')
99-
100-
def test_environ_forward(self):
101-
self.transport.get_extra_info.return_value = 'localhost,127.0.0.1'
102-
environ = self._make_one()
103-
104-
self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')
105-
self.assertEqual(environ['REMOTE_PORT'], '80')
106-
107-
self.transport.get_extra_info.return_value = 'localhost,127.0.0.1:443'
108-
environ = self._make_one()
109-
110-
self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')
111-
self.assertEqual(environ['REMOTE_PORT'], '443')
112-
113-
self.transport.get_extra_info.return_value = ('127.0.0.1', 443)
79+
get_extra_info_calls = self.transport.get_extra_info.mock_calls
80+
expected_calls = [
81+
unittest.mock.call('peername'),
82+
unittest.mock.call('sockname'),
83+
]
84+
self.assertEqual(expected_calls, get_extra_info_calls)
85+
86+
def test_environ_host_header_alternate_port(self):
87+
self.transport.get_extra_info = unittest.mock.Mock(
88+
side_effect=[('1.2.3.4', 1234), ('3.4.5.6', 82)]
89+
)
90+
self.headers.update({'HOST': 'example.com:9999'})
11491
environ = self._make_one()
92+
self.assertEqual(environ['SERVER_PORT'], '82')
11593

116-
self.assertEqual(environ['REMOTE_ADDR'], '127.0.0.1')
117-
self.assertEqual(environ['REMOTE_PORT'], '443')
118-
119-
self.transport.get_extra_info.return_value = '[::1]'
120-
environ = self._make_one()
121-
122-
self.assertEqual(environ['REMOTE_ADDR'], '::1')
123-
self.assertEqual(environ['REMOTE_PORT'], '80')
94+
def test_environ_host_header_alternate_port_ssl(self):
95+
self.transport.get_extra_info = unittest.mock.Mock(
96+
side_effect=[('1.2.3.4', 1234), ('3.4.5.6', 82)]
97+
)
98+
self.headers.update({'HOST': 'example.com:9999'})
99+
environ = self._make_one(is_ssl=True)
100+
self.assertEqual(environ['SERVER_PORT'], '82')
124101

125102
def test_wsgi_response(self):
126103
srv = self._make_srv()
@@ -280,3 +257,20 @@ def test_dont_unquote_environ_path_info(self):
280257
'GET', path, (1, 0), self.headers, True, 'deflate')
281258
environ = self._make_one()
282259
self.assertEqual(environ['PATH_INFO'], path)
260+
261+
def test_not_add_authorization(self):
262+
self.headers.extend({'AUTHORIZATION': 'spam',
263+
'X-CUSTOM-HEADER': 'eggs'})
264+
self.message = protocol.RawRequestMessage(
265+
'GET', '/', (1, 1), self.headers, True, 'deflate')
266+
environ = self._make_one()
267+
self.assertEqual('eggs', environ['HTTP_X_CUSTOM_HEADER'])
268+
self.assertFalse('AUTHORIZATION' in environ)
269+
270+
def test_http_1_0_no_host(self):
271+
headers = multidict.MultiDict({})
272+
self.message = protocol.RawRequestMessage(
273+
'GET', '/', (1, 0), headers, True, 'deflate')
274+
environ = self._make_one()
275+
self.assertEqual(environ['SERVER_NAME'], '2.3.4.5')
276+
self.assertEqual(environ['SERVER_PORT'], '80')

0 commit comments

Comments
 (0)