Software / code / prosody
Comparison
plugins/mod_http_file_share.lua @ 11321:15ab878a7d23
mod_http_file_share: Add some logging
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Wed, 27 Jan 2021 17:29:26 +0100 |
| parent | 11320:817cadf6be92 |
| child | 11322:4ade9810ce35 |
comparison
equal
deleted
inserted
replaced
| 11320:817cadf6be92 | 11321:15ab878a7d23 |
|---|---|
| 13 local url = require "socket.url"; | 13 local url = require "socket.url"; |
| 14 local dm = require "core.storagemanager".olddm; | 14 local dm = require "core.storagemanager".olddm; |
| 15 local jwt = require "util.jwt"; | 15 local jwt = require "util.jwt"; |
| 16 local errors = require "util.error"; | 16 local errors = require "util.error"; |
| 17 local dataform = require "util.dataforms".new; | 17 local dataform = require "util.dataforms".new; |
| 18 local dt = require "util.datetime"; | |
| 19 local hi = require "util.human.units"; | |
| 18 | 20 |
| 19 local namespace = "urn:xmpp:http:upload:0"; | 21 local namespace = "urn:xmpp:http:upload:0"; |
| 20 | 22 |
| 21 module:depends("disco"); | 23 module:depends("disco"); |
| 22 | 24 |
| 49 filesize = { type = "modify"; condition = "not-acceptable"; text = "File too large"; | 51 filesize = { type = "modify"; condition = "not-acceptable"; text = "File too large"; |
| 50 extra = {tag = st.stanza("file-too-large", {xmlns = namespace}):tag("max-file-size"):text(tostring(file_size_limit)) }; | 52 extra = {tag = st.stanza("file-too-large", {xmlns = namespace}):tag("max-file-size"):text(tostring(file_size_limit)) }; |
| 51 filesizefmt = { type = "modify"; condition = "bad-request"; text = "File size must be positive integer"; } | 53 filesizefmt = { type = "modify"; condition = "bad-request"; text = "File size must be positive integer"; } |
| 52 }; | 54 }; |
| 53 }); | 55 }); |
| 56 | |
| 57 -- Convenience wrapper for logging file sizes | |
| 58 local function B(bytes) return hi.format(bytes, "B", "b"); end | |
| 54 | 59 |
| 55 function may_upload(uploader, filename, filesize, filetype) -- > boolean, error | 60 function may_upload(uploader, filename, filesize, filetype) -- > boolean, error |
| 56 local uploader_host = jid.host(uploader); | 61 local uploader_host = jid.host(uploader); |
| 57 if not ((access:empty() and prosody.hosts[uploader_host]) or access:contains(uploader) or access:contains(uploader_host)) then | 62 if not ((access:empty() and prosody.hosts[uploader_host]) or access:contains(uploader) or access:contains(uploader_host)) then |
| 58 return false, upload_errors.new("access"); | 63 return false, upload_errors.new("access"); |
| 116 if not may then | 121 if not may then |
| 117 origin.send(st.error_reply(stanza, why_not)); | 122 origin.send(st.error_reply(stanza, why_not)); |
| 118 return true; | 123 return true; |
| 119 end | 124 end |
| 120 | 125 |
| 126 module:log("info", "Issuing upload slot to %s for %s", uploader, B(filesize)); | |
| 121 local slot, storage_err = errors.coerce(uploads:append(nil, nil, request, os.time(), uploader)) | 127 local slot, storage_err = errors.coerce(uploads:append(nil, nil, request, os.time(), uploader)) |
| 122 if not slot then | 128 if not slot then |
| 123 origin.send(st.error_reply(stanza, storage_err)); | 129 origin.send(st.error_reply(stanza, storage_err)); |
| 124 return true; | 130 return true; |
| 125 end | 131 end |
| 141 | 147 |
| 142 function handle_upload(event, path) -- PUT /upload/:slot | 148 function handle_upload(event, path) -- PUT /upload/:slot |
| 143 local request = event.request; | 149 local request = event.request; |
| 144 local authz = request.headers.authorization; | 150 local authz = request.headers.authorization; |
| 145 if not authz or not authz:find"^Bearer ." then | 151 if not authz or not authz:find"^Bearer ." then |
| 152 module:log("debug", "Missing Authorization"); | |
| 146 return 403; | 153 return 403; |
| 147 end | 154 end |
| 148 local authed, upload_info = jwt.verify(secret, authz:match("^Bearer (.*)")); | 155 local authed, upload_info = jwt.verify(secret, authz:match("^Bearer (.*)")); |
| 149 if not (authed and type(upload_info) == "table" and type(upload_info.exp) == "number") then | 156 if not (authed and type(upload_info) == "table" and type(upload_info.exp) == "number") then |
| 157 module:log("debug", "Unauthorized or invalid token: %s, %q", authed, upload_info); | |
| 150 return 401; | 158 return 401; |
| 151 end | 159 end |
| 152 if upload_info.exp < os.time() then | 160 if upload_info.exp < os.time() then |
| 161 module:log("debug", "Authorization token expired on %s", dt.datetime(upload_info.exp)); | |
| 153 return 410; | 162 return 410; |
| 154 end | 163 end |
| 155 if not path or upload_info.slot ~= path:match("^[^/]+") then | 164 if not path or upload_info.slot ~= path:match("^[^/]+") then |
| 165 module:log("debug", "Invalid upload slot: %q, path: %q", upload_info.slot, path); | |
| 156 return 400; | 166 return 400; |
| 157 end | 167 end |
| 158 | 168 |
| 159 local filename = dm.getpath(upload_info.slot, module.host, module.name, nil, true); | 169 local filename = dm.getpath(upload_info.slot, module.host, module.name, nil, true); |
| 160 | 170 |
| 161 if not request.body_sink then | 171 if not request.body_sink then |
| 172 module:log("debug", "Preparing to receive upload into %q, expecting %s", filename, B(upload_info.filesize)); | |
| 162 local fh, err = errors.coerce(io.open(filename.."~", "w")); | 173 local fh, err = errors.coerce(io.open(filename.."~", "w")); |
| 163 if not fh then | 174 if not fh then |
| 164 return err; | 175 return err; |
| 165 end | 176 end |
| 166 request.body_sink = fh; | 177 request.body_sink = fh; |
| 168 return true; | 179 return true; |
| 169 end | 180 end |
| 170 end | 181 end |
| 171 | 182 |
| 172 if request.body then | 183 if request.body then |
| 184 module:log("debug", "Complete upload available, %s", B(#request.body)); | |
| 185 -- Small enough to have been uploaded already | |
| 173 local written, err = errors.coerce(request.body_sink:write(request.body)); | 186 local written, err = errors.coerce(request.body_sink:write(request.body)); |
| 174 if not written then | 187 if not written then |
| 175 return err; | 188 return err; |
| 176 end | 189 end |
| 177 request.body = nil; | 190 request.body = nil; |
| 183 if final_size ~= upload_info.filesize then | 196 if final_size ~= upload_info.filesize then |
| 184 -- Could be too short as well, but we say the same thing | 197 -- Could be too short as well, but we say the same thing |
| 185 uploaded, err = false, 413; | 198 uploaded, err = false, 413; |
| 186 end | 199 end |
| 187 if uploaded then | 200 if uploaded then |
| 201 module:log("debug", "Upload of %q completed, %s", filename, B(final_size)); | |
| 188 assert(os.rename(filename.."~", filename)); | 202 assert(os.rename(filename.."~", filename)); |
| 189 return 201; | 203 return 201; |
| 190 else | 204 else |
| 191 assert(os.remove(filename.."~")); | 205 assert(os.remove(filename.."~")); |
| 192 return err; | 206 return err; |