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]; |