78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
# 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 <http://www.gnu.org/licenses/>.
|
|
|
|
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:
|
|
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())
|