summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Robenolt <matt@ydekproductions.com>2015-08-02 16:56:54 -0700
committerTim Graham <timograham@gmail.com>2015-08-04 09:50:57 -0400
commit4dcfbd792342667174834c40e792f1b8ac2f0609 (patch)
tree27fd26c9e063a4aabb4427230f52f89758b25fa1
parentf6259ce776eb022d1ca05fc5f4e5bc56ca1a4728 (diff)
Fixed #25211 -- Added HttpRequest.get_port() and USE_X_FORWARDED_PORT setting.
-rw-r--r--django/conf/global_settings.py1
-rw-r--r--django/http/request.py10
-rw-r--r--docs/ref/request-response.txt8
-rw-r--r--docs/ref/settings.txt14
-rw-r--r--docs/releases/1.9.txt3
-rw-r--r--tests/requests/tests.py32
6 files changed, 67 insertions, 1 deletions
diff --git a/django/conf/global_settings.py b/django/conf/global_settings.py
index 0febd3f08b..f0055a9496 100644
--- a/django/conf/global_settings.py
+++ b/django/conf/global_settings.py
@@ -428,6 +428,7 @@ DEFAULT_INDEX_TABLESPACE = ''
X_FRAME_OPTIONS = 'SAMEORIGIN'
USE_X_FORWARDED_HOST = False
+USE_X_FORWARDED_PORT = False
# The Python dotted path to the WSGI application that Django's internal server
# (runserver) will use. If `None`, the return value of
diff --git a/django/http/request.py b/django/http/request.py
index 3f23077565..938d833551 100644
--- a/django/http/request.py
+++ b/django/http/request.py
@@ -79,7 +79,7 @@ class HttpRequest(object):
else:
# Reconstruct the host using the algorithm from PEP 333.
host = self.META['SERVER_NAME']
- server_port = str(self.META['SERVER_PORT'])
+ server_port = self.get_port()
if server_port != ('443' if self.is_secure() else '80'):
host = '%s:%s' % (host, server_port)
@@ -98,6 +98,14 @@ class HttpRequest(object):
msg += " The domain name provided is not valid according to RFC 1034/1035."
raise DisallowedHost(msg)
+ def get_port(self):
+ """Return the port number for the request as a string."""
+ if settings.USE_X_FORWARDED_PORT and 'HTTP_X_FORWARDED_PORT' in self.META:
+ port = self.META['HTTP_X_FORWARDED_PORT']
+ else:
+ port = self.META['SERVER_PORT']
+ return str(port)
+
def get_full_path(self, force_append_slash=False):
# RFC 3986 requires query string arguments to be in the ASCII range.
# Rather than crash if this doesn't happen, we encode defensively.
diff --git a/docs/ref/request-response.txt b/docs/ref/request-response.txt
index 3f84d0d144..06f4d1dc4a 100644
--- a/docs/ref/request-response.txt
+++ b/docs/ref/request-response.txt
@@ -254,6 +254,14 @@ Methods
:class:`~django.middleware.common.CommonMiddleware` or
:class:`~django.middleware.csrf.CsrfViewMiddleware`.
+.. method:: HttpRequest.get_port()
+
+ .. versionadded:: 1.9
+
+ Returns the originating port of the request using information from the
+ ``HTTP_X_FORWARDED_PORT`` (if :setting:`USE_X_FORWARDED_PORT` is enabled)
+ and ``SERVER_PORT`` ``META`` variables, in that order.
+
.. method:: HttpRequest.get_full_path()
Returns the ``path``, plus an appended query string, if applicable.
diff --git a/docs/ref/settings.txt b/docs/ref/settings.txt
index 0cd83615e7..1077b910f2 100644
--- a/docs/ref/settings.txt
+++ b/docs/ref/settings.txt
@@ -2621,6 +2621,19 @@ A boolean that specifies whether to use the X-Forwarded-Host header in
preference to the Host header. This should only be enabled if a proxy
which sets this header is in use.
+.. setting:: USE_X_FORWARDED_PORT
+
+USE_X_FORWARDED_PORT
+--------------------
+
+.. versionadded:: 1.9
+
+Default: ``False``
+
+A boolean that specifies whether to use the X-Forwarded-Port header in
+preference to the ``SERVER_PORT`` ``META`` variable. This should only be
+enabled if a proxy which sets this header is in use.
+
.. setting:: WSGI_APPLICATION
WSGI_APPLICATION
@@ -3329,6 +3342,7 @@ HTTP
* :setting:`SIGNING_BACKEND`
* :setting:`USE_ETAGS`
* :setting:`USE_X_FORWARDED_HOST`
+* :setting:`USE_X_FORWARDED_PORT`
* :setting:`WSGI_APPLICATION`
Logging
diff --git a/docs/releases/1.9.txt b/docs/releases/1.9.txt
index f016a08c32..6f2611f267 100644
--- a/docs/releases/1.9.txt
+++ b/docs/releases/1.9.txt
@@ -538,6 +538,9 @@ Requests and Responses
returning an :class:`~django.http.HttpResponseForbidden` so that
:data:`~django.conf.urls.handler403` is invoked.
+* Added :meth:`HttpRequest.get_port() <django.http.HttpRequest.get_port>` to
+ fetch the originating port of the request.
+
Tests
^^^^^
diff --git a/tests/requests/tests.py b/tests/requests/tests.py
index bbf19df4ba..8a0b32d1c0 100644
--- a/tests/requests/tests.py
+++ b/tests/requests/tests.py
@@ -651,6 +651,38 @@ class HostValidationTests(SimpleTestCase):
}
request.get_host()
+ @override_settings(USE_X_FORWARDED_PORT=False)
+ def test_get_port(self):
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_PORT': '8080',
+ 'HTTP_X_FORWARDED_PORT': '80',
+ }
+ # Shouldn't use the X-Forwarded-Port header
+ self.assertEqual(request.get_port(), '8080')
+
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_PORT': '8080',
+ }
+ self.assertEqual(request.get_port(), '8080')
+
+ @override_settings(USE_X_FORWARDED_PORT=True)
+ def test_get_port_with_x_forwarded_port(self):
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_PORT': '8080',
+ 'HTTP_X_FORWARDED_PORT': '80',
+ }
+ # Should use the X-Forwarded-Port header
+ self.assertEqual(request.get_port(), '80')
+
+ request = HttpRequest()
+ request.META = {
+ 'SERVER_PORT': '8080',
+ }
+ self.assertEqual(request.get_port(), '8080')
+
@override_settings(DEBUG=True, ALLOWED_HOSTS=[])
def test_host_validation_disabled_in_debug_mode(self):
"""If ALLOWED_HOSTS is empty and DEBUG is True, all hosts pass."""