Fixed #28828 -- Improved performance of HttpRequest.build_absolute_uri().

This commit is contained in:
George-Cristian Bîrzan 2017-11-22 13:27:15 +02:00 committed by Tim Graham
parent a613feb5d3
commit 5bf62825b5
1 changed files with 21 additions and 7 deletions

View File

@ -15,6 +15,7 @@ from django.http.multipartparser import MultiPartParser, MultiPartParserError
from django.utils.datastructures import ImmutableList, MultiValueDict from django.utils.datastructures import ImmutableList, MultiValueDict
from django.utils.deprecation import RemovedInDjango30Warning from django.utils.deprecation import RemovedInDjango30Warning
from django.utils.encoding import escape_uri_path, force_bytes, iri_to_uri from django.utils.encoding import escape_uri_path, force_bytes, iri_to_uri
from django.utils.functional import cached_property
from django.utils.http import is_same_domain, limited_parse_qsl from django.utils.http import is_same_domain, limited_parse_qsl
RAISE_ERROR = object() RAISE_ERROR = object()
@ -176,15 +177,28 @@ class HttpRequest:
location = '//%s' % self.get_full_path() location = '//%s' % self.get_full_path()
bits = urlsplit(location) bits = urlsplit(location)
if not (bits.scheme and bits.netloc): if not (bits.scheme and bits.netloc):
current_uri = '{scheme}://{host}{path}'.format(scheme=self.scheme, # Handle the simple, most common case. If the location is absolute
host=self.get_host(), # and a scheme or host (netloc) isn't provided, skip an expensive
path=self.path) # urljoin() as long as no path segments are '.' or '..'.
# Join the constructed URL with the provided location, which will if (bits.path.startswith('/') and not bits.scheme and not bits.netloc and
# allow the provided ``location`` to apply query strings to the '/./' not in bits.path and '/../' not in bits.path):
# base path as well as override the host, if it begins with // # If location starts with '//' but has no netloc, reuse the
location = urljoin(current_uri, location) # schema and netloc from the current request. Strip the double
# slashes and continue as if it wasn't specified.
if location.startswith('//'):
location = location[2:]
location = self._current_scheme_host + location
else:
# Join the constructed URL with the provided location, which
# allows the provided location to apply query strings to the
# base path.
location = urljoin(self._current_scheme_host + self.path, location)
return iri_to_uri(location) return iri_to_uri(location)
@cached_property
def _current_scheme_host(self):
return '{}://{}'.format(self.scheme, self.get_host())
def _get_scheme(self): def _get_scheme(self):
""" """
Hook for subclasses like WSGIRequest to implement. Return 'http' by Hook for subclasses like WSGIRequest to implement. Return 'http' by