~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/web2/filter/gzip.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
from __future__ import generators
 
2
import struct
 
3
import zlib
 
4
from twisted.web2 import stream
 
5
 
 
6
# TODO: ungzip (can any browsers actually generate gzipped
 
7
# upload data?) But it's necessary for client anyways.
 
8
 
 
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'
 
13
    # timestamp
 
14
    header += struct.pack('<L', 0)
 
15
    # uh.. stuff
 
16
    header += '\002\377'
 
17
    yield header
 
18
    
 
19
    compress = zlib.compressobj(compressLevel, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0)
 
20
    _compress = compress.compress
 
21
    _crc32 = zlib.crc32
 
22
    
 
23
    yield input.wait
 
24
    for buf in input:
 
25
        if len(buf) != 0:
 
26
            crc = _crc32(buf, crc)
 
27
            size += len(buf)
 
28
            yield _compress(buf)
 
29
        yield input.wait
 
30
    
 
31
    yield compress.flush()
 
32
    yield struct.pack('<LL', crc & 0xFFFFFFFFL, size & 0xFFFFFFFFL)
 
33
gzipStream=stream.generatorToStream(gzipStream)
 
34
 
 
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
 
42
    yield input.wait
 
43
    for buf in input:
 
44
        if len(buf) != 0:
 
45
            yield _compress(buf)
 
46
        yield input.wait
 
47
 
 
48
    yield compress.flush()
 
49
deflateStream=stream.generatorToStream(deflateStream)
 
50
 
 
51
def gzipfilter(request, response):
 
52
    if response.stream is None or response.headers.getHeader('content-encoding'):
 
53
        # Empty stream, or already compressed.
 
54
        return response
 
55
    
 
56
    # FIXME: make this a more flexible matching scheme
 
57
    mimetype = response.headers.getHeader('content-type')
 
58
    if not mimetype or mimetype.mediaType != 'text':
 
59
        return response
 
60
    
 
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'])
 
66
    
 
67
    ae = request.headers.getHeader('accept-encoding', {})
 
68
    compressor = None
 
69
    # Always prefer gzip over deflate no matter what their q-values are.
 
70
    if ae.get('gzip', 0):
 
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'])
 
76
    
 
77
    return response
 
78
 
 
79
__all__ = ['gzipfilter']