summaryrefslogtreecommitdiff
path: root/django/http
diff options
context:
space:
mode:
Diffstat (limited to 'django/http')
-rw-r--r--django/http/multipartparser.py15
-rw-r--r--django/http/request.py14
-rw-r--r--django/http/response.py74
-rw-r--r--django/http/utils.py4
4 files changed, 89 insertions, 18 deletions
diff --git a/django/http/multipartparser.py b/django/http/multipartparser.py
index 0e999f2ded..eeb435fa57 100644
--- a/django/http/multipartparser.py
+++ b/django/http/multipartparser.py
@@ -11,7 +11,7 @@ import cgi
import sys
from django.conf import settings
-from django.core.exceptions import SuspiciousOperation
+from django.core.exceptions import SuspiciousMultipartForm
from django.utils.datastructures import MultiValueDict
from django.utils.encoding import force_text
from django.utils import six
@@ -48,9 +48,9 @@ class MultiPartParser(object):
The standard ``META`` dictionary in Django request objects.
:input_data:
The raw post data, as a file-like object.
- :upload_handler:
- An UploadHandler instance that performs operations on the uploaded
- data.
+ :upload_handlers:
+ A list of UploadHandler instances that perform operations on the uploaded
+ data.
:encoding:
The encoding with which to treat the incoming data.
"""
@@ -113,14 +113,15 @@ class MultiPartParser(object):
if self._content_length == 0:
return QueryDict('', encoding=self._encoding), MultiValueDict()
- # See if the handler will want to take care of the parsing.
- # This allows overriding everything if somebody wants it.
+ # See if any of the handlers take care of the parsing.
+ # This allows overriding everything if need be.
for handler in handlers:
result = handler.handle_raw_input(self._input_data,
self._meta,
self._content_length,
self._boundary,
encoding)
+ #Check to see if it was handled
if result is not None:
return result[0], result[1]
@@ -369,7 +370,7 @@ class LazyStream(six.Iterator):
if current_number == num_bytes])
if number_equal > 40:
- raise SuspiciousOperation(
+ raise SuspiciousMultipartForm(
"The multipart parser got stuck, which shouldn't happen with"
" normal uploaded files. Check for malicious upload activity;"
" if there is none, report this to the Django developers."
diff --git a/django/http/request.py b/django/http/request.py
index 749b9f2561..37aa1a355a 100644
--- a/django/http/request.py
+++ b/django/http/request.py
@@ -14,7 +14,7 @@ except ImportError:
from django.conf import settings
from django.core import signing
-from django.core.exceptions import SuspiciousOperation, ImproperlyConfigured
+from django.core.exceptions import DisallowedHost, ImproperlyConfigured
from django.core.files import uploadhandler
from django.http.multipartparser import MultiPartParser
from django.utils import six
@@ -72,7 +72,7 @@ class HttpRequest(object):
msg = "Invalid HTTP_HOST header: %r." % host
if domain:
msg += "You may need to add %r to ALLOWED_HOSTS." % domain
- raise SuspiciousOperation(msg)
+ raise DisallowedHost(msg)
def get_full_path(self):
# RFC 3986 requires query string arguments to be in the ASCII range.
@@ -238,11 +238,17 @@ class HttpRequest(object):
def read(self, *args, **kwargs):
self._read_started = True
- return self._stream.read(*args, **kwargs)
+ try:
+ return self._stream.read(*args, **kwargs)
+ except IOError as e:
+ six.reraise(UnreadablePostError, UnreadablePostError(*e.args), sys.exc_info()[2])
def readline(self, *args, **kwargs):
self._read_started = True
- return self._stream.readline(*args, **kwargs)
+ try:
+ return self._stream.readline(*args, **kwargs)
+ except IOError as e:
+ six.reraise(UnreadablePostError, UnreadablePostError(*e.args), sys.exc_info()[2])
def xreadlines(self):
while True:
diff --git a/django/http/response.py b/django/http/response.py
index 88ac8848c2..9aa49b1d5f 100644
--- a/django/http/response.py
+++ b/django/http/response.py
@@ -12,7 +12,7 @@ except ImportError:
from django.conf import settings
from django.core import signals
from django.core import signing
-from django.core.exceptions import SuspiciousOperation
+from django.core.exceptions import DisallowedRedirect
from django.http.cookie import SimpleCookie
from django.utils import six, timezone
from django.utils.encoding import force_bytes, iri_to_uri
@@ -20,6 +20,65 @@ from django.utils.http import cookie_date
from django.utils.six.moves import map
+# See http://www.iana.org/assignments/http-status-codes
+REASON_PHRASES = {
+ 100: 'CONTINUE',
+ 101: 'SWITCHING PROTOCOLS',
+ 102: 'PROCESSING',
+ 200: 'OK',
+ 201: 'CREATED',
+ 202: 'ACCEPTED',
+ 203: 'NON-AUTHORITATIVE INFORMATION',
+ 204: 'NO CONTENT',
+ 205: 'RESET CONTENT',
+ 206: 'PARTIAL CONTENT',
+ 207: 'MULTI-STATUS',
+ 208: 'ALREADY REPORTED',
+ 226: 'IM USED',
+ 300: 'MULTIPLE CHOICES',
+ 301: 'MOVED PERMANENTLY',
+ 302: 'FOUND',
+ 303: 'SEE OTHER',
+ 304: 'NOT MODIFIED',
+ 305: 'USE PROXY',
+ 306: 'RESERVED',
+ 307: 'TEMPORARY REDIRECT',
+ 400: 'BAD REQUEST',
+ 401: 'UNAUTHORIZED',
+ 402: 'PAYMENT REQUIRED',
+ 403: 'FORBIDDEN',
+ 404: 'NOT FOUND',
+ 405: 'METHOD NOT ALLOWED',
+ 406: 'NOT ACCEPTABLE',
+ 407: 'PROXY AUTHENTICATION REQUIRED',
+ 408: 'REQUEST TIMEOUT',
+ 409: 'CONFLICT',
+ 410: 'GONE',
+ 411: 'LENGTH REQUIRED',
+ 412: 'PRECONDITION FAILED',
+ 413: 'REQUEST ENTITY TOO LARGE',
+ 414: 'REQUEST-URI TOO LONG',
+ 415: 'UNSUPPORTED MEDIA TYPE',
+ 416: 'REQUESTED RANGE NOT SATISFIABLE',
+ 417: 'EXPECTATION FAILED',
+ 418: "I'M A TEAPOT",
+ 422: 'UNPROCESSABLE ENTITY',
+ 423: 'LOCKED',
+ 424: 'FAILED DEPENDENCY',
+ 426: 'UPGRADE REQUIRED',
+ 500: 'INTERNAL SERVER ERROR',
+ 501: 'NOT IMPLEMENTED',
+ 502: 'BAD GATEWAY',
+ 503: 'SERVICE UNAVAILABLE',
+ 504: 'GATEWAY TIMEOUT',
+ 505: 'HTTP VERSION NOT SUPPORTED',
+ 506: 'VARIANT ALSO NEGOTIATES',
+ 507: 'INSUFFICIENT STORAGE',
+ 508: 'LOOP DETECTED',
+ 510: 'NOT EXTENDED',
+}
+
+
class BadHeaderError(ValueError):
pass
@@ -33,8 +92,9 @@ class HttpResponseBase(six.Iterator):
"""
status_code = 200
+ reason_phrase = None # Use default reason phrase for status code.
- def __init__(self, content_type=None, status=None, mimetype=None):
+ def __init__(self, content_type=None, status=None, reason=None, mimetype=None):
# _headers is a mapping of the lower-case name to the original case of
# the header (required for working with legacy systems) and the header
# value. Both the name of the header and its value are ASCII strings.
@@ -53,9 +113,13 @@ class HttpResponseBase(six.Iterator):
content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE,
self._charset)
self.cookies = SimpleCookie()
- if status:
+ if status is not None:
self.status_code = status
-
+ if reason is not None:
+ self.reason_phrase = reason
+ elif self.reason_phrase is None:
+ self.reason_phrase = REASON_PHRASES.get(self.status_code,
+ 'UNKNOWN STATUS CODE')
self['Content-Type'] = content_type
def serialize_headers(self):
@@ -388,7 +452,7 @@ class HttpResponseRedirectBase(HttpResponse):
def __init__(self, redirect_to, *args, **kwargs):
parsed = urlparse(redirect_to)
if parsed.scheme and parsed.scheme not in self.allowed_schemes:
- raise SuspiciousOperation("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)
+ raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme)
super(HttpResponseRedirectBase, self).__init__(*args, **kwargs)
self['Location'] = iri_to_uri(redirect_to)
diff --git a/django/http/utils.py b/django/http/utils.py
index fcb3fecb6c..e13dc4cbb6 100644
--- a/django/http/utils.py
+++ b/django/http/utils.py
@@ -31,13 +31,13 @@ def conditional_content_removal(request, response):
if response.streaming:
response.streaming_content = []
else:
- response.content = ''
+ response.content = b''
response['Content-Length'] = '0'
if request.method == 'HEAD':
if response.streaming:
response.streaming_content = []
else:
- response.content = ''
+ response.content = b''
return response