def inner(request, *args, **kwargs): # Compute values (if any) for the requested resource. def get_last_modified(): if last_modified_func: dt = last_modified_func(request, *args, **kwargs) if dt: return timegm(dt.utctimetuple()) # The value from etag_func() could be quoted or unquoted. res_etag = etag_func(request, *args, **kwargs) if etag_func else None res_etag = quote_etag(res_etag) if res_etag is not None else None res_last_modified = get_last_modified() response = get_conditional_response( request, etag=res_etag, last_modified=res_last_modified, ) if response is None: response = func(request, *args, **kwargs) # Set relevant headers on the response if they don't already exist # and if the request method is safe. if request.method in ('GET', 'HEAD'): if res_last_modified and not response.has_header('Last-Modified'): response['Last-Modified'] = http_date(res_last_modified) if res_etag: response.setdefault('ETag', res_etag) return response
def wrapped_func(self, request, *args, **kwargs): response_format = self.perform_content_negotiation( request)[0].format etag_user = ( ':' + str(request.user.pk or 0)) if response_format == 'api' else '' raw_etag = '%s%s:%s:%s' % (response_format, etag_user, get_language(), (etag_func(request) if permissions else MapUpdate.current_cache_key())) etag = quote_etag(raw_etag) response = get_conditional_response(request, etag=etag) if response is None: cache_key = 'mapdata:api:' + request.path_info[5:].replace( '/', '-').strip('-') + ':' + raw_etag if cache_parameters is not None: for param, type_ in cache_parameters.items(): value = int( param in request.GET) if type_ == bool else type_( request.GET.get(param)) cache_key += ':' + urlsafe_base64_encode( str(value).encode()).decode() data = cache.get(cache_key) if data is not None: response = Response(data) if response is None: response = func(self, request, *args, **kwargs) if cache_parameters is not None and response.status_code == 200: cache.set(cache_key, response.data, 300) response['ETag'] = etag response['Cache-Control'] = 'no-cache' return response
def generate_etag(instance): # This method can hit the database. It's slow. Don't call it # in a request-response cycle. serializer_class = MODELS_SERIALIZERS_MAPPING[instance.__class__] serializer = serializer_class(instance=instance) json_data = JSONRenderer().render(serializer.data) return quote_etag(hashlib.md5(json_data).hexdigest())
def etag_from_value(request, value, add_quotes=False): if value is None: return None result = hashlib.sha1(request.path + str(value)).hexdigest() if add_quotes: result = quote_etag(result) return result
def process_conditional_request(self, view_instance, view_method, request, args, kwargs): etags, if_none_match, if_match = self.get_etags_and_matchers(request) res_etag = self.calculate_etag( view_instance=view_instance, view_method=view_method, request=request, args=args, kwargs=kwargs, ) if self.is_if_none_match_failed(res_etag, etags, if_none_match): if request.method in SAFE_METHODS: response = Response(status=status.HTTP_304_NOT_MODIFIED) else: response = self._get_and_log_precondition_failed_response( request=request) elif self.is_if_match_failed(res_etag, etags, if_match): response = self._get_and_log_precondition_failed_response( request=request) else: response = view_method(view_instance, request, *args, **kwargs) if self.rebuild_after_method_evaluation: res_etag = self.calculate_etag( view_instance=view_instance, view_method=view_method, request=request, args=args, kwargs=kwargs, ) if res_etag and not response.has_header('ETag'): response['ETag'] = quote_etag(res_etag) return response
def inner(request, *args, **kwargs): # Compute values (if any) for the requested resource. def get_last_modified(): if last_modified_func: dt = last_modified_func(request, *args, **kwargs) if dt: if not timezone.is_aware(dt): dt = timezone.make_aware(dt, datetime.timezone.utc) return int(dt.timestamp()) # The value from etag_func() could be quoted or unquoted. res_etag = etag_func(request, *args, **kwargs) if etag_func else None res_etag = quote_etag(res_etag) if res_etag is not None else None res_last_modified = get_last_modified() response = get_conditional_response( request, etag=res_etag, last_modified=res_last_modified, ) if response is None: response = func(request, *args, **kwargs) # Set relevant headers on the response if they don't already exist # and if the request method is safe. if request.method in ("GET", "HEAD"): if res_last_modified and not response.has_header("Last-Modified"): response.headers["Last-Modified"] = http_date(res_last_modified) if res_etag: response.headers.setdefault("ETag", res_etag) return response
def wrapped_func(self, request, *args, **kwargs): response_format = self.perform_content_negotiation(request)[0].format etag_user = (':'+str(request.user.pk or 0)) if response_format == 'api' else '' raw_etag = '%s%s:%s:%s' % (response_format, etag_user, get_language(), (etag_func(request) if permissions else MapUpdate.current_cache_key())) if base_mapdata_check and self.base_mapdata: raw_etag += ':%d' % request.user_permissions.can_access_base_mapdata etag = quote_etag(raw_etag) response = get_conditional_response(request, etag=etag) if response is None: cache_key = 'mapdata:api:'+request.path_info[5:].replace('/', '-').strip('-')+':'+raw_etag if cache_parameters is not None: for param, type_ in cache_parameters.items(): value = int(param in request.GET) if type_ == bool else type_(request.GET.get(param)) cache_key += ':'+urlsafe_base64_encode(str(value).encode()).decode() data = request_cache.get(cache_key) if data is not None: response = Response(data) if response is None: with GeometryMixin.dont_keep_originals(): response = func(self, request, *args, **kwargs) if cache_parameters is not None and response.status_code == 200: request_cache.set(cache_key, response.data, 900) if response.status_code == 200: response['ETag'] = etag response['Cache-Control'] = 'no-cache' return response
def handle_save(request, entry_id, handle): if not request.is_ajax(): return HttpResponseBadRequest() command = request.POST.get("command") messages = [] entry = None if command: messages += version_check(request.POST.get("version")) if command == "check": pass elif command in ("save", "autosave", "recover"): entry = _save_command(request, entry_id, handle, command, messages) else: return HttpResponseBadRequest("unrecognized command") resp = json.dumps({'messages': messages}, ensure_ascii=False) response = HttpResponse(resp, content_type=JSON_TYPE) # We want to set ETag ourselves to the correct value because the # etag decorator will actually set it to the value it had before the # request was processed! if entry: response['ETag'] = quote_etag(entry.latest.etag) return response
def inner(request, *args, **kwargs): # Compute values (if any) for the requested resource. def get_last_modified(): if last_modified_func: dt = last_modified_func(request, *args, **kwargs) if dt: return timegm(dt.utctimetuple()) res_etag = etag_func(request, *args, ** kwargs) if etag_func else None res_last_modified = get_last_modified() response = get_conditional_response( request, etag=res_etag, last_modified=res_last_modified, ) if response is None: response = func(request, *args, **kwargs) # Set relevant headers on the response if they don't already exist. if res_last_modified and not response.has_header('Last-Modified'): response['Last-Modified'] = http_date(res_last_modified) if res_etag and not response.has_header('ETag'): response['ETag'] = quote_etag(res_etag) return response
def get(self, request, *args, **kwargs): """Mixin implementation of django.views.decorators.http.condition""" # Resolve etag and last_modified etag = self.get_etag(request) etag = quote_etag(etag) if etag is not None else None last_modified = self.get_last_modified(request) last_modified = timegm( last_modified.utctimetuple()) if last_modified else None # Check request headers response = get_conditional_response(request, etag=etag, last_modified=last_modified) if response: return response # If we need get new data, do that response = super().get(request, *args, **kwargs) # Set relevant headers on the response if they don't already exist. if last_modified and not response.has_header('Last-Modified'): response['Last-Modified'] = http_date(last_modified) if etag and not response.has_header('ETag'): response['ETag'] = etag return response
def wrapper(*args, **kwargs): request = args[0] timestamp = request.GET.get('t', '') if timestamp: etag = quote_etag( hashlib.md5(timestamp.encode('utf-8')).hexdigest()) last_modified = formatdate(timeval=int(timestamp) // 1000, localtime=False, usegmt=True) else: etag = '' last_modified = '' if_none_match_etags = request.META.get('HTTP_IF_NONE_MATCH', '') if_modified_since = request.META.get('HTTP_IF_MODIFIED_SINCE', '') if ((if_none_match_etags and if_none_match_etags == etag) or (if_modified_since and if_modified_since == last_modified)): response = HttpResponse(status=304) response['ETag'] = etag response['Last-Modified'] = last_modified return response response = func(*args, **kwargs) response['ETag'] = etag response['Last-Modified'] = last_modified return response
def inner(request, *args, **kwargs): # Compute values (if any) for the requested resource. def get_last_modified(): if last_modified_func: dt = last_modified_func(request, *args, **kwargs) if dt: return timegm(dt.utctimetuple()) res_etag = etag_func(request, *args, **kwargs) if etag_func else None res_last_modified = get_last_modified() response = get_conditional_response( request, etag=res_etag, last_modified=res_last_modified, ) if response is None: response = func(request, *args, **kwargs) # Set relevant headers on the response if they don't already exist. if res_last_modified and not response.has_header('Last-Modified'): response['Last-Modified'] = http_date(res_last_modified) if res_etag and not response.has_header('ETag'): response['ETag'] = quote_etag(res_etag) return response
def dispatch(self, request, *args, **kwargs): def get_not_modified_response(resource_etag): if not request.method in ('GET', 'HEAD'): return None if_none_match = request.META.get("HTTP_IF_NONE_MATCH") if if_none_match: # There can be more than one ETag in the request, so we # consider the list of values. try: etags = parse_etags(if_none_match) except ValueError: # In case of invalid etag ignore all ETag headers. # Apparently Opera sends invalidly quoted headers at times # (we should be returning a 400 response, but that's a # little extreme) -- this is Django bug #10681. if_none_match = None if not if_none_match: return None if not resource_etag: return None if resource_etag in etags: return Response(status=status.HTTP_304_NOT_MODIFIED) else: return None # Code adapted from the original dispatch method: request = self.initialize_request(request, *args, **kwargs) self.request = request self.args = args self.kwargs = kwargs self.headers = self.default_response_headers # deprecate? try: self.initial(request, *args, **kwargs) # Get the appropriate handler method if request.method.lower() in self.http_method_names: resource_etag = self.get_etag(request, *args, **kwargs) handler = getattr(self, request.method.lower(), self.http_method_not_allowed) # The ETag header is added! response = handler(request, *args, **kwargs) response['ETag'] = quote_etag(resource_etag) else: handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc: response = self.handle_exception(exc) self.response = self.finalize_response(request, response, *args, **kwargs) return self.response
def test_content_headers_etag(self): self.file_viewer.extract() self.file_viewer.select('install.js') obj = getattr(self.file_viewer, 'left', self.file_viewer) etag = quote_etag(obj.selected.get('sha256')) res = self.client.get(self.file_url('install.js'), HTTP_IF_NONE_MATCH=etag) assert res.status_code == 304
def _add_conditional_request_headers(self, response): etag = self.get_etag() if etag: response['ETag'] = quote_etag(etag) last_modified_dt = self.get_last_modified_dt() if last_modified_dt and isinstance(last_modified_dt, datetime): if not timezone.is_aware(last_modified_dt): last_modified_dt = timezone.make_aware(last_modified_dt, timezone.utc) response['Last-Modified'] = http_date(last_modified_dt.timestamp())
def create(self, request, share, format=None): from django.utils.http import http_date, quote_etag from calendar import timegm obj = ShareObject(share=request.share,data=request.data,last_client=request.auth) obj.save() location = request.build_absolute_uri(reverse('v1:share-detail',kwargs={'share':share,'pk':obj.no})) headers = {'Location':location,'ETag':quote_etag(str(obj.version)), 'Last-modified':http_date(timegm(obj.last_modified.utctimetuple()))} return Response(obj.data,headers=headers,status=status.HTTP_201_CREATED)
def __init__(self, request, path, content=None, status=None, content_type='application/octet-stream', etag=None): super(HttpResponseXSendFile, self).__init__('', status=status, content_type=content_type) # We normalize the path because if it contains dots, nginx will flag # the URI as unsafe. self[settings.XSENDFILE_HEADER] = os.path.normpath(path) if etag: self['ETag'] = quote_etag(etag)
def response_add_last_modified_and_etag(request, response, last_modified): """ Adds the Last-Modified and ETag HTTP headers to the given response based on a datetime value passed as a parameter and the request path. """ response = response_add_last_modified(response, last_modified) etag = quote_etag(hashlib.sha1(request.path + str(last_modified)).hexdigest()) response = response_add_etag(response, etag) return response
def inner(request, *args, **kwargs): # Get HTTP request headers if_modified_since = request.META.get("HTTP_IF_MODIFIED_SINCE") if_none_match = request.META.get("HTTP_IF_NONE_MATCH") if_match = request.META.get("HTTP_IF_MATCH") if if_none_match or if_match: # There can be more than one ETag in the request, so we # consider the list of values. etags = parse_etags(if_none_match or if_match) # Compute values (if any) for the requested resource. if etag_func: res_etag = etag_func(request, *args, **kwargs) else: res_etag = None if last_modified_func: dt = last_modified_func(request, *args, **kwargs) if dt: res_last_modified = formatdate(timegm(dt.utctimetuple()))[:26] + 'GMT' else: res_last_modified = None else: res_last_modified = None response = None if not ((if_match and (if_modified_since or if_none_match)) or (if_match and if_none_match)): # We only get here if no undefined combinations of headers are # specified. if ((if_none_match and (res_etag in etags or "*" in etags and res_etag)) and (not if_modified_since or res_last_modified == if_modified_since)): if request.method in ("GET", "HEAD"): response = HttpResponseNotModified() else: response = HttpResponse(status=412) elif if_match and ((not res_etag and "*" in etags) or (res_etag and res_etag not in etags)): response = HttpResponse(status=412) elif (not if_none_match and if_modified_since and request.method == "GET" and res_last_modified == if_modified_since): response = HttpResponseNotModified() if response is None: response = func(request, *args, **kwargs) # Set relevant headers on the response if they don't already exist. if res_last_modified and not response.has_header('Last-Modified'): response['Last-Modified'] = res_last_modified if res_etag and not response.has_header('ETag'): response['ETag'] = quote_etag(res_etag) return response
def response_add_last_modified_and_etag(request, response, last_modified): """ Adds the Last-Modified and ETag HTTP headers to the given response based on a datetime value passed as a parameter and the request path. """ response = response_add_last_modified(response, last_modified) etag = quote_etag( hashlib.sha1(request.path + str(last_modified)).hexdigest()) response = response_add_etag(response, etag) return response
def postprocess_response(self, response, data, response_data, collection): """ If you need to do any further processing of the HttpResponse objects, this is the place to do it. """ etag = self.generate_etag() if etag: response['ETag'] = quote_etag(etag) response['Cache-Control'] = 'private, max-age=0' return response
def test_should_add_object_etag_value_default_precondition_map_decorator(self): class TestView(views.APIView): @api_etag(dummy_api_etag_func) def get(self, request, *args, **kwargs): return Response('Response from GET method') view_instance = TestView() response = view_instance.get(request=self.request) expected_etag_value = dummy_api_etag_func() self.assertEqual(response.get('Etag'), quote_etag(expected_etag_value)) self.assertEqual(response.data, 'Response from GET method')
def test_should_add_default_etag_value(self): class TestView(views.APIView): @etag() def get(self, request, *args, **kwargs): return Response('Response from method') view_instance = TestView() response = view_instance.get(request=self.request) expected_etag_value = default_etag_func() self.assertEqual(response.get('Etag'), quote_etag(expected_etag_value)) self.assertEqual(response.data, 'Response from method')
def set_etag(self, request, response): if 'ETag' in response: etag = parse_etags(response['ETag'])[0] else: etag = hashlib.md5(response.content).hexdigest() response['ETag'] = quote_etag(etag) # Cache the etag for subsequent look ups. This can be cached # indefinitely since these are unique values cache = self.get_cache(request, response) cache.set(etag, 1, MAX_CACHE_AGE)
def setUp(self): def calculate_etag(**kwargs): return '123' class TestView(views.APIView): @etag(calculate_etag) def get(self, request, *args, **kwargs): return Response('Response from method') self.view_instance = TestView() self.expected_etag_value = quote_etag(calculate_etag())
def __init__(self, request, path, content=None, status=None, content_type='application/octet-stream', etag=None): self.request = request self.path = path super(HttpResponseSendFile, self).__init__('', status=status, content_type=content_type) header_path = self.path if isinstance(header_path, six.text_type): header_path = header_path.encode('utf8') if settings.XSENDFILE: self[settings.XSENDFILE_HEADER] = header_path if etag: self['ETag'] = quote_etag(etag)
def __init__(self, request, path, content=None, status=None, content_type='application/octet-stream', etag=None): self.request = request self.path = path super(HttpResponseSendFile, self).__init__('', status=status, content_type=content_type) header_path = self.path if isinstance(header_path, unicode): header_path = header_path.encode('utf8') if settings.XSENDFILE: self[settings.XSENDFILE_HEADER] = header_path if etag: self['ETag'] = quote_etag(etag)
def test_should_use_custom_func_if_it_is_defined(self): def calculate_etag(**kwargs): return 'Custom etag' class TestView(views.APIView): @etag(calculate_etag) def get(self, request, *args, **kwargs): return Response('Response from method') view_instance = TestView() response = view_instance.get(request=self.request) expected_etag_value = quote_etag('Custom etag') self.assertEqual(response.get('Etag'), expected_etag_value) self.assertEqual(response.data, 'Response from method')
def test_should__rebuild_after_method_evaluation__if_it_asked(self): call_stack = [] def calculate_etag(**kwargs): call_stack.append(1) return ''.join([str(i) for i in call_stack]) class TestView(views.APIView): @etag(calculate_etag, rebuild_after_method_evaluation=True) def get(self, request, *args, **kwargs): return Response('Response from method') view_instance = TestView() response = view_instance.get(self.request) expected_etag_value = quote_etag('11') self.assertEqual(response.get('Etag'), expected_etag_value) self.assertEqual(response.data, 'Response from method')
def wrapper(request, file_id, *args, **kw): file_ = get_object_or_404(File, pk=file_id) result = allowed(request, file_) if result is not True: return result try: obj = FileViewer(file_) except ObjectDoesNotExist: log.error('Error 404 for file %s: %s' % ( file_id, traceback.format_exc())) raise http.Http404 response = func(request, obj, *args, **kw) if obj.selected: response['ETag'] = quote_etag(obj.selected.get('sha256')) response['Last-Modified'] = http_date(obj.selected.get('modified')) return response
def field_updater( submit_url, # url that the ajax will POST the create to if_match=None, # If-Match header will be sent with this value, unless False if_unmodified_since=None, # If-Unmodified-Since header will be sent with this value unless False options=None, # Options for this field updater **kwargs): ''' Renders a value, on click it will render a form, on submit update that value by AJAX ''' # any extra attributes will be editable, currently we only support one try: attribute_name, attribute_value = kwargs.popitem() except KeyError: raise AttributeError( 'This tag requires a key value attribute describing the field to be updated' ) # default values for options to be overridden by parameter updater_options default_options = { 'prefix': 'field-updater', # prefix used for id and class scoping, 'allowDelete': False, # delete will be allowed only if requested 'bodyEncode': 'form-data', # the content encoding for POST bodies 'emptyDisplay': 'empty', # the text displayed when the value is an empty string or none 'headers': {}, # the set of headers sent with ajax requests 'inputAttributes': { # input attributes 'type': 'text', }, } updater_options = dict(default_options, ** options) if options else default_options validate_options(updater_options) # random uuid to scope the DOM elements instance_id = uuid.uuid4() return { 'updater': { 'instanceId': instance_id, 'submitUrl': submit_url, 'attributeName': attribute_name, 'attributeValue': attribute_value, 'ifMatch': quote_etag(if_match) if if_match else if_match, 'ifUnmodifiedSince': if_unmodified_since, 'options': updater_options, }, }
def wrapper(request, file_id, *args, **kw): file_ = get_object_or_404(File, pk=file_id) result = allowed(request, file_) if result is not True: return result try: obj = FileViewer(file_) except ObjectDoesNotExist: log.error('Error 404 for file %s: %s' % (file_id, traceback.format_exc())) raise http.Http404 response = func(request, obj, *args, **kw) if obj.selected: response['ETag'] = quote_etag(obj.selected.get('sha256')) response['Last-Modified'] = http_date(obj.selected.get('modified')) return response
def inner(request, *args, **kwargs): # Compute values (if any) for the requested resource. def get_last_modified(): if last_modified_func: dt = last_modified_func(request, *args, **kwargs) if dt: return timegm(dt.utctimetuple()) # The value from etag_func() could be quoted or unquoted. res_etag = etag_func(request, *args, **kwargs) if etag_func else None res_etag = quote_etag(res_etag) if res_etag is not None else None res_last_modified = get_last_modified() response = get_conditional_response( request, etag=res_etag, last_modified=res_last_modified,
def wrapper(request, one_id, two_id, *args, **kw): one = get_object_or_404(File, pk=one_id) two = get_object_or_404(File, pk=two_id) for obj in [one, two]: result = allowed(request, obj) if result is not True: return result try: obj = DiffHelper(one, two) except ObjectDoesNotExist: raise http.Http404 response = func(request, obj, *args, **kw) if obj.left.selected: response['ETag'] = quote_etag(obj.left.selected.get('sha256')) response['Last-Modified'] = http_date( obj.left.selected.get('modified')) return response
def wrapper(request, one_id, two_id, *args, **kw): one = get_object_or_404(File, pk=one_id) two = get_object_or_404(File, pk=two_id) for obj in [one, two]: result = allowed(request, obj) if result is not True: return result try: obj = DiffHelper(one, two) except ObjectDoesNotExist: raise http.Http404 response = func(request, obj, *args, **kw) if obj.left.selected: response['ETag'] = quote_etag(obj.left.selected.get('sha256')) response['Last-Modified'] = http_date(obj.left.selected .get('modified')) return response
def __init__( self, request, path, content=None, status=None, content_type='application/octet-stream', etag=None, attachment=False, ): super().__init__('', status=status, content_type=content_type) # We normalize the path because if it contains dots, nginx will flag # the URI as unsafe. self[settings.XSENDFILE_HEADER] = os.path.normpath(path) if etag: self['ETag'] = quote_etag(etag) if attachment: self['Content-Disposition'] = 'attachment'
def test_should_use_custom_method_from_view_if__etag_func__is_string(self): used_kwargs = {} class TestView(views.APIView): @etag('calculate_etag') def get(self, request, *args, **kwargs): return Response('Response from method') def calculate_etag(self, **kwargs): used_kwargs.update(kwargs) used_kwargs.update({'self': self}) return 'Custom etag' view_instance = TestView() response = view_instance.get(request=self.request) expected_etag_value = quote_etag('Custom etag') self.assertEqual(response.get('Etag'), expected_etag_value) self.assertEqual(response.data, 'Response from method') self.assertEqual(used_kwargs['self'], used_kwargs['view_instance'])
def test_api_safe(client, section_doc, section_case, if_none_match, method): """ Test GET & HEAD on wiki.document_api endpoint. """ section_id, exp_content = SECTION_CASE_TO_DETAILS[section_case] url = section_doc.get_absolute_url() + '$api' if section_id: url += '?section={}'.format(section_id) headers = {} if method == 'GET': # Starting with Django 1.11, condition headers will be # considered only for GET requests. The one exception # is a PUT request to the wiki.document_api endpoint, # but that's not relevant here. if if_none_match == 'match': response = getattr(client, method.lower())(url, **headers) assert 'etag' in response headers['HTTP_IF_NONE_MATCH'] = response['etag'] elif if_none_match == 'mismatch': headers['HTTP_IF_NONE_MATCH'] = 'ABC' response = getattr(client, method.lower())(url, **headers) if (if_none_match == 'match') and (method == 'GET'): exp_content = '' assert response.status_code == 304 else: assert response.status_code == 200 assert_shared_cache_header(response) assert 'last-modified' not in response if method == 'GET': assert quote_etag(calculate_etag(exp_content)) in response['etag'] assert (response['x-kuma-revision'] == str(section_doc.current_revision_id)) if method == 'GET': assert response.content == exp_content.decode('utf-8')
def test_api_safe(client, section_doc, section_case, if_none_match, method): """ Test GET & HEAD on wiki.document_api endpoint. """ section_id, exp_content = SECTION_CASE_TO_DETAILS[section_case] url = section_doc.get_absolute_url() + "$api" if section_id: url += "?section={}".format(section_id) headers = dict(HTTP_HOST=settings.WIKI_HOST) if method == "GET": # Starting with Django 1.11, condition headers will be # considered only for GET requests. The one exception # is a PUT request to the wiki.document_api endpoint, # but that's not relevant here. if if_none_match == "match": response = getattr(client, method.lower())(url, **headers) assert "etag" in response headers["HTTP_IF_NONE_MATCH"] = response["etag"] elif if_none_match == "mismatch": headers["HTTP_IF_NONE_MATCH"] = "ABC" response = getattr(client, method.lower())(url, **headers) if (if_none_match == "match") and (method == "GET"): exp_content = "" assert response.status_code == 304 else: assert response.status_code == 200 assert_shared_cache_header(response) assert "last-modified" not in response if method == "GET": assert quote_etag(calculate_etag(exp_content)) in response["etag"] assert response["x-kuma-revision"] == str( section_doc.current_revision_id) if method == "GET": assert response.content.decode(response.charset) == exp_content
def test_api_safe(client, section_doc, section_case, if_none_match, method): """ Test GET & HEAD on wiki.document_api endpoint. """ section_id, exp_content = SECTION_CASE_TO_DETAILS[section_case] url = section_doc.get_absolute_url() + '$api' if section_id: url += '?section={}'.format(section_id) headers = {} if method == 'GET': # Starting with Django 1.11, condition headers will be # considered only for GET requests. The one exception # is a PUT request to the wiki.document_api endpoint, # but that's not relevant here. if if_none_match == 'match': response = getattr(client, method.lower())(url, **headers) assert 'etag' in response headers['HTTP_IF_NONE_MATCH'] = response['etag'] elif if_none_match == 'mismatch': headers['HTTP_IF_NONE_MATCH'] = 'ABC' response = getattr(client, method.lower())(url, **headers) if (if_none_match == 'match') and (method == 'GET'): exp_content = '' assert response.status_code == 304 else: assert response.status_code == 200 assert_shared_cache_header(response) assert 'last-modified' not in response if method == 'GET': assert quote_etag(calculate_etag(exp_content)) in response['etag'] assert (response['x-kuma-revision'] == str( section_doc.current_revision_id)) if method == 'GET': assert response.content == exp_content.decode('utf-8')
def thumbnail(request, root_dir=None): """ Scales (conserving aspect ratio) a requested image with given width, height and orientation """ width = request.GET.get('width', None) height = request.GET.get('height', None) crop = request.GET.get('crop', None) orientation = request.GET.get('orientation', constants.ORIENTATION_DEFAULT) geometry_string = make_geometry_string(width, height) if root_dir is None: root_dir = settings.IMAGERESIZER_ROOT resource_path = request.path.replace( settings.IMAGERESIZER_PATH_TO_REMOVE, '', 1 ) path = os.path.realpath(os.path.join(root_dir, resource_path)) if not os.path.exists(path): raise Http404 if geometry_string is None: image = ImageFile(path, storage=default.storage) image.set_size() geometry_string = make_geometry_string(image.width, image.height) thumbnail = get_thumbnail(path, geometry_string, ll_transverse=True \ if orientation == constants.ORIENTATION_LANDSCAPE \ else False) mimetype, encoding = mimetypes.guess_type(path) response = HttpResponse(thumbnail.read(), mimetype=mimetype) last_modified = http_date( time.mktime( thumbnail.storage.modified_time(thumbnail.name).timetuple() ) ) response['Last-Modified'] = last_modified response['ETag'] = quote_etag(hashlib.sha1(last_modified).hexdigest()) response['Content-Length'] = thumbnail.storage.size(thumbnail.name) response['Accept-Ranges'] = 'bytes' return response
def setUp(self): def calculate_etag(**kwargs): return '123' class TestView(views.APIView): @api_etag(calculate_etag) def head(self, request, *args, **kwargs): return Response('Response from HEAD method') @api_etag(calculate_etag) def options(self, request, *args, **kwargs): return Response('Response from OPTIONS method') @api_etag(calculate_etag, precondition_map={}) def post(self, request, *args, **kwargs): return Response('Response from POST method', status=status.HTTP_201_CREATED) @api_etag(calculate_etag) def get(self, request, *args, **kwargs): return Response('Response from GET method') @api_etag(calculate_etag) def put(self, request, *args, **kwargs): return Response('Response from PUT method') @api_etag(calculate_etag) def patch(self, request, *args, **kwargs): return Response('Response from PATCH method') @api_etag(calculate_etag) def delete(self, request, *args, **kwargs): return Response('Response from DELETE method', status=status.HTTP_204_NO_CONTENT) self.view_instance = TestView() self.expected_etag_value = quote_etag(calculate_etag())
def get(self, request, *args, **kwargs): """Mixin implementation of django.views.decorators.http.condition""" # Resolve etag and last_modified etag = self.get_etag(request) etag = quote_etag(etag) if etag is not None else None last_modified = self.get_last_modified(request) last_modified = timegm(last_modified.utctimetuple()) if last_modified else None # Check request headers response = get_conditional_response(request, etag=etag, last_modified=last_modified) if response: return response # If we need get new data, do that response = super().get(request, *args, **kwargs) # Set relevant headers on the response if they don't already exist. if last_modified and not response.has_header('Last-Modified'): response['Last-Modified'] = http_date(last_modified) if etag and not response.has_header('ETag'): response['ETag'] = etag return response
def test_quoting(self): self.assertEqual(http.quote_etag('etag'), '"etag"') # unquoted self.assertEqual(http.quote_etag('"etag"'), '"etag"') # quoted self.assertEqual(http.quote_etag('W/"etag"'), 'W/"etag"') # quoted, weak
def testQuoting(self): quoted_etag = http.quote_etag(r'e\t"ag') self.assertEqual(quoted_etag, r'"e\\t\"ag"')
def test_quoting(self): original_etag = r'e\t"ag' quoted_etag = http.quote_etag(original_etag) self.assertEqual(quoted_etag, r'"e\\t\"ag"') self.assertEqual(http.unquote_etag(quoted_etag), original_etag)
def set_response_etag(response): if not response.streaming: response['ETag'] = quote_etag(hashlib.md5(response.content).hexdigest()) return response