def dispatch(self, request, *args, **kwargs): """Handle a HTTP request and dispatch to a handler. Args: request (django.http.HttpRequest): The HTTP request from the client. *args (tuple): Positional arguments passed to the handler. **kwargs (dict): Keyword arguments passed to the handler. Returns: django.http.HttpResponse: The resulting HTTP response from the handler. """ handle_etag = request.method.upper() in ('GET', 'HEAD') if handle_etag: etag = self.get_etag_data(request, *args, **kwargs) if etag: etag = encode_etag(etag) if etag_if_none_match(request, etag): return HttpResponseNotModified() response = super(ETagViewMixin, self).dispatch(request, *args, **kwargs) if handle_etag and etag and 200 <= response.status_code < 300: set_etag(response, etag) return response
def test_generate_etag_with_encode_etag_true(self): """Testing WebAPIResource.generate_etag with encode_etag=True""" class TestObject(object): my_field = 'abc' request = RequestFactory().request() request.user = User() resource = WebAPIResource() obj = TestObject() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') etag = resource.generate_etag(obj, ['my_field'], request, encode_etag=True) self.assertEqual(len(w), 1) self.assertIn('generate_etag is deprecated', six.text_type(w[0].message)) self.assertEqual( etag, encode_etag(':%s' % repr(resource.serialize_object(obj, request=request))))
def encode_etag(self, request, etag, *args, **kwargs): """Encodes an ETag for usage in a header. This will take a precomputed ETag, augment it with additional information, encode it as a SHA1, and return it. """ return encode_etag('%s:%s' % (request.user.username, etag))
def _test_without_matching_etag(self, method): class MyView(ETagViewMixin, View): def get_etag_data(self, *args, **kwargs): return 'test123' def head(self, *args, **kwargs): return HttpResponse() setattr(MyView, method.lower(), lambda *args, **kwargs: HttpResponse()) view = MyView.as_view() request = RequestFactory().request(REQUEST_METHOD=method) request.META['HTTP_IF_NONE_MATCH'] = encode_etag('nope') response = view(request) self.assertNotIsInstance(response, HttpResponseNotModified) self.assertTrue(response.has_header('ETag')) self.assertEqual(response['ETag'], encode_etag('test123'))
def make_etag(self, renderer_settings): """Return an ETag identifying this render.""" etag = '%s:%s:%s:%s' % ( get_diff_renderer_class(), renderer_settings['collapse_all'], renderer_settings['highlighting'], settings.TEMPLATE_SERIAL) return encode_etag(etag)
def make_etag(self, renderer_settings, filediff_id, interdiffset_or_id=None, **kwargs): """Return an ETag identifying this render.""" if interdiffset_or_id and isinstance(interdiffset_or_id, DiffSet): interdiffset_or_id = interdiffset_or_id.pk etag = "%s:%s:%s:%s:%s:%s" % ( get_diff_renderer_class(), renderer_settings["collapse_all"], renderer_settings["highlighting"], filediff_id, interdiffset_or_id, settings.TEMPLATE_SERIAL, ) return encode_etag(etag)
def _test_ignore_etag(self, method): class MyView(ETagViewMixin, View): def get_etag_data(self, *args, **kwargs): return 'test123' setattr(MyView, method.lower(), lambda *args, **kwargs: HttpResponse('hi there')) view = MyView.as_view() request = RequestFactory().request(REQUEST_METHOD=method) request.META['HTTP_IF_NONE_MATCH'] = encode_etag('test123') response = view(request) self.assertNotIsInstance(response, HttpResponseNotModified) self.assertEqual(response.content, b'hi there') self.assertFalse(response.has_header('ETag'))
def make_etag(self, renderer_settings, filediff_id, interfilediff_id=None, **kwargs): """Return an ETag identifying this render. Args: renderer_settings (dict): The settings determining how to render this diff. The following keys are required: ``collapse_all`` and ``highlighting``. The following key is optional: ``show_deleted``. filediff_id (int): The ID of the :py:class:`~reviewboard.diffviewer.models.filediff.FileDiff` being rendered. interfilediff_id (int): The ID of the :py:class:`~reviewboard.diffviewer.models.filediff.FileDiff` on the other side of the diff revision, if viewing an interdiff. **kwargs (dict): Additional keyword arguments passed to the function. Return: unicode: The encoded ETag identifying this render. """ etag = '%s:%s:%s:%s:%s:%s' % ( get_diff_renderer_class(), renderer_settings['collapse_all'], renderer_settings['highlighting'], filediff_id, interfilediff_id, settings.TEMPLATE_SERIAL) show_deleted = renderer_settings.get('show_deleted') if show_deleted: etag += ':%s' % show_deleted return encode_etag(etag)
def make_etag(self, renderer_settings, filediff_id, interfilediff_id=None, **kwargs): """Return an ETag identifying this render. Args: renderer_settings (dict): The settings determining how to render this diff. The following keys are required: ``collapse_all`` and ``highlighting``. The following key is optional: ``show_deleted``. filediff_id (int): The ID of the :py:class:`~reviewboard.diffviewer.models.FileDiff` being rendered. interfilediff_id (int): The ID of the :py:class:`~reviewboard.diffviewer.models.FileDiff` on the other side of the diff revision, if viewing an interdiff. **kwargs (dict): Additional keyword arguments passed to the function. Return: unicode: The encoded ETag identifying this render. """ etag = '%s:%s:%s:%s:%s:%s' % ( get_diff_renderer_class(), renderer_settings['collapse_all'], renderer_settings['highlighting'], filediff_id, interfilediff_id, settings.TEMPLATE_SERIAL) show_deleted = renderer_settings.get('show_deleted') if show_deleted: etag += ':%s' % show_deleted return encode_etag(etag)
def test_generate_etag_with_encode_etag_true(self): """Testing WebAPIResource.generate_etag with encode_etag=True""" class TestObject(object): my_field = 'abc' request = RequestFactory().request() request.user = User() resource = WebAPIResource() obj = TestObject() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') etag = resource.generate_etag(obj, ['my_field'], request, encode_etag=True) self.assertEqual(len(w), 1) self.assertIn('generate_etag is deprecated', six.text_type(w[0].message)) self.assertEqual( etag, encode_etag( ':%s' % repr(resource.serialize_object(obj, request=request))))
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions( request, review_request): return self.get_no_access_error(request) info = review_request.get_last_activity_info() timestamp = info['timestamp'] updated_object = info['updated_object'] changedesc = info['changedesc'] etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() summary = None update_type = None if isinstance(updated_object, ReviewRequest): if updated_object.status == ReviewRequest.SUBMITTED: summary = _('Review request submitted') elif updated_object.status == ReviewRequest.DISCARDED: summary = _('Review request discarded') else: summary = _('Review request updated') update_type = 'review-request' elif isinstance(updated_object, DiffSet): summary = _('Diff updated') update_type = 'diff' elif isinstance(updated_object, Review): if updated_object.is_reply(): summary = _('New reply') update_type = 'reply' else: summary = _('New review') update_type = 'review' else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False if changedesc: user = changedesc.get_user(review_request) else: # There is no changedesc which means this review request hasn't # been changed since it was first published, so this change must # be due to the original submitter. user = review_request.submitter return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions( request, review_request): return self.get_no_access_error(request) timestamp, updated_object = review_request.get_last_activity() etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() user = None summary = None update_type = None if isinstance(updated_object, ReviewRequest): user = updated_object.submitter if updated_object.status == ReviewRequest.SUBMITTED: summary = _("Review request submitted") elif updated_object.status == ReviewRequest.DISCARDED: summary = _("Review request discarded") else: summary = _("Review request updated") update_type = "review-request" elif isinstance(updated_object, DiffSet): summary = _("Diff updated") update_type = "diff" elif isinstance(updated_object, Review): user = updated_object.user if updated_object.is_reply(): summary = _("New reply") update_type = "reply" else: summary = _("New review") update_type = "review" else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions(request, review_request): return self.get_no_access_error(request) timestamp, updated_object = review_request.get_last_activity() etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() user = None summary = None update_type = None if isinstance(updated_object, ReviewRequest): user = updated_object.submitter if updated_object.status == ReviewRequest.SUBMITTED: summary = _("Review request submitted") elif updated_object.status == ReviewRequest.DISCARDED: summary = _("Review request discarded") else: summary = _("Review request updated") update_type = "review-request" elif isinstance(updated_object, DiffSet): summary = _("Diff updated") update_type = "diff" elif isinstance(updated_object, Review): user = updated_object.user if updated_object.is_reply(): summary = _("New reply") update_type = "reply" else: summary = _("New review") update_type = "review" else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }
def get(self, request, *args, **kwargs): """Returns the last update made to the review request. This shows the type of update that was made, the user who made the update, and when the update was made. Clients can use this to inform the user that the review request was updated, or automatically update it in the background. This does not take into account changes to a draft review request, as that's generally not update information that the owner of the draft is interested in. Only public updates are represented. """ try: review_request = \ resources.review_request.get_object(request, *args, **kwargs) except ObjectDoesNotExist: return DOES_NOT_EXIST if not resources.review_request.has_access_permissions(request, review_request): return self.get_no_access_error(request) info = review_request.get_last_activity_info() timestamp = info['timestamp'] updated_object = info['updated_object'] changedesc = info['changedesc'] etag = encode_etag('%s:%s' % (timestamp, updated_object.pk)) if etag_if_none_match(request, etag): return HttpResponseNotModified() summary = None update_type = None user = None if isinstance(updated_object, ReviewRequest): if updated_object.status == ReviewRequest.SUBMITTED: summary = _('Review request submitted') elif updated_object.status == ReviewRequest.DISCARDED: summary = _('Review request discarded') else: summary = _('Review request updated') update_type = 'review-request' elif isinstance(updated_object, DiffSet): summary = _('Diff updated') update_type = 'diff' elif isinstance(updated_object, Review): if updated_object.is_reply(): summary = _('New reply') update_type = 'reply' else: summary = _('New review') update_type = 'review' user = updated_object.user else: # Should never be able to happen. The object will always at least # be a ReviewRequest. assert False if changedesc: user = changedesc.get_user(review_request) elif user is None: # There is no changedesc which means this review request hasn't # been changed since it was first published, so this change must # be due to the original submitter. user = review_request.submitter return 200, { self.item_result_key: { 'timestamp': timestamp, 'user': user, 'summary': summary, 'type': update_type, } }, { 'ETag': etag, }