Skip to content

Commit 227da1f

Browse files
authored
Merge pull request #5607 from dojutsu-user/remove-proxy-middleware
Remove ProxyMiddleware
2 parents dfe60ed + f89fc24 commit 227da1f

File tree

4 files changed

+64
-37
lines changed

4 files changed

+64
-37
lines changed

readthedocs/analytics/tests.py

+47-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
# -*- coding: utf-8 -*-
2-
from django.test import TestCase
2+
from django.test import TestCase, RequestFactory
33

4-
from .utils import anonymize_ip_address, anonymize_user_agent
4+
from .utils import (
5+
anonymize_ip_address,
6+
anonymize_user_agent,
7+
get_client_ip,
8+
)
59

610

711
class UtilsTests(TestCase):
@@ -28,3 +32,44 @@ def test_anonymize_ua(self):
2832
anonymize_user_agent('Some rare user agent'),
2933
'Rare user agent',
3034
)
35+
36+
def test_get_client_ip_with_x_forwarded_for(self):
37+
38+
# only client's ip is present
39+
request = RequestFactory().get('/')
40+
request.META['HTTP_X_FORWARDED_FOR'] = '203.0.113.195'
41+
client_ip = get_client_ip(request)
42+
self.assertEqual(client_ip, '203.0.113.195')
43+
44+
# proxy1 and proxy2 are present along with client's ip
45+
request = RequestFactory().get('/')
46+
request.META['HTTP_X_FORWARDED_FOR'] = '203.0.113.195, 70.41.3.18, 150.172.238.178'
47+
client_ip = get_client_ip(request)
48+
self.assertEqual(client_ip, '203.0.113.195')
49+
50+
# client ip with port
51+
request = RequestFactory().get('/')
52+
request.META['HTTP_X_FORWARDED_FOR'] = '203.0.113.195:8080, 70.41.3.18, 150.172.238.178'
53+
client_ip = get_client_ip(request)
54+
self.assertEqual(client_ip, '203.0.113.195')
55+
56+
# client ip with port but not proxy1 and proxy2
57+
request = RequestFactory().get('/')
58+
request.META['HTTP_X_FORWARDED_FOR'] = '203.0.113.195:8080'
59+
client_ip = get_client_ip(request)
60+
self.assertEqual(client_ip, '203.0.113.195')
61+
62+
# no header is present
63+
request = RequestFactory().get('/')
64+
if request.META['REMOTE_ADDR']:
65+
del request.META['REMOTE_ADDR']
66+
client_ip = get_client_ip(request)
67+
self.assertEqual(client_ip, None)
68+
69+
def test_get_client_ip_with_remote_addr(self):
70+
71+
request = RequestFactory().get('/')
72+
self.assertIsNone(request.META.get('HTTP_X_FORWARDED_FOR'))
73+
request.META['REMOTE_ADDR'] = '203.0.113.195'
74+
client_ip = get_client_ip(request)
75+
self.assertEqual(client_ip, '203.0.113.195')

readthedocs/analytics/utils.py

+17-6
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,26 @@
1717

1818

1919
def get_client_ip(request):
20-
"""Gets the real IP based on a request object."""
21-
ip_address = request.META.get('REMOTE_ADDR')
20+
"""
21+
Gets the real client's IP address.
2222
23-
# Get the original IP address (eg. "X-Forwarded-For: client, proxy1, proxy2")
24-
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', '').split(',')[0]
23+
It returns the real IP address of the client based on ``HTTP_X_FORWARDED_FOR``
24+
header. If ``HTTP_X_FORWARDED_FOR`` is not found, it returns the value of
25+
``REMOTE_ADDR`` header and returns ``None`` if both the headers are not found.
26+
"""
27+
x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR', None)
2528
if x_forwarded_for:
26-
ip_address = x_forwarded_for.rsplit(':')[0]
29+
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs.
30+
# The client's IP will be the first one.
31+
# (eg. "X-Forwarded-For: client, proxy1, proxy2")
32+
client_ip = x_forwarded_for.split(',')[0].strip()
33+
34+
# Removing the port number (if present)
35+
client_ip = client_ip.rsplit(':')[0]
36+
else:
37+
client_ip = request.META.get('REMOTE_ADDR', None)
2738

28-
return ip_address
39+
return client_ip
2940

3041

3142
def anonymize_ip_address(ip_address):

readthedocs/core/middleware.py

-28
Original file line numberDiff line numberDiff line change
@@ -174,34 +174,6 @@ def process_request(self, request):
174174
return None
175175

176176

177-
# Forked from old Django
178-
class ProxyMiddleware(MiddlewareMixin):
179-
180-
"""
181-
Middleware that sets REMOTE_ADDR based on HTTP_X_FORWARDED_FOR, if the.
182-
183-
latter is set. This is useful if you're sitting behind a reverse proxy that
184-
causes each request's REMOTE_ADDR to be set to 127.0.0.1. Note that this
185-
does NOT validate HTTP_X_FORWARDED_FOR. If you're not behind a reverse proxy
186-
that sets HTTP_X_FORWARDED_FOR automatically, do not use this middleware.
187-
Anybody can spoof the value of HTTP_X_FORWARDED_FOR, and because this sets
188-
REMOTE_ADDR based on HTTP_X_FORWARDED_FOR, that means anybody can "fake"
189-
their IP address. Only use this when you can absolutely trust the value of
190-
HTTP_X_FORWARDED_FOR.
191-
"""
192-
193-
def process_request(self, request):
194-
try:
195-
real_ip = request.META['HTTP_X_FORWARDED_FOR']
196-
except KeyError:
197-
return None
198-
else:
199-
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs. The
200-
# client's IP will be the first one.
201-
real_ip = real_ip.split(',')[0].strip()
202-
request.META['REMOTE_ADDR'] = real_ip
203-
204-
205177
class FooterNoSessionMiddleware(SessionMiddleware):
206178

207179
"""

readthedocs/settings/base.py

-1
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,6 @@ def USE_PROMOS(self): # noqa
154154
return 'readthedocsext.donate' in self.INSTALLED_APPS
155155

156156
MIDDLEWARE = (
157-
'readthedocs.core.middleware.ProxyMiddleware',
158157
'readthedocs.core.middleware.FooterNoSessionMiddleware',
159158
'django.middleware.locale.LocaleMiddleware',
160159
'django.middleware.common.CommonMiddleware',

0 commit comments

Comments
 (0)