Esempio n. 1
0
    def finalize_response(self, request, response, *args, **kwargs):
        """
        Returns the final response object.
        """
        # Make the error obvious if a proper response is not returned
        assert isinstance(response, HttpResponseBase), (
            'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` '
            'to be returned from the view, but received a `%s`'
            % type(response)
        )

        if isinstance(response, Response):
            if not getattr(request, 'accepted_renderer', None):
                neg = self.perform_content_negotiation(request, force=True)
                request.accepted_renderer, request.accepted_media_type = neg

            response.accepted_renderer = request.accepted_renderer
            response.accepted_media_type = request.accepted_media_type
            response.renderer_context = self.get_renderer_context()

        # Add new vary headers to the response instead of overwriting.
        vary_headers = self.headers.pop('Vary', None)
        if vary_headers is not None:
            patch_vary_headers(response, cc_delim_re.split(vary_headers))

        for key, value in self.headers.items():
            response[key] = value

        return response
Esempio n. 2
0
    def check_merged_vary_header(self, request, main_header, fragment_header_1,
                                 fragment_header_2):
        fragment_urls = [
            '/vary/?headers=%s' % urllib.quote_plus(vary)
            for vary in (fragment_header_1, fragment_header_2) if vary
        ]
        html = '\n'.join('<esi:include src="%s" />' % url
                         for url in fragment_urls)
        response = HttpResponse(html)
        if main_header:
            response['Vary'] = main_header

        request_url = '/page-with-esi-tags/'
        request.has_attr(_esi={'used': True})
        request.provides('get_full_path').returns(request_url)
        request.provides('build_absolute_uri').returns('http://example.com%s' %
                                                       request_url)

        result = full_process_response(request, response)
        vary_result = result.get('Vary', '')

        for header in (main_header, fragment_header_1, fragment_header_2):
            if not header:
                continue
            vary_fields = cc_delim_re.split(header)
            for field in vary_fields:
                self.assertEqual(len(re.findall(field, vary_result, re.I)), 1)
Esempio n. 3
0
def learn_cache_key(request, response, tags=(), cache_timeout=None, key_prefix=None, cache=None):  # patched
    """
    Learns what headers to take into account for some request path from the
    response object. It stores those headers in a global path registry so that
    later access to that path will know what headers to take into account
    without building the response object itself. The headers are named in the
    Vary header of the response, but we want to prevent response generation.

    The list of headers to use for cache key generation is stored in the same
    cache as the pages themselves. If the cache ages some data out of the
    cache, this just means that we have to build the response once to get at
    the Vary header and so at the list of headers to use for the cache key.
    """
    if key_prefix is None:
        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
    if cache_timeout is None:
        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
    cache_key = _generate_cache_header_key(key_prefix, request)
    if cache is None:
        cache = get_cache(settings.CACHE_MIDDLEWARE_ALIAS)
    if response.has_header('Vary'):
        headerlist = ['HTTP_'+header.upper().replace('-', '_')
                      for header in cc_delim_re.split(response['Vary'])]
        cache.set(cache_key, headerlist, tags, cache_timeout)  # patched
        return _generate_cache_key(request, request.method, headerlist, key_prefix)
    else:
        # if there is no Vary header, we still need a cache key
        # for the request.get_full_path()
        cache.set(cache_key, [], tags, cache_timeout)  # patched
        return _generate_cache_key(request, request.method, [], key_prefix)
Esempio n. 4
0
def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
    """
    Learns what headers to take into account for some request path from the
    response object. It stores those headers in a global path registry so that
    later access to that path will know what headers to take into account
    without building the response object itself. The headers are named in the
    Vary header of the response, but we want to prevent response generation.

    The list of headers to use for cache key generation is stored in the same
    cache as the pages themselves. If the cache ages some data out of the
    cache, this just means that we have to build the response once to get at
    the Vary header and so at the list of headers to use for the cache key.
    """
    if key_prefix is None:
        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
    if cache_timeout is None:
        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
    cache_key = _generate_cache_header_key(key_prefix, request)
    if response.has_header('Vary'):
        headerlist = [
            'HTTP_' + header.upper().replace('-', '_')
            for header in cc_delim_re.split(response['Vary'])
        ]
        cache.set(cache_key, headerlist, cache_timeout)
        return _generate_cache_key(request, headerlist, key_prefix)
    else:
        # if there is no Vary header, we still need a cache key
        # for the request.path
        cache.set(cache_key, [], cache_timeout)
        return _generate_cache_key(request, [], key_prefix)
Esempio n. 5
0
    def check_merged_vary_header(self, request, main_header, fragment_header_1,
      fragment_header_2):
        fragment_urls = ['/vary/?headers=%s' % urllib.quote_plus(vary) for vary in
            (fragment_header_1, fragment_header_2) if vary]
        html = '\n'.join('<esi:include src="%s" />' % url for url in
            fragment_urls)
        response = HttpResponse(html)
        if main_header:
            response['Vary'] = main_header

        request_url = '/page-with-esi-tags/'
        request.has_attr(_esi={'used': True})
        request.provides('get_full_path').returns(request_url)
        request.provides('build_absolute_uri').returns(
            'http://example.com%s' % request_url)

        result = full_process_response(request, response)
        vary_result = result.get('Vary', '')

        for header in (main_header, fragment_header_1, fragment_header_2):
            if not header:
                continue
            vary_fields = cc_delim_re.split(header)
            for field in vary_fields:
                self.assertEqual(len(re.findall(field, vary_result, re.I)), 1)
Esempio n. 6
0
    def finalize_response(self, request, response, *args, **kwargs):
        """
        Returns the final response object.
        """
        # Make the error obvious if a proper response is not returned
        assert isinstance(response, HttpResponseBase), (
            'Expected a `Response`, `HttpResponse` or `HttpStreamingResponse` '
            'to be returned from the view, but received a `%s`'
            % type(response)
        )

        if isinstance(response, Response):
            if not getattr(request, 'accepted_renderer', None):
                neg = self.perform_content_negotiation(request, force=True)
                request.accepted_renderer, request.accepted_media_type = neg

            response.accepted_renderer = request.accepted_renderer
            response.accepted_media_type = request.accepted_media_type
            response.renderer_context = self.get_renderer_context()

        # Add new vary headers to the response instead of overwriting.
        vary_headers = self.headers.pop('Vary', None)
        if vary_headers is not None:
            patch_vary_headers(response, cc_delim_re.split(vary_headers))

        for key, value in self.headers.items():
            response[key] = value

        return response
Esempio n. 7
0
 def needs_etag(self, response):
     """
     Return True if an ETag header should be added to response.
     """
     cache_control_headers = cc_delim_re.split(
         response.get('Cache-Control', ''))
     return all(header.lower() != 'no-store'
                for header in cache_control_headers)
def has_vary_header(response, header_query):
    """
    Checks to see if the response has a given header name in its Vary header.
    Copied from Django 1.2.5 so we can use it in Django 1.2.4
    """
    if not response.has_header('Vary'):
        return False
    vary_headers = cc_delim_re.split(response['Vary'])
    existing_headers = set([header.lower() for header in vary_headers])
    return header_query.lower() in existing_headers
def has_vary_header(response, header_query):
    """
    Checks to see if the response has a given header name in its Vary header.
    Copied from Django 1.2.5 so we can use it in Django 1.2.4
    """
    if not response.has_header('Vary'):
        return False
    vary_headers = cc_delim_re.split(response['Vary'])
    existing_headers = set([header.lower() for header in vary_headers])
    return header_query.lower() in existing_headers
Esempio n. 10
0
def remove_vary_headers(response, deleteheaders):
    """
    Removes the "Vary" header in the given HttpResponse object.
    newheaders is a list of header names that should be in "Vary".
    """
    # Note that we need to keep the original order intact, because cache
    # implementations may rely on the order of the Vary contents in, say,
    # computing an MD5 hash.
    if response.has_header('Vary'):
        vary_headers = cc_delim_re.split(response['Vary'])
        # Use .lower() here so we treat headers as case-insensitive.
        deleteheaders = set(deleteheaders)
        headers = [header for header in vary_headers if header.lower() not in deleteheaders]
        if headers:
            response['Vary'] = ', '.join(headers)
        else:
            del response['Vary']
Esempio n. 11
0
def learn_cache_key(request,
                    response,
                    tags=(),
                    cache_timeout=None,
                    key_prefix=None,
                    cache=None):  # patched
    """
    Learns what headers to take into account for some request URL from the
    response object. It stores those headers in a global URL registry so that
    later access to that URL will know what headers to take into account
    without building the response object itself. The headers are named in the
    Vary header of the response, but we want to prevent response generation.

    The list of headers to use for cache key generation is stored in the same
    cache as the pages themselves. If the cache ages some data out of the
    cache, this just means that we have to build the response once to get at
    the Vary header and so at the list of headers to use for the cache key.
    """
    if key_prefix is None:
        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
    if cache_timeout is None:
        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
    cache_key = _generate_cache_header_key(key_prefix, request)
    if cache is None:
        cache = caches[settings.CACHE_MIDDLEWARE_ALIAS]
    if response.has_header('Vary'):
        is_accept_language_redundant = settings.USE_I18N or settings.USE_L10N
        # If i18n or l10n are used, the generated cache key will be suffixed
        # with the current locale. Adding the raw value of Accept-Language is
        # redundant in that case and would result in storing the same content
        # under multiple keys in the cache. See #18191 for details.
        headerlist = []
        for header in cc_delim_re.split(response['Vary']):
            header = header.upper().replace('-', '_')
            if header == 'ACCEPT_LANGUAGE' and is_accept_language_redundant:
                continue
            headerlist.append('HTTP_' + header)
        headerlist.sort()
        cache.set(cache_key, headerlist, tags, cache_timeout)  # patched
        return _generate_cache_key(request, request.method, headerlist,
                                   key_prefix)
    else:
        # if there is no Vary header, we still need a cache key
        # for the request.build_absolute_uri()
        cache.set(cache_key, [], tags, cache_timeout)  # patched
        return _generate_cache_key(request, request.method, [], key_prefix)
Esempio n. 12
0
def reduce_vary_headers(response, additional):
    '''Merges the Vary header values so all headers are included.'''
    original = response.get('Vary', None)
    if original is not None:
        additional.append(original)
    # Keep track of normalized, lowercase header names in seen_headers while
    # maintaining the order and case of the header names in final_headers.
    seen_headers = set()
    final_headers = []
    for vary_value in additional:
        headers = cc_delim_re.split(vary_value)
        for header in headers:
            if header.lower() in seen_headers:
                continue
            seen_headers.add(header.lower())
            final_headers.append(header)
    response['Vary'] = ', '.join(final_headers)
Esempio n. 13
0
def reduce_vary_headers(response, additional):
    '''Merges the Vary header values so all headers are included.'''
    original = response.get('Vary', None)
    if original is not None:
        additional.append(original)
    # Keep track of normalized, lowercase header names in seen_headers while
    # maintaining the order and case of the header names in final_headers.
    seen_headers = set()
    final_headers = []
    for vary_value in additional:
        headers = cc_delim_re.split(vary_value)
        for header in headers:
            if header.lower() in seen_headers:
                continue
            seen_headers.add(header.lower())
            final_headers.append(header)
    response['Vary'] = ', '.join(final_headers)
Esempio n. 14
0
def get_header_dict(response, header):
    """ returns a dictionary of the cache control headers
        the same as is used by django.utils.cache.patch_cache_control 
        if there are no Cache-Control headers returns and empty dict
    """
    def dictitem(s):
        t = s.split('=', 1)
        if len(t) > 1:
            return (t[0].lower(), t[1])
        else:
            return (t[0].lower(), True)

    if response.has_header(header):
        hd = dict([dictitem(el) for el in cc_delim_re.split(response[header])])
    else:
        hd= {}
    return hd
Esempio n. 15
0
def get_header_dict(response, header):
    """ returns a dictionary of the cache control headers
        the same as is used by django.utils.cache.patch_cache_control
        if there are no Cache-Control headers returns and empty dict
    """
    def dictitem(s):
        t = s.split('=', 1)
        if len(t) > 1:
            return (t[0].lower(), t[1])
        else:
            return (t[0].lower(), True)

    if response.has_header(header):
        hd = dict([dictitem(el) for el in cc_delim_re.split(response[header])])
    else:
        hd = {}
    return hd
Esempio n. 16
0
def remove_vary_headers(response, deleteheaders):
    """
    Removes the "Vary" header in the given HttpResponse object.
    newheaders is a list of header names that should be in "Vary".
    """
    # Note that we need to keep the original order intact, because cache
    # implementations may rely on the order of the Vary contents in, say,
    # computing an MD5 hash.
    if response.has_header('Vary'):
        vary_headers = cc_delim_re.split(response['Vary'])
        # Use .lower() here so we treat headers as case-insensitive.
        deleteheaders = set(deleteheaders)
        headers = [
            header for header in vary_headers
            if header.lower() not in deleteheaders
        ]
        if headers:
            response['Vary'] = ', '.join(headers)
        else:
            del response['Vary']
Esempio n. 17
0
def learn_orderless_cache_key(request, response, cache_timeout=None, key_prefix=None, cache=None):
    """
    Learns what headers to take into account for some request URL from the
    response object. It stores those headers in a global URL registry so that
    later access to that URL will know what headers to take into account
    without building the response object itself. The headers are named in the
    Vary header of the response, but we want to prevent response generation.

    The list of headers to use for cache key generation is stored in the same
    cache as the pages themselves. If the cache ages some data out of the
    cache, this just means that we have to build the response once to get at
    the Vary header and so at the list of headers to use for the cache key.
    """
    if key_prefix is None:
        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX
    if cache_timeout is None:
        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS
    cache_key = _generate_cache_header_key(key_prefix, request)
    if cache is None:
        cache = caches[settings.CACHE_MIDDLEWARE_ALIAS]
    if response.has_header('Vary'):
        is_accept_language_redundant = settings.USE_I18N or settings.USE_L10N
        # If i18n or l10n are used, the generated cache key will be suffixed
        # with the current locale. Adding the raw value of Accept-Language is
        # redundant in that case and would result in storing the same content
        # under multiple keys in the cache. See #18191 for details.
        headerlist = []
        for header in cc_delim_re.split(response['Vary']):
            header = header.upper().replace('-', '_')
            if header == 'ACCEPT_LANGUAGE' and is_accept_language_redundant:
                continue
            headerlist.append('HTTP_' + header)
        headerlist.sort()
        cache.set(cache_key, headerlist, cache_timeout)
        return _generate_orderless_cache_key(request, request.method, headerlist, key_prefix)
    else:
        # if there is no Vary header, we still need a cache key
        # for the request.build_absolute_uri()
        cache.set(cache_key, [], cache_timeout)
        return _generate_orderless_cache_key(request, request.method, [], key_prefix)
Esempio n. 18
0
def drop_vary_headers(response, headers_to_drop):
    """
    Remove an item from the "Vary" header of an ``HttpResponse`` object.
    If no items remain, delete the "Vary" header.
    This does the opposite effect of django.utils.cache.patch_vary_headers.
    """
    if response.has_header('Vary'):
        vary_headers = cc_delim_re.split(response['Vary'])
    else:
        vary_headers = []

    headers_to_drop = [header.lower() for header in headers_to_drop]

    updated_vary_headers = []
    for header in vary_headers:
        if len(header):
            if header.lower() not in headers_to_drop:
                updated_vary_headers.append(header)

    if len(updated_vary_headers):
        response['Vary'] = ', '.join(updated_vary_headers)
    else:
        del response['Vary']
Esempio n. 19
0
def drop_vary_headers(response, headers_to_drop):
    """
    Remove an item from the "Vary" header of an ``HttpResponse`` object.
    If no items remain, delete the "Vary" header.
    This does the opposite effect of django.utils.cache.patch_vary_headers.
    """
    if response.has_header('Vary'):
        vary_headers = cc_delim_re.split(response['Vary'])
    else:
        vary_headers = []

    headers_to_drop = [header.lower() for header in headers_to_drop]

    updated_vary_headers = []
    for header in vary_headers:
        if len(header):
            if header.lower() not in headers_to_drop:
                updated_vary_headers.append(header)

    if len(updated_vary_headers):
        response['Vary'] = ', '.join(updated_vary_headers)
    else:
        del response['Vary']
def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
    """
    NOTE: This was copied from Django, with the following changes:
    * Caches based on full path, including the query string.
    * Stores the ETag and Last-Modified headers to support responding with
      "304 Not Modified" responses.
    * Supports custom "X-Vary-On-View" headers that can be used instead of the
      cookie header in the cache key for a response. This provides more control
      over what is cached, without altering the actual response.

    Learns what headers to take into account for some request path from the
    response object. It stores those headers in a global path registry so that
    later access to that path will know what headers to take into account
    without building the response object itself. The headers are named in the
    Vary header of the response, but we want to prevent response generation.

    The list of headers to use for cache key generation is stored in the same
    cache as the pages themselves. If the cache ages some data out of the
    cache, this just means that we have to build the response once to get at
    the Vary header and so at the list of headers to use for the cache key.

    """

    if key_prefix is None:
        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX

    if cache_timeout is None:
        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS

    # Get the Vary headers, to build a cache key for this response. For
    # example, a response that varies on cookie would result in multiple
    # cached responses; one for each cookie value that is encountered. This
    # dictionary is effectively a list, as it does not have any values.
    response_headers = {}
    if response.has_header('Vary'):
        for header in cc_delim_re.split(response['Vary']):
            response_headers['HTTP_' + header.upper().replace('-', '_')] = None

    if response.has_header('X-Vary-On-View'):
        # When available, use the Vary-On-View header instead of the Cookie.
        response_headers['X-Vary-On-View'] = response['X-Vary-On-View']
        if 'HTTP_COOKIE' in response_headers:
            del response_headers['HTTP_COOKIE']
        key_headers = response_headers
    else:
        # When there is no vary on view, we can store the Etags/Last-Modified
        # values in the header list. Nothing varies, so we can be sure that
        # the values are not for a different version of the page. This avoids
        # fetching the response for no reason.
        key_headers = {}
        if response.has_header('Etag'):
            key_headers['HTTP_ETAG'] = response['Etag']
        if response.has_header('Last-Modified'):
            key_headers['HTTP_LAST_MODIFIED'] = response['Last-Modified']
        key_headers.update(response_headers)

    # Cache this list of headers against this request URL.
    # This is the "global path registry" that everyone is talking about.
    cache_key = _generate_cache_header_key(key_prefix, request)
    cache.set(cache_key, key_headers, cache_timeout)

    # Generate a cache key for this response. This will be based on the
    # request path and the request HTTP header values (the vary ones).
    return generate_cache_key(request, response_headers, key_prefix)
Esempio n. 21
0
def vary(request):
    response = HttpResponse(request.GET['headers'])
    patch_vary_headers(response, cc_delim_re.split(request.GET['headers']))
    return response
Esempio n. 22
0
 def needs_etag(self, response):
     """Return True if an ETag header should be added to response."""
     cache_control_headers = cc_delim_re.split(response.get('Cache-Control', ''))
     return all(header.lower() != 'no-store' for header in cache_control_headers)
Esempio n. 23
0
                session_key = response.cookies[settings.SESSION_COOKIE_NAME]
            except KeyError:
                session_key = None

        if session_key is None:
            return response

        # Remove outgoing session cookie
        try:
            del response.cookies[settings.SESSION_COOKIE_NAME]
        except KeyError:
            pass

        # Strip "Vary: Coookie" header
        try:
            vary_headers = [x for x in cc_delim_re.split(response['Vary']) if x.lower() != 'cookie']
            if vary_headers:
                response['Vary'] = ', '.join([x for x in vary_headers])
            else:
                del response['Vary']
        except KeyError:
            pass

        if isinstance(response, HttpResponseRedirect):
            location = embed_session_id(response['Location'],
                                        session_key,
                                        domain=request.get_host())
            response = HttpResponseRedirect(location)
            return response

        response.content = session_uri(response.content,
def learn_cache_key(request, response, cache_timeout=None, key_prefix=None):
    """
    NOTE: This was copied from Django, with the following changes:
    * Caches based on full path, including the query string.
    * Stores the ETag and Last-Modified headers to support responding with
      "304 Not Modified" responses.
    * Supports custom "X-Vary-On-View" headers that can be used instead of the
      cookie header in the cache key for a response. This provides more control
      over what is cached, without altering the actual response.

    Learns what headers to take into account for some request path from the
    response object. It stores those headers in a global path registry so that
    later access to that path will know what headers to take into account
    without building the response object itself. The headers are named in the
    Vary header of the response, but we want to prevent response generation.

    The list of headers to use for cache key generation is stored in the same
    cache as the pages themselves. If the cache ages some data out of the
    cache, this just means that we have to build the response once to get at
    the Vary header and so at the list of headers to use for the cache key.

    """

    if key_prefix is None:
        key_prefix = settings.CACHE_MIDDLEWARE_KEY_PREFIX

    if cache_timeout is None:
        cache_timeout = settings.CACHE_MIDDLEWARE_SECONDS

    # Get the Vary headers, to build a cache key for this response. For
    # example, a response that varies on cookie would result in multiple
    # cached responses; one for each cookie value that is encountered. This
    # dictionary is effectively a list, as it does not have any values.
    response_headers = {}
    if response.has_header('Vary'):
        for header in cc_delim_re.split(response['Vary']):
            response_headers['HTTP_' + header.upper().replace('-', '_')] = None

    if response.has_header('X-Vary-On-View'):
        # When available, use the Vary-On-View header instead of the Cookie.
        response_headers['X-Vary-On-View'] = response['X-Vary-On-View']
        if 'HTTP_COOKIE' in response_headers:
            del response_headers['HTTP_COOKIE']
        key_headers = response_headers
    else:
        # When there is no vary on view, we can store the Etags/Last-Modified
        # values in the header list. Nothing varies, so we can be sure that
        # the values are not for a different version of the page. This avoids
        # fetching the response for no reason.
        key_headers = {}
        if response.has_header('Etag'):
            key_headers['HTTP_ETAG'] = response['Etag']
        if response.has_header('Last-Modified'):
            key_headers['HTTP_LAST_MODIFIED'] = response['Last-Modified']
        key_headers.update(response_headers)

    # Cache this list of headers against this request URL.
    # This is the "global path registry" that everyone is talking about.
    cache_key = _generate_cache_header_key(key_prefix, request)
    cache.set(cache_key, key_headers, cache_timeout)

    # Generate a cache key for this response. This will be based on the
    # request path and the request HTTP header values (the vary ones).
    return generate_cache_key(request, response_headers, key_prefix)
Esempio n. 25
0
            return response

        if self.needs_etag(response) and not response.has_header('ETag'):
            set_response_etag(response)

        etag = response.get('ETag')
        last_modified = response.get('Last-Modified')
        if last_modified:
            last_modified = parse_http_date_safe(last_modified)

        if etag or last_modified:
            return get_conditional_response(
                request,
                etag=etag,
                last_modified=last_modified,
                response=response,
            )

        return response

    def needs_etag(self, response):
<<<<<<< HEAD
        """
        Return True if an ETag header should be added to response.
        """
=======
        """Return True if an ETag header should be added to response."""
>>>>>>> 37c99181c9a6b95433d60f8c8ef9af5731096435
        cache_control_headers = cc_delim_re.split(response.get('Cache-Control', ''))
        return all(header.lower() != 'no-store' for header in cache_control_headers)