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 |