î
ªÍ X•:  ã               @   sÝ  d  Z  d d l m Z d d l Z d d l Z d d l Z d d l Z d d l m Z d d l	 m
 Z
 d d l m Z m Z d d l m Z m Z m Z d d l m Z m Z m Z m Z d d	 l m Z d d
 l m Z e j d ƒ Z e j d ƒ Z d d „  Z d d „  Z  d d „  Z! d d „  Z" d d d „ Z# d d d d d „ Z$ d d d „ Z% d d „  Z& d d „  Z' d d  „  Z( d! d" „  Z) d# d$ „  Z* d% d& „  Z+ d d' d d( d) „ Z, d d d d* d+ „ Z- d, d- „  Z. d S).aß  
This module contains helper functions for controlling caching. It does so by
managing the "Vary" header of responses. It includes functions to patch the
header of response objects directly and decorators that change functions to do
that header-patching themselves.

For information on the Vary header, see:

    https://tools.ietf.org/html/rfc7231#section-7.1.4

Essentially, the "Vary" HTTP header defines which headers a cache should take
into account when building its cache key. Requests with the same path but
different header content for headers named in "Vary" need to get different
cache keys to prevent delivery of wrong content.

An example: i18n middleware would need to distinguish caches by the
"Accept-language" header.
é    )Úunicode_literalsN)Úsettings)Úcaches)ÚHttpResponseÚHttpResponseNotModified)Úforce_bytesÚ
force_textÚ
iri_to_uri)Ú	http_dateÚparse_etagsÚparse_http_date_safeÚ
quote_etag)Úget_current_timezone_name)Úget_languagez\s*,\s*zdjango.requestc                sK  d d „  ‰  d d „  ‰ |  j  d ƒ r\ t j |  d ƒ } t ‡  f d d †  | Dƒ ƒ } n i  } d | k rž d	 | k rž t t | d ƒ | d	 ƒ | d	 <n  d
 | k rÀ d | k rÀ | d
 =n" d | k râ d
 | k râ | d =n  x0 | j ƒ  D]" \ } } | | | j d d ƒ <qï Wd j ‡ f d d †  | j ƒ  Dƒ ƒ } | |  d <d S)aÑ  
    This function patches the Cache-Control header by adding all
    keyword arguments to it. The transformation is as follows:

    * All keyword parameter names are turned to lowercase, and underscores
      are converted to hyphens.
    * If the value of a parameter is True (exactly True, not just a
      true value), only the parameter name is added to the header.
    * All other parameters are added with their value, after applying
      str() to it.
    c             S   sT   |  j  d d ƒ } t | ƒ d k r< | d j ƒ  | d f S| d j ƒ  d f Sd  S)Nú=é   r   T)ÚsplitÚlenÚlower)ÚsÚt© r   ú@/home/ubuntu/projects/ifolica/build/django/django/utils/cache.pyÚdictitem5   s    z%patch_cache_control.<locals>.dictitemc             S   s2   |  d d k r |  d Sd |  d |  d f Sd  S)Nr   Tr   z%s=%sr   )r   r   r   r   Ú	dictvalue<   s    z&patch_cache_control.<locals>.dictvaluezCache-Controlc             3   s   |  ] } ˆ  | ƒ Vq d  S)Nr   )Ú.0Úel)r   r   r   ú	<genexpr>D   s    z&patch_cache_control.<locals>.<genexpr>zmax-ageÚmax_ageZprivateZpublicÚ_ú-z, c             3   s   |  ] } ˆ  | ƒ Vq d  S)Nr   )r   r   )r   r   r   r   V   s    N)	ÚgetÚcc_delim_rer   ÚdictÚminÚintÚitemsÚreplaceÚjoin)ÚresponseÚkwargsÚccÚkÚvr   )r   r   r   Úpatch_cache_control)   s     "$

(r.   c             C   sy   |  j  d ƒ s d St d d „  t j |  d ƒ Dƒ ƒ } d | k ru y t | d ƒ SWqu t t f k
 rq Yqu Xn  d S)zŒ
    Returns the max-age from the response Cache-Control header as an integer
    (or ``None`` if it wasn't found or wasn't an integer.
    zCache-ControlNc             s   s   |  ] } t  | ƒ Vq d  S)N)Ú	_to_tuple)r   r   r   r   r   r   a   s    zget_max_age.<locals>.<genexpr>zmax-age)Ú
has_headerr#   r"   r   r%   Ú
ValueErrorÚ	TypeError)r)   r+   r   r   r   Úget_max_ageZ   s    &r3   c             C   s2   |  j  s. t t j |  j ƒ j ƒ  ƒ |  d <n  |  S)NÚETag)Z	streamingr   ÚhashlibÚmd5ÚcontentÚ	hexdigest)r)   r   r   r   Úset_response_etagi   s    	%r9   c             C   s4   t  j d |  j d i d d 6|  d 6ƒt d d ƒ S)NzPrecondition Failed: %sÚextraiœ  Ústatus_codeÚrequestÚstatus)ÚloggerÚwarningÚpathr   )r<   r   r   r   Ú_precondition_failedo   s    rA   c             C   s0   | r% | j  } t ƒ  } | | _  | St ƒ  Sd  S)N)Úcookiesr   )r<   r)   rB   r   r   r   Ú_not_modifiedz   s    			rC   c       	      C   sk  |  j  j d ƒ } | r' t | ƒ } n  |  j  j d ƒ } | rN t | ƒ } n  |  j  j d ƒ } |  j  j d ƒ } g  } | s„ | r¾ y t | p“ | ƒ } Wq¾ t k
 rº d  } d  } Yq¾ Xn  | ró d | j k oÞ d k  n ró d  } d  } n  | r| j d k rd  } d  } n  | r#| pD| r/| pD| r;| pD| oD| sg| r³| | k skd | k r³| r³| sŠ| r³| r³| | k r³|  j d
 k r¦t |  | ƒ St |  ƒ Sqg| r | rÌd | k sö| rÞ| | k sö| r | r | | k r t |  ƒ S| r;|  j d k r;| r;| r;| | k r;t |  | ƒ S| rg| rg| rg| | k rgt |  ƒ Sn  | S)NZHTTP_IF_MODIFIED_SINCEZHTTP_IF_UNMODIFIED_SINCEZHTTP_IF_NONE_MATCHZHTTP_IF_MATCHéÈ   i,  Ú*ÚGETÚHEAD)úGETúHEAD)rH   rI   )	ÚMETAr!   r   r   r1   r;   ÚmethodrC   rA   )	r<   ZetagZlast_modifiedr)   Zif_modified_sinceZif_unmodified_sinceZif_none_matchZif_matchZetagsr   r   r   Úget_conditional_response…   sX    &		$%
rL   c             C   sâ   | d k r t  j } n  | d k  r- d } n  t  j rƒ |  j d ƒ rƒ t |  d ƒ rt t |  j ƒ rt |  j t ƒ qƒ t |  ƒ }  n  |  j d ƒ s¢ t	 ƒ  |  d <n  |  j d ƒ sÎ t	 t
 j
 ƒ  | ƒ |  d <n  t |  d | ƒd S)a  
    Adds some useful headers to the given HttpResponse object:
        ETag, Last-Modified, Expires and Cache-Control

    Each header is only added if it isn't already set.

    cache_timeout is in seconds. The CACHE_MIDDLEWARE_SECONDS setting is used
    by default.
    Nr   r4   ÚrenderzLast-ModifiedZExpiresr   )r   ÚCACHE_MIDDLEWARE_SECONDSZ	USE_ETAGSr0   ÚhasattrÚcallablerM   Zadd_post_render_callbackr9   r
   Útimer.   )r)   Úcache_timeoutr   r   r   Úpatch_response_headersÈ   s    
	rS   c             C   s0   t  |  d d ƒt |  d d d d d d ƒd S)	zT
    Adds headers to a response to indicate that a page should never be cached.
    rR   r   Zno_cacheTZno_storeZmust_revalidateNéÿÿÿÿ)rS   r.   )r)   r   r   r   Úadd_never_cache_headersâ   s    rU   c                sx   |  j  d ƒ r% t j |  d ƒ } n g  } t d d „  | Dƒ ƒ ‰  ‡  f d d †  | Dƒ } d j | | ƒ |  d <d S)zÁ
    Adds (or updates) the "Vary" header in the given HttpResponse object.
    newheaders is a list of header names that should be in "Vary". Existing
    headers in "Vary" aren't removed.
    ÚVaryc             s   s   |  ] } | j  ƒ  Vq d  S)N)r   )r   Úheaderr   r   r   r   ø   s    z%patch_vary_headers.<locals>.<genexpr>c                s(   g  |  ] } | j  ƒ  ˆ  k r | ‘ q Sr   )r   )r   Z	newheader)Úexisting_headersr   r   ú
<listcomp>ù   s   	 z&patch_vary_headers.<locals>.<listcomp>z, N)r0   r"   r   Úsetr(   )r)   Ú
newheadersÚvary_headersZadditional_headersr   )rX   r   Úpatch_vary_headersê   s    	r]   c             C   sO   |  j  d ƒ s d St j |  d ƒ } t d d „  | Dƒ ƒ } | j ƒ  | k S)zS
    Checks to see if the response has a given header name in its Vary header.
    rV   Fc             s   s   |  ] } | j  ƒ  Vq d  S)N)r   )r   rW   r   r   r   r     s    z"has_vary_header.<locals>.<genexpr>)r0   r"   r   rZ   r   )r)   Zheader_queryr\   rX   r   r   r   Úhas_vary_headerþ   s
    r^   c             C   s†   t  j s t  j r2 | d t |  d t ƒ  ƒ 7} n  t  j r‚ t t ƒ  d d ƒ} | d | j d d ƒ j	 d ƒ j
 d d ƒ 7} n  | S)zDIf necessary, adds the current locale or time zone to the cache key.z.%sZLANGUAGE_CODEÚerrorsÚignoreÚasciiú r   )r   ÚUSE_I18NÚUSE_L10NÚgetattrr   ZUSE_TZr   r   ÚencodeÚdecoder'   )r<   Ú	cache_keyZtz_namer   r   r   Ú_i18n_cache_key_suffix	  s     	2ri   c       	      C   s¡   t  j ƒ  } xB | D]: } |  j j | ƒ } | d k	 r | j t | ƒ ƒ q q Wt  j t t |  j ƒ  ƒ ƒ ƒ } d | | | j ƒ  | j ƒ  f } t	 |  | ƒ S)z>Returns a cache key from the headers given in the header list.Nz-views.decorators.cache.cache_page.%s.%s.%s.%s)
r5   r6   rJ   r!   Úupdater   r	   Úbuild_absolute_urir8   ri   )	r<   rK   Ú
headerlistÚ
key_prefixÚctxrW   ÚvalueÚurlrh   r   r   r   Ú_generate_cache_key  s    !rq   c             C   sD   t  j t t | j ƒ  ƒ ƒ ƒ } d |  | j ƒ  f } t | | ƒ S)z)Returns a cache key for the header cache.z)views.decorators.cache.cache_header.%s.%s)r5   r6   r   r	   rk   r8   ri   )rm   r<   rp   rh   r   r   r   Ú_generate_cache_header_key'  s    !rr   rF   c             C   sy   | d k r t  j } n  t | |  ƒ } | d k rC t t  j } n  | j | ƒ } | d k	 rq t |  | | | ƒ Sd Sd S)af  
    Returns a cache key based on the request URL and query. It can be used
    in the request phase because it pulls the list of headers to take into
    account from the global URL registry and uses those to build a cache key
    to check against.

    If there is no headerlist stored, the page needs to be rebuilt, so this
    function returns None.
    N)r   ÚCACHE_MIDDLEWARE_KEY_PREFIXrr   r   ÚCACHE_MIDDLEWARE_ALIASr!   rq   )r<   rm   rK   Úcacherh   rl   r   r   r   Úget_cache_key/  s    
rv   c       	      C   sA  | d k r t  j } n  | d k r0 t  j } n  t | |  ƒ } | d k r[ t t  j } n  | j d ƒ rt  j py t  j } g  } x\ t	 j
 | d ƒ D]G } | j ƒ  j d d ƒ } | d k rÌ | rÌ q– n  | j d | ƒ q– W| j ƒ  | j | | | ƒ t |  |  j | | ƒ S| j | g  | ƒ t |  |  j g  | ƒ Sd S)a´  
    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.
    NrV   r    r   ZACCEPT_LANGUAGEZHTTP_)r   rs   rN   rr   r   rt   r0   rc   rd   r"   r   Úupperr'   ÚappendÚsortrZ   rq   rK   )	r<   r)   rR   rm   ru   rh   Zis_accept_language_redundantrl   rW   r   r   r   Úlearn_cache_keyE  s(    
rz   c             C   sP   |  j  d d ƒ } t | ƒ d k r< | d j ƒ  | d f S| d j ƒ  d f S)Nr   r   é   r   T)r   r   r   )r   r   r   r   r   r/   o  s    r/   )/Ú__doc__Ú
__future__r   r5   ÚloggingÚrerQ   Zdjango.confr   Zdjango.core.cacher   Zdjango.httpr   r   Zdjango.utils.encodingr   r   r	   Zdjango.utils.httpr
   r   r   r   Zdjango.utils.timezoner   Zdjango.utils.translationr   Úcompiler"   Ú	getLoggerr>   r.   r3   r9   rA   rC   rL   rS   rU   r]   r^   ri   rq   rr   rv   rz   r/   r   r   r   r   Ú<module>   s<   "1C*