support davfs2 LOCK (uploads) + misc windows support + logue filtering
This commit is contained in:
parent
e413007eb0
commit
d8dfc4ccb2
@ -13,9 +13,18 @@ from pyftpdlib.filesystems import AbstractedFS, FilesystemError
|
|||||||
from pyftpdlib.handlers import FTPHandler
|
from pyftpdlib.handlers import FTPHandler
|
||||||
from pyftpdlib.servers import FTPServer
|
from pyftpdlib.servers import FTPServer
|
||||||
|
|
||||||
from .__init__ import PY2, TYPE_CHECKING, E
|
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, E
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
from .util import Daemon, Pebkac, exclude_dotfiles, fsenc, ipnorm
|
from .util import (
|
||||||
|
Daemon,
|
||||||
|
Pebkac,
|
||||||
|
exclude_dotfiles,
|
||||||
|
fsenc,
|
||||||
|
ipnorm,
|
||||||
|
relchk,
|
||||||
|
sanitize_fn,
|
||||||
|
vjoin,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from pyftpdlib.ioloop import IOLoop
|
from pyftpdlib.ioloop import IOLoop
|
||||||
@ -125,6 +134,12 @@ class FtpFs(AbstractedFS):
|
|||||||
) -> str:
|
) -> str:
|
||||||
try:
|
try:
|
||||||
vpath = vpath.replace("\\", "/").lstrip("/")
|
vpath = vpath.replace("\\", "/").lstrip("/")
|
||||||
|
rd, fn = os.path.split(vpath)
|
||||||
|
if ANYWIN and not relchk(rd):
|
||||||
|
raise FilesystemError("unsupported characters in filepath")
|
||||||
|
|
||||||
|
fn = sanitize_fn(fn or "", "", [".prologue.html", ".epilogue.html"])
|
||||||
|
vpath = vjoin(rd, fn)
|
||||||
vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d)
|
vfs, rem = self.hub.asrv.vfs.get(vpath, self.uname, r, w, m, d)
|
||||||
if not vfs.realpath:
|
if not vfs.realpath:
|
||||||
raise FilesystemError("no filesystem mounted at this path")
|
raise FilesystemError("no filesystem mounted at this path")
|
||||||
|
@ -51,6 +51,7 @@ from .util import (
|
|||||||
guess_mime,
|
guess_mime,
|
||||||
gzip_orig_sz,
|
gzip_orig_sz,
|
||||||
hashcopy,
|
hashcopy,
|
||||||
|
hidedir,
|
||||||
html_bescape,
|
html_bescape,
|
||||||
html_escape,
|
html_escape,
|
||||||
humansize,
|
humansize,
|
||||||
@ -64,7 +65,6 @@ from .util import (
|
|||||||
relchk,
|
relchk,
|
||||||
ren_open,
|
ren_open,
|
||||||
runhook,
|
runhook,
|
||||||
hidedir,
|
|
||||||
s3enc,
|
s3enc,
|
||||||
sanitize_fn,
|
sanitize_fn,
|
||||||
sendfile_kern,
|
sendfile_kern,
|
||||||
@ -1057,11 +1057,14 @@ class HttpCli(object):
|
|||||||
lk = parse_xml(txt)
|
lk = parse_xml(txt)
|
||||||
assert lk.tag == "{DAV:}lockinfo"
|
assert lk.tag == "{DAV:}lockinfo"
|
||||||
|
|
||||||
if not lk.find(r"./{DAV:}depth"):
|
token = str(uuid.uuid4())
|
||||||
lk.append(mktnod("D:depth", "infinity"))
|
|
||||||
|
|
||||||
lk.append(mkenod("D:timeout", mktnod("D:href", "Second-3310")))
|
if not lk.find(r"./{DAV:}depth"):
|
||||||
lk.append(mkenod("D:locktoken", mktnod("D:href", uuid.uuid4().urn)))
|
depth = self.headers.get("depth", "infinity")
|
||||||
|
lk.append(mktnod("D:depth", depth))
|
||||||
|
|
||||||
|
lk.append(mktnod("D:timeout", "Second-3310"))
|
||||||
|
lk.append(mkenod("D:locktoken", mktnod("D:href", token)))
|
||||||
lk.append(
|
lk.append(
|
||||||
mkenod("D:lockroot", mktnod("D:href", quotep(self.args.SRS + self.vpath)))
|
mkenod("D:lockroot", mktnod("D:href", quotep(self.args.SRS + self.vpath)))
|
||||||
)
|
)
|
||||||
@ -1074,11 +1077,13 @@ class HttpCli(object):
|
|||||||
ret = '<?xml version="1.0" encoding="{}"?>\n'.format(uenc)
|
ret = '<?xml version="1.0" encoding="{}"?>\n'.format(uenc)
|
||||||
ret += ET.tostring(xroot).decode("utf-8")
|
ret += ET.tostring(xroot).decode("utf-8")
|
||||||
|
|
||||||
|
rc = 200
|
||||||
if self.can_write and not bos.path.isfile(abspath):
|
if self.can_write and not bos.path.isfile(abspath):
|
||||||
with open(fsenc(abspath), "wb") as _:
|
with open(fsenc(abspath), "wb") as _:
|
||||||
pass
|
rc = 201
|
||||||
|
|
||||||
self.reply(ret.encode(enc, "replace"), 200, "text/xml; charset=" + enc)
|
self.out_headers["Lock-Token"] = "<{}>".format(token)
|
||||||
|
self.reply(ret.encode(enc, "replace"), rc, "text/xml; charset=" + enc)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def handle_unlock(self) -> bool:
|
def handle_unlock(self) -> bool:
|
||||||
@ -1388,9 +1393,12 @@ class HttpCli(object):
|
|||||||
params.update(open_ka)
|
params.update(open_ka)
|
||||||
assert fn
|
assert fn
|
||||||
|
|
||||||
if rnd and not self.args.nw:
|
if not self.args.nw:
|
||||||
|
if rnd:
|
||||||
fn = self.rand_name(fdir, fn, rnd)
|
fn = self.rand_name(fdir, fn, rnd)
|
||||||
|
|
||||||
|
fn = sanitize_fn(fn or "", "", [".prologue.html", ".epilogue.html"])
|
||||||
|
|
||||||
path = os.path.join(fdir, fn)
|
path = os.path.join(fdir, fn)
|
||||||
|
|
||||||
if xbu:
|
if xbu:
|
||||||
|
@ -8,7 +8,7 @@ from email.utils import formatdate
|
|||||||
|
|
||||||
from .__init__ import TYPE_CHECKING
|
from .__init__ import TYPE_CHECKING
|
||||||
from .multicast import MC_Sck, MCast
|
from .multicast import MC_Sck, MCast
|
||||||
from .util import CachedSet, min_ex, html_escape
|
from .util import CachedSet, html_escape, min_ex
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .broker_util import BrokerCli
|
from .broker_util import BrokerCli
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
from __future__ import print_function, unicode_literals
|
from __future__ import print_function, unicode_literals
|
||||||
|
|
||||||
import calendar
|
import calendar
|
||||||
import time
|
|
||||||
import stat
|
import stat
|
||||||
|
import time
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
|
Loading…
Reference in New Issue
Block a user