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