comparison mod_json_streams/mod_json_streams.lua @ 353:8ef36af30181

merge with upstream
author Phil Stewart <phil.stewart@lichp.co.uk>
date Sun, 03 Apr 2011 22:49:36 +0100
parents 98569ec25ac2
children
comparison
equal deleted inserted replaced
347:cd838419a85d 353:8ef36af30181
1 --
2 -- XEP-0295: JSON Encodings for XMPP
3 --
4
5 module.host = "*"
6
7 local httpserver = require "net.httpserver";
8 local filters = require "util.filters"
9 local json = require "util.json"
10
11 local json_escapes = {
12 ["\""] = "\\\"", ["\\"] = "\\\\", ["\b"] = "\\b", ["\f"] = "\\f",
13 ["\n"] = "\\n", ["\r"] = "\\r", ["\t"] = "\\t"};
14
15 local s_char = string.char;
16 for i=0,31 do
17 local ch = s_char(i);
18 if not json_escapes[ch] then json_escapes[ch] = ("\\u%.4X"):format(i); end
19 end
20
21 local state_out = 0;
22 local state_key_before = 1;
23 local state_key_in = 2;
24 local state_key_escape = 3;
25 local state_key_after = 4;
26 local state_val_before = 5;
27 local state_val_in = 6;
28 local state_val_escape = 7;
29 local state_val_after = 8;
30
31 local whitespace = { [" "] = true, ["\n"] = true, ["\r"] = true, ["\t"] = true };
32 function json_decoder()
33 local state = state_out;
34 local quote;
35 local output = "";
36 local buffer = "";
37 return function(input)
38 for ch in input:gmatch(".") do
39 module:log("debug", "%s | %d", ch, state)
40 local final = false;
41 if state == state_out then
42 if whitespace[ch] then
43 elseif ch ~= "{" then return nil, "{ expected";
44 else state = state_key_before end
45 elseif state == state_key_before then
46 if whitespace[ch] then
47 elseif ch ~= "'" and ch ~= "\"" then return nil, "\" expected";
48 else quote = ch; state = state_key_in; end
49 elseif state == state_key_in then
50 if ch == quote then state = state_key_after;
51 elseif ch ~= "s" then return nil, "invalid key, 's' expected"; -- only s as key allowed
52 else end -- ignore key
53 elseif state == state_key_after then
54 if whitespace[ch] then
55 elseif ch ~= ":" then return nil, ": expected";
56 else state = state_val_before; end
57 elseif state == state_val_before then
58 if whitespace[ch] then
59 elseif ch ~= "'" and ch ~= "\"" then return nil, "\" expected";
60 else quote = ch; state = state_val_in; end
61 elseif state == state_val_in then
62 if ch == quote then state = state_val_after;
63 elseif ch == "\\" then state = state_val_escape;
64 else end
65 elseif state == state_val_after then
66 if whitespace[ch] then
67 elseif ch ~= "}" then return nil, "} expected";
68 else state = state_out;
69 final = true;
70 end
71 elseif state == state_val_escape then
72 state = state_val_in;
73 else
74 module:log("error", "Unhandled state: "..state);
75 return nil, "Unhandled state in parser"
76 end
77 buffer = buffer..ch;
78 if final then
79 module:log("debug", "%s", buffer)
80 local tmp;
81 pcall(function() tmp = json.decode(buffer); end);
82 if not tmp then return nil, "Invalid JSON"; end
83 output, buffer = output..tmp.s, "";
84 end
85 end
86 local _ = output; output = "";
87 return _;
88 end;
89 end
90
91 function filter_hook(session)
92 local determined = false;
93 local is_json = false;
94 local function in_filter(t)
95 if not determined then
96 is_json = (t:sub(1,1) == "{") and json_decoder();
97 determined = true;
98 end
99 if is_json then
100 local s, err = is_json(t);
101 if not err then return s; end
102 session:close("not-well-formed");
103 return;
104 end
105 return t;
106 end
107 local function out_filter(t)
108 if is_json then
109 return '{"s":"' .. t:gsub(".", json_escapes) .. '"}'; -- encode
110 end
111 return t;
112 end
113 filters.add_filter(session, "bytes/in", in_filter, 100);
114 filters.add_filter(session, "bytes/out", out_filter, 100);
115 end
116
117 function module.load()
118 filters.add_filter_hook(filter_hook);
119 end
120 function module.unload()
121 filters.remove_filter_hook(filter_hook);
122 end
123
124 function encode(data)
125 if type(data) == "string" then
126 data = json.encode({ s = data });
127 elseif type(data) == "table" and data.body then
128 data.body = json.encode({ s = data.body });
129 data.headers["Content-Type"] = "application/json";
130 end
131 return data;
132 end
133 function handle_request(method, body, request)
134 local mod_bosh = modulemanager.get_module("*", "bosh")
135 if mod_bosh then
136 if body and method == "POST" then
137 pcall(function() body = json.decode(body).s; end);
138 end
139 local _send = request.send;
140 function request:send(data) return _send(self, encode(data)); end
141 return encode(mod_bosh.handle_request(method, body, request));
142 end
143 return "<html><body>mod_bosh not loaded</body></html>";
144 end
145
146 local function setup()
147 local ports = module:get_option("jsonstreams_ports") or { 5280 };
148 httpserver.new_from_config(ports, handle_request, { base = "jsonstreams" });
149 end
150 if prosody.start_time then -- already started
151 setup();
152 else
153 prosody.events.add_handler("server-started", setup);
154 end