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;