1
from __future__ import generators
4
from twisted.web2 import stream
6
# TODO: ungzip (can any browsers actually generate gzipped
7
# upload data?) But it's necessary for client anyways.
9
def gzipStream(input, compressLevel=6):
10
crc, size = zlib.crc32(''), 0
11
# magic header, compression method, no flags
12
header = '\037\213\010\000'
14
header += struct.pack('<L', 0)
19
compress = zlib.compressobj(compressLevel, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0)
20
_compress = compress.compress
26
crc = _crc32(buf, crc)
31
yield compress.flush()
32
yield struct.pack('<LL', crc & 0xFFFFFFFFL, size & 0xFFFFFFFFL)
33
gzipStream=stream.generatorToStream(gzipStream)
35
def deflateStream(input, compressLevel=6):
36
# NOTE: this produces RFC-conformant but some-browser-incompatible output.
37
# The RFC says that you're supposed to output zlib-format data, but many
38
# browsers expect raw deflate output. Luckily all those browsers support
39
# gzip, also, so they won't even see deflate output.
40
compress = zlib.compressobj(compressLevel, zlib.DEFLATED, zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0)
41
_compress = compress.compress
48
yield compress.flush()
49
deflateStream=stream.generatorToStream(deflateStream)
51
def gzipfilter(request, response):
52
if response.stream is None or response.headers.getHeader('content-encoding'):
53
# Empty stream, or already compressed.
56
# FIXME: make this a more flexible matching scheme
57
mimetype = response.headers.getHeader('content-type')
58
if not mimetype or mimetype.mediaType != 'text':
61
# Make sure to note we're going to return different content depending on
62
# the accept-encoding header.
63
vary = response.headers.getHeader('vary', [])
64
if 'accept-encoding' not in vary:
65
response.headers.setHeader('vary', vary+['accept-encoding'])
67
ae = request.headers.getHeader('accept-encoding', {})
69
# Always prefer gzip over deflate no matter what their q-values are.
71
response.stream = gzipStream(response.stream)
72
response.headers.setHeader('content-encoding', ['gzip'])
73
elif ae.get('deflate', 0):
74
response.stream = deflateStream(response.stream)
75
response.headers.setHeader('content-encoding', ['deflate'])
79
__all__ = ['gzipfilter']