diff options
Diffstat (limited to 'lib/python2.7/site-packages/django/http/response.py')
-rw-r--r-- | lib/python2.7/site-packages/django/http/response.py | 518 |
1 files changed, 0 insertions, 518 deletions
diff --git a/lib/python2.7/site-packages/django/http/response.py b/lib/python2.7/site-packages/django/http/response.py deleted file mode 100644 index 60739ab..0000000 --- a/lib/python2.7/site-packages/django/http/response.py +++ /dev/null @@ -1,518 +0,0 @@ -from __future__ import absolute_import, unicode_literals - -import datetime -import time -import warnings -from email.header import Header - -from django.conf import settings -from django.core import signals -from django.core import signing -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, force_text, iri_to_uri -from django.utils.http import cookie_date -from django.utils.six.moves import map -from django.utils.six.moves.urllib.parse import urlparse - - -# 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', - 428: 'PRECONDITION REQUIRED', - 429: 'TOO MANY REQUESTS', - 431: 'REQUEST HEADER FIELDS TOO LARGE', - 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', - 511: 'NETWORK AUTHENTICATION REQUIRED', -} - - -class BadHeaderError(ValueError): - pass - - -class HttpResponseBase(six.Iterator): - """ - An HTTP response base class with dictionary-accessed headers. - - This class doesn't handle content. It should not be used directly. - Use the HttpResponse and StreamingHttpResponse subclasses instead. - """ - - status_code = 200 - reason_phrase = None # Use default reason phrase for status code. - - 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. - self._headers = {} - self._charset = settings.DEFAULT_CHARSET - self._closable_objects = [] - # This parameter is set by the handler. It's necessary to preserve the - # historical behavior of request_finished. - self._handler_class = None - if mimetype: - warnings.warn("Using mimetype keyword argument is deprecated, use" - " content_type instead", - DeprecationWarning, stacklevel=2) - content_type = mimetype - if not content_type: - content_type = "%s; charset=%s" % (settings.DEFAULT_CONTENT_TYPE, - self._charset) - self.cookies = SimpleCookie() - 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): - """HTTP headers as a bytestring.""" - def to_bytes(val, encoding): - return val if isinstance(val, bytes) else val.encode(encoding) - - headers = [ - (b': '.join([to_bytes(key, 'ascii'), to_bytes(value, 'latin-1')])) - for key, value in self._headers.values() - ] - return b'\r\n'.join(headers) - - if six.PY3: - __bytes__ = serialize_headers - else: - __str__ = serialize_headers - - def _convert_to_charset(self, value, charset, mime_encode=False): - """Converts headers key/value to ascii/latin-1 native strings. - - `charset` must be 'ascii' or 'latin-1'. If `mime_encode` is True and - `value` value can't be represented in the given charset, MIME-encoding - is applied. - """ - if not isinstance(value, (bytes, six.text_type)): - value = str(value) - try: - if six.PY3: - if isinstance(value, str): - # Ensure string is valid in given charset - value.encode(charset) - else: - # Convert bytestring using given charset - value = value.decode(charset) - else: - if isinstance(value, str): - # Ensure string is valid in given charset - value.decode(charset) - else: - # Convert unicode string to given charset - value = value.encode(charset) - except UnicodeError as e: - if mime_encode: - # Wrapping in str() is a workaround for #12422 under Python 2. - value = str(Header(value, 'utf-8').encode()) - else: - e.reason += ', HTTP response headers must be in %s format' % charset - raise - if str('\n') in value or str('\r') in value: - raise BadHeaderError("Header values can't contain newlines (got %r)" % value) - return value - - def __setitem__(self, header, value): - header = self._convert_to_charset(header, 'ascii') - value = self._convert_to_charset(value, 'latin-1', mime_encode=True) - self._headers[header.lower()] = (header, value) - - def __delitem__(self, header): - try: - del self._headers[header.lower()] - except KeyError: - pass - - def __getitem__(self, header): - return self._headers[header.lower()][1] - - def __getstate__(self): - # SimpleCookie is not pickeable with pickle.HIGHEST_PROTOCOL, so we - # serialise to a string instead - state = self.__dict__.copy() - state['cookies'] = str(state['cookies']) - return state - - def __setstate__(self, state): - self.__dict__.update(state) - self.cookies = SimpleCookie(self.cookies) - - def has_header(self, header): - """Case-insensitive check for a header.""" - return header.lower() in self._headers - - __contains__ = has_header - - def items(self): - return self._headers.values() - - def get(self, header, alternate=None): - return self._headers.get(header.lower(), (None, alternate))[1] - - def set_cookie(self, key, value='', max_age=None, expires=None, path='/', - domain=None, secure=False, httponly=False): - """ - Sets a cookie. - - ``expires`` can be: - - a string in the correct format, - - a naive ``datetime.datetime`` object in UTC, - - an aware ``datetime.datetime`` object in any time zone. - If it is a ``datetime.datetime`` object then ``max_age`` will be calculated. - - """ - self.cookies[key] = value - if expires is not None: - if isinstance(expires, datetime.datetime): - if timezone.is_aware(expires): - expires = timezone.make_naive(expires, timezone.utc) - delta = expires - expires.utcnow() - # Add one second so the date matches exactly (a fraction of - # time gets lost between converting to a timedelta and - # then the date string). - delta = delta + datetime.timedelta(seconds=1) - # Just set max_age - the max_age logic will set expires. - expires = None - max_age = max(0, delta.days * 86400 + delta.seconds) - else: - self.cookies[key]['expires'] = expires - if max_age is not None: - self.cookies[key]['max-age'] = max_age - # IE requires expires, so set it if hasn't been already. - if not expires: - self.cookies[key]['expires'] = cookie_date(time.time() + - max_age) - if path is not None: - self.cookies[key]['path'] = path - if domain is not None: - self.cookies[key]['domain'] = domain - if secure: - self.cookies[key]['secure'] = True - if httponly: - self.cookies[key]['httponly'] = True - - def set_signed_cookie(self, key, value, salt='', **kwargs): - value = signing.get_cookie_signer(salt=key + salt).sign(value) - return self.set_cookie(key, value, **kwargs) - - def delete_cookie(self, key, path='/', domain=None): - self.set_cookie(key, max_age=0, path=path, domain=domain, - expires='Thu, 01-Jan-1970 00:00:00 GMT') - - # Common methods used by subclasses - - def make_bytes(self, value): - """Turn a value into a bytestring encoded in the output charset.""" - # Per PEP 3333, this response body must be bytes. To avoid returning - # an instance of a subclass, this function returns `bytes(value)`. - # This doesn't make a copy when `value` already contains bytes. - - # If content is already encoded (eg. gzip), assume bytes. - if self.has_header('Content-Encoding'): - return bytes(value) - - # Handle string types -- we can't rely on force_bytes here because: - # - under Python 3 it attemps str conversion first - # - when self._charset != 'utf-8' it re-encodes the content - if isinstance(value, bytes): - return bytes(value) - if isinstance(value, six.text_type): - return bytes(value.encode(self._charset)) - - # Handle non-string types (#16494) - return force_bytes(value, self._charset) - - def __iter__(self): - return self - - def __next__(self): - # Subclasses must define self._iterator for this function. - return self.make_bytes(next(self._iterator)) - - # These methods partially implement the file-like object interface. - # See http://docs.python.org/lib/bltin-file-objects.html - - # The WSGI server must call this method upon completion of the request. - # See http://blog.dscpl.com.au/2012/10/obligations-for-calling-close-on.html - def close(self): - for closable in self._closable_objects: - try: - closable.close() - except Exception: - pass - signals.request_finished.send(sender=self._handler_class) - - def write(self, content): - raise Exception("This %s instance is not writable" % self.__class__.__name__) - - def flush(self): - pass - - def tell(self): - raise Exception("This %s instance cannot tell its position" % self.__class__.__name__) - - -class HttpResponse(HttpResponseBase): - """ - An HTTP response class with a string as content. - - This content that can be read, appended to or replaced. - """ - - streaming = False - - def __init__(self, content=b'', *args, **kwargs): - super(HttpResponse, self).__init__(*args, **kwargs) - # Content is a bytestring. See the `content` property methods. - self.content = content - - def serialize(self): - """Full HTTP message, including headers, as a bytestring.""" - return self.serialize_headers() + b'\r\n\r\n' + self.content - - if six.PY3: - __bytes__ = serialize - else: - __str__ = serialize - - def _consume_content(self): - # If the response was instantiated with an iterator, when its content - # is accessed, the iterator is going be exhausted and the content - # loaded in memory. At this point, it's better to abandon the original - # iterator and save the content for later reuse. This is a temporary - # solution. See the comment in __iter__ below for the long term plan. - if self._base_content_is_iter: - self.content = b''.join(self.make_bytes(e) for e in self._container) - - @property - def content(self): - self._consume_content() - return b''.join(self.make_bytes(e) for e in self._container) - - @content.setter - def content(self, value): - if hasattr(value, '__iter__') and not isinstance(value, (bytes, six.string_types)): - self._container = value - self._base_content_is_iter = True - if hasattr(value, 'close'): - self._closable_objects.append(value) - else: - self._container = [value] - self._base_content_is_iter = False - - def __iter__(self): - # Raise a deprecation warning only if the content wasn't consumed yet, - # because the response may be intended to be streamed. - # Once the deprecation completes, iterators should be consumed upon - # assignment rather than upon access. The _consume_content method - # should be removed. See #6527. - if self._base_content_is_iter: - warnings.warn( - 'Creating streaming responses with `HttpResponse` is ' - 'deprecated. Use `StreamingHttpResponse` instead ' - 'if you need the streaming behavior.', - DeprecationWarning, stacklevel=2) - if not hasattr(self, '_iterator'): - self._iterator = iter(self._container) - return self - - def write(self, content): - self._consume_content() - self._container.append(content) - - def tell(self): - self._consume_content() - return len(self.content) - - -class StreamingHttpResponse(HttpResponseBase): - """ - A streaming HTTP response class with an iterator as content. - - This should only be iterated once, when the response is streamed to the - client. However, it can be appended to or replaced with a new iterator - that wraps the original content (or yields entirely new content). - """ - - streaming = True - - def __init__(self, streaming_content=(), *args, **kwargs): - super(StreamingHttpResponse, self).__init__(*args, **kwargs) - # `streaming_content` should be an iterable of bytestrings. - # See the `streaming_content` property methods. - self.streaming_content = streaming_content - - @property - def content(self): - raise AttributeError("This %s instance has no `content` attribute. " - "Use `streaming_content` instead." % self.__class__.__name__) - - @property - def streaming_content(self): - return map(self.make_bytes, self._iterator) - - @streaming_content.setter - def streaming_content(self, value): - # Ensure we can never iterate on "value" more than once. - self._iterator = iter(value) - if hasattr(value, 'close'): - self._closable_objects.append(value) - - -class CompatibleStreamingHttpResponse(StreamingHttpResponse): - """ - This class maintains compatibility with middleware that doesn't know how - to handle the content of a streaming response by exposing a `content` - attribute that will consume and cache the content iterator when accessed. - - These responses will stream only if no middleware attempts to access the - `content` attribute. Otherwise, they will behave like a regular response, - and raise a `DeprecationWarning`. - """ - @property - def content(self): - warnings.warn( - 'Accessing the `content` attribute on a streaming response is ' - 'deprecated. Use the `streaming_content` attribute instead.', - DeprecationWarning, stacklevel=2) - content = b''.join(self) - self.streaming_content = [content] - return content - - @content.setter - def content(self, content): - warnings.warn( - 'Accessing the `content` attribute on a streaming response is ' - 'deprecated. Use the `streaming_content` attribute instead.', - DeprecationWarning, stacklevel=2) - self.streaming_content = [content] - - -class HttpResponseRedirectBase(HttpResponse): - allowed_schemes = ['http', 'https', 'ftp'] - - def __init__(self, redirect_to, *args, **kwargs): - parsed = urlparse(force_text(redirect_to)) - if parsed.scheme and parsed.scheme not in self.allowed_schemes: - raise DisallowedRedirect("Unsafe redirect to URL with protocol '%s'" % parsed.scheme) - super(HttpResponseRedirectBase, self).__init__(*args, **kwargs) - self['Location'] = iri_to_uri(redirect_to) - - url = property(lambda self: self['Location']) - - -class HttpResponseRedirect(HttpResponseRedirectBase): - status_code = 302 - - -class HttpResponsePermanentRedirect(HttpResponseRedirectBase): - status_code = 301 - - -class HttpResponseNotModified(HttpResponse): - status_code = 304 - - def __init__(self, *args, **kwargs): - super(HttpResponseNotModified, self).__init__(*args, **kwargs) - del self['content-type'] - - @HttpResponse.content.setter - def content(self, value): - if value: - raise AttributeError("You cannot set content to a 304 (Not Modified) response") - self._container = [] - self._base_content_is_iter = False - - -class HttpResponseBadRequest(HttpResponse): - status_code = 400 - - -class HttpResponseNotFound(HttpResponse): - status_code = 404 - - -class HttpResponseForbidden(HttpResponse): - status_code = 403 - - -class HttpResponseNotAllowed(HttpResponse): - status_code = 405 - - def __init__(self, permitted_methods, *args, **kwargs): - super(HttpResponseNotAllowed, self).__init__(*args, **kwargs) - self['Allow'] = ', '.join(permitted_methods) - - -class HttpResponseGone(HttpResponse): - status_code = 410 - - -class HttpResponseServerError(HttpResponse): - status_code = 500 - - -class Http404(Exception): - pass |