diff --git a/copyparty/__main__.py b/copyparty/__main__.py index c707033c..4ead56e8 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1024,7 +1024,7 @@ def add_upload(ap): ap2.add_argument("--u2ts", metavar="TXT", type=u, default="c", help="how to timestamp uploaded files; [\033[32mc\033[0m]=client-last-modified, [\033[32mu\033[0m]=upload-time, [\033[32mfc\033[0m]=force-c, [\033[32mfu\033[0m]=force-u (volflag=u2ts)") ap2.add_argument("--rand", action="store_true", help="force randomized filenames, \033[33m--nrand\033[0m chars long (volflag=rand)") ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)") - ap2.add_argument("--magic", action="store_true", help="enable filetype detection on nameless uploads (volflag=magic)") + ap2.add_argument("--magic", action="store_true", help="enable filetype detection on extensionless files (volflag=magic)") ap2.add_argument("--df", metavar="GiB", type=u, default="0", help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests; assumes gigabytes unless a unit suffix is given: [\033[32m256m\033[0m], [\033[32m4\033[0m], [\033[32m2T\033[0m] (volflag=df)") ap2.add_argument("--sparse", metavar="MiB", type=int, default=4, help="windows-only: minimum size of incoming uploads through up2k before they are made into sparse files") ap2.add_argument("--turbo", metavar="LVL", type=int, default=0, help="configure turbo-mode in up2k client; [\033[32m-1\033[0m] = forbidden/always-off, [\033[32m0\033[0m] = default-off and warn if enabled, [\033[32m1\033[0m] = default-off, [\033[32m2\033[0m] = on, [\033[32m3\033[0m] = on and disable datecheck") diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index d490f19c..e68a3327 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -1413,6 +1413,8 @@ class HttpCli(object): pass for i in hits: + f = fsenc(os.path.join(self.vn.realpath, i["rp"])) if "magic" in self.vn.flags else None + iurl = html_escape("%s%s" % (baseurl, i["rp"]), True, True) title = unquotep(i["rp"].split("?")[0].split("/")[-1]) title = html_escape(title, True, True) @@ -1420,7 +1422,7 @@ class HttpCli(object): tag_a = str(i["tags"].get("artist") or "") desc = "%s - %s" % (tag_a, tag_t) if tag_t and tag_a else (tag_t or tag_a) desc = html_escape(desc, True, True) if desc else title - mime = html_escape(guess_mime(title)) + mime = html_escape(guess_mime(title, f)) lmod = formatdate(max(0, i["ts"])) zsa = (iurl, iurl, title, desc, lmod, iurl, mime, i["sz"]) zs = ( @@ -1599,7 +1601,9 @@ class HttpCli(object): "supportedlock": '', } if not isdir: - pvs["getcontenttype"] = html_escape(guess_mime(rp)) + f = fsenc(os.path.join(tap, x["vp"])) if "magic" in self.vn.flags else None + + pvs["getcontenttype"] = html_escape(guess_mime(rp), f) pvs["getcontentlength"] = str(st.st_size) for k, v in pvs.items(): @@ -4156,6 +4160,8 @@ class HttpCli(object): mime = "text/plain; charset={}".format(self.uparam["txt"] or "utf-8") elif "mime" in self.uparam: mime = str(self.uparam.get("mime")) + elif "magic" in self.vn.flags: + mime = guess_mime(req_path, fsenc(fs_path)) else: mime = guess_mime(req_path) diff --git a/copyparty/util.py b/copyparty/util.py index a219b779..f0c4433d 100644 --- a/copyparty/util.py +++ b/copyparty/util.py @@ -3152,11 +3152,11 @@ def unescape_cookie(orig: str) -> str: return "".join(ret) -def guess_mime(url: str, fallback: str = "application/octet-stream") -> str: +def guess_mime_ext(url: str) -> str: try: ext = url.rsplit(".", 1)[1].lower() except: - return fallback + return None ret = MIMES.get(ext) @@ -3164,6 +3164,24 @@ def guess_mime(url: str, fallback: str = "application/octet-stream") -> str: x = mimetypes.guess_type(url) ret = "application/{}".format(x[1]) if x[1] else x[0] + return ret + + +def guess_mime(url: str, path: str = None, fallback: str = "application/octet-stream") -> str: + ret = guess_mime_ext(url) + + if not ret and path: + import magic + + try: + with open(path, 'rb', 0) as f: + ret = magic.from_buffer(f.read(4096), mime = True) + if ret == "text/html": + # avoid serving up HTML content unless there was actually a .html extension + ret = "text/plain" + except: + pass + if not ret: ret = fallback