o a?@sFdZddlZddlZddlmZddlmZddlmZddl m Z m Z ddl m Z mZmZmZddlmZdd lmZdd lmZdd lmZed Zd dZddZddZddZd6ddZd7ddZddZ ddZ!ddZ"dd Z#d6d!d"Z$d#d$Z%d%d&Z&d'd(Z'd)d*Z(d+d,Z)d-d.Z*d8d0d1Z+d7d2d3Z,d4d5Z-dS)9a 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. N) defaultdict)settings)caches) HttpResponseHttpResponseNotModified) http_date parse_etagsparse_http_date_safe quote_etag) log_response)_lazy_re_compile)get_current_timezone_name) get_languagez\s*,\s*c  sldd}ddtt}|dr2t|jdD]}||\}dkr-||q||<qd|vrGd|vrGtt|d|d|d<d |vrSd |vrS|d =n d |vr^d |vr^|d =| D]\}}| d d dkrx||qb||<qbg}| D]&\} t | trd | vrd h} | fdd| Dq| | qd|}||jd<dS)a Patch 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. cSs<|dd}t|dkr|d|dfS|ddfS)N=rTsplitlenlowerstr4/usr/lib/python3/dist-packages/django/utils/cache.pydictitem1s  z%patch_cache_control..dictitemcWs(|ddur |dSd|d|dfS)NrTrz%s=%sr)rrrr dictvalue8s z&patch_cache_control..dictvalue Cache-Controlzno-cachemax-agemax_ageprivatepublic_-Tcsg|]}|qSrr).0valuer directiverr bsz'patch_cache_control.., N)rsetget cc_delim_rerheadersaddminintitemsreplace isinstanceextendappendjoin) responsekwargsrccfieldr$kv directivesvaluesrr%rpatch_cache_control%s:        r>c CsV|dsdStddt|jdD}zt|dWStttfy*YdSw)z Return the max-age from the response Cache-Control header as an integer, or None if it wasn't found or wasn't an integer. rNcss|]}t|VqdSN) _to_tuple)r#elrrr pszget_max_age..r) has_headerdictr+rr,r/ ValueError TypeErrorKeyError)r6r8rrr get_max_ageis rHcCs*|js|jrtt|j|jd<|S)NETag) streamingcontentr hashlibmd5 hexdigestr,r6rrrset_response_etagws rPcCs tdd}td|j||d|S)Ni)statuszPrecondition Failed: %s)r6request)rr path)rRr6rrr_precondition_failed}s rTcCs8t}|rdD]}||vr|j||j|<q|j|_|S)N)rzContent-LocationDaterIExpiresz Last-ModifiedVary)rr,cookies)rRr6 new_responseheaderrrr _not_modifiedsr[cCs|rd|jkrdks|S|St|jdd}|jd}|o%t|}t|jdd}|jd}|o:t|}|rFt||sFt|S|sS|rSt||sSt|S|rht||sh|j dvrdt ||St|S|s{|r{t ||s{|j dvr{t ||S|S) Ni, HTTP_IF_MATCHHTTP_IF_UNMODIFIED_SINCEHTTP_IF_NONE_MATCHHTTP_IF_MODIFIED_SINCE)GETHEAD) status_coderMETAr*r _if_match_passesrT_if_unmodified_since_passes_if_none_match_passesmethodr[_if_modified_since_passes)rRetag last_modifiedr6if_match_etagsif_unmodified_sinceif_none_match_etagsif_modified_sincerrrget_conditional_responses:        rqcCs,|sdS|dgkr dS|drdS||vS)zM Test the If-Match comparison as defined in section 3.1 of RFC 7232. F*TW/) startswith target_etagetagsrrrrfs  rfcCs |o||kS)z\ Test the If-Unmodified-Since comparison as defined in section 3.4 of RFC 7232. r)rlrnrrrrgs rgcCs6|sdS|dgkr dS|d}dd|D}||vS)zR Test the If-None-Match comparison as defined in section 3.2 of RFC 7232. TrrFrscss|]}|dVqdS)rsNstrip)r#rkrrrrBsz(_if_none_match_passes..rxrurrrrhs  rhcCs| p||kS)zV Test the If-Modified-Since comparison as defined in section 3.3 of RFC 7232. r)rlrprrrrjsrjcCsJ|durtj}|dkr d}|dstt||jd<t||ddS)z Add HTTP caching headers to the given HttpResponse: 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. NrrV)r)rCACHE_MIDDLEWARE_SECONDSrCrtimer,r>)r6 cache_timeoutrrrpatch_response_headerss  r}cCs"t|ddt|ddddddS)zS Add headers to a response to indicate that a page should never be cached. )r|T)no_cacheno_storemust_revalidaterN)r}r>rOrrradd_never_cache_headerss rcsr|drt|jd}ng}dd|Dfdd|D}||7}d|vr/d|jd<dSd||jd<dS) a) Add (or update) the "Vary" header in the given HttpResponse object. newheaders is a list of header names that should be in "Vary". If headers contains an asterisk, then "Vary" header will consist of a single asterisk '*'. Otherwise, existing headers in "Vary" aren't removed. rWcSh|]}|qSrrr#rZrrr %z%patch_vary_headers..csg|] }|vr|qSrr)r# newheaderexisting_headersrrr'&s z&patch_vary_headers..rrr(N)rCr+rr,r5)r6 newheaders vary_headersadditional_headersrrrpatch_vary_headerss rcCs8|dsdSt|jd}dd|D}||vS)zR Check to see if the response has a given header name in its Vary header. rWFcSrrrrrrrr6rz"has_vary_header..)rCr+rr,r)r6 header_queryrrrrrhas_vary_header/s  rcCs4tjr|dt|dt7}tjr|dt7}|S)zCIf necessary, add the current locale or time zone to the cache key.z.%s LANGUAGE_CODE)rUSE_I18NgetattrrUSE_TZr )rR cache_keyrrr_i18n_cache_key_suffix:s rc Csjt}|D]}|j|}|dur||qt|d}d||||f}t||S)z=Return a cache key from the headers given in the header list.Nasciiz-views.decorators.cache.cache_page.%s.%s.%s.%s) rLrMrer*updateencodebuild_absolute_urirNr) rRri headerlist key_prefixctxrZr$urlrrrr_generate_cache_keyFs  rcCs.t|d}d||f}t||S)z(Return a cache key for the header cache.rz)views.decorators.cache.cache_header.%s.%s)rLrMrrrNr)rrRrrrrr_generate_cache_header_keySs  rrbcCsN|durtj}t||}|durttj}||}|dur%t||||SdS)ae Return 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 isn't a headerlist stored, return None, indicating that the page needs to be rebuilt. N)rCACHE_MIDDLEWARE_KEY_PREFIXrrCACHE_MIDDLEWARE_ALIASr*r)rRrricacherrrrr get_cache_key[s    rc Cs|durtj}|durtj}t||}|durttj}|drYtj}g}t |j dD]}| dd}|dks>|sE| d|q.|||||t||j||S||g|t||jg|S)a Learn what headers to take into account for some request URL from the response object. Store 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. NrWr"r!ACCEPT_LANGUAGEHTTP_)rrrzrrrrCrr+rr,upperr1r4sortr)rri) rRr6r|rrris_accept_language_redundantrrZrrrlearn_cache_keyqs(     rcCs<|dd}t|dkr|d|dfS|ddfS)NrrrTrrrrrr@s  r@r?)NNN)NrbN).__doc__rLr{ collectionsr django.confrdjango.core.cacher django.httprrdjango.utils.httprrr r django.utils.logr django.utils.regex_helperr django.utils.timezoner django.utils.translationrr+r>rHrPrTr[rqrfrgrhrjr}rrrrrrrrr@rrrrsB       D +      )