httpzlib.py 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. #!/usr/bin/env python
  2. # Copyright 2011 Google Inc. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. """Apply gzip/deflate to separate chunks of data."""
  16. import struct
  17. import zlib
  18. GZIP_HEADER = (
  19. '\037\213' # magic header
  20. '\010' # compression method
  21. '\000' # flags (none)
  22. '\000\000\000\000' # packed time (use zero)
  23. '\002'
  24. '\377')
  25. def compress_chunks(uncompressed_chunks, use_gzip):
  26. """Compress a list of data with gzip or deflate.
  27. The returned chunks may be used with HTTP chunked encoding.
  28. Args:
  29. uncompressed_chunks: a list of strings
  30. (e.g. ["this is the first chunk", "and the second"])
  31. use_gzip: if True, compress with gzip. Otherwise, use deflate.
  32. Returns:
  33. [compressed_chunk_1, compressed_chunk_2, ...]
  34. """
  35. if use_gzip:
  36. size = 0
  37. crc = zlib.crc32("") & 0xffffffffL
  38. compressor = zlib.compressobj(
  39. 6, zlib.DEFLATED, -zlib.MAX_WBITS, zlib.DEF_MEM_LEVEL, 0)
  40. else:
  41. compressor = zlib.compressobj()
  42. compressed_chunks = []
  43. last_index = len(uncompressed_chunks) - 1
  44. for index, data in enumerate(uncompressed_chunks):
  45. chunk = ''
  46. if use_gzip:
  47. size += len(data)
  48. crc = zlib.crc32(data, crc) & 0xffffffffL
  49. if index == 0:
  50. chunk += GZIP_HEADER
  51. chunk += compressor.compress(data)
  52. if index < last_index:
  53. chunk += compressor.flush(zlib.Z_SYNC_FLUSH)
  54. else:
  55. chunk += (compressor.flush(zlib.Z_FULL_FLUSH) +
  56. compressor.flush())
  57. if use_gzip:
  58. chunk += (struct.pack("<L", long(crc)) +
  59. struct.pack("<L", long(size)))
  60. compressed_chunks.append(chunk)
  61. return compressed_chunks
  62. def uncompress_chunks(compressed_chunks, use_gzip):
  63. """Uncompress a list of data compressed with gzip or deflate.
  64. Args:
  65. compressed_chunks: a list of compressed data
  66. use_gzip: if True, uncompress with gzip. Otherwise, use deflate.
  67. Returns:
  68. [uncompressed_chunk_1, uncompressed_chunk_2, ...]
  69. """
  70. if use_gzip:
  71. decompress = zlib.decompressobj(16 + zlib.MAX_WBITS).decompress
  72. else:
  73. decompress = zlib.decompressobj(-zlib.MAX_WBITS).decompress
  74. return [decompress(c) for c in compressed_chunks]