|
| 1 | +import sys |
| 2 | + |
| 3 | +from django.core.servers.basehttp import WSGIRequestHandler |
| 4 | +from django.test import TestCase |
| 5 | +from django.utils.six import BytesIO, StringIO |
| 6 | + |
| 7 | + |
| 8 | +class Stub(object): |
| 9 | + def __init__(self, **kwargs): |
| 10 | + self.__dict__.update(kwargs) |
| 11 | + |
| 12 | + |
| 13 | +class WSGIRequestHandlerTestCase(TestCase): |
| 14 | + |
| 15 | + def test_strips_underscore_headers(self): |
| 16 | + """WSGIRequestHandler ignores headers containing underscores. |
| 17 | +
|
| 18 | + This follows the lead of nginx and Apache 2.4, and is to avoid |
| 19 | + ambiguity between dashes and underscores in mapping to WSGI environ, |
| 20 | + which can have security implications. |
| 21 | + """ |
| 22 | + def test_app(environ, start_response): |
| 23 | + """A WSGI app that just reflects its HTTP environ.""" |
| 24 | + start_response('200 OK', []) |
| 25 | + http_environ_items = sorted( |
| 26 | + '%s:%s' % (k, v) for k, v in environ.items() |
| 27 | + if k.startswith('HTTP_') |
| 28 | + ) |
| 29 | + yield (','.join(http_environ_items)).encode('utf-8') |
| 30 | + |
| 31 | + rfile = BytesIO() |
| 32 | + rfile.write(b"GET / HTTP/1.0\r\n") |
| 33 | + rfile.write(b"Some-Header: good\r\n") |
| 34 | + rfile.write(b"Some_Header: bad\r\n") |
| 35 | + rfile.write(b"Other_Header: bad\r\n") |
| 36 | + rfile.seek(0) |
| 37 | + |
| 38 | + # WSGIRequestHandler closes the output file; we need to make this a |
| 39 | + # no-op so we can still read its contents. |
| 40 | + class UnclosableBytesIO(BytesIO): |
| 41 | + def close(self): |
| 42 | + pass |
| 43 | + |
| 44 | + wfile = UnclosableBytesIO() |
| 45 | + |
| 46 | + def makefile(mode, *a, **kw): |
| 47 | + if mode == 'rb': |
| 48 | + return rfile |
| 49 | + elif mode == 'wb': |
| 50 | + return wfile |
| 51 | + |
| 52 | + request = Stub(makefile=makefile) |
| 53 | + server = Stub(base_environ={}, get_app=lambda: test_app) |
| 54 | + |
| 55 | + # We don't need to check stderr, but we don't want it in test output |
| 56 | + old_stderr = sys.stderr |
| 57 | + sys.stderr = StringIO() |
| 58 | + try: |
| 59 | + # instantiating a handler runs the request as side effect |
| 60 | + WSGIRequestHandler(request, '192.168.0.2', server) |
| 61 | + finally: |
| 62 | + sys.stderr = old_stderr |
| 63 | + |
| 64 | + wfile.seek(0) |
| 65 | + body = list(wfile.readlines())[-1] |
| 66 | + |
| 67 | + self.assertEqual(body, b'HTTP_SOME_HEADER:good') |
0 commit comments