Mercurial > prosody-modules
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 |
parents | |
children | 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 |