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.
Files changed (42) hide show
  1. copyparty/__main__.py +25 -7
  2. copyparty/__version__.py +2 -2
  3. copyparty/authsrv.py +9 -6
  4. copyparty/cert.py +1 -1
  5. copyparty/fsutil.py +3 -3
  6. copyparty/ftpd.py +15 -2
  7. copyparty/httpcli.py +221 -81
  8. copyparty/httpconn.py +3 -0
  9. copyparty/httpsrv.py +35 -11
  10. copyparty/ico.py +1 -1
  11. copyparty/mtag.py +15 -6
  12. copyparty/pwhash.py +10 -0
  13. copyparty/smbd.py +20 -2
  14. copyparty/ssdp.py +3 -3
  15. copyparty/stolen/dnslib/dns.py +6 -0
  16. copyparty/stolen/ifaddr/__init__.py +15 -1
  17. copyparty/stolen/ifaddr/_shared.py +1 -0
  18. copyparty/stolen/qrcodegen.py +6 -0
  19. copyparty/sutil.py +1 -1
  20. copyparty/svchub.py +72 -3
  21. copyparty/szip.py +1 -3
  22. copyparty/tcpsrv.py +60 -8
  23. copyparty/tftpd.py +30 -4
  24. copyparty/th_srv.py +22 -1
  25. copyparty/u2idx.py +4 -1
  26. copyparty/up2k.py +221 -93
  27. copyparty/util.py +166 -31
  28. copyparty/web/a/u2c.py +10 -3
  29. copyparty/web/browser.css.gz +0 -0
  30. copyparty/web/browser2.html +0 -1
  31. copyparty/web/md.html +3 -0
  32. copyparty/web/mde.html +3 -0
  33. copyparty/web/msg.html +3 -0
  34. copyparty/web/splash.html +3 -0
  35. copyparty/web/svcs.html +3 -0
  36. copyparty/web/up2k.js.gz +0 -0
  37. {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/METADATA +64 -14
  38. {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/RECORD +42 -42
  39. {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/LICENSE +0 -0
  40. {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/WHEEL +0 -0
  41. {copyparty-1.13.6.dist-info → copyparty-1.13.7.dist-info}/entry_points.txt +0 -0
  42. {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 formatdate, parsedate
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
- zs = "%s:%s" % self.s.getsockname()[:2]
303
- self.host = zs[7:] if zs.startswith("::ffff:") else zs
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(usegmt=True))
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
- # best practice to separate headers and body into different packets
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 == "" and not self.ouparam:
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, rem = self.asrv.vfs.get(self.vpath, self.uname, False, False, err=401)
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, usegmt=True),
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 {} does not have write-access here"
1552
- raise Pebkac(403, t.format(self.uname))
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 not runhook(
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
- self.vpath,
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 and not runhook(
1867
- self.log,
1868
- xau,
1869
- path,
1870
- self.vpath,
1871
- self.host,
1872
- self.uname,
1873
- self.asrv.vfs.get_perms(self.vpath, self.uname),
1874
- mt,
1875
- post_sz,
1876
- self.ip,
1877
- at,
1878
- "",
1879
- ):
1880
- t = "upload blocked by xau server config"
1881
- self.log(t, 1)
1882
- wunlink(self.log, path, vfs.flags)
1883
- raise Pebkac(403, t)
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
- post_sz,
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
- if not runhook(
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
- self.vpath,
2625
+ vjoin(upload_vpath, fname),
2566
2626
  self.host,
2567
2627
  self.uname,
2568
- self.asrv.vfs.get_perms(self.vpath, self.uname),
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
- sz,
2705
- 0 if ANYWIN or not ap else bos.stat(ap).st_ino,
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, usegmt=True)
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 = os.path.join(abspath, fn)
3034
- if bos.path.exists(fn):
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 = os.path.join(abspath, 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, usegmt=True)
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
@@ -9,6 +9,9 @@ import threading # typechk
9
9
  import time
10
10
 
11
11
  try:
12
+ if os.environ.get("PRTY_NO_TLS"):
13
+ raise Exception()
14
+
12
15
  HAVE_SSL = True
13
16
  import ssl
14
17
  except:
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
- sck.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
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
- ip, port = sck.getsockname()[:2]
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
- hip = "[{}]".format(ip) if ":" in ip else ip
262
- msg = "subscribed @ {}:{} f{} p{}".format(hip, port, fno, os.getpid())
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
- cip = unicode(saddr[0])
335
- if cip.startswith("::ffff:"):
336
- cip = cip[7:]
337
-
338
- addr = (cip, saddr[1])
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
copyparty/ico.py CHANGED
@@ -74,7 +74,7 @@ class Ico(object):
74
74
  try:
75
75
  _, _, tw, th = pb.textbbox((0, 0), ext)
76
76
  except:
77
- tw, th = pb.textsize(ext)
77
+ tw, th = pb.textsize(ext) # type: ignore
78
78
 
79
79
  tw += len(ext)
80
80
  cw = tw // len(ext)