Comparison

mod_json_streams/mod_json_streams.lua @ 349:ee99eafdd168

mod_json_streams: An implementation of XEP-0295: JSON Encodings for XMPP.
author Waqas Hussain <waqas20@gmail.com>
date Sat, 02 Apr 2011 00:04:26 +0500
child 350:98569ec25ac2
comparison
equal deleted inserted replaced
348:03e1dc036a28 349:ee99eafdd168
1 --
2 -- XEP-0295: JSON Encodings for XMPP
3 --
4
5 module.host = "*"
6
7 local filters = require "util.filters"
8 local json = require "util.json"
9
10 local json_escapes = {
11 ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
12 ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"};
13
14 local s_char = string.char;
15 for i=0,31 do
16 local ch = s_char(i);
17 if not json_escapes[ch] then json_escapes[ch] = ("\\u%.4X"):format(i); end
18 end
19
20 local state_out = 0;
21 local state_key_before = 1;
22 local state_key_in = 2;
23 local state_key_escape = 3;
24 local state_key_after = 4;
25 local state_val_before = 5;
26 local state_val_in = 6;
27 local state_val_escape = 7;
28 local state_val_after = 8;
29
30 local whitespace = { [" "] = true, ["\n"] = true, ["\r"] = true, ["\t"] = true };
31 function json_decoder()
32 local state = state_out;
33 local quote;
34 local output = "";
35 local buffer = "";
36 return function(input)
37 for ch in input:gmatch(".") do
38 module:log("debug", "%s | %d", ch, state)
39 local final = false;
40 if state == state_out then
41 if whitespace[ch] then
42 elseif ch ~= "{" then return nil, "{ expected";
43 else state = state_key_before end
44 elseif state == state_key_before then
45 if whitespace[ch] then
46 elseif ch ~= "'" and ch ~= "\"" then return nil, "\" expected";
47 else quote = ch; state = state_key_in; end
48 elseif state == state_key_in then
49 if ch == quote then state = state_key_after;
50 elseif ch ~= "s" then return nil, "invalid key, 's' expected"; -- only s as key allowed
51 else end -- ignore key
52 elseif state == state_key_after then
53 if whitespace[ch] then
54 elseif ch ~= ":" then return nil, ": expected";
55 else state = state_val_before; end
56 elseif state == state_val_before then
57 if whitespace[ch] then
58 elseif ch ~= "'" and ch ~= "\"" then return nil, "\" expected";
59 else quote = ch; state = state_val_in; end
60 elseif state == state_val_in then
61 if ch == quote then state = state_val_after;
62 elseif ch == "\\" then state = state_val_escape;
63 else end
64 elseif state == state_val_after then
65 if whitespace[ch] then
66 elseif ch ~= "}" then return nil, "} expected";
67 else state = state_out;
68 final = true;
69 end
70 elseif state == state_val_escape then
71 state = state_val_in;
72 else
73 module:log("error", "Unhandled state: "..state);
74 return nil, "Unhandled state in parser"
75 end
76 buffer = buffer..ch;
77 if final then
78 module:log("debug", "%s", buffer)
79 local tmp;
80 pcall(function() tmp = json.decode(buffer); end);
81 if not tmp then return nil, "Invalid JSON"; end
82 output, buffer = output..tmp.s, "";
83 end
84 end
85 local _ = output; output = "";
86 return _;
87 end;
88 end
89
90 function filter_hook(session)
91 local determined = false;
92 local is_json = false;
93 local function in_filter(t)
94 if not determined then
95 is_json = (t:sub(1,1) == "{") and json_decoder();
96 determined = true;
97 end
98 if is_json then
99 local s, err = is_json(t);
100 if not err then return s; end
101 session:close("not-well-formed");
102 return;
103 end
104 return t;
105 end
106 local function out_filter(t)
107 if is_json then
108 return '{"s":"' .. t:gsub(".", json_escapes) .. '"}'; -- encode
109 end
110 return t;
111 end
112 filters.add_filter(session, "bytes/in", in_filter, 100);
113 filters.add_filter(session, "bytes/out", out_filter, 100);
114 end
115
116 function module.load()
117 filters.add_filter_hook(filter_hook);
118 end
119 function module.unload()
120 filters.remove_filter_hook(filter_hook);
121 end
122
123