Software /
code /
prosody
Annotate
plugins/mod_http_file_share.lua @ 11493:77f2d45799ed
mod_http_file_share: Fix reporting of missing files
This just gave an unhelpful 500 error.
It would be nice to have some wrapper code that could untangle the
embedded filename in the io libs errors.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 28 Mar 2021 13:51:06 +0200 |
parent | 11491:c3fb802f9e45 |
child | 11495:6d3f84148729 |
rev | line source |
---|---|
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
1 -- Prosody IM |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
2 -- Copyright (C) 2021 Kim Alvefur |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
3 -- |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
4 -- This project is MIT/X11 licensed. Please see the |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
5 -- COPYING file in the source package for more information. |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
6 -- |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
7 -- XEP-0363: HTTP File Upload |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
8 -- Again, from the top! |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
9 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
10 local t_insert = table.insert; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
11 local jid = require "util.jid"; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
12 local st = require "util.stanza"; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
13 local url = require "socket.url"; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
14 local dm = require "core.storagemanager".olddm; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
15 local jwt = require "util.jwt"; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
16 local errors = require "util.error"; |
11314
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
17 local dataform = require "util.dataforms".new; |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
18 local dt = require "util.datetime"; |
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
19 local hi = require "util.human.units"; |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
20 local cache = require "util.cache"; |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
21 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
22 local namespace = "urn:xmpp:http:upload:0"; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
23 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
24 module:depends("disco"); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
25 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
26 module:add_identity("store", "file", module:get_option_string("name", "HTTP File Upload")); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
27 module:add_feature(namespace); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
28 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
29 local uploads = module:open_store("uploads", "archive"); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
30 -- id, <request>, time, owner |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
31 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
32 local secret = module:get_option_string(module.name.."_secret", require"util.id".long()); |
11310
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
33 local external_base_url = module:get_option_string(module.name .. "_base_url"); |
11314
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
34 local file_size_limit = module:get_option_number(module.name .. "_size_limit", 10 * 1024 * 1024); -- 10 MB |
11315
c52fcea39c8e
mod_http_file_share: Add file type filter
Kim Alvefur <zash@zash.se>
parents:
11314
diff
changeset
|
35 local file_types = module:get_option_set(module.name .. "_allowed_file_types", {}); |
11333
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
36 local safe_types = module:get_option_set(module.name .. "_safe_file_types", {"image/*","video/*","audio/*","text/plain"}); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
37 local expiry = module:get_option_number(module.name .. "_expires_after", 7 * 86400); |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
38 local daily_quota = module:get_option_number(module.name .. "_daily_quota", file_size_limit*10); -- 100 MB / day |
11310
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
39 |
11311
9edda2026e57
mod_http_file_share: Add basic access control
Kim Alvefur <zash@zash.se>
parents:
11310
diff
changeset
|
40 local access = module:get_option_set(module.name .. "_access", {}); |
9edda2026e57
mod_http_file_share: Add basic access control
Kim Alvefur <zash@zash.se>
parents:
11310
diff
changeset
|
41 |
11310
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
42 if not external_base_url then |
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
43 module:depends("http"); |
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
44 end |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
45 |
11314
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
46 module:add_extension(dataform { |
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
47 { name = "FORM_TYPE", type = "hidden", value = namespace }, |
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
48 { name = "max-file-size", type = "text-single" }, |
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
49 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result")); |
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
50 |
11312
aade4a6179a3
mod_http_file_share: Return proper error if unauthorized
Kim Alvefur <zash@zash.se>
parents:
11311
diff
changeset
|
51 local upload_errors = errors.init(module.name, namespace, { |
11317
79e1f407b6f5
mod_http_file_share: Expand registry to fix extra tag
Kim Alvefur <zash@zash.se>
parents:
11316
diff
changeset
|
52 access = { type = "auth"; condition = "forbidden" }; |
79e1f407b6f5
mod_http_file_share: Expand registry to fix extra tag
Kim Alvefur <zash@zash.se>
parents:
11316
diff
changeset
|
53 filename = { type = "modify"; condition = "bad-request"; text = "Invalid filename" }; |
79e1f407b6f5
mod_http_file_share: Expand registry to fix extra tag
Kim Alvefur <zash@zash.se>
parents:
11316
diff
changeset
|
54 filetype = { type = "modify"; condition = "not-acceptable"; text = "File type not allowed" }; |
79e1f407b6f5
mod_http_file_share: Expand registry to fix extra tag
Kim Alvefur <zash@zash.se>
parents:
11316
diff
changeset
|
55 filesize = { type = "modify"; condition = "not-acceptable"; text = "File too large"; |
11318
3b16aba6285f
mod_http_file_share: Fix name of max-file-size tag
Kim Alvefur <zash@zash.se>
parents:
11317
diff
changeset
|
56 extra = {tag = st.stanza("file-too-large", {xmlns = namespace}):tag("max-file-size"):text(tostring(file_size_limit)) }; |
11330
f2c9492e3d25
mod_http_file_share: Fix the obligatory misplaced closing bracket (thanks scansion)
Kim Alvefur <zash@zash.se>
parents:
11329
diff
changeset
|
57 }; |
11345
0fec04b64a49
mod_http_file_share: Add missing semicolon
Kim Alvefur <zash@zash.se>
parents:
11343
diff
changeset
|
58 filesizefmt = { type = "modify"; condition = "bad-request"; text = "File size must be positive integer"; }; |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
59 quota = { type = "wait"; condition = "resource-constraint"; text = "Daily quota reached"; }; |
11312
aade4a6179a3
mod_http_file_share: Return proper error if unauthorized
Kim Alvefur <zash@zash.se>
parents:
11311
diff
changeset
|
60 }); |
aade4a6179a3
mod_http_file_share: Return proper error if unauthorized
Kim Alvefur <zash@zash.se>
parents:
11311
diff
changeset
|
61 |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
62 local upload_cache = cache.new(1024); |
11348
f076199b4d38
mod_http_file_share: Cache quotas to avoid hitting storage
Kim Alvefur <zash@zash.se>
parents:
11347
diff
changeset
|
63 local quota_cache = cache.new(1024); |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
64 |
11491
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
65 local measure_upload_cache_size = module:measure("upload_cache", "amount"); |
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
66 local measure_quota_cache_size = module:measure("quota_cache", "amount"); |
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
67 |
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
68 module:hook_global("stats-update", function () |
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
69 measure_upload_cache_size(upload_cache:count()); |
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
70 measure_quota_cache_size(quota_cache:count()); |
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
71 end); |
c3fb802f9e45
mod_http_file_share: Report number of items in caches to statsmanager
Kim Alvefur <zash@zash.se>
parents:
11406
diff
changeset
|
72 |
11355
89efa3f2966b
mod_http_file_share: Collect statistics of files uploaded
Kim Alvefur <zash@zash.se>
parents:
11350
diff
changeset
|
73 local measure_uploads = module:measure("upload", "sizes"); |
89efa3f2966b
mod_http_file_share: Collect statistics of files uploaded
Kim Alvefur <zash@zash.se>
parents:
11350
diff
changeset
|
74 |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
75 -- Convenience wrapper for logging file sizes |
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
76 local function B(bytes) return hi.format(bytes, "B", "b"); end |
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
77 |
11325
76fc73d39092
mod_http_file_share: Factor out function for generating full filename
Kim Alvefur <zash@zash.se>
parents:
11324
diff
changeset
|
78 local function get_filename(slot, create) |
76fc73d39092
mod_http_file_share: Factor out function for generating full filename
Kim Alvefur <zash@zash.se>
parents:
11324
diff
changeset
|
79 return dm.getpath(slot, module.host, module.name, "bin", create) |
76fc73d39092
mod_http_file_share: Factor out function for generating full filename
Kim Alvefur <zash@zash.se>
parents:
11324
diff
changeset
|
80 end |
76fc73d39092
mod_http_file_share: Factor out function for generating full filename
Kim Alvefur <zash@zash.se>
parents:
11324
diff
changeset
|
81 |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
82 function get_daily_quota(uploader) |
11347
5b3ad3c7fe47
mod_http_file_share: Split out some variables for later reuse
Kim Alvefur <zash@zash.se>
parents:
11346
diff
changeset
|
83 local now = os.time(); |
5b3ad3c7fe47
mod_http_file_share: Split out some variables for later reuse
Kim Alvefur <zash@zash.se>
parents:
11346
diff
changeset
|
84 local max_age = now - 86400; |
11348
f076199b4d38
mod_http_file_share: Cache quotas to avoid hitting storage
Kim Alvefur <zash@zash.se>
parents:
11347
diff
changeset
|
85 local cached = quota_cache:get(uploader); |
f076199b4d38
mod_http_file_share: Cache quotas to avoid hitting storage
Kim Alvefur <zash@zash.se>
parents:
11347
diff
changeset
|
86 if cached and cached.time > max_age then |
f076199b4d38
mod_http_file_share: Cache quotas to avoid hitting storage
Kim Alvefur <zash@zash.se>
parents:
11347
diff
changeset
|
87 return cached.size; |
f076199b4d38
mod_http_file_share: Cache quotas to avoid hitting storage
Kim Alvefur <zash@zash.se>
parents:
11347
diff
changeset
|
88 end |
11347
5b3ad3c7fe47
mod_http_file_share: Split out some variables for later reuse
Kim Alvefur <zash@zash.se>
parents:
11346
diff
changeset
|
89 local iter, err = uploads:find(nil, {with = uploader; start = max_age }); |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
90 if not iter then return iter, err; end |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
91 local total_bytes = 0; |
11349
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
92 local oldest_upload = now; |
11348
f076199b4d38
mod_http_file_share: Cache quotas to avoid hitting storage
Kim Alvefur <zash@zash.se>
parents:
11347
diff
changeset
|
93 for _, slot, when in iter do |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
94 local size = tonumber(slot.attr.size); |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
95 if size then total_bytes = total_bytes + size; end |
11349
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
96 if when < oldest_upload then oldest_upload = when; end |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
97 end |
11349
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
98 -- If there were no uploads then we end up caching [now, 0], which is fine |
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
99 -- since we increase the size on new uploads |
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
100 quota_cache:set(uploader, { time = oldest_upload, size = total_bytes }); |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
101 return total_bytes; |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
102 end |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
103 |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
104 function may_upload(uploader, filename, filesize, filetype) -- > boolean, error |
11311
9edda2026e57
mod_http_file_share: Add basic access control
Kim Alvefur <zash@zash.se>
parents:
11310
diff
changeset
|
105 local uploader_host = jid.host(uploader); |
9edda2026e57
mod_http_file_share: Add basic access control
Kim Alvefur <zash@zash.se>
parents:
11310
diff
changeset
|
106 if not ((access:empty() and prosody.hosts[uploader_host]) or access:contains(uploader) or access:contains(uploader_host)) then |
11312
aade4a6179a3
mod_http_file_share: Return proper error if unauthorized
Kim Alvefur <zash@zash.se>
parents:
11311
diff
changeset
|
107 return false, upload_errors.new("access"); |
11311
9edda2026e57
mod_http_file_share: Add basic access control
Kim Alvefur <zash@zash.se>
parents:
11310
diff
changeset
|
108 end |
9edda2026e57
mod_http_file_share: Add basic access control
Kim Alvefur <zash@zash.se>
parents:
11310
diff
changeset
|
109 |
11313
e53894d26092
mod_http_file_share: Validate that filename does not contain '/'
Kim Alvefur <zash@zash.se>
parents:
11312
diff
changeset
|
110 if not filename or filename:find"/" then |
e53894d26092
mod_http_file_share: Validate that filename does not contain '/'
Kim Alvefur <zash@zash.se>
parents:
11312
diff
changeset
|
111 -- On Linux, only '/' and '\0' are invalid in filenames and NUL can't be in XML |
e53894d26092
mod_http_file_share: Validate that filename does not contain '/'
Kim Alvefur <zash@zash.se>
parents:
11312
diff
changeset
|
112 return false, upload_errors.new("filename"); |
e53894d26092
mod_http_file_share: Validate that filename does not contain '/'
Kim Alvefur <zash@zash.se>
parents:
11312
diff
changeset
|
113 end |
e53894d26092
mod_http_file_share: Validate that filename does not contain '/'
Kim Alvefur <zash@zash.se>
parents:
11312
diff
changeset
|
114 |
11319
a4b299e37909
mod_http_file_share: Reject invalid file sizes
Kim Alvefur <zash@zash.se>
parents:
11318
diff
changeset
|
115 if not filesize or filesize < 0 or filesize % 1 ~= 0 then |
a4b299e37909
mod_http_file_share: Reject invalid file sizes
Kim Alvefur <zash@zash.se>
parents:
11318
diff
changeset
|
116 return false, upload_errors.new("filesizefmt"); |
a4b299e37909
mod_http_file_share: Reject invalid file sizes
Kim Alvefur <zash@zash.se>
parents:
11318
diff
changeset
|
117 end |
11314
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
118 if filesize > file_size_limit then |
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
119 return false, upload_errors.new("filesize"); |
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
120 end |
7c8b02c5a335
mod_http_file_share: Add file size limit (default 10M)
Kim Alvefur <zash@zash.se>
parents:
11313
diff
changeset
|
121 |
11346
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
122 local uploader_quota = get_daily_quota(uploader); |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
123 if uploader_quota + filesize > daily_quota then |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
124 return false, upload_errors.new("quota"); |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
125 end |
315faec1a920
mod_http_file_share: Add support for daily upload quotas.
Kim Alvefur <zash@zash.se>
parents:
11345
diff
changeset
|
126 |
11315
c52fcea39c8e
mod_http_file_share: Add file type filter
Kim Alvefur <zash@zash.se>
parents:
11314
diff
changeset
|
127 if not ( file_types:empty() or file_types:contains(filetype) or file_types:contains(filetype:gsub("/.*", "/*")) ) then |
c52fcea39c8e
mod_http_file_share: Add file type filter
Kim Alvefur <zash@zash.se>
parents:
11314
diff
changeset
|
128 return false, upload_errors.new("filetype"); |
c52fcea39c8e
mod_http_file_share: Add file type filter
Kim Alvefur <zash@zash.se>
parents:
11314
diff
changeset
|
129 end |
c52fcea39c8e
mod_http_file_share: Add file type filter
Kim Alvefur <zash@zash.se>
parents:
11314
diff
changeset
|
130 |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
131 return true; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
132 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
133 |
11350
3287dbdde33e
mod_http_file_share: Reorder arguments
Kim Alvefur <zash@zash.se>
parents:
11349
diff
changeset
|
134 function get_authz(slot, uploader, filename, filesize, filetype) |
11322
4ade9810ce35
mod_http_file_share: Move Authorization type string
Kim Alvefur <zash@zash.se>
parents:
11321
diff
changeset
|
135 return jwt.sign(secret, { |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
136 sub = uploader; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
137 filename = filename; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
138 filesize = filesize; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
139 filetype = filetype; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
140 slot = slot; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
141 exp = os.time()+300; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
142 }); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
143 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
144 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
145 function get_url(slot, filename) |
11310
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
146 local base_url = external_base_url or module:http_url(); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
147 local slot_url = url.parse(base_url); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
148 slot_url.path = url.parse_path(slot_url.path or "/"); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
149 t_insert(slot_url.path, slot); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
150 if filename then |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
151 t_insert(slot_url.path, filename); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
152 slot_url.path.is_directory = false; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
153 else |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
154 slot_url.path.is_directory = true; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
155 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
156 slot_url.path = url.build_path(slot_url.path); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
157 return url.build(slot_url); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
158 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
159 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
160 function handle_slot_request(event) |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
161 local stanza, origin = event.stanza, event.origin; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
162 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
163 local request = st.clone(stanza.tags[1], true); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
164 local filename = request.attr.filename; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
165 local filesize = tonumber(request.attr.size); |
11320
817cadf6be92
mod_http_file_share: Handle content-type being optional
Kim Alvefur <zash@zash.se>
parents:
11319
diff
changeset
|
166 local filetype = request.attr["content-type"] or "application/octet-stream"; |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
167 local uploader = jid.bare(stanza.attr.from); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
168 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
169 local may, why_not = may_upload(uploader, filename, filesize, filetype); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
170 if not may then |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
171 origin.send(st.error_reply(stanza, why_not)); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
172 return true; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
173 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
174 |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
175 module:log("info", "Issuing upload slot to %s for %s", uploader, B(filesize)); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
176 local slot, storage_err = errors.coerce(uploads:append(nil, nil, request, os.time(), uploader)) |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
177 if not slot then |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
178 origin.send(st.error_reply(stanza, storage_err)); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
179 return true; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
180 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
181 |
11349
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
182 local cached_quota = quota_cache:get(uploader); |
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
183 if cached_quota and cached_quota.time > os.time()-86400 then |
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
184 cached_quota.size = cached_quota.size + filesize; |
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
185 quota_cache:set(uploader, cached_quota); |
a219001b449d
mod_http_file_share: Update cached value while it is reasonably fresh
Kim Alvefur <zash@zash.se>
parents:
11348
diff
changeset
|
186 end |
11348
f076199b4d38
mod_http_file_share: Cache quotas to avoid hitting storage
Kim Alvefur <zash@zash.se>
parents:
11347
diff
changeset
|
187 |
11350
3287dbdde33e
mod_http_file_share: Reorder arguments
Kim Alvefur <zash@zash.se>
parents:
11349
diff
changeset
|
188 local authz = get_authz(slot, uploader, filename, filesize, filetype); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
189 local slot_url = get_url(slot, filename); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
190 local upload_url = slot_url; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
191 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
192 local reply = st.reply(stanza) |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
193 :tag("slot", { xmlns = namespace }) |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
194 :tag("get", { url = slot_url }):up() |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
195 :tag("put", { url = upload_url }) |
11322
4ade9810ce35
mod_http_file_share: Move Authorization type string
Kim Alvefur <zash@zash.se>
parents:
11321
diff
changeset
|
196 :text_tag("header", "Bearer "..authz, {name="Authorization"}) |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
197 :reset(); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
198 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
199 origin.send(reply); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
200 return true; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
201 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
202 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
203 function handle_upload(event, path) -- PUT /upload/:slot |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
204 local request = event.request; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
205 local authz = request.headers.authorization; |
11326
1ecda954fe97
mod_http_file_share: Strip authorization type prefix a bit earlier
Kim Alvefur <zash@zash.se>
parents:
11325
diff
changeset
|
206 if authz then |
1ecda954fe97
mod_http_file_share: Strip authorization type prefix a bit earlier
Kim Alvefur <zash@zash.se>
parents:
11325
diff
changeset
|
207 authz = authz:match("^Bearer (.*)") |
1ecda954fe97
mod_http_file_share: Strip authorization type prefix a bit earlier
Kim Alvefur <zash@zash.se>
parents:
11325
diff
changeset
|
208 end |
1ecda954fe97
mod_http_file_share: Strip authorization type prefix a bit earlier
Kim Alvefur <zash@zash.se>
parents:
11325
diff
changeset
|
209 if not authz then |
11335
b7acab5e7f57
mod_http_file_share: Clarify message about missing Authorization header
Kim Alvefur <zash@zash.se>
parents:
11334
diff
changeset
|
210 module:log("debug", "Missing or malformed Authorization header"); |
11336
b05331cff47a
mod_http_file_share: Indicate missing token via WWW-Authenticate header
Kim Alvefur <zash@zash.se>
parents:
11335
diff
changeset
|
211 event.response.headers.www_authenticate = "Bearer"; |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
212 return 403; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
213 end |
11326
1ecda954fe97
mod_http_file_share: Strip authorization type prefix a bit earlier
Kim Alvefur <zash@zash.se>
parents:
11325
diff
changeset
|
214 local authed, upload_info = jwt.verify(secret, authz); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
215 if not (authed and type(upload_info) == "table" and type(upload_info.exp) == "number") then |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
216 module:log("debug", "Unauthorized or invalid token: %s, %q", authed, upload_info); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
217 return 401; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
218 end |
11334
dbba2d44fda2
mod_http_file_share: Allow started uploads to complete after token expired
Kim Alvefur <zash@zash.se>
parents:
11333
diff
changeset
|
219 if not request.body_sink and upload_info.exp < os.time() then |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
220 module:log("debug", "Authorization token expired on %s", dt.datetime(upload_info.exp)); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
221 return 410; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
222 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
223 if not path or upload_info.slot ~= path:match("^[^/]+") then |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
224 module:log("debug", "Invalid upload slot: %q, path: %q", upload_info.slot, path); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
225 return 400; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
226 end |
11323
a853a018eede
mod_http_file_share: Validate file size early in HTTP PUT request
Kim Alvefur <zash@zash.se>
parents:
11322
diff
changeset
|
227 if request.headers.content_length and tonumber(request.headers.content_length) ~= upload_info.filesize then |
a853a018eede
mod_http_file_share: Validate file size early in HTTP PUT request
Kim Alvefur <zash@zash.se>
parents:
11322
diff
changeset
|
228 return 413; |
a853a018eede
mod_http_file_share: Validate file size early in HTTP PUT request
Kim Alvefur <zash@zash.se>
parents:
11322
diff
changeset
|
229 -- Note: We don't know the size if the upload is streamed in chunked encoding, |
a853a018eede
mod_http_file_share: Validate file size early in HTTP PUT request
Kim Alvefur <zash@zash.se>
parents:
11322
diff
changeset
|
230 -- so we also check the final file size on completion. |
a853a018eede
mod_http_file_share: Validate file size early in HTTP PUT request
Kim Alvefur <zash@zash.se>
parents:
11322
diff
changeset
|
231 end |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
232 |
11325
76fc73d39092
mod_http_file_share: Factor out function for generating full filename
Kim Alvefur <zash@zash.se>
parents:
11324
diff
changeset
|
233 local filename = get_filename(upload_info.slot, true); |
11324
494761f5d7da
mod_http_file_share: Use '.bin' file extension
Kim Alvefur <zash@zash.se>
parents:
11323
diff
changeset
|
234 |
11375
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
235 do |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
236 -- check if upload has been completed already |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
237 -- we want to allow retry of a failed upload attempt, but not after it's been completed |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
238 local f = io.open(filename, "r"); |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
239 if f then |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
240 f:close(); |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
241 return 409; |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
242 end |
6b687210975b
mod_http_file_share: Prevent attempt to upload again after completion
Kim Alvefur <zash@zash.se>
parents:
11374
diff
changeset
|
243 end |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
244 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
245 if not request.body_sink then |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
246 module:log("debug", "Preparing to receive upload into %q, expecting %s", filename, B(upload_info.filesize)); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
247 local fh, err = errors.coerce(io.open(filename.."~", "w")); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
248 if not fh then |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
249 return err; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
250 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
251 request.body_sink = fh; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
252 if request.body == false then |
11374
5b8aec0609f0
mod_http_file_share: Support sending 100 Continue
Kim Alvefur <zash@zash.se>
parents:
11357
diff
changeset
|
253 if request.headers.expect == "100-continue" then |
5b8aec0609f0
mod_http_file_share: Support sending 100 Continue
Kim Alvefur <zash@zash.se>
parents:
11357
diff
changeset
|
254 request.conn:write("HTTP/1.1 100 Continue\r\n\r\n"); |
5b8aec0609f0
mod_http_file_share: Support sending 100 Continue
Kim Alvefur <zash@zash.se>
parents:
11357
diff
changeset
|
255 end |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
256 return true; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
257 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
258 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
259 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
260 if request.body then |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
261 module:log("debug", "Complete upload available, %s", B(#request.body)); |
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
262 -- Small enough to have been uploaded already |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
263 local written, err = errors.coerce(request.body_sink:write(request.body)); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
264 if not written then |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
265 return err; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
266 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
267 request.body = nil; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
268 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
269 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
270 if request.body_sink then |
11316
ae0461b37fbe
mod_http_file_share: Verify final file size on completion of upload
Kim Alvefur <zash@zash.se>
parents:
11315
diff
changeset
|
271 local final_size = request.body_sink:seek(); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
272 local uploaded, err = errors.coerce(request.body_sink:close()); |
11316
ae0461b37fbe
mod_http_file_share: Verify final file size on completion of upload
Kim Alvefur <zash@zash.se>
parents:
11315
diff
changeset
|
273 if final_size ~= upload_info.filesize then |
ae0461b37fbe
mod_http_file_share: Verify final file size on completion of upload
Kim Alvefur <zash@zash.se>
parents:
11315
diff
changeset
|
274 -- Could be too short as well, but we say the same thing |
ae0461b37fbe
mod_http_file_share: Verify final file size on completion of upload
Kim Alvefur <zash@zash.se>
parents:
11315
diff
changeset
|
275 uploaded, err = false, 413; |
ae0461b37fbe
mod_http_file_share: Verify final file size on completion of upload
Kim Alvefur <zash@zash.se>
parents:
11315
diff
changeset
|
276 end |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
277 if uploaded then |
11321
15ab878a7d23
mod_http_file_share: Add some logging
Kim Alvefur <zash@zash.se>
parents:
11320
diff
changeset
|
278 module:log("debug", "Upload of %q completed, %s", filename, B(final_size)); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
279 assert(os.rename(filename.."~", filename)); |
11355
89efa3f2966b
mod_http_file_share: Collect statistics of files uploaded
Kim Alvefur <zash@zash.se>
parents:
11350
diff
changeset
|
280 measure_uploads(final_size); |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
281 |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
282 upload_cache:set(upload_info.slot, { |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
283 name = upload_info.filename; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
284 size = tostring(upload_info.filesize); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
285 type = upload_info.filetype; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
286 time = os.time(); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
287 }); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
288 return 201; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
289 else |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
290 assert(os.remove(filename.."~")); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
291 return err; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
292 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
293 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
294 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
295 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
296 |
11357
8cb2a64b15da
mod_http_file_share: Collect cache hit/miss statistics for downloads
Kim Alvefur <zash@zash.se>
parents:
11356
diff
changeset
|
297 local download_cache_hit = module:measure("download_cache_hit", "rate"); |
8cb2a64b15da
mod_http_file_share: Collect cache hit/miss statistics for downloads
Kim Alvefur <zash@zash.se>
parents:
11356
diff
changeset
|
298 local download_cache_miss = module:measure("download_cache_miss", "rate"); |
8cb2a64b15da
mod_http_file_share: Collect cache hit/miss statistics for downloads
Kim Alvefur <zash@zash.se>
parents:
11356
diff
changeset
|
299 |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
300 function handle_download(event, path) -- GET /uploads/:slot+filename |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
301 local request, response = event.request, event.response; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
302 local slot_id = path:match("^[^/]+"); |
11331
7a915fa49373
mod_http_file_share: Extract all file properties into variables earlier
Kim Alvefur <zash@zash.se>
parents:
11330
diff
changeset
|
303 local basename, filetime, filetype, filesize; |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
304 local cached = upload_cache:get(slot_id); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
305 if cached then |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
306 module:log("debug", "Cache hit"); |
11357
8cb2a64b15da
mod_http_file_share: Collect cache hit/miss statistics for downloads
Kim Alvefur <zash@zash.se>
parents:
11356
diff
changeset
|
307 download_cache_hit(); |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
308 basename = cached.name; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
309 filesize = cached.size; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
310 filetype = cached.type; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
311 filetime = cached.time; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
312 upload_cache:set(slot_id, cached); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
313 -- TODO cache negative hits? |
11331
7a915fa49373
mod_http_file_share: Extract all file properties into variables earlier
Kim Alvefur <zash@zash.se>
parents:
11330
diff
changeset
|
314 else |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
315 module:log("debug", "Cache miss"); |
11357
8cb2a64b15da
mod_http_file_share: Collect cache hit/miss statistics for downloads
Kim Alvefur <zash@zash.se>
parents:
11356
diff
changeset
|
316 download_cache_miss(); |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
317 local slot, when = errors.coerce(uploads:get(nil, slot_id)); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
318 if not slot then |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
319 module:log("debug", "uploads:get(%q) --> not-found, %s", slot_id, when); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
320 else |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
321 module:log("debug", "uploads:get(%q) --> %s, %d", slot_id, slot, when); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
322 basename = slot.attr.filename; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
323 filesize = slot.attr.size; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
324 filetype = slot.attr["content-type"]; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
325 filetime = when; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
326 upload_cache:set(slot_id, { |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
327 name = basename; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
328 size = slot.attr.size; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
329 type = filetype; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
330 time = when; |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
331 }); |
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
332 end |
11331
7a915fa49373
mod_http_file_share: Extract all file properties into variables earlier
Kim Alvefur <zash@zash.se>
parents:
11330
diff
changeset
|
333 end |
7a915fa49373
mod_http_file_share: Extract all file properties into variables earlier
Kim Alvefur <zash@zash.se>
parents:
11330
diff
changeset
|
334 if not basename then |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
335 return 404; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
336 end |
11331
7a915fa49373
mod_http_file_share: Extract all file properties into variables earlier
Kim Alvefur <zash@zash.se>
parents:
11330
diff
changeset
|
337 local last_modified = os.date('!%a, %d %b %Y %H:%M:%S GMT', filetime); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
338 if request.headers.if_modified_since == last_modified then |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
339 return 304; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
340 end |
11325
76fc73d39092
mod_http_file_share: Factor out function for generating full filename
Kim Alvefur <zash@zash.se>
parents:
11324
diff
changeset
|
341 local filename = get_filename(slot_id); |
11493
77f2d45799ed
mod_http_file_share: Fix reporting of missing files
Kim Alvefur <zash@zash.se>
parents:
11491
diff
changeset
|
342 local handle, ferr = io.open(filename); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
343 if not handle then |
11493
77f2d45799ed
mod_http_file_share: Fix reporting of missing files
Kim Alvefur <zash@zash.se>
parents:
11491
diff
changeset
|
344 module:log("error", "Could not open file: %s", filename, ferr); |
77f2d45799ed
mod_http_file_share: Fix reporting of missing files
Kim Alvefur <zash@zash.se>
parents:
11491
diff
changeset
|
345 -- This can be because the upload slot wasn't used, or the file disappeared |
77f2d45799ed
mod_http_file_share: Fix reporting of missing files
Kim Alvefur <zash@zash.se>
parents:
11491
diff
changeset
|
346 -- somehow, or permission issues. |
77f2d45799ed
mod_http_file_share: Fix reporting of missing files
Kim Alvefur <zash@zash.se>
parents:
11491
diff
changeset
|
347 return 410; |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
348 end |
11333
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
349 |
11402
a3be7b3cf1e1
mod_http_file_share: Fix traceback on missing file-type
Kim Alvefur <zash@zash.se>
parents:
11398
diff
changeset
|
350 if not filetype then |
a3be7b3cf1e1
mod_http_file_share: Fix traceback on missing file-type
Kim Alvefur <zash@zash.se>
parents:
11398
diff
changeset
|
351 filetype = "application/octet-stream"; |
a3be7b3cf1e1
mod_http_file_share: Fix traceback on missing file-type
Kim Alvefur <zash@zash.se>
parents:
11398
diff
changeset
|
352 end |
11333
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
353 local disposition = "attachment"; |
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
354 if safe_types:contains(filetype) or safe_types:contains(filetype:gsub("/.*", "/*")) then |
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
355 disposition = "inline"; |
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
356 end |
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
357 |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
358 response.headers.last_modified = last_modified; |
11331
7a915fa49373
mod_http_file_share: Extract all file properties into variables earlier
Kim Alvefur <zash@zash.se>
parents:
11330
diff
changeset
|
359 response.headers.content_length = filesize; |
11402
a3be7b3cf1e1
mod_http_file_share: Fix traceback on missing file-type
Kim Alvefur <zash@zash.se>
parents:
11398
diff
changeset
|
360 response.headers.content_type = filetype; |
11333
f80056b97cf0
mod_http_file_share: Serve configurable set of safe mime types inline (thanks jonas’)
Kim Alvefur <zash@zash.se>
parents:
11332
diff
changeset
|
361 response.headers.content_disposition = string.format("%s; filename=%q", disposition, basename); |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
362 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
363 response.headers.cache_control = "max-age=31556952, immutable"; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
364 response.headers.content_security_policy = "default-src 'none'; frame-ancestors 'none';" |
11327
6f2b69469060
mod_http_file_share: More security headers
Kim Alvefur <zash@zash.se>
parents:
11326
diff
changeset
|
365 response.headers.strict_transport_security = "max-age=31556952"; |
6f2b69469060
mod_http_file_share: More security headers
Kim Alvefur <zash@zash.se>
parents:
11326
diff
changeset
|
366 response.headers.x_content_type_options = "nosniff"; |
6f2b69469060
mod_http_file_share: More security headers
Kim Alvefur <zash@zash.se>
parents:
11326
diff
changeset
|
367 response.headers.x_frame_options = "DENY"; -- replaced by frame-ancestors in CSP? |
6f2b69469060
mod_http_file_share: More security headers
Kim Alvefur <zash@zash.se>
parents:
11326
diff
changeset
|
368 response.headers.x_xss_protection = "1; mode=block"; |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
369 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
370 return response:send_file(handle); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
371 end |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
372 |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
373 if expiry >= 0 and not external_base_url then |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
374 -- TODO HTTP DELETE to the external endpoint? |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
375 local array = require "util.array"; |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
376 local async = require "util.async"; |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
377 local ENOENT = require "util.pposix".ENOENT; |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
378 |
11329
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
379 local function sleep(t) |
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
380 local wait, done = async.waiter(); |
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
381 module:add_timer(t, done) |
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
382 wait(); |
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
383 end |
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
384 |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
385 local reaper_task = async.runner(function(boundary_time) |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
386 local iter, total = assert(uploads:find(nil, {["end"] = boundary_time; total = true})); |
11356
43e5429ab355
mod_http_file_share: Measure how long it takes to prune expired files
Kim Alvefur <zash@zash.se>
parents:
11355
diff
changeset
|
387 local prune_done = module:measure("prune", "times"); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
388 |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
389 if total == 0 then |
11343
f125ac529c22
mod_http_file_share: Clarify log message
Kim Alvefur <zash@zash.se>
parents:
11336
diff
changeset
|
390 module:log("info", "No expired uploaded files to prune"); |
11356
43e5429ab355
mod_http_file_share: Measure how long it takes to prune expired files
Kim Alvefur <zash@zash.se>
parents:
11355
diff
changeset
|
391 prune_done(); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
392 return; |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
393 end |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
394 |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
395 module:log("info", "Pruning expired files uploaded earlier than %s", dt.datetime(boundary_time)); |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
396 |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
397 local obsolete_uploads = array(); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
398 local i = 0; |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
399 for slot_id in iter do |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
400 i = i + 1; |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
401 obsolete_uploads:push(slot_id); |
11332
3e0dcdf6283e
mod_http_file_share: Cache file metadata
Kim Alvefur <zash@zash.se>
parents:
11331
diff
changeset
|
402 upload_cache:set(slot_id, nil); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
403 end |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
404 |
11329
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
405 sleep(0.1); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
406 local n = 0; |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
407 local problem_deleting = false; |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
408 obsolete_uploads:filter(function(slot_id) |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
409 n = n + 1; |
11329
2a431d3ad8f1
mod_http_file_share: Insert pauses to avoid blocknig for long periods
Kim Alvefur <zash@zash.se>
parents:
11328
diff
changeset
|
410 if i % 100 == 0 then sleep(0.1); end |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
411 local filename = get_filename(slot_id); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
412 local deleted, err, errno = os.remove(filename); |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
413 if deleted or errno == ENOENT then |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
414 return true; |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
415 else |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
416 module:log("error", "Could not delete file %q: %s", filename, err); |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
417 problem_deleting = true; |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
418 return false; |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
419 end |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
420 end); |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
421 -- obsolete_uploads now contains slot ids for which the files have been |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
422 -- deleted and that needs to be cleared from the database |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
423 |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
424 local deletion_query = {["end"] = boundary_time}; |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
425 if not problem_deleting then |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
426 module:log("info", "All (%d) expired files successfully deleted", n); |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
427 -- we can delete based on time |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
428 else |
11405
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
429 module:log("warn", "%d out of %d expired files could not be deleted", n-#obsolete_uploads, n); |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
430 -- we'll need to delete only those entries where the files were |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
431 -- successfully deleted, and then try again with the failed ones. |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
432 -- eventually the admin ought to notice and fix the permissions or |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
433 -- whatever the problem is. |
ce8291e89d67
mod_http_file_share: Remove correct entries when not all expired files were deleted
Kim Alvefur <zash@zash.se>
parents:
11402
diff
changeset
|
434 deletion_query = {ids = obsolete_uploads}; |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
435 end |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
436 |
11406
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
437 if #obsolete_uploads == 0 then |
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
438 module:log("debug", "No metadata to remove"); |
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
439 else |
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
440 local removed, err = uploads:delete(nil, deletion_query); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
441 |
11406
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
442 if removed == true or removed == n or removed == #obsolete_uploads then |
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
443 module:log("debug", "Removed all metadata for expired uploaded files"); |
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
444 else |
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
445 module:log("error", "Problem removing metadata for deleted files: %s", err); |
9d6545a7d483
mod_http_file_share: Skip removal of nothing
Kim Alvefur <zash@zash.se>
parents:
11405
diff
changeset
|
446 end |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
447 end |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
448 |
11356
43e5429ab355
mod_http_file_share: Measure how long it takes to prune expired files
Kim Alvefur <zash@zash.se>
parents:
11355
diff
changeset
|
449 prune_done(); |
11328
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
450 end); |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
451 |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
452 module:add_timer(1, function () |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
453 reaper_task:run(os.time()-expiry); |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
454 return 60*60; |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
455 end); |
ceaa3cebf28b
mod_http_file_share: Add support for removing old files (default 2 weeks)
Kim Alvefur <zash@zash.se>
parents:
11327
diff
changeset
|
456 end |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
457 |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
458 module:hook("iq-get/host/urn:xmpp:http:upload:0:request", handle_slot_request); |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
459 |
11310
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
460 if not external_base_url then |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
461 module:provides("http", { |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
462 streaming_uploads = true; |
11398
a1f26d17d70f
mod_http_file_share: Allow credentials via CORS (needed for auth token)
Kim Alvefur <zash@zash.se>
parents:
11394
diff
changeset
|
463 cors = { |
a1f26d17d70f
mod_http_file_share: Allow credentials via CORS (needed for auth token)
Kim Alvefur <zash@zash.se>
parents:
11394
diff
changeset
|
464 credentials = true; |
a1f26d17d70f
mod_http_file_share: Allow credentials via CORS (needed for auth token)
Kim Alvefur <zash@zash.se>
parents:
11394
diff
changeset
|
465 }; |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
466 route = { |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
467 ["PUT /*"] = handle_upload; |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
468 ["GET /*"] = handle_download; |
11394
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
469 ["GET /"] = function (event) |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
470 return prosody.events.fire_event("http-message", { |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
471 response = event.response; |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
472 --- |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
473 title = "Prosody HTTP Upload endpoint"; |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
474 message = "This is where files will be uploaded to, and served from."; |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
475 warning = not (event.request.secure) and "This endpoint is not considered secure!" or nil; |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
476 }) or "This is the Prosody HTTP Upload endpoint."; |
420787340339
mod_http_file_share: Return a message from the base URL
Kim Alvefur <zash@zash.se>
parents:
11375
diff
changeset
|
477 end |
11309
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
478 } |
b59aed75dc5e
mod_http_file_share: Let's write another XEP-0363 implementation
Kim Alvefur <zash@zash.se>
parents:
diff
changeset
|
479 }); |
11310
d1a0f2e918c0
mod_http_file_share: Add support for external file upload service
Kim Alvefur <zash@zash.se>
parents:
11309
diff
changeset
|
480 end |