Software / code / verse
Comparison
plugins/compression.lua @ 71:5b74d155036d
verse.plugins.compression: Support for stream compression (requires brimworks lua-zlib)
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Fri, 28 May 2010 23:27:39 +0100 |
| child | 72:1649a6022adb |
comparison
equal
deleted
inserted
replaced
| 70:36d113fb0f3c | 71:5b74d155036d |
|---|---|
| 1 -- Copyright (C) 2009-2010 Matthew Wild | |
| 2 -- Copyright (C) 2009-2010 Tobias Markmann | |
| 3 -- | |
| 4 -- This project is MIT/X11 licensed. Please see the | |
| 5 -- COPYING file in the source package for more information. | |
| 6 -- | |
| 7 | |
| 8 local st = require "util.stanza"; | |
| 9 local zlib = require "zlib"; | |
| 10 | |
| 11 local xmlns_compression_feature = "http://jabber.org/features/compress" | |
| 12 local xmlns_compression_protocol = "http://jabber.org/protocol/compress" | |
| 13 local xmlns_stream = "http://etherx.jabber.org/streams"; | |
| 14 | |
| 15 local compression_level = 9; | |
| 16 | |
| 17 -- returns either nil or a fully functional ready to use inflate stream | |
| 18 local function get_deflate_stream(session) | |
| 19 local status, deflate_stream = pcall(zlib.deflate, compression_level); | |
| 20 if status == false then | |
| 21 local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed"); | |
| 22 session:send(error_st); | |
| 23 session:error("Failed to create zlib.deflate filter: %s", tostring(deflate_stream)); | |
| 24 return | |
| 25 end | |
| 26 return deflate_stream | |
| 27 end | |
| 28 | |
| 29 -- returns either nil or a fully functional ready to use inflate stream | |
| 30 local function get_inflate_stream(session) | |
| 31 local status, inflate_stream = pcall(zlib.inflate); | |
| 32 if status == false then | |
| 33 local error_st = st.stanza("failure", {xmlns=xmlns_compression_protocol}):tag("setup-failed"); | |
| 34 session:send(error_st); | |
| 35 session:error("Failed to create zlib.inflate filter: %s", tostring(inflate_stream)); | |
| 36 return | |
| 37 end | |
| 38 return inflate_stream | |
| 39 end | |
| 40 | |
| 41 -- setup compression for a stream | |
| 42 local function setup_compression(session, deflate_stream) | |
| 43 function session:send(t) | |
| 44 --TODO: Better code injection in the sending process | |
| 45 local status, compressed, eof = pcall(deflate_stream, tostring(t), 'sync'); | |
| 46 if status == false then | |
| 47 session:close({ | |
| 48 condition = "undefined-condition"; | |
| 49 text = compressed; | |
| 50 extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed"); | |
| 51 }); | |
| 52 session:warn("Compressed send failed: %s", tostring(compressed)); | |
| 53 return; | |
| 54 end | |
| 55 session.conn:write(compressed); | |
| 56 end; | |
| 57 end | |
| 58 | |
| 59 -- setup decompression for a stream | |
| 60 local function setup_decompression(session, inflate_stream) | |
| 61 local old_data = session.data | |
| 62 session.data = function(conn, data) | |
| 63 session:debug("Decompressing data..."); | |
| 64 local status, decompressed, eof = pcall(inflate_stream, data); | |
| 65 if status == false then | |
| 66 session:close({ | |
| 67 condition = "undefined-condition"; | |
| 68 text = decompressed; | |
| 69 extra = st.stanza("failure", {xmlns="http://jabber.org/protocol/compress"}):tag("processing-failed"); | |
| 70 }); | |
| 71 stream:warn("%s", tostring(decompressed)); | |
| 72 return; | |
| 73 end | |
| 74 return old_data(conn, decompressed); | |
| 75 end; | |
| 76 session:debug("Replaced session.data %s with %s", old_data, session.data); | |
| 77 end | |
| 78 | |
| 79 function verse.plugins.compression(stream) | |
| 80 local function handle_features(features) | |
| 81 if not stream.compressed then | |
| 82 -- does remote server support compression? | |
| 83 local comp_st = features:child_with_name("compression"); | |
| 84 if comp_st then | |
| 85 -- do we support the mechanism | |
| 86 for a in comp_st:children() do | |
| 87 local algorithm = a[1] | |
| 88 if algorithm == "zlib" then | |
| 89 stream:send(st.stanza("compress", {xmlns=xmlns_compression_protocol}):tag("method"):text("zlib")) | |
| 90 stream:debug("Enabled compression using zlib.") | |
| 91 return true; | |
| 92 end | |
| 93 end | |
| 94 session:debug("Remote server supports no compression algorithm we support.") | |
| 95 end | |
| 96 end | |
| 97 end | |
| 98 local function handle_compressed(stanza) | |
| 99 if stanza.name == "compressed" then | |
| 100 stream:debug("Activating compression...") | |
| 101 | |
| 102 -- create deflate and inflate streams | |
| 103 local deflate_stream = get_deflate_stream(stream); | |
| 104 if not deflate_stream then return end | |
| 105 | |
| 106 local inflate_stream = get_inflate_stream(stream); | |
| 107 if not inflate_stream then return end | |
| 108 | |
| 109 -- setup compression for stream.w | |
| 110 setup_compression(stream, deflate_stream); | |
| 111 | |
| 112 -- setup decompression for stream.data | |
| 113 setup_decompression(stream, inflate_stream); | |
| 114 | |
| 115 stream.compressed = true; | |
| 116 stream:reopen(); | |
| 117 elseif stanza.name == "failure" then | |
| 118 stream:warn("Failed to establish compression"); | |
| 119 end | |
| 120 end | |
| 121 stream:hook("stream-features", handle_features, 200); | |
| 122 stream:hook("stream/"..xmlns_compression_protocol, handle_compressed); | |
| 123 end |