146 lines
3.9 KiB
Lua
146 lines
3.9 KiB
Lua
|
local zlib = require "zlib"
|
||
|
|
||
|
local function zlib_name(lib)
|
||
|
if lib._VERSION and string.find(lib._VERSION, 'lua-zlib', nil, true) then
|
||
|
return 'lua-zlib'
|
||
|
end
|
||
|
|
||
|
if lib._VERSION and string.find(lib._VERSION, 'lzlib', nil, true) then
|
||
|
return 'lzlib'
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local z_lib_name = assert(zlib_name(zlib), 'Unsupported zlib Lua binding')
|
||
|
|
||
|
local ZlibStream = {} do
|
||
|
ZlibStream.__index = ZlibStream
|
||
|
|
||
|
ZlibStream.NO_COMPRESSION = zlib.NO_COMPRESSION or 0
|
||
|
ZlibStream.BEST_SPEED = zlib.BEST_SPEED or 1
|
||
|
ZlibStream.BEST_COMPRESSION = zlib.BEST_COMPRESSION or 9
|
||
|
ZlibStream.DEFAULT_COMPRESSION = zlib.DEFAULT_COMPRESSION or -1
|
||
|
ZlibStream.STORE = 0
|
||
|
ZlibStream.DEFLATE = 8
|
||
|
|
||
|
if z_lib_name == 'lzlib' then
|
||
|
function ZlibStream:new(writer, level, method, windowBits)
|
||
|
level = level or ZlibStream.DEFAULT_COMPRESSION
|
||
|
method = method or ZlibStream.DEFLATE
|
||
|
|
||
|
local o = setmetatable({
|
||
|
zd = assert(zlib.deflate(writer, level, method, windowBits));
|
||
|
}, self)
|
||
|
|
||
|
return o
|
||
|
end
|
||
|
|
||
|
function ZlibStream:write(chunk)
|
||
|
assert(self.zd:write(chunk))
|
||
|
end
|
||
|
|
||
|
function ZlibStream:close()
|
||
|
self.zd:close()
|
||
|
end
|
||
|
|
||
|
elseif z_lib_name == 'lua-zlib' then
|
||
|
function ZlibStream:new(writer, level, method, windowBits)
|
||
|
level = level or ZlibStream.DEFAULT_COMPRESSION
|
||
|
method = method or ZlibStream.DEFLATE
|
||
|
|
||
|
assert(method == ZlibStream.DEFLATE, 'lua-zlib support only deflated method')
|
||
|
|
||
|
local o = setmetatable({
|
||
|
zd = assert(zlib.deflate(level, windowBits));
|
||
|
writer = writer;
|
||
|
}, self)
|
||
|
|
||
|
return o
|
||
|
end
|
||
|
|
||
|
function ZlibStream:write(chunk)
|
||
|
chunk = assert(self.zd(chunk))
|
||
|
self.writer(chunk)
|
||
|
end
|
||
|
|
||
|
function ZlibStream:close()
|
||
|
local chunk = self.zd('', 'finish')
|
||
|
if chunk and #chunk > 0 then self.writer(chunk) end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local Compress = {} do
|
||
|
Compress.__index = Compress
|
||
|
|
||
|
Compress.NO_COMPRESSION = ZlibStream.NO_COMPRESSION
|
||
|
Compress.BEST_SPEED = ZlibStream.BEST_SPEED
|
||
|
Compress.BEST_COMPRESSION = ZlibStream.BEST_COMPRESSION
|
||
|
Compress.DEFAULT_COMPRESSION = ZlibStream.DEFAULT_COMPRESSION
|
||
|
|
||
|
function Compress:new(options)
|
||
|
local compress = {}
|
||
|
compress.options = options or {}
|
||
|
|
||
|
return setmetatable(compress, self)
|
||
|
end
|
||
|
|
||
|
function Compress:processBodyData(data, stayOpen, request, response)
|
||
|
local accept_encoding
|
||
|
|
||
|
if response.headersSended then
|
||
|
accept_encoding = response.headers['Content-Encoding'] or ''
|
||
|
else
|
||
|
local headers = request:headers()
|
||
|
accept_encoding = headers and headers['Accept-Encoding'] or ''
|
||
|
end
|
||
|
|
||
|
local accept_gzip = not not accept_encoding:find('gzip', nil, true)
|
||
|
|
||
|
if accept_gzip and self.options.level ~= ZlibStream.NO_COMPRESSION then
|
||
|
local stream = response.compress_stream
|
||
|
local buffer = response.compress_buffer
|
||
|
|
||
|
if not stream then
|
||
|
local writer = function (zdata) buffer[#buffer + 1] = zdata end
|
||
|
stream, buffer = ZlibStream:new(writer, self.options.level, nil, 31), {}
|
||
|
end
|
||
|
|
||
|
if stayOpen then
|
||
|
if data == nil then
|
||
|
stream:close()
|
||
|
response.compress_stream = nil
|
||
|
response.compress_buffer = nil
|
||
|
else
|
||
|
stream:write(data)
|
||
|
response.compress_stream = stream
|
||
|
response.compress_buffer = buffer
|
||
|
end
|
||
|
|
||
|
local compressed = table.concat(buffer)
|
||
|
for i = 1, #buffer do buffer[i] = nil end
|
||
|
if not response.headersSended then
|
||
|
response:addHeader('Content-Encoding', 'gzip')
|
||
|
end
|
||
|
|
||
|
return compressed
|
||
|
end
|
||
|
|
||
|
stream:write(data)
|
||
|
stream:close()
|
||
|
local compressed = table.concat(buffer)
|
||
|
|
||
|
if #compressed < #data then
|
||
|
if not response.headersSended then
|
||
|
response:addHeader('Content-Encoding', 'gzip')
|
||
|
end
|
||
|
|
||
|
return compressed
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return data
|
||
|
end
|
||
|
end
|
||
|
|
||
|
return Compress
|