ETag and gzip decorators for Bottle.py

Post date: Mar 2, 2015 3:32:16 PM

from functools import wraps
from gzip import compress
 
def gzipped():
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwds):
            rsp_data = func(*args, **kwds)
            if 'gzip' in request.headers.get('Accept-Encoding', ''):
                response.headers['Content-Encoding'] = 'gzip'
                rsp_data = compress(rsp_data.encode('utf-8'))
            return rsp_data
        return wrapper
    return decorator
 
from base64 import b64encode
 
def etagged():
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwds):
            rsp_data = func(*args, **kwds)
            etag = '"%s"' % b64encode(
                (hash(rsp_data.encode('utf-8')) + 2**63)
                .to_bytes(8, byteorder='big')).decode()[:11]
            if etag == request.headers.get('If-None-Match', '').lstrip('W/'):
                response.status = 304
                return ''
            response.headers['ETag'] = etag
            return rsp_data
        return wrapper
    return decorator

I'm very aware that this etag handing won't make it lighter for the server. But it makes getting response still faster especially for mobile clients.

If you have easy way of validating for ETag content before actually generating the content on server, just move ETag content check stuff above the rsp_data = decorated function line. So the call to the decorated function will be completely avoided if you return results from that stage. Both of these options are designed to be only used with fully dynamic content. Both work well with templates and stuff.

It's recommended to use max-age=0 instead of no-cache for stuff which should be cached, but still could get quickly invalidated. ETags help with that.

I know, if you're using bottle.py with uWSGI or Nginx you can use internal gzip.

kw: uwsgi, bottle.py, python, programming, webdevelopment, websites, webdeveloper, http, header, headers, content compression, deflate, last modified.