From 9b87f181bf1c9f1fd825887cb574ca50181441bf Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Fri, 29 May 2015 16:15:19 -0400 Subject: [PATCH 1/4] add failing test cases for StaticFile IF_MODIFIED_SINCE handling --- demo/demoproject/storage/tests.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/demo/demoproject/storage/tests.py b/demo/demoproject/storage/tests.py index 1924f48..2213f6b 100644 --- a/demo/demoproject/storage/tests.py +++ b/demo/demoproject/storage/tests.py @@ -2,6 +2,7 @@ import unittest from django.core.files.base import ContentFile from django.core.urlresolvers import reverse +from django.http.response import HttpResponseNotModified import django.test from django_downloadview import assert_download_response, temporary_media_root @@ -31,6 +32,30 @@ class StaticPathTestCase(django.test.TestCase): basename='1.txt', mime_type='text/plain') + @temporary_media_root() + def test_not_modified_download_response(self): + """'storage:static_path' sends not modified response if unmodified""" + setup_file('1.txt') + url = reverse('storage:static_path', kwargs={'path': '1.txt'}) + response = self.client.get( + url, + HTTP_IF_MODIFIED_SINCE='Sat, 29 Oct 2025 19:43:31 GMT') + self.assertTrue(isinstance(response, HttpResponseNotModified)) + + @temporary_media_root() + def test_modified_since_download_response(self): + """'storage:static_path' streams file if modified""" + setup_file('1.txt') + url = reverse('storage:static_path', kwargs={'path': '1.txt'}) + response = self.client.get( + url, + HTTP_IF_MODIFIED_SINCE='Sat, 29 Oct 1980 19:43:31 GMT') + assert_download_response(self, + response, + content=file_content, + basename='1.txt', + mime_type='text/plain') + class DynamicPathIntegrationTestCase(django.test.TestCase): """Integration tests around ``storage:dynamic_path`` URL.""" From e685f9909d5c65eccc46fe856e5ccb663d725f82 Mon Sep 17 00:00:00 2001 From: Nikhil Benesch Date: Fri, 29 May 2015 16:16:05 -0400 Subject: [PATCH 2/4] properly compute modified since with StaticFile wrapper --- django_downloadview/views/base.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/django_downloadview/views/base.py b/django_downloadview/views/base.py index a8b9c82..df9c128 100644 --- a/django_downloadview/views/base.py +++ b/django_downloadview/views/base.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- """Base material for download views: :class:`DownloadMixin` and :class:`BaseDownloadView`""" +import datetime + from django.http import HttpResponseNotModified, Http404 from django.views.generic.base import View from django.views.static import was_modified_since @@ -116,7 +118,10 @@ class DownloadMixin(object): except (AttributeError, NotImplementedError): return True else: - return was_modified_since(since, modification_time, size) + epoch_delta = modification_time - datetime.datetime(1970, 1, 1) + return was_modified_since(since, + epoch_delta.total_seconds(), + size) def not_modified_response(self, *response_args, **response_kwargs): """Return :class:`django.http.HttpResponseNotModified` instance.""" From bf7b0f23fdae4e609afa9fe7da7961de6ee191c7 Mon Sep 17 00:00:00 2001 From: zero13cool Date: Thu, 16 Jul 2015 21:05:46 +0300 Subject: [PATCH 3/4] Refs #104 - Convert datetime to unix timestamp --- django_downloadview/views/base.py | 5 ++++- tests/views.py | 3 ++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/django_downloadview/views/base.py b/django_downloadview/views/base.py index a8b9c82..29121c3 100644 --- a/django_downloadview/views/base.py +++ b/django_downloadview/views/base.py @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- """Base material for download views: :class:`DownloadMixin` and :class:`BaseDownloadView`""" +import calendar + from django.http import HttpResponseNotModified, Http404 from django.views.generic.base import View from django.views.static import was_modified_since @@ -111,7 +113,8 @@ class DownloadMixin(object): return file_instance.was_modified_since(since) except (AttributeError, NotImplementedError): try: - modification_time = file_instance.modified_time + modification_time = calendar.timegm( + file_instance.modified_time.utctimetuple()) size = file_instance.size except (AttributeError, NotImplementedError): return True diff --git a/tests/views.py b/tests/views.py index c6c9517..21edc9b 100644 --- a/tests/views.py +++ b/tests/views.py @@ -2,6 +2,7 @@ """Tests around :mod:`django_downloadview.views`.""" import os import unittest +from datetime import datetime try: from unittest import mock except ImportError: @@ -92,7 +93,7 @@ class DownloadMixinTestCase(unittest.TestCase): file_wrapper.was_modified_since = mock.Mock( side_effect=AttributeError) file_wrapper.size = mock.sentinel.size - file_wrapper.modified_time = mock.sentinel.modified_time + file_wrapper.modified_time = datetime.now() was_modified_since_mock = mock.Mock( return_value=mock.sentinel.was_modified) mixin = views.DownloadMixin() From 3a3d3ebb9f36cc3b9a00d7867baaa7db9b7dfd24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20Bryon?= Date: Mon, 20 Jul 2015 18:28:28 +0200 Subject: [PATCH 4/4] Refs #104 - Assert timestamp is passed to was_modified_since(). --- tests/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/views.py b/tests/views.py index 80c6907..6ad8e1d 100644 --- a/tests/views.py +++ b/tests/views.py @@ -1,5 +1,6 @@ # coding=utf-8 """Tests around :mod:`django_downloadview.views`.""" +import calendar import os import unittest from datetime import datetime @@ -104,7 +105,7 @@ class DownloadMixinTestCase(unittest.TestCase): mock.sentinel.was_modified) was_modified_since_mock.assert_called_once_with( mock.sentinel.since, - mock.sentinel.modified_time, + calendar.timegm(file_wrapper.modified_time.utctimetuple()), mock.sentinel.size) def test_was_modified_since_fallback(self):