[Python-modules-commits] [python-django] 01/03: Imported Upstream version 1.7.3
Luke Faraone
lfaraone at moszumanska.debian.org
Fri Jan 16 05:44:51 UTC 2015
This is an automated email from the git hooks/post-receive script.
lfaraone pushed a commit to branch debian/experimental
in repository python-django.
commit 964a50e14d6553f866d750dc26104c81be06f4a7
Author: Luke Faraone <lfaraone at debian.org>
Date: Thu Jan 15 21:40:52 2015 -0800
Imported Upstream version 1.7.3
---
Django.egg-info/PKG-INFO | 2 +-
Django.egg-info/SOURCES.txt | 5 ++
PKG-INFO | 2 +-
django/__init__.py | 2 +-
django/conf/locale/el/formats.py | 36 ++++++++----
django/contrib/auth/decorators.py | 5 +-
django/contrib/auth/hashers.py | 4 +-
django/contrib/auth/tests/test_hashers.py | 6 +-
django/contrib/auth/tests/test_views.py | 26 ++++++++-
django/core/servers/basehttp.py | 11 ++++
django/db/migrations/migration.py | 40 +++++++++-----
django/forms/models.py | 28 ++++++++--
django/middleware/csrf.py | 6 +-
django/shortcuts.py | 7 +++
django/utils/http.py | 1 +
django/views/static.py | 5 +-
docs/howto/auth-remote-user.txt | 16 ++++++
docs/index.txt | 12 ++--
docs/ref/contrib/admin/index.txt | 2 +-
docs/ref/schema-editor.txt | 17 ++++++
docs/releases/1.4.18.txt | 68 +++++++++++++++++++++++
docs/releases/1.6.10.txt | 69 +++++++++++++++++++++++
docs/releases/1.7.3.txt | 91 +++++++++++++++++++++++++++++++
docs/releases/index.txt | 3 +
docs/spelling_wordlist | 1 +
docs/topics/forms/index.txt | 4 +-
docs/topics/migrations.txt | 67 +++++++++++++++++++++++
tests/csrf_tests/tests.py | 5 ++
tests/logging_tests/tests.py | 16 ++++--
tests/migrations/test_operations.py | 28 ++++++----
tests/model_forms/tests.py | 21 +++++++
tests/resolve_url/tests.py | 12 +++-
tests/resolve_url/urls.py | 5 +-
tests/runtests.py | 5 ++
tests/servers/test_basehttp.py | 67 +++++++++++++++++++++++
tests/test_runner/tests.py | 2 +-
tests/utils_tests/test_http.py | 3 +-
tests/view_tests/media/long-line.txt | 1 +
tests/view_tests/tests/test_static.py | 10 +++-
39 files changed, 632 insertions(+), 79 deletions(-)
diff --git a/Django.egg-info/PKG-INFO b/Django.egg-info/PKG-INFO
index 83b4829..acf7c27 100644
--- a/Django.egg-info/PKG-INFO
+++ b/Django.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: Django
-Version: 1.7.2
+Version: 1.7.3
Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
Home-page: http://www.djangoproject.com/
Author: Django Software Foundation
diff --git a/Django.egg-info/SOURCES.txt b/Django.egg-info/SOURCES.txt
index e629edf..92cd27d 100644
--- a/Django.egg-info/SOURCES.txt
+++ b/Django.egg-info/SOURCES.txt
@@ -3981,6 +3981,7 @@ docs/releases/1.4.14.txt
docs/releases/1.4.15.txt
docs/releases/1.4.16.txt
docs/releases/1.4.17.txt
+docs/releases/1.4.18.txt
docs/releases/1.4.2.txt
docs/releases/1.4.3.txt
docs/releases/1.4.4.txt
@@ -4004,6 +4005,7 @@ docs/releases/1.5.8.txt
docs/releases/1.5.9.txt
docs/releases/1.5.txt
docs/releases/1.6.1.txt
+docs/releases/1.6.10.txt
docs/releases/1.6.2.txt
docs/releases/1.6.3.txt
docs/releases/1.6.4.txt
@@ -4015,6 +4017,7 @@ docs/releases/1.6.9.txt
docs/releases/1.6.txt
docs/releases/1.7.1.txt
docs/releases/1.7.2.txt
+docs/releases/1.7.3.txt
docs/releases/1.7.txt
docs/releases/index.txt
docs/releases/security.txt
@@ -5005,6 +5008,7 @@ tests/serializers_regress/models.py
tests/serializers_regress/tests.py
tests/servers/__init__.py
tests/servers/models.py
+tests/servers/test_basehttp.py
tests/servers/tests.py
tests/servers/urls.py
tests/servers/views.py
@@ -5363,6 +5367,7 @@ tests/view_tests/locale/ru/LC_MESSAGES/djangojs.po
tests/view_tests/media/file.txt
tests/view_tests/media/file.txt.gz
tests/view_tests/media/file.unknown
+tests/view_tests/media/long-line.txt
tests/view_tests/other_templates/render_dirs_test.html
tests/view_tests/templates/jsi18n.html
tests/view_tests/templates/debug/render_test.html
diff --git a/PKG-INFO b/PKG-INFO
index 83b4829..acf7c27 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: Django
-Version: 1.7.2
+Version: 1.7.3
Summary: A high-level Python Web framework that encourages rapid development and clean, pragmatic design.
Home-page: http://www.djangoproject.com/
Author: Django Software Foundation
diff --git a/django/__init__.py b/django/__init__.py
index 5df6a56..424dc1f 100644
--- a/django/__init__.py
+++ b/django/__init__.py
@@ -1,4 +1,4 @@
-VERSION = (1, 7, 2, 'final', 0)
+VERSION = (1, 7, 3, 'final', 0)
def get_version(*args, **kwargs):
diff --git a/django/conf/locale/el/formats.py b/django/conf/locale/el/formats.py
index 817f71d..429db4b 100644
--- a/django/conf/locale/el/formats.py
+++ b/django/conf/locale/el/formats.py
@@ -5,20 +5,34 @@ from __future__ import unicode_literals
# The *_FORMAT strings use the Django date format syntax,
# see http://docs.djangoproject.com/en/dev/ref/templates/builtins/#date
-DATE_FORMAT = 'd E Y'
-TIME_FORMAT = 'g:i:s A'
-# DATETIME_FORMAT =
+DATE_FORMAT = 'd/m/Y'
+TIME_FORMAT = 'P'
+DATETIME_FORMAT = 'd/m/Y P'
YEAR_MONTH_FORMAT = 'F Y'
MONTH_DAY_FORMAT = 'j F'
-SHORT_DATE_FORMAT = 'd M Y'
-# SHORT_DATETIME_FORMAT =
-# FIRST_DAY_OF_WEEK =
+SHORT_DATE_FORMAT = 'd/m/Y'
+SHORT_DATETIME_FORMAT = 'd/m/Y P'
+FIRST_DAY_OF_WEEK = 0 # Sunday
# The *_INPUT_FORMATS strings use the Python strftime format syntax,
# see http://docs.python.org/library/datetime.html#strftime-strptime-behavior
-# DATE_INPUT_FORMATS =
-# TIME_INPUT_FORMATS =
-# DATETIME_INPUT_FORMATS =
+DATE_INPUT_FORMATS = (
+ '%d/%m/%Y', '%d/%m/%y', '%Y-%m-%d', # '25/10/2006', '25/10/06', '2006-10-25',
+)
+DATETIME_INPUT_FORMATS = (
+ '%d/%m/%Y %H:%M:%S', # '25/10/2006 14:30:59'
+ '%d/%m/%Y %H:%M:%S.%f', # '25/10/2006 14:30:59.000200'
+ '%d/%m/%Y %H:%M', # '25/10/2006 14:30'
+ '%d/%m/%Y', # '25/10/2006'
+ '%d/%m/%y %H:%M:%S', # '25/10/06 14:30:59'
+ '%d/%m/%y %H:%M:%S.%f', # '25/10/06 14:30:59.000200'
+ '%d/%m/%y %H:%M', # '25/10/06 14:30'
+ '%d/%m/%y', # '25/10/06'
+ '%Y-%m-%d %H:%M:%S', # '2006-10-25 14:30:59'
+ '%Y-%m-%d %H:%M:%S.%f', # '2006-10-25 14:30:59.000200'
+ '%Y-%m-%d %H:%M', # '2006-10-25 14:30'
+ '%Y-%m-%d', # '2006-10-25'
+)
DECIMAL_SEPARATOR = ','
-THOUSAND_SEPARATOR = '.'
-# NUMBER_GROUPING =
+THOUSAND_SEPARATOR = '\xa0' # non-breaking space
+NUMBER_GROUPING = 3
diff --git a/django/contrib/auth/decorators.py b/django/contrib/auth/decorators.py
index 12a79c0..99e2983 100644
--- a/django/contrib/auth/decorators.py
+++ b/django/contrib/auth/decorators.py
@@ -3,7 +3,6 @@ from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import PermissionDenied
from django.utils.decorators import available_attrs
-from django.utils.encoding import force_str
from django.utils.six.moves.urllib.parse import urlparse
from django.shortcuts import resolve_url
@@ -21,9 +20,7 @@ def user_passes_test(test_func, login_url=None, redirect_field_name=REDIRECT_FIE
if test_func(request.user):
return view_func(request, *args, **kwargs)
path = request.build_absolute_uri()
- # urlparse chokes on lazy objects in Python 3, force to str
- resolved_login_url = force_str(
- resolve_url(login_url or settings.LOGIN_URL))
+ resolved_login_url = resolve_url(login_url or settings.LOGIN_URL)
# If the login url is the same scheme and net location then just
# use the path as the "next" url.
login_scheme, login_netloc = urlparse(resolved_login_url)[:2]
diff --git a/django/contrib/auth/hashers.py b/django/contrib/auth/hashers.py
index 4e40a7c..e459f39 100644
--- a/django/contrib/auth/hashers.py
+++ b/django/contrib/auth/hashers.py
@@ -222,12 +222,12 @@ class PBKDF2PasswordHasher(BasePasswordHasher):
"""
Secure password hashing using the PBKDF2 algorithm (recommended)
- Configured to use PBKDF2 + HMAC + SHA256 with 12000 iterations.
+ Configured to use PBKDF2 + HMAC + SHA256 with 15000 iterations.
The result is a 64 byte binary string. Iterations may be changed
safely but you must rename the algorithm if you change SHA256.
"""
algorithm = "pbkdf2_sha256"
- iterations = 12000
+ iterations = 15000
digest = hashlib.sha256
def encode(self, password, salt, iterations=None):
diff --git a/django/contrib/auth/tests/test_hashers.py b/django/contrib/auth/tests/test_hashers.py
index 58628cd..85f1c15 100644
--- a/django/contrib/auth/tests/test_hashers.py
+++ b/django/contrib/auth/tests/test_hashers.py
@@ -47,7 +47,7 @@ class TestUtilsHashPass(SimpleTestCase):
def test_pkbdf2(self):
encoded = make_password('lètmein', 'seasalt', 'pbkdf2_sha256')
self.assertEqual(encoded,
- 'pbkdf2_sha256$12000$seasalt$Ybw8zsFxqja97tY/o6G+Fy1ksY4U/Hw3DRrGED6Up4s=')
+ 'pbkdf2_sha256$15000$seasalt$+qoFTwR4r71UCLMhmQUCou/LMu17XwQWfYIVd/xJ1RI=')
self.assertTrue(is_password_usable(encoded))
self.assertTrue(check_password('lètmein', encoded))
self.assertFalse(check_password('lètmeinz', encoded))
@@ -211,14 +211,14 @@ class TestUtilsHashPass(SimpleTestCase):
hasher = PBKDF2PasswordHasher()
encoded = hasher.encode('lètmein', 'seasalt2')
self.assertEqual(encoded,
- 'pbkdf2_sha256$12000$seasalt2$hlDLKsxgkgb1aeOppkM5atCYw5rPzAjCNQZ4NYyUROw=')
+ 'pbkdf2_sha256$15000$seasalt2$uSQqI+91wgObKdP6L6S75LLzyxrZRWNcaujEZPA3/nA=')
self.assertTrue(hasher.verify('lètmein', encoded))
def test_low_level_pbkdf2_sha1(self):
hasher = PBKDF2SHA1PasswordHasher()
encoded = hasher.encode('lètmein', 'seasalt2')
self.assertEqual(encoded,
- 'pbkdf2_sha1$12000$seasalt2$JeMRVfjjgtWw3/HzlnlfqBnQ6CA=')
+ 'pbkdf2_sha1$15000$seasalt2$iYDXAPKgMsKMsarvA1MErD518Ug=')
self.assertTrue(hasher.verify('lètmein', encoded))
def test_upgrade(self):
diff --git a/django/contrib/auth/tests/test_views.py b/django/contrib/auth/tests/test_views.py
index 1a73af5..d9fbd0b 100644
--- a/django/contrib/auth/tests/test_views.py
+++ b/django/contrib/auth/tests/test_views.py
@@ -1,3 +1,6 @@
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
from importlib import import_module
import itertools
import os
@@ -9,7 +12,7 @@ from django.contrib.sites.requests import RequestSite
from django.contrib.admin.models import LogEntry
from django.contrib.auth.models import User
from django.core import mail
-from django.core.urlresolvers import reverse, NoReverseMatch
+from django.core.urlresolvers import NoReverseMatch, reverse, reverse_lazy
from django.http import QueryDict, HttpRequest
from django.utils.encoding import force_text
from django.utils.http import urlquote
@@ -27,7 +30,7 @@ from django.contrib.auth.forms import (AuthenticationForm, PasswordChangeForm,
# Needed so model is installed when tests are run independently:
from django.contrib.auth.tests.custom_user import CustomUser # NOQA
from django.contrib.auth.tests.utils import skipIfCustomUser
-from django.contrib.auth.views import login as login_view
+from django.contrib.auth.views import login as login_view, redirect_to_login
@override_settings(
@@ -652,6 +655,10 @@ class LoginURLSettings(AuthViewsTestCase):
expected = 'http://remote.example.com/login/?next=%s' % quoted_next
self.assertLoginURLEquals(expected)
+ @override_settings(LOGIN_URL=reverse_lazy('login'))
+ def test_lazy_login_url(self):
+ self.assertLoginURLEquals('/login/?next=/login_required/')
+
@skipIfCustomUser
class LoginRedirectUrlTest(AuthViewsTestCase):
@@ -677,6 +684,21 @@ class LoginRedirectUrlTest(AuthViewsTestCase):
self.assertLoginRedirectURLEqual('http://remote.example.com/welcome/')
+class RedirectToLoginTests(AuthViewsTestCase):
+ """Tests for the redirect_to_login view"""
+ @override_settings(LOGIN_URL=reverse_lazy('login'))
+ def test_redirect_to_login_with_lazy(self):
+ login_redirect_response = redirect_to_login(next='/else/where/')
+ expected = '/login/?next=/else/where/'
+ self.assertEqual(expected, login_redirect_response.url)
+
+ @override_settings(LOGIN_URL=reverse_lazy('login'))
+ def test_redirect_to_login_with_lazy_and_unicode(self):
+ login_redirect_response = redirect_to_login(next='/else/where/झ/')
+ expected = '/login/?next=/else/where/%E0%A4%9D/'
+ self.assertEqual(expected, login_redirect_response.url)
+
+
@skipIfCustomUser
class LogoutTest(AuthViewsTestCase):
diff --git a/django/core/servers/basehttp.py b/django/core/servers/basehttp.py
index 090a694..cc1ff9b 100644
--- a/django/core/servers/basehttp.py
+++ b/django/core/servers/basehttp.py
@@ -155,6 +155,17 @@ class WSGIRequestHandler(simple_server.WSGIRequestHandler, object):
sys.stderr.write(msg)
+ def get_environ(self):
+ # Strip all headers with underscores in the name before constructing
+ # the WSGI environ. This prevents header-spoofing based on ambiguity
+ # between underscores and dashes both normalized to underscores in WSGI
+ # env vars. Nginx and Apache 2.4+ both do this as well.
+ for k, v in self.headers.items():
+ if '_' in k:
+ del self.headers[k]
+
+ return super(WSGIRequestHandler, self).get_environ()
+
def run(addr, port, wsgi_handler, ipv6=False, threading=False):
server_address = (addr, port)
diff --git a/django/db/migrations/migration.py b/django/db/migrations/migration.py
index 80bdb2f..79f6bfb 100644
--- a/django/db/migrations/migration.py
+++ b/django/db/migrations/migration.py
@@ -115,29 +115,39 @@ class Migration(object):
Takes a project_state representing all migrations prior to this one
and a schema_editor for a live database and applies the migration
in a reverse order.
+
+ The backwards migration process consists of two phases:
+
+ 1. The intermediate states from right before the first until right
+ after the last operation inside this migration are preserved.
+ 2. The operations are applied in reverse order using the states
+ recorded in step 1.
"""
- # We need to pre-calculate the stack of project states
+ # Construct all the intermediate states we need for a reverse migration
to_run = []
+ new_state = project_state
+ # Phase 1
for operation in self.operations:
- # If this operation cannot be represented as SQL, place a comment
- # there instead
- if collect_sql and not operation.reduces_to_sql:
- schema_editor.collected_sql.append("--")
- schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE "
- "WRITTEN AS SQL:")
- schema_editor.collected_sql.append("-- %s" % operation.describe())
- schema_editor.collected_sql.append("--")
- continue
# If it's irreversible, error out
if not operation.reversible:
raise Migration.IrreversibleError("Operation %s in %s is not reversible" % (operation, self))
- new_state = project_state.clone()
+ # Preserve new state from previous run to not tamper the same state
+ # over all operations
+ new_state = new_state.clone()
+ old_state = new_state.clone()
operation.state_forwards(self.app_label, new_state)
- to_run.append((operation, project_state, new_state))
- project_state = new_state
- # Now run them in reverse
- to_run.reverse()
+ to_run.insert(0, (operation, old_state, new_state))
+
+ # Phase 2
for operation, to_state, from_state in to_run:
+ if collect_sql:
+ if not operation.reduces_to_sql:
+ schema_editor.collected_sql.append("--")
+ schema_editor.collected_sql.append("-- MIGRATION NOW PERFORMS OPERATION THAT CANNOT BE "
+ "WRITTEN AS SQL:")
+ schema_editor.collected_sql.append("-- %s" % operation.describe())
+ schema_editor.collected_sql.append("--")
+ continue
if not schema_editor.connection.features.can_rollback_ddl and operation.atomic:
# We're forcing a transaction on a non-transactional-DDL backend
with atomic(schema_editor.connection.alias):
diff --git a/django/forms/models.py b/django/forms/models.py
index 0f1f54f..37ef32d 100644
--- a/django/forms/models.py
+++ b/django/forms/models.py
@@ -1221,8 +1221,7 @@ class ModelMultipleChoiceField(ModelChoiceField):
def to_python(self, value):
if not value:
return []
- to_py = super(ModelMultipleChoiceField, self).to_python
- return [to_py(val) for val in value]
+ return list(self._check_values(value))
def clean(self, value):
if self.required and not value:
@@ -1231,7 +1230,29 @@ class ModelMultipleChoiceField(ModelChoiceField):
return self.queryset.none()
if not isinstance(value, (list, tuple)):
raise ValidationError(self.error_messages['list'], code='list')
+ qs = self._check_values(value)
+ # Since this overrides the inherited ModelChoiceField.clean
+ # we run custom validators here
+ self.run_validators(value)
+ return qs
+
+ def _check_values(self, value):
+ """
+ Given a list of possible PK values, returns a QuerySet of the
+ corresponding objects. Raises a ValidationError if a given value is
+ invalid (not a valid PK, not in the queryset, etc.)
+ """
key = self.to_field_name or 'pk'
+ # deduplicate given values to avoid creating many querysets or
+ # requiring the database backend deduplicate efficiently.
+ try:
+ value = frozenset(value)
+ except TypeError:
+ # list of lists isn't hashable, for example
+ raise ValidationError(
+ self.error_messages['list'],
+ code='list',
+ )
for pk in value:
try:
self.queryset.filter(**{key: pk})
@@ -1250,9 +1271,6 @@ class ModelMultipleChoiceField(ModelChoiceField):
code='invalid_choice',
params={'value': val},
)
- # Since this overrides the inherited ModelChoiceField.clean
- # we run custom validators here
- self.run_validators(value)
return qs
def prepare_value(self, value):
diff --git a/django/middleware/csrf.py b/django/middleware/csrf.py
index eb7fe7d..dfeefa4 100644
--- a/django/middleware/csrf.py
+++ b/django/middleware/csrf.py
@@ -148,7 +148,11 @@ class CsrfViewMiddleware(object):
# Barth et al. found that the Referer header is missing for
# same-domain requests in only about 0.2% of cases or less, so
# we can use strict Referer checking.
- referer = request.META.get('HTTP_REFERER')
+ referer = force_text(
+ request.META.get('HTTP_REFERER'),
+ strings_only=True,
+ errors='replace'
+ )
if referer is None:
return self._reject(request, REASON_NO_REFERER)
diff --git a/django/shortcuts.py b/django/shortcuts.py
index 6256047..d995813 100644
--- a/django/shortcuts.py
+++ b/django/shortcuts.py
@@ -11,6 +11,8 @@ from django.db.models.manager import Manager
from django.db.models.query import QuerySet
from django.core import urlresolvers
from django.utils import six
+from django.utils.encoding import force_text
+from django.utils.functional import Promise
def render_to_response(*args, **kwargs):
@@ -148,6 +150,11 @@ def resolve_url(to, *args, **kwargs):
if hasattr(to, 'get_absolute_url'):
return to.get_absolute_url()
+ if isinstance(to, Promise):
+ # Expand the lazy instance, as it can cause issues when it is passed
+ # further to some Python functions like urlparse.
+ to = force_text(to)
+
if isinstance(to, six.string_types):
# Handle relative URLs
if any(to.startswith(path) for path in ('./', '../')):
diff --git a/django/utils/http.py b/django/utils/http.py
index 67414d9..6aa5cd3 100644
--- a/django/utils/http.py
+++ b/django/utils/http.py
@@ -272,6 +272,7 @@ def is_safe_url(url, host=None):
"""
if not url:
return False
+ url = url.strip()
# Chrome treats \ completely as /
url = url.replace('\\', '/')
# Chrome considers any URL with more than two slashes to be absolute, but
diff --git a/django/views/static.py b/django/views/static.py
index 68fb7c4..0ce00a9 100644
--- a/django/views/static.py
+++ b/django/views/static.py
@@ -17,6 +17,8 @@ from django.utils.http import http_date, parse_http_date
from django.utils.six.moves.urllib.parse import unquote
from django.utils.translation import ugettext as _, ugettext_lazy
+STREAM_CHUNK_SIZE = 4096
+
def serve(request, path, document_root=None, show_indexes=False):
"""
@@ -61,7 +63,8 @@ def serve(request, path, document_root=None, show_indexes=False):
return HttpResponseNotModified()
content_type, encoding = mimetypes.guess_type(fullpath)
content_type = content_type or 'application/octet-stream'
- response = StreamingHttpResponse(open(fullpath, 'rb'),
+ f = open(fullpath, 'rb')
+ response = StreamingHttpResponse(iter(lambda: f.read(STREAM_CHUNK_SIZE), b''),
content_type=content_type)
response["Last-Modified"] = http_date(statobj.st_mtime)
if stat.S_ISREG(statobj.st_mode):
diff --git a/docs/howto/auth-remote-user.txt b/docs/howto/auth-remote-user.txt
index 2edab6b..dc96a98 100644
--- a/docs/howto/auth-remote-user.txt
+++ b/docs/howto/auth-remote-user.txt
@@ -64,6 +64,22 @@ If your authentication mechanism uses a custom HTTP header and not
class CustomHeaderMiddleware(RemoteUserMiddleware):
header = 'HTTP_AUTHUSER'
+.. warning::
+
+ Be very careful if using a ``RemoteUserMiddleware`` subclass with a custom
+ HTTP header. You must be sure that your front-end web server always sets or
+ strips that header based on the appropriate authentication checks, never
+ permitting an end-user to submit a fake (or "spoofed") header value. Since
+ the HTTP headers ``X-Auth-User`` and ``X-Auth_User`` (for example) both
+ normalize to the ``HTTP_X_AUTH_USER`` key in ``request.META``, you must
+ also check that your web server doesn't allow a spoofed header using
+ underscores in place of dashes.
+
+ This warning doesn't apply to ``RemoteUserMiddleware`` in its default
+ configuration with ``header = 'REMOTE_USER'``, since a key that doesn't
+ start with ``HTTP_`` in ``request.META`` can only be set by your WSGI
+ server, not directly from an HTTP request header.
+
If you need more control, you can create your own authentication backend
that inherits from :class:`~django.contrib.auth.backends.RemoteUserBackend` and
override one or more of its attributes and methods.
diff --git a/docs/index.txt b/docs/index.txt
index 959b655..f0744d2 100644
--- a/docs/index.txt
+++ b/docs/index.txt
@@ -41,12 +41,12 @@ Are you new to Django or to programming? This is the place to start!
:doc:`Installation <intro/install>`
* **Tutorial:**
- :doc:`Part 1 <intro/tutorial01>` |
- :doc:`Part 2 <intro/tutorial02>` |
- :doc:`Part 3 <intro/tutorial03>` |
- :doc:`Part 4 <intro/tutorial04>` |
- :doc:`Part 5 <intro/tutorial05>` |
- :doc:`Part 6 <intro/tutorial06>`
+ :doc:`Part 1: Models <intro/tutorial01>` |
+ :doc:`Part 2: The admin site <intro/tutorial02>` |
+ :doc:`Part 3: Views and templates <intro/tutorial03>` |
+ :doc:`Part 4: Forms and generic views <intro/tutorial04>` |
+ :doc:`Part 5: Testing <intro/tutorial05>` |
+ :doc:`Part 6: Static files <intro/tutorial06>`
* **Advanced Tutorials:**
:doc:`How to write reusable apps <intro/reusable-apps>` |
diff --git a/docs/ref/contrib/admin/index.txt b/docs/ref/contrib/admin/index.txt
index e25557a..ea00cb3 100644
--- a/docs/ref/contrib/admin/index.txt
+++ b/docs/ref/contrib/admin/index.txt
@@ -681,7 +681,7 @@ subclass::
For example::
- class Person(object):
+ class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
diff --git a/docs/ref/schema-editor.txt b/docs/ref/schema-editor.txt
index e4d3fa0..94456d0 100644
--- a/docs/ref/schema-editor.txt
+++ b/docs/ref/schema-editor.txt
@@ -149,3 +149,20 @@ If the database has the ``supports_combined_alters``, Django will try and
do as many of these in a single database call as possible; otherwise, it will
issue a separate ALTER statement for each change, but will not issue ALTERs
where no change is required (as South often did).
+
+Attributes
+==========
+
+All attributes should be considered read-only unless stated otherwise.
+
+connection
+----------
+
+.. attribute:: SchemaEditor.connection
+
+A connection object to the database. A useful attribute of the connection is
+``alias`` which can be used to determine the name of the database being
+accessed.
+
+This is useful when doing data migrations for :ref:`migrations with multiple
+databases <data-migrations-and-multiple-databases>`.
diff --git a/docs/releases/1.4.18.txt b/docs/releases/1.4.18.txt
new file mode 100644
index 0000000..b154d87
--- /dev/null
+++ b/docs/releases/1.4.18.txt
@@ -0,0 +1,68 @@
+===========================
+Django 1.4.18 release notes
+===========================
+
+*January 13, 2015*
+
+Django 1.4.18 fixes several security issues in 1.4.17 as well as a regression
+on Python 2.5 in the 1.4.17 release.
+
+WSGI header spoofing via underscore/dash conflation
+===================================================
+
+When HTTP headers are placed into the WSGI environ, they are normalized by
+converting to uppercase, converting all dashes to underscores, and prepending
+`HTTP_`. For instance, a header ``X-Auth-User`` would become
+``HTTP_X_AUTH_USER`` in the WSGI environ (and thus also in Django's
+``request.META`` dictionary).
+
+Unfortunately, this means that the WSGI environ cannot distinguish between
+headers containing dashes and headers containing underscores: ``X-Auth-User``
+and ``X-Auth_User`` both become ``HTTP_X_AUTH_USER``. This means that if a
+header is used in a security-sensitive way (for instance, passing
+authentication information along from a front-end proxy), even if the proxy
+carefully strips any incoming value for ``X-Auth-User``, an attacker may be
+able to provide an ``X-Auth_User`` header (with underscore) and bypass this
+protection.
+
+In order to prevent such attacks, both Nginx and Apache 2.4+ strip all headers
+containing underscores from incoming requests by default. Django's built-in
+development server now does the same. Django's development server is not
+recommended for production use, but matching the behavior of common production
+servers reduces the surface area for behavior changes during deployment.
+
+Mitigated possible XSS attack via user-supplied redirect URLs
+=============================================================
+
+Django relies on user input in some cases (e.g.
+:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
+to redirect the user to an "on success" URL. The security checks for these
+redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading
+whitespace on the tested URL and as such considered URLs like
+``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to
+provide safe redirect targets and put such a URL into a link, they could suffer
+from a XSS attack. This bug doesn't affect Django currently, since we only put
+this URL into the ``Location`` response header and browsers seem to ignore
+JavaScript there.
+
+Denial-of-service attack against ``django.views.static.serve``
+==============================================================
+
+In older versions of Django, the :func:`django.views.static.serve` view read
+the files it served one line at a time. Therefore, a big file with no newlines
+would result in memory usage equal to the size of that file. An attacker could
+exploit this and launch a denial-of-service attack by simultaneously requesting
+many large files. This view now reads the file in chunks to prevent large
+memory usage.
+
+Note, however, that this view has always carried a warning that it is not
+hardened for production use and should be used only as a development aid. Now
+may be a good time to audit your project and serve your files in production
+using a real front-end web server if you are not doing so.
+
+Bugfixes
+========
+
+* To maintain compatibility with Python 2.5, Django's vendored version of six,
+ :mod:`django.utils.six`, has been downgraded to 1.8.0 which is the last
+ version to support Python 2.5.
diff --git a/docs/releases/1.6.10.txt b/docs/releases/1.6.10.txt
new file mode 100644
index 0000000..a559bfc
--- /dev/null
+++ b/docs/releases/1.6.10.txt
@@ -0,0 +1,69 @@
+===========================
+Django 1.6.10 release notes
+===========================
+
+*January 13, 2015*
+
+Django 1.6.10 fixes several security issues in 1.6.9.
+
+WSGI header spoofing via underscore/dash conflation
+===================================================
+
+When HTTP headers are placed into the WSGI environ, they are normalized by
+converting to uppercase, converting all dashes to underscores, and prepending
+`HTTP_`. For instance, a header ``X-Auth-User`` would become
+``HTTP_X_AUTH_USER`` in the WSGI environ (and thus also in Django's
+``request.META`` dictionary).
+
+Unfortunately, this means that the WSGI environ cannot distinguish between
+headers containing dashes and headers containing underscores: ``X-Auth-User``
+and ``X-Auth_User`` both become ``HTTP_X_AUTH_USER``. This means that if a
+header is used in a security-sensitive way (for instance, passing
+authentication information along from a front-end proxy), even if the proxy
+carefully strips any incoming value for ``X-Auth-User``, an attacker may be
+able to provide an ``X-Auth_User`` header (with underscore) and bypass this
+protection.
+
+In order to prevent such attacks, both Nginx and Apache 2.4+ strip all headers
+containing underscores from incoming requests by default. Django's built-in
+development server now does the same. Django's development server is not
+recommended for production use, but matching the behavior of common production
+servers reduces the surface area for behavior changes during deployment.
+
+Mitigated possible XSS attack via user-supplied redirect URLs
+=============================================================
+
+Django relies on user input in some cases (e.g.
+:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
+to redirect the user to an "on success" URL. The security checks for these
+redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading
+whitespace on the tested URL and as such considered URLs like
+``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to
+provide safe redirect targets and put such a URL into a link, they could suffer
+from a XSS attack. This bug doesn't affect Django currently, since we only put
+this URL into the ``Location`` response header and browsers seem to ignore
+JavaScript there.
+
+Denial-of-service attack against ``django.views.static.serve``
+==============================================================
+
+In older versions of Django, the :func:`django.views.static.serve` view read
+the files it served one line at a time. Therefore, a big file with no newlines
+would result in memory usage equal to the size of that file. An attacker could
+exploit this and launch a denial-of-service attack by simultaneously requesting
+many large files. This view now reads the file in chunks to prevent large
+memory usage.
+
+Note, however, that this view has always carried a warning that it is not
+hardened for production use and should be used only as a development aid. Now
+may be a good time to audit your project and serve your files in production
+using a real front-end web server if you are not doing so.
+
+Database denial-of-service with ``ModelMultipleChoiceField``
+============================================================
+
+Given a form that uses ``ModelMultipleChoiceField`` and
+``show_hidden_initial=True`` (not a documented API), it was possible for a user
+to cause an unreasonable number of SQL queries by submitting duplicate values
+for the field's data. The validation logic in ``ModelMultipleChoiceField`` now
+deduplicates submitted values to address this issue.
diff --git a/docs/releases/1.7.3.txt b/docs/releases/1.7.3.txt
new file mode 100644
index 0000000..46785bf
--- /dev/null
+++ b/docs/releases/1.7.3.txt
@@ -0,0 +1,91 @@
+==========================
+Django 1.7.3 release notes
+==========================
+
+*January 13, 2015*
+
+Django 1.7.3 fixes several security issues and bugs in 1.7.2.
+
+WSGI header spoofing via underscore/dash conflation
+===================================================
+
+When HTTP headers are placed into the WSGI environ, they are normalized by
+converting to uppercase, converting all dashes to underscores, and prepending
+`HTTP_`. For instance, a header ``X-Auth-User`` would become
+``HTTP_X_AUTH_USER`` in the WSGI environ (and thus also in Django's
+``request.META`` dictionary).
+
+Unfortunately, this means that the WSGI environ cannot distinguish between
+headers containing dashes and headers containing underscores: ``X-Auth-User``
+and ``X-Auth_User`` both become ``HTTP_X_AUTH_USER``. This means that if a
+header is used in a security-sensitive way (for instance, passing
+authentication information along from a front-end proxy), even if the proxy
+carefully strips any incoming value for ``X-Auth-User``, an attacker may be
+able to provide an ``X-Auth_User`` header (with underscore) and bypass this
+protection.
+
+In order to prevent such attacks, both Nginx and Apache 2.4+ strip all headers
+containing underscores from incoming requests by default. Django's built-in
+development server now does the same. Django's development server is not
+recommended for production use, but matching the behavior of common production
+servers reduces the surface area for behavior changes during deployment.
+
+Mitigated possible XSS attack via user-supplied redirect URLs
+=============================================================
+
+Django relies on user input in some cases (e.g.
+:func:`django.contrib.auth.views.login` and :doc:`i18n </topics/i18n/index>`)
+to redirect the user to an "on success" URL. The security checks for these
+redirects (namely ``django.util.http.is_safe_url()``) didn't strip leading
+whitespace on the tested URL and as such considered URLs like
+``\njavascript:...`` safe. If a developer relied on ``is_safe_url()`` to
+provide safe redirect targets and put such a URL into a link, they could suffer
+from a XSS attack. This bug doesn't affect Django currently, since we only put
+this URL into the ``Location`` response header and browsers seem to ignore
+JavaScript there.
+
+Denial-of-service attack against ``django.views.static.serve``
+==============================================================
+
+In older versions of Django, the :func:`django.views.static.serve` view read
+the files it served one line at a time. Therefore, a big file with no newlines
+would result in memory usage equal to the size of that file. An attacker could
+exploit this and launch a denial-of-service attack by simultaneously requesting
+many large files. This view now reads the file in chunks to prevent large
+memory usage.
+
+Note, however, that this view has always carried a warning that it is not
+hardened for production use and should be used only as a development aid. Now
+may be a good time to audit your project and serve your files in production
+using a real front-end web server if you are not doing so.
+
+Database denial-of-service with ``ModelMultipleChoiceField``
+============================================================
+
+Given a form that uses ``ModelMultipleChoiceField`` and
+``show_hidden_initial=True`` (not a documented API), it was possible for a user
+to cause an unreasonable number of SQL queries by submitting duplicate values
+for the field's data. The validation logic in ``ModelMultipleChoiceField`` now
+deduplicates submitted values to address this issue.
+
+Bugfixes
+========
+
+* The default iteration count for the PBKDF2 password hasher has been
+ increased by 25%. This part of the normal major release process was
+ inadvertently omitted in 1.7. This backwards compatible change will not
+ affect users who have subclassed
+ ``django.contrib.auth.hashers.PBKDF2PasswordHasher`` to change the
+ default value.
+
+* Fixed a crash in the CSRF middleware when handling non-ASCII referer header
+ (:ticket:`23815`).
+
+* Fixed a crash in the ``django.contrib.auth.redirect_to_login`` view when
+ passing a :func:`~django.core.urlresolvers.reverse_lazy` result on Python 3
+ (:ticket:`24097`).
+
+* Added correct formats for Greek (``el``) (:ticket:`23967`).
+
+* Fixed a migration crash when unapplying a migration where multiple operations
+ interact with the same model (:ticket:`24110`).
diff --git a/docs/releases/index.txt b/docs/releases/index.txt
index 5f8fa67..4369ef3 100644
--- a/docs/releases/index.txt
+++ b/docs/releases/index.txt
@@ -25,6 +25,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree::
:maxdepth: 1
+ 1.7.3
1.7.2
1.7.1
1.7
@@ -34,6 +35,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree::
:maxdepth: 1
+ 1.6.10
1.6.9
1.6.8
1.6.7
@@ -69,6 +71,7 @@ versions of the documentation contain the release notes for any later releases.
.. toctree::
:maxdepth: 1
+ 1.4.18
1.4.17
1.4.16
1.4.15
diff --git a/docs/spelling_wordlist b/docs/spelling_wordlist
index 23465d2..da7ce09 100644
--- a/docs/spelling_wordlist
+++ b/docs/spelling_wordlist
@@ -134,6 +134,7 @@ dbshell
de
deconstruct
deconstructing
+deduplicates
deepcopy
deserialization
deserialize
diff --git a/docs/topics/forms/index.txt b/docs/topics/forms/index.txt
index 1f0c56f..3006c08 100644
--- a/docs/topics/forms/index.txt
+++ b/docs/topics/forms/index.txt
@@ -389,8 +389,8 @@ The distinction between :ref:`ref-forms-api-bound-unbound` is important:
is valid. If an invalid bound form is rendered, it can include inline error
messages telling the user what data to correct.
-The form's ``is_bound()`` method will tell you whether a form has data bound to
-it or not.
+The form's :attr:`~Form.is_bound` attribute will tell you whether a form has
+data bound to it or not.
More on fields
--------------
diff --git a/docs/topics/migrations.txt b/docs/topics/migrations.txt
index 7594cdf..308ed3f 100755
--- a/docs/topics/migrations.txt
+++ b/docs/topics/migrations.txt
@@ -435,6 +435,73 @@ You can pass a second callable to
want executed when migrating backwards. If this callable is omitted, migrating
backwards will raise an exception.
+.. _data-migrations-and-multiple-databases:
+
+Data migrations and multiple databases
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When using multiple databases, you may need to figure out whether or not to
+run a migration against a particular database. For example, you may want to
+**only** run a migration on a particular database.
+
+In order to do that you can check the database connection's alias inside a
+``RunPython`` operation by looking at the ``schema_editor.connection.alias``
+attribute::
+
+ from django.db import migrations
+
+ def forwards(apps, schema_editor):
+ if not schema_editor.connection.alias == 'default':
+ return
+ # Your migration code goes here
+
+ class Migration(migrations.Migration):
+
+ dependencies = [
+ # Dependencies to other migrations
+ ]
+
+ operations = [
+ migrations.RunPython(forwards),
+ ]
+
+You can also use your database router's ``allow_migrate()`` method, but keep in
+mind that the imported router needs to stay around as long as it is referenced
+inside a migration:
+
+.. snippet::
+ :filename: myapp/dbrouters.py
+
+ class MyRouter(object):
+
+ def allow_migrate(self, db, model):
+ return db == 'default'
+
+Then, to leverage this in your migrations, do the following::
+
+ from django.db import migrations
+
+ from myappname.dbrouters import MyRouter
+
+ def forwards(apps, schema_editor):
+ MyModel = apps.get_model("myappname", "MyModel")
+ if not MyRouter().allow_migrate(schema_editor.connection.alias, MyModel):
+ return
+ # Your migration code goes here
+
+ class Migration(migrations.Migration):
+
+ dependencies = [
+ # Dependencies to other migrations
+ ]
+
+ operations = [
+ migrations.RunPython(forwards),
+ ]
+
+More advanced migrations
+~~~~~~~~~~~~~~~~~~~~~~~~
+
If you're interested in the more advanced migration operations, or want
to be able to write your own, see the :doc:`migration operations reference
</ref/migration-operations>`.
diff --git a/tests/csrf_tests/tests.py b/tests/csrf_tests/tests.py
index 6199ca8..a2a8f1c 100644
--- a/tests/csrf_tests/tests.py
+++ b/tests/csrf_tests/tests.py
@@ -300,6 +300,11 @@ class CsrfViewMiddlewareTest(TestCase):
req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
self.assertNotEqual(None, req2)
self.assertEqual(403, req2.status_code)
+ # Non-ASCII
+ req.META['HTTP_REFERER'] = b'\xd8B\xf6I\xdf'
+ req2 = CsrfViewMiddleware().process_view(req, post_form_view, (), {})
+ self.assertNotEqual(None, req2)
... 311 lines suppressed ...
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/python-django.git
More information about the Python-modules-commits
mailing list