diff options
author | ttt | 2017-05-13 00:29:47 +0530 |
---|---|---|
committer | ttt | 2017-05-13 00:29:47 +0530 |
commit | abf599be33b383a6a5baf9493093b2126a622ac8 (patch) | |
tree | 4c5ab6e0d935d5e65fabcf0258e4a00dd20a5afa /lib/python2.7/site-packages/django/contrib/messages/storage | |
download | SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.tar.gz SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.tar.bz2 SBHS-2018-Rpi-abf599be33b383a6a5baf9493093b2126a622ac8.zip |
added all server files
Diffstat (limited to 'lib/python2.7/site-packages/django/contrib/messages/storage')
5 files changed, 450 insertions, 0 deletions
diff --git a/lib/python2.7/site-packages/django/contrib/messages/storage/__init__.py b/lib/python2.7/site-packages/django/contrib/messages/storage/__init__.py new file mode 100644 index 0000000..9a09aff --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/messages/storage/__init__.py @@ -0,0 +1,8 @@ +from django.conf import settings +from django.utils.module_loading import import_by_path as get_storage + + +# Callable with the same interface as the storage classes i.e. accepts a +# 'request' object. It is wrapped in a lambda to stop 'settings' being used at +# the module level +default_storage = lambda request: get_storage(settings.MESSAGE_STORAGE)(request) diff --git a/lib/python2.7/site-packages/django/contrib/messages/storage/base.py b/lib/python2.7/site-packages/django/contrib/messages/storage/base.py new file mode 100644 index 0000000..7fe8a07 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/messages/storage/base.py @@ -0,0 +1,184 @@ +from __future__ import unicode_literals + +from django.conf import settings +from django.utils.encoding import force_text, python_2_unicode_compatible +from django.contrib.messages import constants, utils + + +LEVEL_TAGS = utils.get_level_tags() + + +@python_2_unicode_compatible +class Message(object): + """ + Represents an actual message that can be stored in any of the supported + storage classes (typically session- or cookie-based) and rendered in a view + or template. + """ + + def __init__(self, level, message, extra_tags=None): + self.level = int(level) + self.message = message + self.extra_tags = extra_tags + + def _prepare(self): + """ + Prepares the message for serialization by forcing the ``message`` + and ``extra_tags`` to unicode in case they are lazy translations. + + Known "safe" types (None, int, etc.) are not converted (see Django's + ``force_text`` implementation for details). + """ + self.message = force_text(self.message, strings_only=True) + self.extra_tags = force_text(self.extra_tags, strings_only=True) + + def __eq__(self, other): + return isinstance(other, Message) and self.level == other.level and \ + self.message == other.message + + def __str__(self): + return force_text(self.message) + + def _get_tags(self): + label_tag = force_text(LEVEL_TAGS.get(self.level, ''), + strings_only=True) + extra_tags = force_text(self.extra_tags, strings_only=True) + if extra_tags and label_tag: + return ' '.join([extra_tags, label_tag]) + elif extra_tags: + return extra_tags + elif label_tag: + return label_tag + return '' + tags = property(_get_tags) + + +class BaseStorage(object): + """ + This is the base backend for temporary message storage. + + This is not a complete class; to be a usable storage backend, it must be + subclassed and the two methods ``_get`` and ``_store`` overridden. + """ + + def __init__(self, request, *args, **kwargs): + self.request = request + self._queued_messages = [] + self.used = False + self.added_new = False + super(BaseStorage, self).__init__(*args, **kwargs) + + def __len__(self): + return len(self._loaded_messages) + len(self._queued_messages) + + def __iter__(self): + self.used = True + if self._queued_messages: + self._loaded_messages.extend(self._queued_messages) + self._queued_messages = [] + return iter(self._loaded_messages) + + def __contains__(self, item): + return item in self._loaded_messages or item in self._queued_messages + + @property + def _loaded_messages(self): + """ + Returns a list of loaded messages, retrieving them first if they have + not been loaded yet. + """ + if not hasattr(self, '_loaded_data'): + messages, all_retrieved = self._get() + self._loaded_data = messages or [] + return self._loaded_data + + def _get(self, *args, **kwargs): + """ + Retrieves a list of stored messages. Returns a tuple of the messages + and a flag indicating whether or not all the messages originally + intended to be stored in this storage were, in fact, stored and + retrieved; e.g., ``(messages, all_retrieved)``. + + **This method must be implemented by a subclass.** + + If it is possible to tell if the backend was not used (as opposed to + just containing no messages) then ``None`` should be returned in + place of ``messages``. + """ + raise NotImplementedError() + + def _store(self, messages, response, *args, **kwargs): + """ + Stores a list of messages, returning a list of any messages which could + not be stored. + + One type of object must be able to be stored, ``Message``. + + **This method must be implemented by a subclass.** + """ + raise NotImplementedError() + + def _prepare_messages(self, messages): + """ + Prepares a list of messages for storage. + """ + for message in messages: + message._prepare() + + def update(self, response): + """ + Stores all unread messages. + + If the backend has yet to be iterated, previously stored messages will + be stored again. Otherwise, only messages added after the last + iteration will be stored. + """ + self._prepare_messages(self._queued_messages) + if self.used: + return self._store(self._queued_messages, response) + elif self.added_new: + messages = self._loaded_messages + self._queued_messages + return self._store(messages, response) + + def add(self, level, message, extra_tags=''): + """ + Queues a message to be stored. + + The message is only queued if it contained something and its level is + not less than the recording level (``self.level``). + """ + if not message: + return + # Check that the message level is not less than the recording level. + level = int(level) + if level < self.level: + return + # Add the message. + self.added_new = True + message = Message(level, message, extra_tags=extra_tags) + self._queued_messages.append(message) + + def _get_level(self): + """ + Returns the minimum recorded level. + + The default level is the ``MESSAGE_LEVEL`` setting. If this is + not found, the ``INFO`` level is used. + """ + if not hasattr(self, '_level'): + self._level = getattr(settings, 'MESSAGE_LEVEL', constants.INFO) + return self._level + + def _set_level(self, value=None): + """ + Sets a custom minimum recorded level. + + If set to ``None``, the default level will be used (see the + ``_get_level`` method). + """ + if value is None and hasattr(self, '_level'): + del self._level + else: + self._level = int(value) + + level = property(_get_level, _set_level, _set_level) diff --git a/lib/python2.7/site-packages/django/contrib/messages/storage/cookie.py b/lib/python2.7/site-packages/django/contrib/messages/storage/cookie.py new file mode 100644 index 0000000..619c692 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/messages/storage/cookie.py @@ -0,0 +1,158 @@ +import json + +from django.conf import settings +from django.contrib.messages.storage.base import BaseStorage, Message +from django.http import SimpleCookie +from django.utils.crypto import salted_hmac, constant_time_compare +from django.utils.safestring import SafeData, mark_safe +from django.utils import six + + +class MessageEncoder(json.JSONEncoder): + """ + Compactly serializes instances of the ``Message`` class as JSON. + """ + message_key = '__json_message' + + def default(self, obj): + if isinstance(obj, Message): + # Using 0/1 here instead of False/True to produce more compact json + is_safedata = 1 if isinstance(obj.message, SafeData) else 0 + message = [self.message_key, is_safedata, obj.level, obj.message] + if obj.extra_tags: + message.append(obj.extra_tags) + return message + return super(MessageEncoder, self).default(obj) + + +class MessageDecoder(json.JSONDecoder): + """ + Decodes JSON that includes serialized ``Message`` instances. + """ + + def process_messages(self, obj): + if isinstance(obj, list) and obj: + if obj[0] == MessageEncoder.message_key: + if obj[1]: + obj[3] = mark_safe(obj[3]) + return Message(*obj[2:]) + return [self.process_messages(item) for item in obj] + if isinstance(obj, dict): + return dict([(key, self.process_messages(value)) + for key, value in six.iteritems(obj)]) + return obj + + def decode(self, s, **kwargs): + decoded = super(MessageDecoder, self).decode(s, **kwargs) + return self.process_messages(decoded) + +class CookieStorage(BaseStorage): + """ + Stores messages in a cookie. + """ + cookie_name = 'messages' + # uwsgi's default configuration enforces a maximum size of 4kb for all the + # HTTP headers. In order to leave some room for other cookies and headers, + # restrict the session cookie to 1/2 of 4kb. See #18781. + max_cookie_size = 2048 + not_finished = '__messagesnotfinished__' + + def _get(self, *args, **kwargs): + """ + Retrieves a list of messages from the messages cookie. If the + not_finished sentinel value is found at the end of the message list, + remove it and return a result indicating that not all messages were + retrieved by this storage. + """ + data = self.request.COOKIES.get(self.cookie_name) + messages = self._decode(data) + all_retrieved = not (messages and messages[-1] == self.not_finished) + if messages and not all_retrieved: + # remove the sentinel value + messages.pop() + return messages, all_retrieved + + def _update_cookie(self, encoded_data, response): + """ + Either sets the cookie with the encoded data if there is any data to + store, or deletes the cookie. + """ + if encoded_data: + response.set_cookie(self.cookie_name, encoded_data, + domain=settings.SESSION_COOKIE_DOMAIN) + else: + response.delete_cookie(self.cookie_name, + domain=settings.SESSION_COOKIE_DOMAIN) + + def _store(self, messages, response, remove_oldest=True, *args, **kwargs): + """ + Stores the messages to a cookie, returning a list of any messages which + could not be stored. + + If the encoded data is larger than ``max_cookie_size``, removes + messages until the data fits (these are the messages which are + returned), and add the not_finished sentinel value to indicate as much. + """ + unstored_messages = [] + encoded_data = self._encode(messages) + if self.max_cookie_size: + # data is going to be stored eventually by SimpleCookie, which + # adds it's own overhead, which we must account for. + cookie = SimpleCookie() # create outside the loop + def stored_length(val): + return len(cookie.value_encode(val)[1]) + + while encoded_data and stored_length(encoded_data) > self.max_cookie_size: + if remove_oldest: + unstored_messages.append(messages.pop(0)) + else: + unstored_messages.insert(0, messages.pop()) + encoded_data = self._encode(messages + [self.not_finished], + encode_empty=unstored_messages) + self._update_cookie(encoded_data, response) + return unstored_messages + + def _hash(self, value): + """ + Creates an HMAC/SHA1 hash based on the value and the project setting's + SECRET_KEY, modified to make it unique for the present purpose. + """ + key_salt = 'django.contrib.messages' + return salted_hmac(key_salt, value).hexdigest() + + def _encode(self, messages, encode_empty=False): + """ + Returns an encoded version of the messages list which can be stored as + plain text. + + Since the data will be retrieved from the client-side, the encoded data + also contains a hash to ensure that the data was not tampered with. + """ + if messages or encode_empty: + encoder = MessageEncoder(separators=(',', ':')) + value = encoder.encode(messages) + return '%s$%s' % (self._hash(value), value) + + def _decode(self, data): + """ + Safely decodes a encoded text stream back into a list of messages. + + If the encoded text stream contained an invalid hash or was in an + invalid format, ``None`` is returned. + """ + if not data: + return None + bits = data.split('$', 1) + if len(bits) == 2: + hash, value = bits + if constant_time_compare(hash, self._hash(value)): + try: + # If we get here (and the JSON decode works), everything is + # good. In any other case, drop back and return None. + return json.loads(value, cls=MessageDecoder) + except ValueError: + pass + # Mark the data as used (so it gets removed) since something was wrong + # with the data. + self.used = True + return None diff --git a/lib/python2.7/site-packages/django/contrib/messages/storage/fallback.py b/lib/python2.7/site-packages/django/contrib/messages/storage/fallback.py new file mode 100644 index 0000000..6c35343 --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/messages/storage/fallback.py @@ -0,0 +1,54 @@ +from django.contrib.messages.storage.base import BaseStorage +from django.contrib.messages.storage.cookie import CookieStorage +from django.contrib.messages.storage.session import SessionStorage + +class FallbackStorage(BaseStorage): + """ + Tries to store all messages in the first backend, storing any unstored + messages in each subsequent backend backend. + """ + storage_classes = (CookieStorage, SessionStorage) + + def __init__(self, *args, **kwargs): + super(FallbackStorage, self).__init__(*args, **kwargs) + self.storages = [storage_class(*args, **kwargs) + for storage_class in self.storage_classes] + self._used_storages = set() + + def _get(self, *args, **kwargs): + """ + Gets a single list of messages from all storage backends. + """ + all_messages = [] + for storage in self.storages: + messages, all_retrieved = storage._get() + # If the backend hasn't been used, no more retrieval is necessary. + if messages is None: + break + if messages: + self._used_storages.add(storage) + all_messages.extend(messages) + # If this storage class contained all the messages, no further + # retrieval is necessary + if all_retrieved: + break + return all_messages, all_retrieved + + def _store(self, messages, response, *args, **kwargs): + """ + Stores the messages, returning any unstored messages after trying all + backends. + + For each storage backend, any messages not stored are passed on to the + next backend. + """ + for storage in self.storages: + if messages: + messages = storage._store(messages, response, + remove_oldest=False) + # Even if there are no more messages, continue iterating to ensure + # storages which contained messages are flushed. + elif storage in self._used_storages: + storage._store([], response) + self._used_storages.remove(storage) + return messages diff --git a/lib/python2.7/site-packages/django/contrib/messages/storage/session.py b/lib/python2.7/site-packages/django/contrib/messages/storage/session.py new file mode 100644 index 0000000..c3e293c --- /dev/null +++ b/lib/python2.7/site-packages/django/contrib/messages/storage/session.py @@ -0,0 +1,46 @@ +import json + +from django.contrib.messages.storage.base import BaseStorage +from django.contrib.messages.storage.cookie import MessageEncoder, MessageDecoder +from django.utils import six + + +class SessionStorage(BaseStorage): + """ + Stores messages in the session (that is, django.contrib.sessions). + """ + session_key = '_messages' + + def __init__(self, request, *args, **kwargs): + assert hasattr(request, 'session'), "The session-based temporary "\ + "message storage requires session middleware to be installed, "\ + "and come before the message middleware in the "\ + "MIDDLEWARE_CLASSES list." + super(SessionStorage, self).__init__(request, *args, **kwargs) + + def _get(self, *args, **kwargs): + """ + Retrieves a list of messages from the request's session. This storage + always stores everything it is given, so return True for the + all_retrieved flag. + """ + return self.deserialize_messages(self.request.session.get(self.session_key)), True + + def _store(self, messages, response, *args, **kwargs): + """ + Stores a list of messages to the request's session. + """ + if messages: + self.request.session[self.session_key] = self.serialize_messages(messages) + else: + self.request.session.pop(self.session_key, None) + return [] + + def serialize_messages(self, messages): + encoder = MessageEncoder(separators=(',', ':')) + return encoder.encode(messages) + + def deserialize_messages(self, data): + if data and isinstance(data, six.string_types): + return json.loads(data, cls=MessageDecoder) + return data |