summaryrefslogtreecommitdiff
path: root/tests/view_tests/tests/test_static.py
blob: f7e5604d06e2fd58201138ac8a6e24b6933d7922 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import mimetypes
import unittest
from os import path

from django.conf.urls.static import static
from django.core.exceptions import ImproperlyConfigured
from django.http import FileResponse, HttpResponseNotModified
from django.test import SimpleTestCase, override_settings
from django.utils.http import http_date
from django.views.static import was_modified_since

from .. import urls
from ..urls import media_dir


@override_settings(DEBUG=True, ROOT_URLCONF='view_tests.urls')
class StaticTests(SimpleTestCase):
    """Tests django views in django/views/static.py"""

    prefix = 'site_media'

    def test_serve(self):
        "The static view can serve static media"
        media_files = ['file.txt', 'file.txt.gz']
        for filename in media_files:
            response = self.client.get('/%s/%s' % (self.prefix, filename))
            response_content = b''.join(response)
            file_path = path.join(media_dir, filename)
            with open(file_path, 'rb') as fp:
                self.assertEqual(fp.read(), response_content)
            self.assertEqual(len(response_content), int(response['Content-Length']))
            self.assertEqual(mimetypes.guess_type(file_path)[1], response.get('Content-Encoding', None))

    def test_chunked(self):
        "The static view should stream files in chunks to avoid large memory usage"
        response = self.client.get('/%s/%s' % (self.prefix, 'long-line.txt'))
        first_chunk = next(response.streaming_content)
        self.assertEqual(len(first_chunk), FileResponse.block_size)
        second_chunk = next(response.streaming_content)
        response.close()
        # strip() to prevent OS line endings from causing differences
        self.assertEqual(len(second_chunk.strip()), 1449)

    def test_unknown_mime_type(self):
        response = self.client.get('/%s/file.unknown' % self.prefix)
        self.assertEqual('application/octet-stream', response['Content-Type'])
        response.close()

    def test_copes_with_empty_path_component(self):
        file_name = 'file.txt'
        response = self.client.get('/%s//%s' % (self.prefix, file_name))
        response_content = b''.join(response)
        with open(path.join(media_dir, file_name), 'rb') as fp:
            self.assertEqual(fp.read(), response_content)

    def test_is_modified_since(self):
        file_name = 'file.txt'
        response = self.client.get(
            '/%s/%s' % (self.prefix, file_name),
            HTTP_IF_MODIFIED_SINCE='Thu, 1 Jan 1970 00:00:00 GMT'
        )
        response_content = b''.join(response)
        with open(path.join(media_dir, file_name), 'rb') as fp:
            self.assertEqual(fp.read(), response_content)

    def test_not_modified_since(self):
        file_name = 'file.txt'
        response = self.client.get(
            '/%s/%s' % (self.prefix, file_name),
            HTTP_IF_MODIFIED_SINCE='Mon, 18 Jan 2038 05:14:07 GMT'
            # This is 24h before max Unix time. Remember to fix Django and
            # update this test well before 2038 :)
        )
        self.assertIsInstance(response, HttpResponseNotModified)

    def test_invalid_if_modified_since(self):
        """Handle bogus If-Modified-Since values gracefully

        Assume that a file is modified since an invalid timestamp as per RFC
        2616, section 14.25.
        """
        file_name = 'file.txt'
        invalid_date = 'Mon, 28 May 999999999999 28:25:26 GMT'
        response = self.client.get('/%s/%s' % (self.prefix, file_name),
                                   HTTP_IF_MODIFIED_SINCE=invalid_date)
        response_content = b''.join(response)
        with open(path.join(media_dir, file_name), 'rb') as fp:
            self.assertEqual(fp.read(), response_content)
        self.assertEqual(len(response_content), int(response['Content-Length']))

    def test_invalid_if_modified_since2(self):
        """Handle even more bogus If-Modified-Since values gracefully

        Assume that a file is modified since an invalid timestamp as per RFC
        2616, section 14.25.
        """
        file_name = 'file.txt'
        invalid_date = ': 1291108438, Wed, 20 Oct 2010 14:05:00 GMT'
        response = self.client.get('/%s/%s' % (self.prefix, file_name),
                                   HTTP_IF_MODIFIED_SINCE=invalid_date)
        response_content = b''.join(response)
        with open(path.join(media_dir, file_name), 'rb') as fp:
            self.assertEqual(fp.read(), response_content)
        self.assertEqual(len(response_content), int(response['Content-Length']))

    def test_404(self):
        response = self.client.get('/%s/nonexistent_resource' % self.prefix)
        self.assertEqual(404, response.status_code)

    def test_index(self):
        response = self.client.get('/%s/' % self.prefix)
        self.assertContains(response, 'Index of /')


class StaticHelperTest(StaticTests):
    """
    Test case to make sure the static URL pattern helper works as expected
    """
    def setUp(self):
        super().setUp()
        self._old_views_urlpatterns = urls.urlpatterns[:]
        urls.urlpatterns += static('/media/', document_root=media_dir)

    def tearDown(self):
        super().tearDown()
        urls.urlpatterns = self._old_views_urlpatterns

    def test_prefix(self):
        self.assertEqual(static('test')[0].regex.pattern, '^test(?P<path>.*)$')

    @override_settings(DEBUG=False)
    def test_debug_off(self):
        """No URLs are served if DEBUG=False."""
        self.assertEqual(static('test'), [])

    def test_empty_prefix(self):
        with self.assertRaisesMessage(ImproperlyConfigured, 'Empty static prefix not permitted'):
            static('')

    def test_special_prefix(self):
        """No URLs are served if prefix contains '://'."""
        self.assertEqual(static('http://'), [])


class StaticUtilsTests(unittest.TestCase):
    def test_was_modified_since_fp(self):
        """
        A floating point mtime does not disturb was_modified_since (#18675).
        """
        mtime = 1343416141.107817
        header = http_date(mtime)
        self.assertFalse(was_modified_since(header, mtime))