~ubuntu-branches/debian/sid/python-django/sid

« back to all changes in this revision

Viewing changes to tests/middleware/tests.py

  • Committer: Package Import Robot
  • Author(s): Luke Faraone
  • Date: 2013-11-07 15:33:49 UTC
  • mfrom: (1.3.12)
  • Revision ID: package-import@ubuntu.com-20131107153349-e31sc149l2szs3jb
Tags: 1.6-1
* New upstream version. Closes: #557474, #724637.
* python-django now also suggests the installation of ipython,
  bpython, python-django-doc, and libgdal1.
  Closes: #636511, #686333, #704203
* Set package maintainer to Debian Python Modules Team.
* Bump standards version to 3.9.5, no changes needed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# -*- coding: utf-8 -*-
 
2
from __future__ import absolute_import, unicode_literals
 
3
 
 
4
import gzip
 
5
from io import BytesIO
 
6
import random
 
7
import re
 
8
import warnings
 
9
 
 
10
from django.conf import settings
 
11
from django.core import mail
 
12
from django.db import (transaction, connections, DEFAULT_DB_ALIAS,
 
13
                       IntegrityError)
 
14
from django.http import HttpRequest, HttpResponse, StreamingHttpResponse
 
15
from django.middleware.clickjacking import XFrameOptionsMiddleware
 
16
from django.middleware.common import CommonMiddleware, BrokenLinkEmailsMiddleware
 
17
from django.middleware.http import ConditionalGetMiddleware
 
18
from django.middleware.gzip import GZipMiddleware
 
19
from django.middleware.transaction import TransactionMiddleware
 
20
from django.test import TransactionTestCase, TestCase, RequestFactory
 
21
from django.test.utils import override_settings, IgnorePendingDeprecationWarningsMixin
 
22
from django.utils import six
 
23
from django.utils.encoding import force_str
 
24
from django.utils.six.moves import xrange
 
25
from django.utils.unittest import expectedFailure, skipIf
 
26
 
 
27
from .models import Band
 
28
 
 
29
 
 
30
class CommonMiddlewareTest(TestCase):
 
31
 
 
32
    def _get_request(self, path):
 
33
        request = HttpRequest()
 
34
        request.META = {
 
35
            'SERVER_NAME': 'testserver',
 
36
            'SERVER_PORT': 80,
 
37
        }
 
38
        request.path = request.path_info = "/middleware/%s" % path
 
39
        return request
 
40
 
 
41
    @override_settings(APPEND_SLASH=True)
 
42
    def test_append_slash_have_slash(self):
 
43
        """
 
44
        Tests that URLs with slashes go unmolested.
 
45
        """
 
46
        request = self._get_request('slash/')
 
47
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
48
 
 
49
    @override_settings(APPEND_SLASH=True)
 
50
    def test_append_slash_slashless_resource(self):
 
51
        """
 
52
        Tests that matches to explicit slashless URLs go unmolested.
 
53
        """
 
54
        request = self._get_request('noslash')
 
55
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
56
 
 
57
    @override_settings(APPEND_SLASH=True)
 
58
    def test_append_slash_slashless_unknown(self):
 
59
        """
 
60
        Tests that APPEND_SLASH doesn't redirect to unknown resources.
 
61
        """
 
62
        request = self._get_request('unknown')
 
63
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
64
 
 
65
    @override_settings(APPEND_SLASH=True)
 
66
    def test_append_slash_redirect(self):
 
67
        """
 
68
        Tests that APPEND_SLASH redirects slashless URLs to a valid pattern.
 
69
        """
 
70
        request = self._get_request('slash')
 
71
        r = CommonMiddleware().process_request(request)
 
72
        self.assertEqual(r.status_code, 301)
 
73
        self.assertEqual(r.url, 'http://testserver/middleware/slash/')
 
74
 
 
75
    @override_settings(APPEND_SLASH=True, DEBUG=True)
 
76
    def test_append_slash_no_redirect_on_POST_in_DEBUG(self):
 
77
        """
 
78
        Tests that while in debug mode, an exception is raised with a warning
 
79
        when a failed attempt is made to POST to an URL which would normally be
 
80
        redirected to a slashed version.
 
81
        """
 
82
        request = self._get_request('slash')
 
83
        request.method = 'POST'
 
84
        with six.assertRaisesRegex(self, RuntimeError, 'end in a slash'):
 
85
            CommonMiddleware().process_request(request)
 
86
 
 
87
    @override_settings(APPEND_SLASH=False)
 
88
    def test_append_slash_disabled(self):
 
89
        """
 
90
        Tests disabling append slash functionality.
 
91
        """
 
92
        request = self._get_request('slash')
 
93
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
94
 
 
95
    @override_settings(APPEND_SLASH=True)
 
96
    def test_append_slash_quoted(self):
 
97
        """
 
98
        Tests that URLs which require quoting are redirected to their slash
 
99
        version ok.
 
100
        """
 
101
        request = self._get_request('needsquoting#')
 
102
        r = CommonMiddleware().process_request(request)
 
103
        self.assertEqual(r.status_code, 301)
 
104
        self.assertEqual(
 
105
            r.url,
 
106
            'http://testserver/middleware/needsquoting%23/')
 
107
 
 
108
    @override_settings(APPEND_SLASH=False, PREPEND_WWW=True)
 
109
    def test_prepend_www(self):
 
110
        request = self._get_request('path/')
 
111
        r = CommonMiddleware().process_request(request)
 
112
        self.assertEqual(r.status_code, 301)
 
113
        self.assertEqual(
 
114
            r.url,
 
115
            'http://www.testserver/middleware/path/')
 
116
 
 
117
    @override_settings(APPEND_SLASH=True, PREPEND_WWW=True)
 
118
    def test_prepend_www_append_slash_have_slash(self):
 
119
        request = self._get_request('slash/')
 
120
        r = CommonMiddleware().process_request(request)
 
121
        self.assertEqual(r.status_code, 301)
 
122
        self.assertEqual(r.url,
 
123
                          'http://www.testserver/middleware/slash/')
 
124
 
 
125
    @override_settings(APPEND_SLASH=True, PREPEND_WWW=True)
 
126
    def test_prepend_www_append_slash_slashless(self):
 
127
        request = self._get_request('slash')
 
128
        r = CommonMiddleware().process_request(request)
 
129
        self.assertEqual(r.status_code, 301)
 
130
        self.assertEqual(r.url,
 
131
                          'http://www.testserver/middleware/slash/')
 
132
 
 
133
 
 
134
    # The following tests examine expected behavior given a custom urlconf that
 
135
    # overrides the default one through the request object.
 
136
 
 
137
    @override_settings(APPEND_SLASH=True)
 
138
    def test_append_slash_have_slash_custom_urlconf(self):
 
139
        """
 
140
        Tests that URLs with slashes go unmolested.
 
141
        """
 
142
        request = self._get_request('customurlconf/slash/')
 
143
        request.urlconf = 'middleware.extra_urls'
 
144
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
145
 
 
146
    @override_settings(APPEND_SLASH=True)
 
147
    def test_append_slash_slashless_resource_custom_urlconf(self):
 
148
        """
 
149
        Tests that matches to explicit slashless URLs go unmolested.
 
150
        """
 
151
        request = self._get_request('customurlconf/noslash')
 
152
        request.urlconf = 'middleware.extra_urls'
 
153
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
154
 
 
155
    @override_settings(APPEND_SLASH=True)
 
156
    def test_append_slash_slashless_unknown_custom_urlconf(self):
 
157
        """
 
158
        Tests that APPEND_SLASH doesn't redirect to unknown resources.
 
159
        """
 
160
        request = self._get_request('customurlconf/unknown')
 
161
        request.urlconf = 'middleware.extra_urls'
 
162
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
163
 
 
164
    @override_settings(APPEND_SLASH=True)
 
165
    def test_append_slash_redirect_custom_urlconf(self):
 
166
        """
 
167
        Tests that APPEND_SLASH redirects slashless URLs to a valid pattern.
 
168
        """
 
169
        request = self._get_request('customurlconf/slash')
 
170
        request.urlconf = 'middleware.extra_urls'
 
171
        r = CommonMiddleware().process_request(request)
 
172
        self.assertFalse(r is None,
 
173
            "CommonMiddlware failed to return APPEND_SLASH redirect using request.urlconf")
 
174
        self.assertEqual(r.status_code, 301)
 
175
        self.assertEqual(r.url, 'http://testserver/middleware/customurlconf/slash/')
 
176
 
 
177
    @override_settings(APPEND_SLASH=True, DEBUG=True)
 
178
    def test_append_slash_no_redirect_on_POST_in_DEBUG_custom_urlconf(self):
 
179
        """
 
180
        Tests that while in debug mode, an exception is raised with a warning
 
181
        when a failed attempt is made to POST to an URL which would normally be
 
182
        redirected to a slashed version.
 
183
        """
 
184
        request = self._get_request('customurlconf/slash')
 
185
        request.urlconf = 'middleware.extra_urls'
 
186
        request.method = 'POST'
 
187
        with six.assertRaisesRegex(self, RuntimeError, 'end in a slash'):
 
188
            CommonMiddleware().process_request(request)
 
189
 
 
190
    @override_settings(APPEND_SLASH=False)
 
191
    def test_append_slash_disabled_custom_urlconf(self):
 
192
        """
 
193
        Tests disabling append slash functionality.
 
194
        """
 
195
        request = self._get_request('customurlconf/slash')
 
196
        request.urlconf = 'middleware.extra_urls'
 
197
        self.assertEqual(CommonMiddleware().process_request(request), None)
 
198
 
 
199
    @override_settings(APPEND_SLASH=True)
 
200
    def test_append_slash_quoted_custom_urlconf(self):
 
201
        """
 
202
        Tests that URLs which require quoting are redirected to their slash
 
203
        version ok.
 
204
        """
 
205
        request = self._get_request('customurlconf/needsquoting#')
 
206
        request.urlconf = 'middleware.extra_urls'
 
207
        r = CommonMiddleware().process_request(request)
 
208
        self.assertFalse(r is None,
 
209
            "CommonMiddlware failed to return APPEND_SLASH redirect using request.urlconf")
 
210
        self.assertEqual(r.status_code, 301)
 
211
        self.assertEqual(
 
212
            r.url,
 
213
            'http://testserver/middleware/customurlconf/needsquoting%23/')
 
214
 
 
215
    @override_settings(APPEND_SLASH=False, PREPEND_WWW=True)
 
216
    def test_prepend_www_custom_urlconf(self):
 
217
        request = self._get_request('customurlconf/path/')
 
218
        request.urlconf = 'middleware.extra_urls'
 
219
        r = CommonMiddleware().process_request(request)
 
220
        self.assertEqual(r.status_code, 301)
 
221
        self.assertEqual(
 
222
            r.url,
 
223
            'http://www.testserver/middleware/customurlconf/path/')
 
224
 
 
225
    @override_settings(APPEND_SLASH=True, PREPEND_WWW=True)
 
226
    def test_prepend_www_append_slash_have_slash_custom_urlconf(self):
 
227
        request = self._get_request('customurlconf/slash/')
 
228
        request.urlconf = 'middleware.extra_urls'
 
229
        r = CommonMiddleware().process_request(request)
 
230
        self.assertEqual(r.status_code, 301)
 
231
        self.assertEqual(r.url,
 
232
                          'http://www.testserver/middleware/customurlconf/slash/')
 
233
 
 
234
    @override_settings(APPEND_SLASH=True, PREPEND_WWW=True)
 
235
    def test_prepend_www_append_slash_slashless_custom_urlconf(self):
 
236
        request = self._get_request('customurlconf/slash')
 
237
        request.urlconf = 'middleware.extra_urls'
 
238
        r = CommonMiddleware().process_request(request)
 
239
        self.assertEqual(r.status_code, 301)
 
240
        self.assertEqual(r.url,
 
241
                          'http://www.testserver/middleware/customurlconf/slash/')
 
242
 
 
243
    # Legacy tests for the 404 error reporting via email (to be removed in 1.8)
 
244
 
 
245
    @override_settings(IGNORABLE_404_URLS=(re.compile(r'foo'),),
 
246
                       SEND_BROKEN_LINK_EMAILS=True,
 
247
                       MANAGERS=('PHB@dilbert.com',))
 
248
    def test_404_error_reporting(self):
 
249
        request = self._get_request('regular_url/that/does/not/exist')
 
250
        request.META['HTTP_REFERER'] = '/another/url/'
 
251
        with warnings.catch_warnings():
 
252
            warnings.simplefilter("ignore", PendingDeprecationWarning)
 
253
            response = self.client.get(request.path)
 
254
            CommonMiddleware().process_response(request, response)
 
255
        self.assertEqual(len(mail.outbox), 1)
 
256
        self.assertIn('Broken', mail.outbox[0].subject)
 
257
 
 
258
    @override_settings(IGNORABLE_404_URLS=(re.compile(r'foo'),),
 
259
                       SEND_BROKEN_LINK_EMAILS=True,
 
260
                       MANAGERS=('PHB@dilbert.com',))
 
261
    def test_404_error_reporting_no_referer(self):
 
262
        request = self._get_request('regular_url/that/does/not/exist')
 
263
        with warnings.catch_warnings():
 
264
            warnings.simplefilter("ignore", PendingDeprecationWarning)
 
265
            response = self.client.get(request.path)
 
266
            CommonMiddleware().process_response(request, response)
 
267
        self.assertEqual(len(mail.outbox), 0)
 
268
 
 
269
    @override_settings(IGNORABLE_404_URLS=(re.compile(r'foo'),),
 
270
                       SEND_BROKEN_LINK_EMAILS=True,
 
271
                       MANAGERS=('PHB@dilbert.com',))
 
272
    def test_404_error_reporting_ignored_url(self):
 
273
        request = self._get_request('foo_url/that/does/not/exist/either')
 
274
        request.META['HTTP_REFERER'] = '/another/url/'
 
275
        with warnings.catch_warnings():
 
276
            warnings.simplefilter("ignore", PendingDeprecationWarning)
 
277
            response = self.client.get(request.path)
 
278
            CommonMiddleware().process_response(request, response)
 
279
        self.assertEqual(len(mail.outbox), 0)
 
280
 
 
281
    # Other tests
 
282
 
 
283
    def test_non_ascii_query_string_does_not_crash(self):
 
284
        """Regression test for #15152"""
 
285
        request = self._get_request('slash')
 
286
        request.META['QUERY_STRING'] = force_str('drink=café')
 
287
        response = CommonMiddleware().process_request(request)
 
288
        self.assertEqual(response.status_code, 301)
 
289
 
 
290
 
 
291
@override_settings(
 
292
    IGNORABLE_404_URLS=(re.compile(r'foo'),),
 
293
    MANAGERS=('PHB@dilbert.com',),
 
294
)
 
295
class BrokenLinkEmailsMiddlewareTest(TestCase):
 
296
 
 
297
    def setUp(self):
 
298
        self.req = HttpRequest()
 
299
        self.req.META = {
 
300
            'SERVER_NAME': 'testserver',
 
301
            'SERVER_PORT': 80,
 
302
        }
 
303
        self.req.path = self.req.path_info = 'regular_url/that/does/not/exist'
 
304
        self.resp = self.client.get(self.req.path)
 
305
 
 
306
    def test_404_error_reporting(self):
 
307
        self.req.META['HTTP_REFERER'] = '/another/url/'
 
308
        BrokenLinkEmailsMiddleware().process_response(self.req, self.resp)
 
309
        self.assertEqual(len(mail.outbox), 1)
 
310
        self.assertIn('Broken', mail.outbox[0].subject)
 
311
 
 
312
    def test_404_error_reporting_no_referer(self):
 
313
        BrokenLinkEmailsMiddleware().process_response(self.req, self.resp)
 
314
        self.assertEqual(len(mail.outbox), 0)
 
315
 
 
316
    def test_404_error_reporting_ignored_url(self):
 
317
        self.req.path = self.req.path_info = 'foo_url/that/does/not/exist'
 
318
        BrokenLinkEmailsMiddleware().process_response(self.req, self.resp)
 
319
        self.assertEqual(len(mail.outbox), 0)
 
320
 
 
321
    @skipIf(six.PY3, "HTTP_REFERER is str type on Python 3")
 
322
    def test_404_error_nonascii_referrer(self):
 
323
        # Such referer strings should not happen, but anyway, if it happens,
 
324
        # let's not crash
 
325
        self.req.META['HTTP_REFERER'] = b'http://testserver/c/\xd0\xbb\xd0\xb8/'
 
326
        BrokenLinkEmailsMiddleware().process_response(self.req, self.resp)
 
327
        self.assertEqual(len(mail.outbox), 1)
 
328
 
 
329
    def test_custom_request_checker(self):
 
330
        class SubclassedMiddleware(BrokenLinkEmailsMiddleware):
 
331
            ignored_user_agent_patterns = (re.compile(r'Spider.*'),
 
332
                                           re.compile(r'Robot.*'))
 
333
            def is_ignorable_request(self, request, uri, domain, referer):
 
334
                '''Check user-agent in addition to normal checks.'''
 
335
                if super(SubclassedMiddleware, self).is_ignorable_request(request, uri, domain, referer):
 
336
                    return True
 
337
                user_agent = request.META['HTTP_USER_AGENT']
 
338
                return any(pattern.search(user_agent) for pattern in
 
339
                               self.ignored_user_agent_patterns)
 
340
 
 
341
        self.req.META['HTTP_REFERER'] = '/another/url/'
 
342
        self.req.META['HTTP_USER_AGENT'] = 'Spider machine 3.4'
 
343
        SubclassedMiddleware().process_response(self.req, self.resp)
 
344
        self.assertEqual(len(mail.outbox), 0)
 
345
        self.req.META['HTTP_USER_AGENT'] = 'My user agent'
 
346
        SubclassedMiddleware().process_response(self.req, self.resp)
 
347
        self.assertEqual(len(mail.outbox), 1)
 
348
 
 
349
class ConditionalGetMiddlewareTest(TestCase):
 
350
    urls = 'middleware.cond_get_urls'
 
351
    def setUp(self):
 
352
        self.req = HttpRequest()
 
353
        self.req.META = {
 
354
            'SERVER_NAME': 'testserver',
 
355
            'SERVER_PORT': 80,
 
356
        }
 
357
        self.req.path = self.req.path_info = "/"
 
358
        self.resp = self.client.get(self.req.path)
 
359
 
 
360
    # Tests for the Date header
 
361
 
 
362
    def test_date_header_added(self):
 
363
        self.assertFalse('Date' in self.resp)
 
364
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
365
        self.assertTrue('Date' in self.resp)
 
366
 
 
367
    # Tests for the Content-Length header
 
368
 
 
369
    def test_content_length_header_added(self):
 
370
        content_length = len(self.resp.content)
 
371
        self.assertFalse('Content-Length' in self.resp)
 
372
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
373
        self.assertTrue('Content-Length' in self.resp)
 
374
        self.assertEqual(int(self.resp['Content-Length']), content_length)
 
375
 
 
376
    def test_content_length_header_not_added(self):
 
377
        resp = StreamingHttpResponse('content')
 
378
        self.assertFalse('Content-Length' in resp)
 
379
        resp = ConditionalGetMiddleware().process_response(self.req, resp)
 
380
        self.assertFalse('Content-Length' in resp)
 
381
 
 
382
    def test_content_length_header_not_changed(self):
 
383
        bad_content_length = len(self.resp.content) + 10
 
384
        self.resp['Content-Length'] = bad_content_length
 
385
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
386
        self.assertEqual(int(self.resp['Content-Length']), bad_content_length)
 
387
 
 
388
    # Tests for the ETag header
 
389
 
 
390
    def test_if_none_match_and_no_etag(self):
 
391
        self.req.META['HTTP_IF_NONE_MATCH'] = 'spam'
 
392
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
393
        self.assertEqual(self.resp.status_code, 200)
 
394
 
 
395
    def test_no_if_none_match_and_etag(self):
 
396
        self.resp['ETag'] = 'eggs'
 
397
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
398
        self.assertEqual(self.resp.status_code, 200)
 
399
 
 
400
    def test_if_none_match_and_same_etag(self):
 
401
        self.req.META['HTTP_IF_NONE_MATCH'] = self.resp['ETag'] = 'spam'
 
402
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
403
        self.assertEqual(self.resp.status_code, 304)
 
404
 
 
405
    def test_if_none_match_and_different_etag(self):
 
406
        self.req.META['HTTP_IF_NONE_MATCH'] = 'spam'
 
407
        self.resp['ETag'] = 'eggs'
 
408
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
409
        self.assertEqual(self.resp.status_code, 200)
 
410
 
 
411
    @override_settings(USE_ETAGS=True)
 
412
    def test_etag(self):
 
413
        req = HttpRequest()
 
414
        res = HttpResponse('content')
 
415
        self.assertTrue(
 
416
            CommonMiddleware().process_response(req, res).has_header('ETag'))
 
417
 
 
418
    @override_settings(USE_ETAGS=True)
 
419
    def test_etag_streaming_response(self):
 
420
        req = HttpRequest()
 
421
        res = StreamingHttpResponse(['content'])
 
422
        res['ETag'] = 'tomatoes'
 
423
        self.assertEqual(
 
424
            CommonMiddleware().process_response(req, res).get('ETag'),
 
425
            'tomatoes')
 
426
 
 
427
    @override_settings(USE_ETAGS=True)
 
428
    def test_no_etag_streaming_response(self):
 
429
        req = HttpRequest()
 
430
        res = StreamingHttpResponse(['content'])
 
431
        self.assertFalse(
 
432
            CommonMiddleware().process_response(req, res).has_header('ETag'))
 
433
 
 
434
    # Tests for the Last-Modified header
 
435
 
 
436
    def test_if_modified_since_and_no_last_modified(self):
 
437
        self.req.META['HTTP_IF_MODIFIED_SINCE'] = 'Sat, 12 Feb 2011 17:38:44 GMT'
 
438
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
439
        self.assertEqual(self.resp.status_code, 200)
 
440
 
 
441
    def test_no_if_modified_since_and_last_modified(self):
 
442
        self.resp['Last-Modified'] = 'Sat, 12 Feb 2011 17:38:44 GMT'
 
443
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
444
        self.assertEqual(self.resp.status_code, 200)
 
445
 
 
446
    def test_if_modified_since_and_same_last_modified(self):
 
447
        self.req.META['HTTP_IF_MODIFIED_SINCE'] = 'Sat, 12 Feb 2011 17:38:44 GMT'
 
448
        self.resp['Last-Modified'] = 'Sat, 12 Feb 2011 17:38:44 GMT'
 
449
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
450
        self.assertEqual(self.resp.status_code, 304)
 
451
 
 
452
    def test_if_modified_since_and_last_modified_in_the_past(self):
 
453
        self.req.META['HTTP_IF_MODIFIED_SINCE'] = 'Sat, 12 Feb 2011 17:38:44 GMT'
 
454
        self.resp['Last-Modified'] = 'Sat, 12 Feb 2011 17:35:44 GMT'
 
455
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
456
        self.assertEqual(self.resp.status_code, 304)
 
457
 
 
458
    def test_if_modified_since_and_last_modified_in_the_future(self):
 
459
        self.req.META['HTTP_IF_MODIFIED_SINCE'] = 'Sat, 12 Feb 2011 17:38:44 GMT'
 
460
        self.resp['Last-Modified'] = 'Sat, 12 Feb 2011 17:41:44 GMT'
 
461
        self.resp = ConditionalGetMiddleware().process_response(self.req, self.resp)
 
462
        self.assertEqual(self.resp.status_code, 200)
 
463
 
 
464
 
 
465
class XFrameOptionsMiddlewareTest(TestCase):
 
466
    """
 
467
    Tests for the X-Frame-Options clickjacking prevention middleware.
 
468
    """
 
469
 
 
470
    def test_same_origin(self):
 
471
        """
 
472
        Tests that the X_FRAME_OPTIONS setting can be set to SAMEORIGIN to
 
473
        have the middleware use that value for the HTTP header.
 
474
        """
 
475
        with override_settings(X_FRAME_OPTIONS='SAMEORIGIN'):
 
476
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
477
                                                           HttpResponse())
 
478
            self.assertEqual(r['X-Frame-Options'], 'SAMEORIGIN')
 
479
 
 
480
        with override_settings(X_FRAME_OPTIONS='sameorigin'):
 
481
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
482
                                                       HttpResponse())
 
483
            self.assertEqual(r['X-Frame-Options'], 'SAMEORIGIN')
 
484
 
 
485
    def test_deny(self):
 
486
        """
 
487
        Tests that the X_FRAME_OPTIONS setting can be set to DENY to
 
488
        have the middleware use that value for the HTTP header.
 
489
        """
 
490
        with override_settings(X_FRAME_OPTIONS='DENY'):
 
491
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
492
                                                           HttpResponse())
 
493
            self.assertEqual(r['X-Frame-Options'], 'DENY')
 
494
 
 
495
        with override_settings(X_FRAME_OPTIONS='deny'):
 
496
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
497
                                                           HttpResponse())
 
498
            self.assertEqual(r['X-Frame-Options'], 'DENY')
 
499
 
 
500
    def test_defaults_sameorigin(self):
 
501
        """
 
502
        Tests that if the X_FRAME_OPTIONS setting is not set then it defaults
 
503
        to SAMEORIGIN.
 
504
        """
 
505
        with override_settings(X_FRAME_OPTIONS=None):
 
506
            del settings.X_FRAME_OPTIONS    # restored by override_settings
 
507
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
508
                                                           HttpResponse())
 
509
            self.assertEqual(r['X-Frame-Options'], 'SAMEORIGIN')
 
510
 
 
511
    def test_dont_set_if_set(self):
 
512
        """
 
513
        Tests that if the X-Frame-Options header is already set then the
 
514
        middleware does not attempt to override it.
 
515
        """
 
516
        with override_settings(X_FRAME_OPTIONS='DENY'):
 
517
            response = HttpResponse()
 
518
            response['X-Frame-Options'] = 'SAMEORIGIN'
 
519
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
520
                                                           response)
 
521
            self.assertEqual(r['X-Frame-Options'], 'SAMEORIGIN')
 
522
 
 
523
        with override_settings(X_FRAME_OPTIONS='SAMEORIGIN'):
 
524
            response = HttpResponse()
 
525
            response['X-Frame-Options'] = 'DENY'
 
526
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
527
                                                           response)
 
528
            self.assertEqual(r['X-Frame-Options'], 'DENY')
 
529
 
 
530
    def test_response_exempt(self):
 
531
        """
 
532
        Tests that if the response has a xframe_options_exempt attribute set
 
533
        to False then it still sets the header, but if it's set to True then
 
534
        it does not.
 
535
        """
 
536
        with override_settings(X_FRAME_OPTIONS='SAMEORIGIN'):
 
537
            response = HttpResponse()
 
538
            response.xframe_options_exempt = False
 
539
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
540
                                                           response)
 
541
            self.assertEqual(r['X-Frame-Options'], 'SAMEORIGIN')
 
542
 
 
543
            response = HttpResponse()
 
544
            response.xframe_options_exempt = True
 
545
            r = XFrameOptionsMiddleware().process_response(HttpRequest(),
 
546
                                                           response)
 
547
            self.assertEqual(r.get('X-Frame-Options', None), None)
 
548
 
 
549
    def test_is_extendable(self):
 
550
        """
 
551
        Tests that the XFrameOptionsMiddleware method that determines the
 
552
        X-Frame-Options header value can be overridden based on something in
 
553
        the request or response.
 
554
        """
 
555
        class OtherXFrameOptionsMiddleware(XFrameOptionsMiddleware):
 
556
            # This is just an example for testing purposes...
 
557
            def get_xframe_options_value(self, request, response):
 
558
                if getattr(request, 'sameorigin', False):
 
559
                    return 'SAMEORIGIN'
 
560
                if getattr(response, 'sameorigin', False):
 
561
                    return 'SAMEORIGIN'
 
562
                return 'DENY'
 
563
 
 
564
        with override_settings(X_FRAME_OPTIONS='DENY'):
 
565
            response = HttpResponse()
 
566
            response.sameorigin = True
 
567
            r = OtherXFrameOptionsMiddleware().process_response(HttpRequest(),
 
568
                                                                response)
 
569
            self.assertEqual(r['X-Frame-Options'], 'SAMEORIGIN')
 
570
 
 
571
            request = HttpRequest()
 
572
            request.sameorigin = True
 
573
            r = OtherXFrameOptionsMiddleware().process_response(request,
 
574
                                                                HttpResponse())
 
575
            self.assertEqual(r['X-Frame-Options'], 'SAMEORIGIN')
 
576
 
 
577
        with override_settings(X_FRAME_OPTIONS='SAMEORIGIN'):
 
578
            r = OtherXFrameOptionsMiddleware().process_response(HttpRequest(),
 
579
                                                                HttpResponse())
 
580
            self.assertEqual(r['X-Frame-Options'], 'DENY')
 
581
 
 
582
 
 
583
class GZipMiddlewareTest(TestCase):
 
584
    """
 
585
    Tests the GZip middleware.
 
586
    """
 
587
    short_string = b"This string is too short to be worth compressing."
 
588
    compressible_string = b'a' * 500
 
589
    uncompressible_string = b''.join(six.int2byte(random.randint(0, 255)) for _ in xrange(500))
 
590
    sequence = [b'a' * 500, b'b' * 200, b'a' * 300]
 
591
 
 
592
    def setUp(self):
 
593
        self.req = HttpRequest()
 
594
        self.req.META = {
 
595
            'SERVER_NAME': 'testserver',
 
596
            'SERVER_PORT': 80,
 
597
        }
 
598
        self.req.path = self.req.path_info = "/"
 
599
        self.req.META['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate'
 
600
        self.req.META['HTTP_USER_AGENT'] = 'Mozilla/5.0 (Windows NT 5.1; rv:9.0.1) Gecko/20100101 Firefox/9.0.1'
 
601
        self.resp = HttpResponse()
 
602
        self.resp.status_code = 200
 
603
        self.resp.content = self.compressible_string
 
604
        self.resp['Content-Type'] = 'text/html; charset=UTF-8'
 
605
        self.stream_resp = StreamingHttpResponse(self.sequence)
 
606
        self.stream_resp['Content-Type'] = 'text/html; charset=UTF-8'
 
607
 
 
608
    @staticmethod
 
609
    def decompress(gzipped_string):
 
610
        return gzip.GzipFile(mode='rb', fileobj=BytesIO(gzipped_string)).read()
 
611
 
 
612
    def test_compress_response(self):
 
613
        """
 
614
        Tests that compression is performed on responses with compressible content.
 
615
        """
 
616
        r = GZipMiddleware().process_response(self.req, self.resp)
 
617
        self.assertEqual(self.decompress(r.content), self.compressible_string)
 
618
        self.assertEqual(r.get('Content-Encoding'), 'gzip')
 
619
        self.assertEqual(r.get('Content-Length'), str(len(r.content)))
 
620
 
 
621
    def test_compress_streaming_response(self):
 
622
        """
 
623
        Tests that compression is performed on responses with streaming content.
 
624
        """
 
625
        r = GZipMiddleware().process_response(self.req, self.stream_resp)
 
626
        self.assertEqual(self.decompress(b''.join(r)), b''.join(self.sequence))
 
627
        self.assertEqual(r.get('Content-Encoding'), 'gzip')
 
628
        self.assertFalse(r.has_header('Content-Length'))
 
629
 
 
630
    def test_compress_non_200_response(self):
 
631
        """
 
632
        Tests that compression is performed on responses with a status other than 200.
 
633
        See #10762.
 
634
        """
 
635
        self.resp.status_code = 404
 
636
        r = GZipMiddleware().process_response(self.req, self.resp)
 
637
        self.assertEqual(self.decompress(r.content), self.compressible_string)
 
638
        self.assertEqual(r.get('Content-Encoding'), 'gzip')
 
639
 
 
640
    def test_no_compress_short_response(self):
 
641
        """
 
642
        Tests that compression isn't performed on responses with short content.
 
643
        """
 
644
        self.resp.content = self.short_string
 
645
        r = GZipMiddleware().process_response(self.req, self.resp)
 
646
        self.assertEqual(r.content, self.short_string)
 
647
        self.assertEqual(r.get('Content-Encoding'), None)
 
648
 
 
649
    def test_no_compress_compressed_response(self):
 
650
        """
 
651
        Tests that compression isn't performed on responses that are already compressed.
 
652
        """
 
653
        self.resp['Content-Encoding'] = 'deflate'
 
654
        r = GZipMiddleware().process_response(self.req, self.resp)
 
655
        self.assertEqual(r.content, self.compressible_string)
 
656
        self.assertEqual(r.get('Content-Encoding'), 'deflate')
 
657
 
 
658
    def test_no_compress_ie_js_requests(self):
 
659
        """
 
660
        Tests that compression isn't performed on JavaScript requests from Internet Explorer.
 
661
        """
 
662
        self.req.META['HTTP_USER_AGENT'] = 'Mozilla/4.0 (compatible; MSIE 5.00; Windows 98)'
 
663
        self.resp['Content-Type'] = 'application/javascript; charset=UTF-8'
 
664
        r = GZipMiddleware().process_response(self.req, self.resp)
 
665
        self.assertEqual(r.content, self.compressible_string)
 
666
        self.assertEqual(r.get('Content-Encoding'), None)
 
667
 
 
668
    def test_no_compress_uncompressible_response(self):
 
669
        """
 
670
        Tests that compression isn't performed on responses with uncompressible content.
 
671
        """
 
672
        self.resp.content = self.uncompressible_string
 
673
        r = GZipMiddleware().process_response(self.req, self.resp)
 
674
        self.assertEqual(r.content, self.uncompressible_string)
 
675
        self.assertEqual(r.get('Content-Encoding'), None)
 
676
 
 
677
 
 
678
@override_settings(USE_ETAGS=True)
 
679
class ETagGZipMiddlewareTest(TestCase):
 
680
    """
 
681
    Tests if the ETag middleware behaves correctly with GZip middleware.
 
682
    """
 
683
    compressible_string = b'a' * 500
 
684
 
 
685
    def setUp(self):
 
686
        self.rf = RequestFactory()
 
687
 
 
688
    def test_compress_response(self):
 
689
        """
 
690
        Tests that ETag is changed after gzip compression is performed.
 
691
        """
 
692
        request = self.rf.get('/', HTTP_ACCEPT_ENCODING='gzip, deflate')
 
693
        response = GZipMiddleware().process_response(request,
 
694
            CommonMiddleware().process_response(request,
 
695
                HttpResponse(self.compressible_string)))
 
696
        gzip_etag = response.get('ETag')
 
697
 
 
698
        request = self.rf.get('/', HTTP_ACCEPT_ENCODING='')
 
699
        response = GZipMiddleware().process_response(request,
 
700
            CommonMiddleware().process_response(request,
 
701
                HttpResponse(self.compressible_string)))
 
702
        nogzip_etag = response.get('ETag')
 
703
 
 
704
        self.assertNotEqual(gzip_etag, nogzip_etag)
 
705
 
 
706
class TransactionMiddlewareTest(IgnorePendingDeprecationWarningsMixin, TransactionTestCase):
 
707
    """
 
708
    Test the transaction middleware.
 
709
    """
 
710
 
 
711
    available_apps = ['middleware']
 
712
 
 
713
    def setUp(self):
 
714
        super(TransactionMiddlewareTest, self).setUp()
 
715
        self.request = HttpRequest()
 
716
        self.request.META = {
 
717
            'SERVER_NAME': 'testserver',
 
718
            'SERVER_PORT': 80,
 
719
        }
 
720
        self.request.path = self.request.path_info = "/"
 
721
        self.response = HttpResponse()
 
722
        self.response.status_code = 200
 
723
 
 
724
    def tearDown(self):
 
725
        transaction.abort()
 
726
        super(TransactionMiddlewareTest, self).tearDown()
 
727
 
 
728
    def test_request(self):
 
729
        TransactionMiddleware().process_request(self.request)
 
730
        self.assertFalse(transaction.get_autocommit())
 
731
 
 
732
    def test_managed_response(self):
 
733
        transaction.enter_transaction_management()
 
734
        Band.objects.create(name='The Beatles')
 
735
        self.assertTrue(transaction.is_dirty())
 
736
        TransactionMiddleware().process_response(self.request, self.response)
 
737
        self.assertFalse(transaction.is_dirty())
 
738
        self.assertEqual(Band.objects.count(), 1)
 
739
 
 
740
    def test_exception(self):
 
741
        transaction.enter_transaction_management()
 
742
        Band.objects.create(name='The Beatles')
 
743
        self.assertTrue(transaction.is_dirty())
 
744
        TransactionMiddleware().process_exception(self.request, None)
 
745
        self.assertFalse(transaction.is_dirty())
 
746
        self.assertEqual(Band.objects.count(), 0)
 
747
 
 
748
    def test_failing_commit(self):
 
749
        # It is possible that connection.commit() fails. Check that
 
750
        # TransactionMiddleware handles such cases correctly.
 
751
        try:
 
752
            def raise_exception():
 
753
                raise IntegrityError()
 
754
            connections[DEFAULT_DB_ALIAS].commit = raise_exception
 
755
            transaction.enter_transaction_management()
 
756
            Band.objects.create(name='The Beatles')
 
757
            self.assertTrue(transaction.is_dirty())
 
758
            with self.assertRaises(IntegrityError):
 
759
                TransactionMiddleware().process_response(self.request, None)
 
760
            self.assertFalse(transaction.is_dirty())
 
761
            self.assertEqual(Band.objects.count(), 0)
 
762
            self.assertFalse(transaction.is_managed())
 
763
        finally:
 
764
            del connections[DEFAULT_DB_ALIAS].commit