diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 0c7a9cb9..096c8311 100755 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -636,6 +636,7 @@ def run_argparse(argv: list[str], formatter: Any, retry: bool) -> argparse.Names ap2.add_argument("--dav", action="store_true", help="enable webdav; read-only even if user has write-access") ap2.add_argument("--daw", action="store_true", help="enable full write support. \033[1;31mNB!\033[0m This has side-effects -- PUT-operations will now \033[1;31mOVERWRITE\033[0m existing files, rather than inventing new filenames to avoid loss of data. You might want to instead set this as a volflag where needed. By not setting this flag, uploaded files can get written to a filename which the client does not expect (which might be okay, depending on client)") ap2.add_argument("--dav-nr", action="store_true", help="reject depth:infinite requests (recursive file listing); breaks spec compliance and some clients, which might be a good thing since depth:infinite is extremely server-heavy") + ap2.add_argument("--dav-mac", action="store_true", help="disable apple-garbage filter -- allow macos to create junk files (._* and .DS_Store, .Spotlight-*, .fseventsd, .Trashes, .AppleDouble, __MACOS)") ap2 = ap.add_argument_group('opt-outs') ap2.add_argument("-nw", action="store_true", help="never write anything to disk (debug/benchmark)") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 307ac502..d71bfccd 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -856,6 +856,9 @@ class HttpCli(object): if not rbuf or len(buf) >= 128 * 1024: break + if self._applesan(): + return True + txt = buf.decode("ascii", "replace").lower() enc = self.get_xml_enc(txt) uenc = enc.upper() @@ -910,6 +913,9 @@ class HttpCli(object): if not rbuf or len(buf) >= 128 * 1024: break + if self._applesan(): + return True + txt = buf.decode("ascii", "replace").lower() enc = self.get_xml_enc(txt) uenc = enc.upper() @@ -956,6 +962,9 @@ class HttpCli(object): return True def handle_mkcol(self) -> bool: + if self._applesan(): + return True + return self._mkdir(self.vpath) def handle_move(self) -> bool: @@ -976,6 +985,20 @@ class HttpCli(object): return True + def _applesan(self) -> bool: + if self.args.dav_mac or "Darwin/" not in self.ua: + return False + + vp = "/" + self.vpath + ptn = r"/\.(_|DS_Store|Spotlight-|fseventsd|Trashes|AppleDouble)|/__MACOS" + if re.search(ptn, vp): + zt = '\n{}' + zb = zt.format(vp).encode("utf-8", "replace") + self.reply(zb, 423, "text/xml; charset=utf-8") + return True + + return False + def send_chunk(self, txt: str, enc: str, bmax: int) -> str: orig_len = len(txt) buf = txt[:bmax].encode(enc, "replace")[:bmax] @@ -1025,6 +1048,9 @@ class HttpCli(object): t = "{} does not have write-access here" raise Pebkac(403, t.format(self.uname)) + if self.args.dav and self._applesan(): + return self.headers.get("content-length") == "0" + if self.headers.get("expect", "").lower() == "100-continue": try: self.s.sendall(b"HTTP/1.1 100 Continue\r\n\r\n") diff --git a/copyparty/util.py b/copyparty/util.py index ec75f3a2..95e3c456 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -167,6 +167,7 @@ HTTPCODE = { 413: "Payload Too Large", 416: "Requested Range Not Satisfiable", 422: "Unprocessable Entity", + 423: "Locked", 429: "Too Many Requests", 500: "Internal Server Error", 501: "Not Implemented", diff --git a/copyparty/web/browser.js b/copyparty/web/browser.js index f7d0ea4c..8a0b12cf 100644 --- a/copyparty/web/browser.js +++ b/copyparty/web/browser.js @@ -3123,7 +3123,7 @@ var fileman = (function () { var dst = base + uricom_enc(f[0].inew.value, false); function rename_cb() { - if (this.status !== 200) { + if (this.status !== 201) { var msg = this.responseText; toast.err(9, L.fr_efail + msg); return; @@ -3278,7 +3278,7 @@ var fileman = (function () { xhr.send(); } function paste_cb() { - if (this.status !== 200) { + if (this.status !== 201) { var msg = this.responseText; toast.err(9, L.fp_err + msg); return;