Software /
code /
prosody-modules
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]; |