copyparty 1.13.6__py3-none-any.whl → 1.13.7__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- copyparty/__main__.py +25 -7
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +9 -6
- copyparty/cert.py +1 -1
- copyparty/fsutil.py +3 -3
- copyparty/ftpd.py +15 -2
- copyparty/httpcli.py +221 -81
- copyparty/httpconn.py +3 -0
- copyparty/httpsrv.py +35 -11
- copyparty/ico.py +1 -1
- copyparty/mtag.py +15 -6
- copyparty/pwhash.py +10 -0
- copyparty/smbd.py +20 -2
- copyparty/ssdp.py +3 -3
- copyparty/stolen/dnslib/dns.py +6 -0
- copyparty/stolen/ifaddr/__init__.py +15 -1
- copyparty/stolen/ifaddr/_shared.py +1 -0
- copyparty/stolen/qrcodegen.py +6 -0
- copyparty/sutil.py +1 -1
- copyparty/svchub.py +72 -3
- copyparty/szip.py +1 -3
- copyparty/tcpsrv.py +60 -8
- copyparty/tftpd.py +30 -4
- copyparty/th_srv.py +22 -1
- copyparty/u2idx.py +4 -1
- copyparty/up2k.py +221 -93
- copyparty/util.py +166 -31
- copyparty/web/a/u2c.py +10 -3
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser2.html +0 -1
- copyparty/web/md.html +3 -0
- copyparty/web/mde.html +3 -0
- copyparty/web/msg.html +3 -0
- copyparty/web/splash.html +3 -0
- copyparty/web/svcs.html +3 -0
- copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/METADATA +64 -14
- {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/RECORD +42 -42
- {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/LICENSE +0 -0
- {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/WHEEL +0 -0
- {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/entry_points.txt +0 -0
- {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/top_level.txt +0 -0
copyparty/httpcli.py
CHANGED
@@ -13,18 +13,22 @@ import json
|
|
13
13
|
import os
|
14
14
|
import random
|
15
15
|
import re
|
16
|
+
import socket
|
16
17
|
import stat
|
17
18
|
import string
|
18
19
|
import threading # typechk
|
19
20
|
import time
|
20
21
|
import uuid
|
21
22
|
from datetime import datetime
|
22
|
-
from email.utils import
|
23
|
+
from email.utils import parsedate
|
23
24
|
from operator import itemgetter
|
24
25
|
|
25
26
|
import jinja2 # typechk
|
26
27
|
|
27
28
|
try:
|
29
|
+
if os.environ.get("PRTY_NO_LZMA"):
|
30
|
+
raise Exception()
|
31
|
+
|
28
32
|
import lzma
|
29
33
|
except:
|
30
34
|
pass
|
@@ -54,6 +58,7 @@ from .util import (
|
|
54
58
|
alltrace,
|
55
59
|
atomic_move,
|
56
60
|
exclude_dotfiles,
|
61
|
+
formatdate,
|
57
62
|
fsenc,
|
58
63
|
gen_filekey,
|
59
64
|
gen_filekey_dbg,
|
@@ -69,7 +74,9 @@ from .util import (
|
|
69
74
|
humansize,
|
70
75
|
ipnorm,
|
71
76
|
loadpy,
|
77
|
+
log_reloc,
|
72
78
|
min_ex,
|
79
|
+
pathmod,
|
73
80
|
quotep,
|
74
81
|
rand_name,
|
75
82
|
read_header,
|
@@ -218,6 +225,11 @@ class HttpCli(object):
|
|
218
225
|
ka["s_doctitle"] = self.args.doctitle
|
219
226
|
ka["tcolor"] = self.vn.flags["tcolor"]
|
220
227
|
|
228
|
+
if self.args.js_other and "js" not in ka:
|
229
|
+
zs = self.args.js_other
|
230
|
+
zs += "&" if "?" in zs else "?"
|
231
|
+
ka["js"] = zs
|
232
|
+
|
221
233
|
zso = self.vn.flags.get("html_head")
|
222
234
|
if zso:
|
223
235
|
ka["this"] = self
|
@@ -299,8 +311,11 @@ class HttpCli(object):
|
|
299
311
|
)
|
300
312
|
self.host = self.headers.get("host") or ""
|
301
313
|
if not self.host:
|
302
|
-
|
303
|
-
|
314
|
+
if self.s.family == socket.AF_UNIX:
|
315
|
+
self.host = self.args.name
|
316
|
+
else:
|
317
|
+
zs = "%s:%s" % self.s.getsockname()[:2]
|
318
|
+
self.host = zs[7:] if zs.startswith("::ffff:") else zs
|
304
319
|
|
305
320
|
trusted_xff = False
|
306
321
|
n = self.args.rproxy
|
@@ -687,6 +702,9 @@ class HttpCli(object):
|
|
687
702
|
xban = self.vn.flags.get("xban")
|
688
703
|
if not xban or not runhook(
|
689
704
|
self.log,
|
705
|
+
self.conn.hsrv.broker,
|
706
|
+
None,
|
707
|
+
"xban",
|
690
708
|
xban,
|
691
709
|
self.vn.canonical(self.rem),
|
692
710
|
self.vpath,
|
@@ -783,7 +801,7 @@ class HttpCli(object):
|
|
783
801
|
|
784
802
|
# close if unknown length, otherwise take client's preference
|
785
803
|
response.append("Connection: " + ("Keep-Alive" if self.keepalive else "Close"))
|
786
|
-
response.append("Date: " + formatdate(
|
804
|
+
response.append("Date: " + formatdate())
|
787
805
|
|
788
806
|
# headers{} overrides anything set previously
|
789
807
|
if headers:
|
@@ -807,9 +825,9 @@ class HttpCli(object):
|
|
807
825
|
self.cbonk(self.conn.hsrv.gmal, zs, "cc_hdr", "Cc in out-hdr")
|
808
826
|
raise Pebkac(999)
|
809
827
|
|
828
|
+
response.append("\r\n")
|
810
829
|
try:
|
811
|
-
|
812
|
-
self.s.sendall("\r\n".join(response).encode("utf-8") + b"\r\n\r\n")
|
830
|
+
self.s.sendall("\r\n".join(response).encode("utf-8"))
|
813
831
|
except:
|
814
832
|
raise Pebkac(400, "client d/c while replying headers")
|
815
833
|
|
@@ -1142,7 +1160,7 @@ class HttpCli(object):
|
|
1142
1160
|
return self.tx_mounts()
|
1143
1161
|
|
1144
1162
|
# conditional redirect to single volumes
|
1145
|
-
if self.vpath
|
1163
|
+
if not self.vpath and not self.ouparam:
|
1146
1164
|
nread = len(self.rvol)
|
1147
1165
|
nwrite = len(self.wvol)
|
1148
1166
|
if nread + nwrite == 1 or (self.rvol == self.wvol and nread == 1):
|
@@ -1164,7 +1182,8 @@ class HttpCli(object):
|
|
1164
1182
|
if self.args.no_dav:
|
1165
1183
|
raise Pebkac(405, "WebDAV is disabled in server config")
|
1166
1184
|
|
1167
|
-
vn
|
1185
|
+
vn = self.vn
|
1186
|
+
rem = self.rem
|
1168
1187
|
tap = vn.canonical(rem)
|
1169
1188
|
|
1170
1189
|
if "davauth" in vn.flags and self.uname == "*":
|
@@ -1301,7 +1320,7 @@ class HttpCli(object):
|
|
1301
1320
|
|
1302
1321
|
pvs = {
|
1303
1322
|
"displayname": html_escape(rp.split("/")[-1]),
|
1304
|
-
"getlastmodified": formatdate(mtime
|
1323
|
+
"getlastmodified": formatdate(mtime),
|
1305
1324
|
"resourcetype": '<D:collection xmlns:D="DAV:"/>' if isdir else "",
|
1306
1325
|
"supportedlock": '<D:lockentry xmlns:D="DAV:"><D:lockscope><D:exclusive/></D:lockscope><D:locktype><D:write/></D:locktype></D:lockentry>',
|
1307
1326
|
}
|
@@ -1548,8 +1567,8 @@ class HttpCli(object):
|
|
1548
1567
|
self.log("PUT %s @%s" % (self.req, self.uname))
|
1549
1568
|
|
1550
1569
|
if not self.can_write:
|
1551
|
-
t = "user
|
1552
|
-
raise Pebkac(403, t
|
1570
|
+
t = "user %s does not have write-access under /%s"
|
1571
|
+
raise Pebkac(403, t % (self.uname, self.vn.vpath))
|
1553
1572
|
|
1554
1573
|
if not self.args.no_dav and self._applesan():
|
1555
1574
|
return self.headers.get("content-length") == "0"
|
@@ -1624,6 +1643,9 @@ class HttpCli(object):
|
|
1624
1643
|
if xm:
|
1625
1644
|
runhook(
|
1626
1645
|
self.log,
|
1646
|
+
self.conn.hsrv.broker,
|
1647
|
+
None,
|
1648
|
+
"xm",
|
1627
1649
|
xm,
|
1628
1650
|
self.vn.canonical(self.rem),
|
1629
1651
|
self.vpath,
|
@@ -1772,11 +1794,15 @@ class HttpCli(object):
|
|
1772
1794
|
|
1773
1795
|
if xbu:
|
1774
1796
|
at = time.time() - lifetime
|
1775
|
-
if
|
1797
|
+
vp = vjoin(self.vpath, fn) if nameless else self.vpath
|
1798
|
+
hr = runhook(
|
1776
1799
|
self.log,
|
1800
|
+
self.conn.hsrv.broker,
|
1801
|
+
None,
|
1802
|
+
"xbu.http.dump",
|
1777
1803
|
xbu,
|
1778
1804
|
path,
|
1779
|
-
|
1805
|
+
vp,
|
1780
1806
|
self.host,
|
1781
1807
|
self.uname,
|
1782
1808
|
self.asrv.vfs.get_perms(self.vpath, self.uname),
|
@@ -1785,10 +1811,25 @@ class HttpCli(object):
|
|
1785
1811
|
self.ip,
|
1786
1812
|
at,
|
1787
1813
|
"",
|
1788
|
-
)
|
1814
|
+
)
|
1815
|
+
if not hr:
|
1789
1816
|
t = "upload blocked by xbu server config"
|
1790
1817
|
self.log(t, 1)
|
1791
1818
|
raise Pebkac(403, t)
|
1819
|
+
if hr.get("reloc"):
|
1820
|
+
x = pathmod(self.asrv.vfs, path, vp, hr["reloc"])
|
1821
|
+
if x:
|
1822
|
+
if self.args.hook_v:
|
1823
|
+
log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
|
1824
|
+
fdir, self.vpath, fn, (vfs, rem) = x
|
1825
|
+
if self.args.nw:
|
1826
|
+
fn = os.devnull
|
1827
|
+
else:
|
1828
|
+
bos.makedirs(fdir)
|
1829
|
+
path = os.path.join(fdir, fn)
|
1830
|
+
if not nameless:
|
1831
|
+
self.vpath = vjoin(self.vpath, fn)
|
1832
|
+
params["fdir"] = fdir
|
1792
1833
|
|
1793
1834
|
if is_put and not (self.args.no_dav or self.args.nw) and bos.path.exists(path):
|
1794
1835
|
# allow overwrite if...
|
@@ -1863,24 +1904,45 @@ class HttpCli(object):
|
|
1863
1904
|
fn = fn2
|
1864
1905
|
path = path2
|
1865
1906
|
|
1866
|
-
if xau
|
1867
|
-
self.
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1907
|
+
if xau:
|
1908
|
+
vp = vjoin(self.vpath, fn) if nameless else self.vpath
|
1909
|
+
hr = runhook(
|
1910
|
+
self.log,
|
1911
|
+
self.conn.hsrv.broker,
|
1912
|
+
None,
|
1913
|
+
"xau.http.dump",
|
1914
|
+
xau,
|
1915
|
+
path,
|
1916
|
+
vp,
|
1917
|
+
self.host,
|
1918
|
+
self.uname,
|
1919
|
+
self.asrv.vfs.get_perms(self.vpath, self.uname),
|
1920
|
+
mt,
|
1921
|
+
post_sz,
|
1922
|
+
self.ip,
|
1923
|
+
at,
|
1924
|
+
"",
|
1925
|
+
)
|
1926
|
+
if not hr:
|
1927
|
+
t = "upload blocked by xau server config"
|
1928
|
+
self.log(t, 1)
|
1929
|
+
wunlink(self.log, path, vfs.flags)
|
1930
|
+
raise Pebkac(403, t)
|
1931
|
+
if hr.get("reloc"):
|
1932
|
+
x = pathmod(self.asrv.vfs, path, vp, hr["reloc"])
|
1933
|
+
if x:
|
1934
|
+
if self.args.hook_v:
|
1935
|
+
log_reloc(self.log, hr["reloc"], x, path, vp, fn, vfs, rem)
|
1936
|
+
fdir, self.vpath, fn, (vfs, rem) = x
|
1937
|
+
bos.makedirs(fdir)
|
1938
|
+
path2 = os.path.join(fdir, fn)
|
1939
|
+
atomic_move(self.log, path, path2, vfs.flags)
|
1940
|
+
path = path2
|
1941
|
+
if not nameless:
|
1942
|
+
self.vpath = vjoin(self.vpath, fn)
|
1943
|
+
sz = bos.path.getsize(path)
|
1944
|
+
else:
|
1945
|
+
sz = post_sz
|
1884
1946
|
|
1885
1947
|
vfs, rem = vfs.get_dbv(rem)
|
1886
1948
|
self.conn.hsrv.broker.say(
|
@@ -1903,7 +1965,7 @@ class HttpCli(object):
|
|
1903
1965
|
alg,
|
1904
1966
|
self.args.fk_salt,
|
1905
1967
|
path,
|
1906
|
-
|
1968
|
+
sz,
|
1907
1969
|
0 if ANYWIN else bos.stat(path).st_ino,
|
1908
1970
|
)[: vfs.flags["fk"]]
|
1909
1971
|
|
@@ -2206,13 +2268,21 @@ class HttpCli(object):
|
|
2206
2268
|
raise Pebkac(400, "need hash and wark headers for binary POST")
|
2207
2269
|
|
2208
2270
|
chashes = [x.strip() for x in chashes]
|
2271
|
+
if len(chashes) == 3 and len(chashes[1]) == 1:
|
2272
|
+
# the first hash, then length of consecutive hashes,
|
2273
|
+
# then a list of stitched hashes as one long string
|
2274
|
+
clen = int(chashes[1])
|
2275
|
+
siblings = chashes[2]
|
2276
|
+
chashes = [chashes[0]]
|
2277
|
+
for n in range(0, len(siblings), clen):
|
2278
|
+
chashes.append(siblings[n : n + clen])
|
2209
2279
|
|
2210
2280
|
vfs, _ = self.asrv.vfs.get(self.vpath, self.uname, False, True)
|
2211
2281
|
ptop = (vfs.dbv or vfs).realpath
|
2212
2282
|
|
2213
2283
|
x = self.conn.hsrv.broker.ask("up2k.handle_chunks", ptop, wark, chashes)
|
2214
2284
|
response = x.get()
|
2215
|
-
chunksize, cstarts, path, lastmod, sprs = response
|
2285
|
+
chashes, chunksize, cstarts, path, lastmod, sprs = response
|
2216
2286
|
maxsize = chunksize * len(chashes)
|
2217
2287
|
cstart0 = cstarts[0]
|
2218
2288
|
|
@@ -2520,18 +2590,15 @@ class HttpCli(object):
|
|
2520
2590
|
fname = sanitize_fn(
|
2521
2591
|
p_file or "", "", [".prologue.html", ".epilogue.html"]
|
2522
2592
|
)
|
2593
|
+
abspath = os.path.join(fdir, fname)
|
2594
|
+
suffix = "-%.6f-%s" % (time.time(), dip)
|
2523
2595
|
if p_file and not nullwrite:
|
2524
2596
|
if rnd:
|
2525
2597
|
fname = rand_name(fdir, fname, rnd)
|
2526
2598
|
|
2527
|
-
if not bos.path.isdir(fdir):
|
2528
|
-
raise Pebkac(404, "that folder does not exist")
|
2529
|
-
|
2530
|
-
suffix = "-{:.6f}-{}".format(time.time(), dip)
|
2531
2599
|
open_args = {"fdir": fdir, "suffix": suffix}
|
2532
2600
|
|
2533
2601
|
if "replace" in self.uparam:
|
2534
|
-
abspath = os.path.join(fdir, fname)
|
2535
2602
|
if not self.can_delete:
|
2536
2603
|
self.log("user not allowed to overwrite with ?replace")
|
2537
2604
|
elif bos.path.exists(abspath):
|
@@ -2541,16 +2608,6 @@ class HttpCli(object):
|
|
2541
2608
|
except:
|
2542
2609
|
t = "toctou while deleting for ?replace: %s"
|
2543
2610
|
self.log(t % (abspath,))
|
2544
|
-
|
2545
|
-
# reserve destination filename
|
2546
|
-
with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw:
|
2547
|
-
fname = zfw["orz"][1]
|
2548
|
-
|
2549
|
-
tnam = fname + ".PARTIAL"
|
2550
|
-
if self.args.dotpart:
|
2551
|
-
tnam = "." + tnam
|
2552
|
-
|
2553
|
-
abspath = os.path.join(fdir, fname)
|
2554
2611
|
else:
|
2555
2612
|
open_args = {}
|
2556
2613
|
tnam = fname = os.devnull
|
@@ -2558,23 +2615,65 @@ class HttpCli(object):
|
|
2558
2615
|
|
2559
2616
|
if xbu:
|
2560
2617
|
at = time.time() - lifetime
|
2561
|
-
|
2618
|
+
hr = runhook(
|
2562
2619
|
self.log,
|
2620
|
+
self.conn.hsrv.broker,
|
2621
|
+
None,
|
2622
|
+
"xbu.http.bup",
|
2563
2623
|
xbu,
|
2564
2624
|
abspath,
|
2565
|
-
|
2625
|
+
vjoin(upload_vpath, fname),
|
2566
2626
|
self.host,
|
2567
2627
|
self.uname,
|
2568
|
-
self.asrv.vfs.get_perms(
|
2628
|
+
self.asrv.vfs.get_perms(upload_vpath, self.uname),
|
2569
2629
|
at,
|
2570
2630
|
0,
|
2571
2631
|
self.ip,
|
2572
2632
|
at,
|
2573
2633
|
"",
|
2574
|
-
)
|
2634
|
+
)
|
2635
|
+
if not hr:
|
2575
2636
|
t = "upload blocked by xbu server config"
|
2576
2637
|
self.log(t, 1)
|
2577
2638
|
raise Pebkac(403, t)
|
2639
|
+
if hr.get("reloc"):
|
2640
|
+
zs = vjoin(upload_vpath, fname)
|
2641
|
+
x = pathmod(self.asrv.vfs, abspath, zs, hr["reloc"])
|
2642
|
+
if x:
|
2643
|
+
if self.args.hook_v:
|
2644
|
+
log_reloc(
|
2645
|
+
self.log,
|
2646
|
+
hr["reloc"],
|
2647
|
+
x,
|
2648
|
+
abspath,
|
2649
|
+
zs,
|
2650
|
+
fname,
|
2651
|
+
vfs,
|
2652
|
+
rem,
|
2653
|
+
)
|
2654
|
+
fdir, upload_vpath, fname, (vfs, rem) = x
|
2655
|
+
abspath = os.path.join(fdir, fname)
|
2656
|
+
if nullwrite:
|
2657
|
+
fdir = abspath = ""
|
2658
|
+
else:
|
2659
|
+
open_args["fdir"] = fdir
|
2660
|
+
|
2661
|
+
if p_file and not nullwrite:
|
2662
|
+
bos.makedirs(fdir)
|
2663
|
+
|
2664
|
+
# reserve destination filename
|
2665
|
+
with ren_open(fname, "wb", fdir=fdir, suffix=suffix) as zfw:
|
2666
|
+
fname = zfw["orz"][1]
|
2667
|
+
|
2668
|
+
tnam = fname + ".PARTIAL"
|
2669
|
+
if self.args.dotpart:
|
2670
|
+
tnam = "." + tnam
|
2671
|
+
|
2672
|
+
abspath = os.path.join(fdir, fname)
|
2673
|
+
else:
|
2674
|
+
open_args = {}
|
2675
|
+
tnam = fname = os.devnull
|
2676
|
+
fdir = abspath = ""
|
2578
2677
|
|
2579
2678
|
if lim:
|
2580
2679
|
lim.chk_bup(self.ip)
|
@@ -2618,29 +2717,58 @@ class HttpCli(object):
|
|
2618
2717
|
|
2619
2718
|
tabspath = ""
|
2620
2719
|
|
2720
|
+
at = time.time() - lifetime
|
2721
|
+
if xau:
|
2722
|
+
hr = runhook(
|
2723
|
+
self.log,
|
2724
|
+
self.conn.hsrv.broker,
|
2725
|
+
None,
|
2726
|
+
"xau.http.bup",
|
2727
|
+
xau,
|
2728
|
+
abspath,
|
2729
|
+
vjoin(upload_vpath, fname),
|
2730
|
+
self.host,
|
2731
|
+
self.uname,
|
2732
|
+
self.asrv.vfs.get_perms(upload_vpath, self.uname),
|
2733
|
+
at,
|
2734
|
+
sz,
|
2735
|
+
self.ip,
|
2736
|
+
at,
|
2737
|
+
"",
|
2738
|
+
)
|
2739
|
+
if not hr:
|
2740
|
+
t = "upload blocked by xau server config"
|
2741
|
+
self.log(t, 1)
|
2742
|
+
wunlink(self.log, abspath, vfs.flags)
|
2743
|
+
raise Pebkac(403, t)
|
2744
|
+
if hr.get("reloc"):
|
2745
|
+
zs = vjoin(upload_vpath, fname)
|
2746
|
+
x = pathmod(self.asrv.vfs, abspath, zs, hr["reloc"])
|
2747
|
+
if x:
|
2748
|
+
if self.args.hook_v:
|
2749
|
+
log_reloc(
|
2750
|
+
self.log,
|
2751
|
+
hr["reloc"],
|
2752
|
+
x,
|
2753
|
+
abspath,
|
2754
|
+
zs,
|
2755
|
+
fname,
|
2756
|
+
vfs,
|
2757
|
+
rem,
|
2758
|
+
)
|
2759
|
+
fdir, upload_vpath, fname, (vfs, rem) = x
|
2760
|
+
ap2 = os.path.join(fdir, fname)
|
2761
|
+
if nullwrite:
|
2762
|
+
fdir = ap2 = ""
|
2763
|
+
else:
|
2764
|
+
bos.makedirs(fdir)
|
2765
|
+
atomic_move(self.log, abspath, ap2, vfs.flags)
|
2766
|
+
abspath = ap2
|
2767
|
+
sz = bos.path.getsize(abspath)
|
2768
|
+
|
2621
2769
|
files.append(
|
2622
2770
|
(sz, sha_hex, sha_b64, p_file or "(discarded)", fname, abspath)
|
2623
2771
|
)
|
2624
|
-
at = time.time() - lifetime
|
2625
|
-
if xau and not runhook(
|
2626
|
-
self.log,
|
2627
|
-
xau,
|
2628
|
-
abspath,
|
2629
|
-
self.vpath,
|
2630
|
-
self.host,
|
2631
|
-
self.uname,
|
2632
|
-
self.asrv.vfs.get_perms(self.vpath, self.uname),
|
2633
|
-
at,
|
2634
|
-
sz,
|
2635
|
-
self.ip,
|
2636
|
-
at,
|
2637
|
-
"",
|
2638
|
-
):
|
2639
|
-
t = "upload blocked by xau server config"
|
2640
|
-
self.log(t, 1)
|
2641
|
-
wunlink(self.log, abspath, vfs.flags)
|
2642
|
-
raise Pebkac(403, t)
|
2643
|
-
|
2644
2772
|
dbv, vrem = vfs.get_dbv(rem)
|
2645
2773
|
self.conn.hsrv.broker.say(
|
2646
2774
|
"up2k.hash_file",
|
@@ -2696,13 +2824,14 @@ class HttpCli(object):
|
|
2696
2824
|
for sz, sha_hex, sha_b64, ofn, lfn, ap in files:
|
2697
2825
|
vsuf = ""
|
2698
2826
|
if (self.can_read or self.can_upget) and "fk" in vfs.flags:
|
2827
|
+
st = bos.stat(ap)
|
2699
2828
|
alg = 2 if "fka" in vfs.flags else 1
|
2700
2829
|
vsuf = "?k=" + self.gen_fk(
|
2701
2830
|
alg,
|
2702
2831
|
self.args.fk_salt,
|
2703
2832
|
ap,
|
2704
|
-
|
2705
|
-
0 if ANYWIN or not ap else
|
2833
|
+
st.st_size,
|
2834
|
+
0 if ANYWIN or not ap else st.st_ino,
|
2706
2835
|
)[: vfs.flags["fk"]]
|
2707
2836
|
|
2708
2837
|
if "media" in self.uparam or "medialinks" in vfs.flags:
|
@@ -2869,6 +2998,9 @@ class HttpCli(object):
|
|
2869
2998
|
if xbu:
|
2870
2999
|
if not runhook(
|
2871
3000
|
self.log,
|
3001
|
+
self.conn.hsrv.broker,
|
3002
|
+
None,
|
3003
|
+
"xbu.http.txt",
|
2872
3004
|
xbu,
|
2873
3005
|
fp,
|
2874
3006
|
self.vpath,
|
@@ -2908,6 +3040,9 @@ class HttpCli(object):
|
|
2908
3040
|
xau = vfs.flags.get("xau")
|
2909
3041
|
if xau and not runhook(
|
2910
3042
|
self.log,
|
3043
|
+
self.conn.hsrv.broker,
|
3044
|
+
None,
|
3045
|
+
"xau.http.txt",
|
2911
3046
|
xau,
|
2912
3047
|
fp,
|
2913
3048
|
self.vpath,
|
@@ -2948,7 +3083,7 @@ class HttpCli(object):
|
|
2948
3083
|
return True
|
2949
3084
|
|
2950
3085
|
def _chk_lastmod(self, file_ts ) :
|
2951
|
-
file_lastmod = formatdate(file_ts
|
3086
|
+
file_lastmod = formatdate(file_ts)
|
2952
3087
|
cli_lastmod = self.headers.get("if-modified-since")
|
2953
3088
|
if cli_lastmod:
|
2954
3089
|
try:
|
@@ -3030,8 +3165,8 @@ class HttpCli(object):
|
|
3030
3165
|
for n, fn in enumerate([".prologue.html", ".epilogue.html"]):
|
3031
3166
|
if lnames is not None and fn not in lnames:
|
3032
3167
|
continue
|
3033
|
-
fn =
|
3034
|
-
if bos.path.
|
3168
|
+
fn = "%s/%s" % (abspath, fn)
|
3169
|
+
if bos.path.isfile(fn):
|
3035
3170
|
with open(fsenc(fn), "rb") as f:
|
3036
3171
|
logues[n] = f.read().decode("utf-8")
|
3037
3172
|
if "exp" in vn.flags:
|
@@ -3049,7 +3184,7 @@ class HttpCli(object):
|
|
3049
3184
|
fns = []
|
3050
3185
|
|
3051
3186
|
for fn in fns:
|
3052
|
-
fn =
|
3187
|
+
fn = "%s/%s" % (abspath, fn)
|
3053
3188
|
if bos.path.isfile(fn):
|
3054
3189
|
with open(fsenc(fn), "rb") as f:
|
3055
3190
|
readme = f.read().decode("utf-8")
|
@@ -3584,7 +3719,7 @@ class HttpCli(object):
|
|
3584
3719
|
# (useragent-sniffing kinshi due to caching proxies)
|
3585
3720
|
mime, ico = self.ico.get(txt, not small, "raster" in self.uparam)
|
3586
3721
|
|
3587
|
-
lm = formatdate(self.E.t0
|
3722
|
+
lm = formatdate(self.E.t0)
|
3588
3723
|
self.reply(ico, mime=mime, headers={"Last-Modified": lm})
|
3589
3724
|
return True
|
3590
3725
|
|
@@ -3663,6 +3798,11 @@ class HttpCli(object):
|
|
3663
3798
|
"arg_base": arg_base,
|
3664
3799
|
}
|
3665
3800
|
|
3801
|
+
if self.args.js_other and "js" not in targs:
|
3802
|
+
zs = self.args.js_other
|
3803
|
+
zs += "&" if "?" in zs else "?"
|
3804
|
+
targs["js"] = zs
|
3805
|
+
|
3666
3806
|
zfv = self.vn.flags.get("html_head")
|
3667
3807
|
if zfv:
|
3668
3808
|
targs["this"] = self
|
@@ -4140,7 +4280,7 @@ class HttpCli(object):
|
|
4140
4280
|
if self.args.no_mv:
|
4141
4281
|
raise Pebkac(403, "the rename/move feature is disabled in server config")
|
4142
4282
|
|
4143
|
-
x = self.conn.hsrv.broker.ask("up2k.handle_mv", self.uname, vsrc, vdst)
|
4283
|
+
x = self.conn.hsrv.broker.ask("up2k.handle_mv", self.uname, self.ip, vsrc, vdst)
|
4144
4284
|
self.loud_reply(x.get(), status=201)
|
4145
4285
|
return True
|
4146
4286
|
|
copyparty/httpconn.py
CHANGED
copyparty/httpsrv.py
CHANGED
@@ -12,7 +12,7 @@ import time
|
|
12
12
|
|
13
13
|
import queue
|
14
14
|
|
15
|
-
from .__init__ import ANYWIN, CORES, EXE, MACOS, TYPE_CHECKING, EnvParams, unicode
|
15
|
+
from .__init__ import ANYWIN, CORES, EXE, MACOS, PY2, TYPE_CHECKING, EnvParams, unicode
|
16
16
|
|
17
17
|
try:
|
18
18
|
MNFE = ModuleNotFoundError
|
@@ -81,6 +81,10 @@ if TYPE_CHECKING:
|
|
81
81
|
from .broker_util import BrokerCli
|
82
82
|
from .ssdp import SSDPr
|
83
83
|
|
84
|
+
if PY2:
|
85
|
+
range = xrange # type: ignore
|
86
|
+
|
87
|
+
|
84
88
|
class HttpSrv(object):
|
85
89
|
"""
|
86
90
|
handles incoming connections using HttpConn to process http,
|
@@ -236,15 +240,24 @@ class HttpSrv(object):
|
|
236
240
|
return
|
237
241
|
|
238
242
|
def listen(self, sck , nlisteners ) :
|
243
|
+
tcp = sck.family != socket.AF_UNIX
|
244
|
+
|
239
245
|
if self.args.j != 1:
|
240
246
|
# lost in the pickle; redefine
|
241
247
|
if not ANYWIN or self.args.reuseaddr:
|
242
248
|
sck.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
243
249
|
|
244
|
-
|
250
|
+
if tcp:
|
251
|
+
sck.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
252
|
+
|
245
253
|
sck.settimeout(None) # < does not inherit, ^ opts above do
|
246
254
|
|
247
|
-
|
255
|
+
if tcp:
|
256
|
+
ip, port = sck.getsockname()[:2]
|
257
|
+
else:
|
258
|
+
ip = re.sub(r"\.[0-9]+$", "", sck.getsockname().split("/")[-1])
|
259
|
+
port = 0
|
260
|
+
|
248
261
|
self.srvs.append(sck)
|
249
262
|
self.bound.add((ip, port))
|
250
263
|
self.nclimax = math.ceil(self.args.nc * 1.0 / nlisteners)
|
@@ -256,10 +269,19 @@ class HttpSrv(object):
|
|
256
269
|
|
257
270
|
def thr_listen(self, srv_sck ) :
|
258
271
|
"""listens on a shared tcp server"""
|
259
|
-
ip, port = srv_sck.getsockname()[:2]
|
260
272
|
fno = srv_sck.fileno()
|
261
|
-
|
262
|
-
|
273
|
+
if srv_sck.family == socket.AF_UNIX:
|
274
|
+
ip = re.sub(r"\.[0-9]+$", "", srv_sck.getsockname())
|
275
|
+
msg = "subscribed @ %s f%d p%d" % (ip, fno, os.getpid())
|
276
|
+
ip = ip.split("/")[-1]
|
277
|
+
port = 0
|
278
|
+
tcp = False
|
279
|
+
else:
|
280
|
+
tcp = True
|
281
|
+
ip, port = srv_sck.getsockname()[:2]
|
282
|
+
hip = "[%s]" % (ip,) if ":" in ip else ip
|
283
|
+
msg = "subscribed @ %s:%d f%d p%d" % (hip, port, fno, os.getpid())
|
284
|
+
|
263
285
|
self.log(self.name, msg)
|
264
286
|
|
265
287
|
Daemon(self.broker.say, "sig-hsrv-up1", ("cb_httpsrv_up",))
|
@@ -331,11 +353,13 @@ class HttpSrv(object):
|
|
331
353
|
|
332
354
|
try:
|
333
355
|
sck, saddr = srv_sck.accept()
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
356
|
+
if tcp:
|
357
|
+
cip = unicode(saddr[0])
|
358
|
+
if cip.startswith("::ffff:"):
|
359
|
+
cip = cip[7:]
|
360
|
+
addr = (cip, saddr[1])
|
361
|
+
else:
|
362
|
+
addr = (ip, sck.fileno())
|
339
363
|
except (OSError, socket.error) as ex:
|
340
364
|
if self.stopping:
|
341
365
|
break
|