Comparison

mod_http_upload/mod_http_upload.lua @ 2641:2d83e6c8160b

mod_http_upload: add support for XEP-0363 version 0.3
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Wed, 22 Mar 2017 19:47:52 +0100
parent 2607:a7ef9b765891
child 2646:45ef16ebe565
comparison
equal deleted inserted replaced
2640:c06c59b99b3c 2641:2d83e6c8160b
34 34
35 -- depends 35 -- depends
36 module:depends("http"); 36 module:depends("http");
37 module:depends("disco"); 37 module:depends("disco");
38 38
39 -- namespace 39 -- namespaces
40 local xmlns_http_upload = "urn:xmpp:http:upload"; 40 local namespace = "urn:xmpp:http:upload:0";
41 local legacy_namespace = "urn:xmpp:http:upload";
41 42
42 -- identity and feature advertising 43 -- identity and feature advertising
43 module:add_identity("store", "file", module:get_option_string("name", "HTTP File Upload")); 44 module:add_identity("store", "file", module:get_option_string("name", "HTTP File Upload"));
44 module:add_feature(xmlns_http_upload); 45 module:add_feature(namespace);
46 module:add_feature(legacy_namespace);
45 47
46 module:add_extension(dataform { 48 module:add_extension(dataform {
47 { name = "FORM_TYPE", type = "hidden", value = xmlns_http_upload }, 49 { name = "FORM_TYPE", type = "hidden", value = namespace },
48 { name = "max-file-size", type = "text-single" }, 50 { name = "max-file-size", type = "text-single" },
49 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result")); 51 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result"));
50 52
53 module:add_extension(dataform {
54 { name = "FORM_TYPE", type = "hidden", value = legacy_namespace },
55 { name = "max-file-size", type = "text-single" },
56 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result"));
57
51 -- state 58 -- state
52 local pending_slots = module:shared("upload_slots"); 59 local pending_slots = module:shared("upload_slots");
53 60
54 local storage_path = module:get_option_string(module.name .. "_path", join_path(prosody.paths.data, module.name)); 61 local storage_path = module:get_option_string(module.name .. "_path", join_path(prosody.paths.data, module.name));
55 lfs.mkdir(storage_path); 62 lfs.mkdir(storage_path);
56 63
57 -- hooks 64 local function handle_request(origin, stanza, xmlns, filename, filesize)
58 module:hook("iq/host/"..xmlns_http_upload..":request", function (event)
59 local stanza, origin = event.stanza, event.origin;
60 local request = stanza.tags[1];
61 -- local clients only 65 -- local clients only
62 if origin.type ~= "c2s" then 66 if origin.type ~= "c2s" then
63 module:log("debug", "Request for upload slot from a %s", origin.type); 67 module:log("debug", "Request for upload slot from a %s", origin.type);
64 origin.send(st.error_reply(stanza, "cancel", "not-authorized")); 68 origin.send(st.error_reply(stanza, "cancel", "not-authorized"));
65 return true; 69 return true;
66 end 70 end
67 -- validate 71 -- validate
68 local filename = request:get_child_text("filename");
69 if not filename or filename:find("/") then 72 if not filename or filename:find("/") then
70 module:log("debug", "Filename %q not allowed", filename or ""); 73 module:log("debug", "Filename %q not allowed", filename or "");
71 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid filename")); 74 origin.send(st.error_reply(stanza, "modify", "bad-request", "Invalid filename"));
72 return true; 75 return true;
73 end 76 end
74 local filesize = tonumber(request:get_child_text("size"));
75 if not filesize then 77 if not filesize then
76 module:log("debug", "Missing file size"); 78 module:log("debug", "Missing file size");
77 origin.send(st.error_reply(stanza, "modify", "bad-request", "Missing or invalid file size")); 79 origin.send(st.error_reply(stanza, "modify", "bad-request", "Missing or invalid file size"));
78 return true; 80 return true;
79 elseif filesize > file_size_limit then 81 elseif filesize > file_size_limit then
80 module:log("debug", "File too large (%d > %d)", filesize, file_size_limit); 82 module:log("debug", "File too large (%d > %d)", filesize, file_size_limit);
81 origin.send(st.error_reply(stanza, "modify", "not-acceptable", "File too large") 83 origin.send(st.error_reply(stanza, "modify", "not-acceptable", "File too large")
82 :tag("file-too-large", {xmlns=xmlns_http_upload}) 84 :tag("file-too-large", {xmlns=xmlns})
83 :tag("max-file-size"):text(tostring(file_size_limit))); 85 :tag("max-file-size"):text(tostring(file_size_limit)));
84 return true; 86 return true;
85 end 87 end
86 local reply = st.reply(stanza); 88 local reply = st.reply(stanza);
87 reply:tag("slot", { xmlns = xmlns_http_upload }); 89 reply:tag("slot", { xmlns = xmlns });
88 90
89 local random; 91 local random;
90 repeat random = uuid(); 92 repeat random = uuid();
91 until lfs.mkdir(join_path(storage_path, random)) or not lfs.attributes(join_path(storage_path, random, filename)) 93 until lfs.mkdir(join_path(storage_path, random)) or not lfs.attributes(join_path(storage_path, random, filename))
92 94
104 reply:tag("get"):text(slot_url):up(); 106 reply:tag("get"):text(slot_url):up();
105 reply:tag("put"):text(slot_url):up(); 107 reply:tag("put"):text(slot_url):up();
106 origin.send(reply); 108 origin.send(reply);
107 origin.log("debug", "Given upload slot %q", slot); 109 origin.log("debug", "Given upload slot %q", slot);
108 return true; 110 return true;
111 end
112
113 -- hooks
114 module:hook("iq/host/"..namespace..":request", function (event)
115 local stanza, origin = event.stanza, event.origin;
116 local request = stanza.tags[1];
117 local filename = request.attr.filename;
118 local filesize = tonumber(request.attr.size);
119 handle_request(origin, stanza, namespace, filename, filesize);
120 end);
121
122 module:hook("iq/host/"..legacy_namespace..":request", function (event)
123 local stanza, origin = event.stanza, event.origin;
124 local request = stanza.tags[1];
125 local filename = request:get_child_text("filename");
126 local filesize = tonumber(request:get_child_text("size"));
127 handle_request(origin, stanza, legacy_namespace, filename, filesize);
109 end); 128 end);
110 129
111 -- http service 130 -- http service
112 local function upload_data(event, path) 131 local function upload_data(event, path)
113 local uploader = pending_slots[path]; 132 local uploader = pending_slots[path];