[1.4.x] Fixed #24238 -- Removed unused WSGIRequestHandler.get_environ()

Also moved the test as it wasn't running.
This commit is contained in:
Tim Graham 2015-01-28 12:03:05 -05:00
parent 4376d6ef7b
commit e60557c249
3 changed files with 66 additions and 101 deletions

View File

@ -138,39 +138,6 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler, object):
self.style = color_style()
super(WSGIRequestHandler, self).__init__(*args, **kwargs)
def get_environ(self):
env = self.server.base_environ.copy()
env['SERVER_PROTOCOL'] = self.request_version
env['REQUEST_METHOD'] = self.command
if '?' in self.path:
path,query = self.path.split('?',1)
else:
path,query = self.path,''
env['PATH_INFO'] = urllib.unquote(path)
env['QUERY_STRING'] = query
env['REMOTE_ADDR'] = self.client_address[0]
if self.headers.typeheader is None:
env['CONTENT_TYPE'] = self.headers.type
else:
env['CONTENT_TYPE'] = self.headers.typeheader
length = self.headers.getheader('content-length')
if length:
env['CONTENT_LENGTH'] = length
for h in self.headers.headers:
k,v = h.split(':',1)
k=k.replace('-','_').upper(); v=v.strip()
if k in env:
continue # skip content length, type,etc.
if 'HTTP_'+k in env:
env['HTTP_'+k] += ','+v # comma-separate multiple headers
else:
env['HTTP_'+k] = v
return env
def log_message(self, format, *args):
# Don't bother logging requests for admin images or the favicon.
if (self.path.startswith(self.admin_media_prefix)

View File

@ -1,67 +0,0 @@
import sys
from django.core.servers.basehttp import WSGIRequestHandler
from django.test import TestCase
from django.utils.six import BytesIO, StringIO
class Stub(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
class WSGIRequestHandlerTestCase(TestCase):
def test_strips_underscore_headers(self):
"""WSGIRequestHandler ignores headers containing underscores.
This follows the lead of nginx and Apache 2.4, and is to avoid
ambiguity between dashes and underscores in mapping to WSGI environ,
which can have security implications.
"""
def test_app(environ, start_response):
"""A WSGI app that just reflects its HTTP environ."""
start_response('200 OK', [])
http_environ_items = sorted(
'%s:%s' % (k, v) for k, v in environ.items()
if k.startswith('HTTP_')
)
yield (','.join(http_environ_items)).encode('utf-8')
rfile = BytesIO()
rfile.write(b"GET / HTTP/1.0\r\n")
rfile.write(b"Some-Header: good\r\n")
rfile.write(b"Some_Header: bad\r\n")
rfile.write(b"Other_Header: bad\r\n")
rfile.seek(0)
# WSGIRequestHandler closes the output file; we need to make this a
# no-op so we can still read its contents.
class UnclosableBytesIO(BytesIO):
def close(self):
pass
wfile = UnclosableBytesIO()
def makefile(mode, *a, **kw):
if mode == 'rb':
return rfile
elif mode == 'wb':
return wfile
request = Stub(makefile=makefile)
server = Stub(base_environ={}, get_app=lambda: test_app)
# We don't need to check stderr, but we don't want it in test output
old_stderr = sys.stderr
sys.stderr = StringIO()
try:
# instantiating a handler runs the request as side effect
WSGIRequestHandler(request, '192.168.0.2', server)
finally:
sys.stderr = old_stderr
wfile.seek(0)
body = list(wfile.readlines())[-1]
self.assertEqual(body, b'HTTP_SOME_HEADER:good')

View File

@ -2,6 +2,7 @@
Tests for django.core.servers.
"""
import os
import sys
from urlparse import urljoin
import urllib2
@ -10,8 +11,10 @@ from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase, LiveServerTestCase
from django.core.handlers.wsgi import WSGIHandler
from django.core.servers.basehttp import AdminMediaHandler, WSGIServerException
from django.core.servers.basehttp import (
AdminMediaHandler, WSGIRequestHandler, WSGIServerException)
from django.test.utils import override_settings
from django.utils.six import BytesIO, StringIO
from .models import Person
@ -213,3 +216,65 @@ class LiveServerDatabase(LiveServerBase):
self.urlopen('/create_model_instance/')
names = [person.name for person in Person.objects.all()]
self.assertEquals(names, ['jane', 'robert', 'emily'])
class Stub(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
class WSGIRequestHandlerTestCase(TestCase):
def test_strips_underscore_headers(self):
"""WSGIRequestHandler ignores headers containing underscores.
This follows the lead of nginx and Apache 2.4, and is to avoid
ambiguity between dashes and underscores in mapping to WSGI environ,
which can have security implications.
"""
def test_app(environ, start_response):
"""A WSGI app that just reflects its HTTP environ."""
start_response('200 OK', [])
http_environ_items = sorted(
'%s:%s' % (k, v) for k, v in environ.items()
if k.startswith('HTTP_')
)
yield (','.join(http_environ_items)).encode('utf-8')
rfile = BytesIO()
rfile.write("GET / HTTP/1.0\r\n")
rfile.write("Some-Header: good\r\n")
rfile.write("Some_Header: bad\r\n")
rfile.write("Other_Header: bad\r\n")
rfile.seek(0)
# WSGIRequestHandler closes the output file; we need to make this a
# no-op so we can still read its contents.
class UnclosableBytesIO(BytesIO):
def close(self):
pass
wfile = UnclosableBytesIO()
def makefile(mode, *a, **kw):
if mode == 'rb':
return rfile
elif mode == 'wb':
return wfile
request = Stub(makefile=makefile)
server = Stub(base_environ={}, get_app=lambda: test_app)
# We don't need to check stderr, but we don't want it in test output
old_stderr = sys.stderr
sys.stderr = StringIO()
try:
# instantiating a handler runs the request as side effect
WSGIRequestHandler(request, '192.168.0.2', server)
finally:
sys.stderr = old_stderr
wfile.seek(0)
body = list(wfile.readlines())[-1]
self.assertEqual(body, 'HTTP_SOME_HEADER:good')