2023-08-20 17:58:06 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
# coding: utf-8
|
|
|
|
|
from __future__ import print_function, unicode_literals
|
|
|
|
|
|
2021-04-24 02:48:41 +02:00
|
|
|
import os
|
2024-09-15 13:18:43 +00:00
|
|
|
import random
|
2023-07-23 15:43:38 +00:00
|
|
|
import re
|
2021-06-01 05:49:41 +02:00
|
|
|
import shutil
|
2024-08-12 21:58:02 +00:00
|
|
|
import socket
|
2021-04-24 02:48:41 +02:00
|
|
|
import subprocess as sp
|
2023-11-30 17:33:07 +00:00
|
|
|
import sys
|
|
|
|
|
import tempfile
|
|
|
|
|
import threading
|
|
|
|
|
import time
|
2024-12-01 14:44:41 +00:00
|
|
|
import unittest
|
2022-07-27 00:15:49 +02:00
|
|
|
from argparse import Namespace
|
2021-04-24 02:48:41 +02:00
|
|
|
|
2023-11-30 17:33:07 +00:00
|
|
|
import jinja2
|
2021-04-24 02:48:41 +02:00
|
|
|
|
2024-08-30 22:06:25 +00:00
|
|
|
from copyparty.__init__ import MACOS, WINDOWS, E
|
2021-04-24 02:48:41 +02:00
|
|
|
|
2023-11-30 17:33:07 +00:00
|
|
|
J2_ENV = jinja2.Environment(loader=jinja2.BaseLoader) # type: ignore
|
2023-09-11 01:46:25 +00:00
|
|
|
J2_FILES = J2_ENV.from_string("{{ files|join('\n') }}\nJ2EOT")
|
2021-04-24 02:48:41 +02:00
|
|
|
|
|
|
|
|
|
2021-06-04 19:35:08 +02:00
|
|
|
def nah(*a, **ka):
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
2023-08-20 17:58:06 +00:00
|
|
|
def eprint(*a, **ka):
|
|
|
|
|
ka["file"] = sys.stderr
|
|
|
|
|
print(*a, **ka)
|
|
|
|
|
sys.stderr.flush()
|
|
|
|
|
|
|
|
|
|
|
2022-09-18 00:16:40 +02:00
|
|
|
from copyparty.__main__ import init_E
|
2024-08-30 22:06:25 +00:00
|
|
|
from copyparty.broker_thr import BrokerThr
|
2024-06-16 21:35:43 +02:00
|
|
|
from copyparty.ico import Ico
|
2023-12-16 15:38:48 +00:00
|
|
|
from copyparty.u2idx import U2idx
|
2024-08-30 22:06:25 +00:00
|
|
|
from copyparty.up2k import Up2k
|
2024-04-20 20:13:31 +00:00
|
|
|
from copyparty.util import FHC, CachedDict, Garda, Unrecv
|
2021-06-04 19:35:08 +02:00
|
|
|
|
2022-09-18 00:16:40 +02:00
|
|
|
init_E(E)
|
|
|
|
|
|
2021-06-04 19:35:08 +02:00
|
|
|
|
2024-09-15 13:18:43 +00:00
|
|
|
def randbytes(n):
|
|
|
|
|
return random.getrandbits(n * 8).to_bytes(n, "little")
|
|
|
|
|
|
|
|
|
|
|
2021-07-28 01:18:38 +02:00
|
|
|
def runcmd(argv):
|
2021-04-24 02:48:41 +02:00
|
|
|
p = sp.Popen(argv, stdout=sp.PIPE, stderr=sp.PIPE)
|
|
|
|
|
stdout, stderr = p.communicate()
|
|
|
|
|
stdout = stdout.decode("utf-8")
|
|
|
|
|
stderr = stderr.decode("utf-8")
|
|
|
|
|
return [p.returncode, stdout, stderr]
|
|
|
|
|
|
|
|
|
|
|
2021-07-28 01:18:38 +02:00
|
|
|
def chkcmd(argv):
|
|
|
|
|
ok, sout, serr = runcmd(argv)
|
2021-04-24 02:48:41 +02:00
|
|
|
if ok != 0:
|
|
|
|
|
raise Exception(serr)
|
|
|
|
|
|
|
|
|
|
return sout, serr
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_ramdisk():
|
2021-06-01 05:49:41 +02:00
|
|
|
def subdir(top):
|
2024-08-11 14:52:32 +00:00
|
|
|
for d in os.listdir(top):
|
|
|
|
|
if not d.startswith("cptd-"):
|
|
|
|
|
continue
|
|
|
|
|
p = os.path.join(top, d)
|
|
|
|
|
st = os.stat(p)
|
|
|
|
|
if time.time() - st.st_mtime > 300:
|
|
|
|
|
shutil.rmtree(p)
|
2021-06-01 05:49:41 +02:00
|
|
|
ret = os.path.join(top, "cptd-{}".format(os.getpid()))
|
|
|
|
|
shutil.rmtree(ret, True)
|
|
|
|
|
os.mkdir(ret)
|
|
|
|
|
return ret
|
|
|
|
|
|
2021-04-24 02:48:41 +02:00
|
|
|
for vol in ["/dev/shm", "/Volumes/cptd"]: # nosec (singleton test)
|
|
|
|
|
if os.path.exists(vol):
|
2021-06-01 05:49:41 +02:00
|
|
|
return subdir(vol)
|
2021-04-24 02:48:41 +02:00
|
|
|
|
|
|
|
|
if os.path.exists("/Volumes"):
|
2025-05-16 12:28:34 +02:00
|
|
|
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
|
|
|
while True:
|
|
|
|
|
try:
|
|
|
|
|
sck.bind(("127.0.0.1", 2775))
|
|
|
|
|
break
|
|
|
|
|
except:
|
|
|
|
|
print("waiting for 2775")
|
|
|
|
|
time.sleep(0.5)
|
|
|
|
|
|
|
|
|
|
v = "/Volumes/cptd"
|
|
|
|
|
if os.path.exists(v):
|
|
|
|
|
return subdir(v)
|
|
|
|
|
|
2021-06-01 05:49:41 +02:00
|
|
|
# hdiutil eject /Volumes/cptd/
|
2021-07-28 01:18:38 +02:00
|
|
|
devname, _ = chkcmd("hdiutil attach -nomount ram://131072".split())
|
2021-04-24 02:48:41 +02:00
|
|
|
devname = devname.strip()
|
|
|
|
|
print("devname: [{}]".format(devname))
|
|
|
|
|
for _ in range(10):
|
|
|
|
|
try:
|
2021-07-28 01:18:38 +02:00
|
|
|
_, _ = chkcmd(["diskutil", "eraseVolume", "HFS+", "cptd", devname])
|
2023-11-30 17:33:07 +00:00
|
|
|
with open("/Volumes/cptd/.metadata_never_index", "wb") as f:
|
|
|
|
|
f.write(b"orz")
|
2021-07-17 16:43:22 +02:00
|
|
|
|
2021-07-17 16:45:25 +02:00
|
|
|
try:
|
|
|
|
|
shutil.rmtree("/Volumes/cptd/.fseventsd")
|
|
|
|
|
except:
|
|
|
|
|
pass
|
|
|
|
|
|
2025-05-16 12:28:34 +02:00
|
|
|
sck.close()
|
2021-06-01 05:49:41 +02:00
|
|
|
return subdir("/Volumes/cptd")
|
2021-04-24 02:48:41 +02:00
|
|
|
except Exception as ex:
|
|
|
|
|
print(repr(ex))
|
|
|
|
|
time.sleep(0.25)
|
|
|
|
|
|
|
|
|
|
raise Exception("ramdisk creation failed")
|
|
|
|
|
|
|
|
|
|
ret = os.path.join(tempfile.gettempdir(), "copyparty-test")
|
2023-11-30 17:33:07 +00:00
|
|
|
if not os.path.isdir(ret):
|
2021-04-24 02:48:41 +02:00
|
|
|
os.mkdir(ret)
|
2023-11-30 17:33:07 +00:00
|
|
|
|
|
|
|
|
return subdir(ret)
|
2021-04-24 02:48:41 +02:00
|
|
|
|
|
|
|
|
|
2024-12-01 14:44:41 +00:00
|
|
|
def pfind2ls(xml):
|
|
|
|
|
return [x.split("<", 1)[0] for x in xml.split("<D:href>")[1:]]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class TC(unittest.TestCase):
|
|
|
|
|
def __init__(self, *a, **ka):
|
|
|
|
|
super(TC, self).__init__(*a, **ka)
|
|
|
|
|
|
|
|
|
|
def assertStart(self, member, container, msg=None):
|
|
|
|
|
if not container.startswith(member):
|
|
|
|
|
standardMsg = "%s not found in %s" % (member, container)
|
|
|
|
|
self.fail(self._formatMessage(msg, standardMsg))
|
|
|
|
|
|
|
|
|
|
|
2022-07-27 00:15:49 +02:00
|
|
|
class Cfg(Namespace):
|
2023-12-16 15:38:48 +00:00
|
|
|
def __init__(self, a=None, v=None, c=None, **ka0):
|
2022-07-27 00:15:49 +02:00
|
|
|
ka = {}
|
|
|
|
|
|
2025-08-07 20:29:44 +00:00
|
|
|
ex = "allow_flac allow_wav chpw cookie_lax daw dav_auth dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid gsel hardlink hardlink_only ih ihead localtime magic nid nih no_acode no_athumb no_bauth no_clone no_cp no_dav no_db_ip no_del no_dirsz no_dupe no_fnugg no_lifetime no_logues no_mv no_pipe no_poll no_readme no_robots no_sb_md no_sb_lg no_scandir no_tail no_tarcmp no_thumb no_vthumb no_zip nrand nsort nw og og_no_head og_s_title ohead q rand re_dirsz reflink rmagic rss smb srch_dbg srch_excl stats uqe usernames vague_403 vc ver wo_up_readme write_uplog xdev xlink xvol zipmaxu zs"
|
2022-07-27 00:15:49 +02:00
|
|
|
ka.update(**{k: False for k in ex.split()})
|
|
|
|
|
|
2025-06-08 18:32:32 +02:00
|
|
|
ex = "dav_inf dedup dotpart dotsrch hook_v no_dhash no_fastboot no_fpool no_htp no_rescan no_sendfile no_ses no_snap no_up_list no_voldump re_dhash see_dots plain_ip"
|
2022-07-27 00:15:49 +02:00
|
|
|
ka.update(**{k: True for k in ex.split()})
|
|
|
|
|
|
2025-03-30 16:08:28 +00:00
|
|
|
ex = "ah_cli ah_gen css_browser dbpath hist ipu js_browser js_other mime mimes no_forget no_hash no_idx nonsus_urls og_tpl og_ua ua_nodoc ua_nozip"
|
2022-07-27 00:15:49 +02:00
|
|
|
ka.update(**{k: None for k in ex.split()})
|
|
|
|
|
|
2025-07-30 19:35:00 +00:00
|
|
|
ex = "gid uid"
|
|
|
|
|
ka.update(**{k: -1 for k in ex.split()})
|
|
|
|
|
|
2025-07-25 18:31:49 +00:00
|
|
|
ex = "hash_mt hsortn qdel safe_dedup srch_time tail_fd tail_rate u2abort u2j u2sz"
|
2023-12-16 15:38:48 +00:00
|
|
|
ka.update(**{k: 1 for k in ex.split()})
|
|
|
|
|
|
2025-06-21 23:36:19 +00:00
|
|
|
ex = "au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who"
|
2023-04-24 20:04:22 +00:00
|
|
|
ka.update(**{k: 9 for k in ex.split()})
|
|
|
|
|
|
2025-08-07 17:57:10 +00:00
|
|
|
ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
|
2022-07-27 00:15:49 +02:00
|
|
|
ka.update(**{k: 0 for k in ex.split()})
|
|
|
|
|
|
2025-08-07 19:11:28 +00:00
|
|
|
ex = "ah_alg bname chmod_f chpw_db doctitle df exit favico idp_h_usr ipa html_head lg_sba lg_sbf log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR"
|
2022-07-27 00:15:49 +02:00
|
|
|
ka.update(**{k: "" for k in ex.split()})
|
|
|
|
|
|
2025-07-28 17:15:19 +00:00
|
|
|
ex = "ban_403 ban_404 ban_422 ban_pw ban_pwc ban_url spinner"
|
2024-08-30 22:06:25 +00:00
|
|
|
ka.update(**{k: "no" for k in ex.split()})
|
|
|
|
|
|
2025-02-13 20:57:04 +00:00
|
|
|
ex = "ext_th grp on403 on404 xac xad xar xau xban xbc xbd xbr xbu xiu xm"
|
2023-01-28 13:35:49 +00:00
|
|
|
ka.update(**{k: [] for k in ex.split()})
|
|
|
|
|
|
2024-07-13 00:54:38 +02:00
|
|
|
ex = "exp_lg exp_md"
|
2023-10-24 16:37:32 +00:00
|
|
|
ka.update(**{k: {} for k in ex.split()})
|
|
|
|
|
|
2023-12-16 15:38:48 +00:00
|
|
|
ka.update(ka0)
|
|
|
|
|
|
2022-07-27 00:15:49 +02:00
|
|
|
super(Cfg, self).__init__(
|
|
|
|
|
a=a or [],
|
|
|
|
|
v=v or [],
|
|
|
|
|
c=c,
|
2022-09-18 00:16:40 +02:00
|
|
|
E=E,
|
2025-05-17 16:55:29 +02:00
|
|
|
bup_ck="sha512",
|
2025-07-21 22:46:28 +00:00
|
|
|
chmod_d="755",
|
2022-12-10 19:22:16 +00:00
|
|
|
dbd="wal",
|
2023-12-17 22:30:22 +00:00
|
|
|
dk_salt="b" * 16,
|
2023-12-16 15:38:48 +00:00
|
|
|
fk_salt="a" * 16,
|
2024-03-12 21:21:53 +00:00
|
|
|
idp_gsep=re.compile("[|:;+,]"),
|
2024-03-23 16:17:40 +00:00
|
|
|
iobuf=256 * 1024,
|
2023-12-16 15:38:48 +00:00
|
|
|
lang="eng",
|
|
|
|
|
log_badpwd=1,
|
|
|
|
|
logout=573,
|
2025-03-26 20:07:35 +00:00
|
|
|
md_hist="s",
|
2023-12-16 15:38:48 +00:00
|
|
|
mte={"a": True},
|
|
|
|
|
mth={},
|
|
|
|
|
mtp=[],
|
2025-05-17 16:55:29 +02:00
|
|
|
put_ck="sha512",
|
2025-05-12 10:30:41 +02:00
|
|
|
put_name="put-{now.6f}-{cip}.bin",
|
2024-04-12 20:38:30 +00:00
|
|
|
mv_retry="0/0",
|
2024-01-25 21:39:30 +00:00
|
|
|
rm_retry="0/0",
|
2024-03-23 16:35:14 +00:00
|
|
|
s_rd_sz=256 * 1024,
|
|
|
|
|
s_wr_sz=256 * 1024,
|
2023-12-16 15:38:48 +00:00
|
|
|
sort="href",
|
|
|
|
|
srch_hits=99999,
|
2024-08-17 18:17:40 +00:00
|
|
|
SRS="/",
|
2024-06-16 21:35:43 +02:00
|
|
|
th_covers=["folder.png"],
|
2024-07-13 00:54:38 +02:00
|
|
|
th_coversd=["folder.png"],
|
|
|
|
|
th_covers_set=set(["folder.png"]),
|
|
|
|
|
th_coversd_set=set(["folder.png"]),
|
2024-02-18 13:04:22 +00:00
|
|
|
th_crop="y",
|
2023-07-11 22:15:37 +00:00
|
|
|
th_size="320x256",
|
2024-02-18 13:04:22 +00:00
|
|
|
th_x3="n",
|
2022-07-27 00:15:49 +02:00
|
|
|
u2sort="s",
|
2023-10-20 23:41:58 +00:00
|
|
|
u2ts="c",
|
2023-12-16 15:38:48 +00:00
|
|
|
unpost=600,
|
|
|
|
|
warksalt="hunter2",
|
2022-07-27 00:15:49 +02:00
|
|
|
**ka
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
2021-04-24 03:35:58 +02:00
|
|
|
class NullBroker(object):
|
2024-08-11 14:52:32 +00:00
|
|
|
def __init__(self, args, asrv):
|
|
|
|
|
self.args = args
|
|
|
|
|
self.asrv = asrv
|
|
|
|
|
|
2023-11-30 17:33:07 +00:00
|
|
|
def say(self, *args):
|
2022-06-16 01:07:15 +02:00
|
|
|
pass
|
|
|
|
|
|
2023-11-30 17:33:07 +00:00
|
|
|
def ask(self, *args):
|
2021-04-24 03:35:58 +02:00
|
|
|
pass
|
|
|
|
|
|
|
|
|
|
|
2021-04-24 02:48:41 +02:00
|
|
|
class VSock(object):
|
|
|
|
|
def __init__(self, buf):
|
|
|
|
|
self._query = buf
|
|
|
|
|
self._reply = b""
|
2024-08-12 21:58:02 +00:00
|
|
|
self.family = socket.AF_INET
|
2021-04-24 02:48:41 +02:00
|
|
|
self.sendall = self.send
|
|
|
|
|
|
|
|
|
|
def recv(self, sz):
|
|
|
|
|
ret = self._query[:sz]
|
|
|
|
|
self._query = self._query[sz:]
|
|
|
|
|
return ret
|
|
|
|
|
|
|
|
|
|
def send(self, buf):
|
|
|
|
|
self._reply += buf
|
|
|
|
|
return len(buf)
|
|
|
|
|
|
2022-01-18 22:28:33 +01:00
|
|
|
def getsockname(self):
|
|
|
|
|
return ("a", 1)
|
|
|
|
|
|
2022-10-31 22:42:47 +00:00
|
|
|
def settimeout(self, a):
|
|
|
|
|
pass
|
|
|
|
|
|
2021-04-24 02:48:41 +02:00
|
|
|
|
2024-08-30 22:06:25 +00:00
|
|
|
class VHub(object):
|
|
|
|
|
def __init__(self, args, asrv, log):
|
|
|
|
|
self.args = args
|
|
|
|
|
self.asrv = asrv
|
|
|
|
|
self.log = log
|
|
|
|
|
self.is_dut = True
|
|
|
|
|
self.up2k = Up2k(self)
|
|
|
|
|
|
2025-07-20 23:49:36 +02:00
|
|
|
def reload(self, a, b):
|
|
|
|
|
pass
|
|
|
|
|
|
2024-08-30 22:06:25 +00:00
|
|
|
|
|
|
|
|
class VBrokerThr(BrokerThr):
|
|
|
|
|
def __init__(self, hub):
|
|
|
|
|
self.hub = hub
|
|
|
|
|
self.log = hub.log
|
|
|
|
|
self.args = hub.args
|
|
|
|
|
self.asrv = hub.asrv
|
|
|
|
|
|
|
|
|
|
|
2021-04-24 02:48:41 +02:00
|
|
|
class VHttpSrv(object):
|
2023-12-16 15:38:48 +00:00
|
|
|
def __init__(self, args, asrv, log):
|
|
|
|
|
self.args = args
|
|
|
|
|
self.asrv = asrv
|
|
|
|
|
self.log = log
|
2024-08-30 22:06:25 +00:00
|
|
|
self.hub = None
|
2023-12-16 15:38:48 +00:00
|
|
|
|
2024-08-11 14:52:32 +00:00
|
|
|
self.broker = NullBroker(args, asrv)
|
2021-11-06 23:27:21 +01:00
|
|
|
self.prism = None
|
2022-09-23 22:53:51 +02:00
|
|
|
self.bans = {}
|
2024-11-10 02:12:18 +00:00
|
|
|
self.tdls = self.dls = {}
|
|
|
|
|
self.tdli = self.dli = {}
|
2023-11-11 17:38:43 +00:00
|
|
|
self.nreq = 0
|
2023-12-16 15:38:48 +00:00
|
|
|
self.nsus = 0
|
2021-04-24 03:35:58 +02:00
|
|
|
|
2024-08-18 22:49:13 +00:00
|
|
|
aliases = ["splash", "shares", "browser", "browser2", "msg", "md", "mde"]
|
2021-04-24 02:48:41 +02:00
|
|
|
self.j2 = {x: J2_FILES for x in aliases}
|
|
|
|
|
|
2023-07-16 13:09:31 +00:00
|
|
|
self.gpwd = Garda("")
|
|
|
|
|
self.g404 = Garda("")
|
2023-08-26 13:52:24 +00:00
|
|
|
self.g403 = Garda("")
|
|
|
|
|
self.gurl = Garda("")
|
2023-07-16 13:09:31 +00:00
|
|
|
|
2023-12-16 15:38:48 +00:00
|
|
|
self.u2idx = None
|
2023-07-23 15:43:38 +00:00
|
|
|
|
2021-07-01 20:10:02 +02:00
|
|
|
def cachebuster(self):
|
|
|
|
|
return "a"
|
|
|
|
|
|
2023-12-16 15:38:48 +00:00
|
|
|
def get_u2idx(self):
|
|
|
|
|
self.u2idx = self.u2idx or U2idx(self)
|
|
|
|
|
return self.u2idx
|
|
|
|
|
|
2024-11-22 22:21:43 +00:00
|
|
|
def shutdown(self):
|
|
|
|
|
if self.u2idx:
|
|
|
|
|
self.u2idx.shutdown()
|
|
|
|
|
|
2021-04-24 02:48:41 +02:00
|
|
|
|
2024-08-30 22:06:25 +00:00
|
|
|
class VHttpSrvUp2k(VHttpSrv):
|
|
|
|
|
def __init__(self, args, asrv, log):
|
|
|
|
|
super(VHttpSrvUp2k, self).__init__(args, asrv, log)
|
|
|
|
|
self.hub = VHub(args, asrv, log)
|
|
|
|
|
self.broker = VBrokerThr(self.hub)
|
|
|
|
|
|
2024-11-22 22:21:43 +00:00
|
|
|
def shutdown(self):
|
|
|
|
|
self.hub.up2k.shutdown()
|
|
|
|
|
if self.u2idx:
|
|
|
|
|
self.u2idx.shutdown()
|
|
|
|
|
|
2024-08-30 22:06:25 +00:00
|
|
|
|
2021-04-24 02:48:41 +02:00
|
|
|
class VHttpConn(object):
|
2024-08-30 22:06:25 +00:00
|
|
|
def __init__(self, args, asrv, log, buf, use_up2k=False):
|
2023-12-16 15:38:48 +00:00
|
|
|
self.t0 = time.time()
|
|
|
|
|
self.aclose = {}
|
2021-04-24 02:48:41 +02:00
|
|
|
self.addr = ("127.0.0.1", "42069")
|
|
|
|
|
self.args = args
|
2021-06-11 23:01:13 +02:00
|
|
|
self.asrv = asrv
|
2023-12-16 15:38:48 +00:00
|
|
|
self.bans = {}
|
2024-11-10 02:12:18 +00:00
|
|
|
self.tdls = self.dls = {}
|
|
|
|
|
self.tdli = self.dli = {}
|
2023-12-16 15:38:48 +00:00
|
|
|
self.freshen_pwd = 0.0
|
2024-08-30 22:06:25 +00:00
|
|
|
|
|
|
|
|
Ctor = VHttpSrvUp2k if use_up2k else VHttpSrv
|
|
|
|
|
self.hsrv = Ctor(args, asrv, log)
|
2024-06-16 21:35:43 +02:00
|
|
|
self.ico = Ico(args)
|
2024-03-14 19:07:35 +01:00
|
|
|
self.ipa_nm = None
|
2023-12-16 15:38:48 +00:00
|
|
|
self.lf_url = None
|
2021-04-24 02:48:41 +02:00
|
|
|
self.log_func = log
|
|
|
|
|
self.log_src = "a"
|
2021-10-03 19:59:47 +02:00
|
|
|
self.mutex = threading.Lock()
|
2024-04-20 20:13:31 +00:00
|
|
|
self.pipes = CachedDict(1)
|
up2k: fix a mostly-harmless race
as each chunk is written to the file, httpcli calls
up2k.confirm_chunk to register the chunk as completed, and the reply
indicates whether that was the final outstanding chunk, in which case
httpcli closes the file descriptors since there's nothing more to write
the issue is that the final chunk is registered as completed before the
file descriptors are closed, meaning there could be writes that haven't
finished flushing to disk yet
if the client decides to issue another handshake during this window,
up2k sees that all chunks are complete and calls up2k.finish_upload
even as some threads might still be flushing the final writes to disk
so the conditions to hit this bug were as follows (all must be true):
* multiprocessing is disabled
* there is a reverse-proxy
* a client has several idle connections and reuses one of those
* the server's filesystem is EXTREMELY slow, to the point where
closing a file takes over 30 seconds
the fix is to stop handshakes from being processed while a file is
being closed, which is unfortunately a small bottleneck in that it
prohibits initiating another upload while one is being finalized, but
the required complexity to handle this better is probably not worth it
(a separate mutex for each upload session or something like that)
this issue is mostly harmless, partially because it is super tricky to
hit (only aware of it happening synthetically), and because there is
usually no harmful consequences; the worst-case is if this were to
happen exactly as the server OS decides to crash, which would make the
file appear to be fully uploaded even though it's missing some data
(all extremely unlikely, but not impossible)
there is no performance impact; if anything it should now accept
new tcp connections slightly faster thanks to more granular locking
2024-02-13 19:24:06 +00:00
|
|
|
self.u2mutex = threading.Lock()
|
2021-04-24 02:48:41 +02:00
|
|
|
self.nbyte = 0
|
2023-12-16 15:38:48 +00:00
|
|
|
self.nid = None
|
|
|
|
|
self.nreq = -1
|
2021-06-01 03:55:31 +02:00
|
|
|
self.thumbcli = None
|
2023-12-16 15:38:48 +00:00
|
|
|
self.u2fh = FHC()
|
|
|
|
|
|
2024-03-21 18:51:23 +00:00
|
|
|
self.get_u2idx = self.hsrv.get_u2idx
|
2024-08-30 22:06:25 +00:00
|
|
|
self.setbuf(buf)
|
|
|
|
|
|
|
|
|
|
def setbuf(self, buf):
|
|
|
|
|
self.s = VSock(buf)
|
|
|
|
|
self.sr = Unrecv(self.s, None) # type: ignore
|
|
|
|
|
return self
|
2024-04-25 22:25:38 +00:00
|
|
|
|
2024-11-22 22:21:43 +00:00
|
|
|
def shutdown(self):
|
|
|
|
|
self.hsrv.shutdown()
|
|
|
|
|
|
2024-04-25 22:25:38 +00:00
|
|
|
|
|
|
|
|
if WINDOWS:
|
|
|
|
|
os.system("rem")
|