# Petale - Simple App as Key/Value Storage Interface # Copyright (C) 2017 Entr'ouvert # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU Affero General Public License as published # by the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . import hashlib import logging from functools import wraps DEFAULT_HASH_ALGO = 'sha1' def logit(func): @wraps(func) def wrapper(self, request, *args, **kwargs): logger = logging.getLogger('petale') req_url = '%s %s %s' % (request.method, request.path, request.GET.urlencode()) logger.info(req_url, extra={'request_url': req_url}) req_headers = ''.join( ['%s: %s | ' % (k, v) for k, v in request.META.items() if k.isupper()]) logger.debug('Request Headers: %s', req_headers, extra={'request_headers': req_headers}) response = func(self, request, *args, **kwargs) resp_headers = ''.join(['%s: %s | ' % (k, v) for k, v in response.items()]) logger.debug('Response Headers: %s', resp_headers, extra={'response_headers': resp_headers}) if hasattr(response, 'data'): logger.debug('Response Data: %r', response.data, extra={'response_body': response.data}) logger.debug('Response Status Code: %s', response.status_code, extra={'response_status_code': response.status_code}) return response return wrapper def etag(stream): # f must be a Django file object digest = hashlib.new(DEFAULT_HASH_ALGO) if hasattr(stream, 'chunks'): for chunk in stream.chunks(): digest.update(chunk) elif hasattr(stream, 'isdecimal'): digest.update(stream.encode('utf-8')) else: digest.update(stream) return '"%s:%s"' % (DEFAULT_HASH_ALGO, digest.hexdigest()) class StreamingHash(object): def __init__(self, readable, hash_algo=DEFAULT_HASH_ALGO): self.readable = readable self.hash_algo = hash_algo self.digest = hashlib.new(hash_algo) self.size = 0 def read(self, n=-1): # pylint: disable=C0103 buf = self.readable.read(n) self.size += len(buf) self.digest.update(buf) return buf def hexdigest(self): return self.digest.hexdigest() def etag(self): return '"%s:%s"' % (self.hash_algo, self.hexdigest())