Created
January 16, 2014 20:41
-
-
Save onionhammer/8463022 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Imports | |
import zlib | |
import sockets, jester | |
# Types | |
type TCompressStream* = ref object of TObject | |
client: TSocket | |
when defined(usegzip): | |
stream: TZStream | |
buffer: string | |
len*: int | |
checksum: int | |
# Fields | |
const CHUNK = 16 * 1024 # 16 Kilobytes | |
const MAX = 4294967296 | |
const LEVEL = 1 # Z_DEFAULT_COMPRESSION | |
# Build gzip header | |
var gzipHeader = newString(10) | |
gzipHeader[0] = char(0x1f) | |
gzipHeader[1] = char(0x8b) | |
gzipHeader[2] = char(8) | |
gzipHeader[8] = char(4) | |
# Normal behavior | |
template send(stream: TCompressStream, value: string): expr = | |
stream.client.send(value) | |
template send(stream: TCompressStream, value: pointer, size: int): expr = | |
stream.client.send(value, size) | |
# Utilities | |
template put(into: var string, value: int, at = 0) = | |
into[at] = char((value shr 24) and 0xff) | |
into[at + 1] = char((value shr 16) and 0xff) | |
into[at + 2] = char((value shr 8) and 0xff) | |
into[at + 3] = char(value and 0xff) | |
template test(condition) = | |
if condition: continue | |
break | |
proc minifier*(client: TSocket): TCompressStream = | |
## Create a minifier stream object, removing | |
## whitespace, compressing with GZIP and writing | |
## the output to the http response stream | |
result = TCompressStream(client: client) | |
when defined(usegzip): | |
result.stream = TZStream(zalloc: nil, zfree: nil, opaque: nil) | |
result.buffer = newString(CHUNK) | |
# Initialize GZIP stream | |
let ret = zlib.deflateInit(result.stream, LEVEL) | |
assert ret == Z_OK, "Failed to initialize TZStream" | |
# Write GZIP header to response stream | |
client.send(gzipHeader) | |
template do_deflate(flush: expr) = | |
var ret: int | |
var have: zlib.uint | |
while true: | |
writer.stream.avail_out = CHUNK | |
writer.stream.next_out = writer.buffer | |
ret = zlib.deflate(writer.stream, flush) | |
have = CHUNK - writer.stream.avail_out | |
assert ret != Z_STREAM_ERROR | |
# Ensure first 2 bytes are skipped & last 5 bytes are skipped | |
var src_index = | |
if writer.len == 0: 2 | |
else: 0 | |
var dest_index = | |
if ret == Z_STREAM_END: have - 4 | |
else: have - zlib.uint(src_index) | |
# Write to destination | |
discard writer.send(addr writer.buffer[src_index], dest_index) | |
# Until all bytes have been processed | |
test writer.stream.avail_out == 0 | |
assert writer.stream.avail_in == 0, "All input must be used" | |
when flush == Z_FINISH: | |
assert ret == Z_STREAM_END | |
proc close*(writer: TCompressStream) = | |
## Flush stream & write GZIP footer | |
do_deflate(Z_FINISH) | |
# Write GZIP footer | |
var footer = newString(8) | |
footer.put(writer.checksum) | |
footer.put(writer.len mod MAX, 4) | |
writer.send(footer) | |
# Cleanup | |
discard zlib.deflateEnd(writer.stream) | |
proc `&=`*(writer: TCompressStream, value: string) = | |
## Put string into minifier | |
when defined(usegzip): | |
# Compress value & send to underlying response | |
writer.stream.avail_in = zlib.uint(value.len) | |
writer.stream.next_in = value | |
# Update source length & checksum | |
var to_write = writer.stream.avail_in | |
writer.checksum = zlib.crc32(writer.checksum, writer.buffer, to_write) | |
# Write to stream | |
do_deflate(Z_NO_FLUSH) | |
# Increment amount written | |
inc(writer.len, to_write) | |
else: | |
writer.send(value.minify) | |
template add*(writer, value) = | |
## Put string into minifier | |
writer &= value |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment