go x/net/webdav: 除非目标被锁定,否则移动一个被锁定的文件会失败,

14ifxucb  于 4个月前  发布在  Go
关注(0)|答案(4)|浏览(57)

你正在使用的Go版本是什么( go version )?

$ go version
go version go1.15 linux/amd64

这个问题在最新版本的发布中是否重现?

还没有尝试,但看起来相关代码没有发生变化。

你正在使用什么操作系统和处理器架构( go env )?

go env 输出

$ go env
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/kyle/.cache/go-build"
GOENV="/home/kyle/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/kyle/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/kyle/"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/home/kyle/src/klarose/golang/net/go.mod"
CGO_CFLAGS="-g -O2"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-g -O2"
CGO_FFLAGS="-g -O2"
CGO_LDFLAGS="-g -O2"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build211380463=/tmp/go-build -gno-record-gcc-switches"

你做了什么?

在使用x/net/webdav运行一个webdav服务器时,我发现任何试图重命名一个被锁定文件的操作都会失败,除非客户端对目标文件持有锁。这似乎是错误的。
复现步骤:
编译 https://github.com/hacdias/webdav (这个使用x/net/webdav作为其服务器)。
运行以下命令:

cd $(mktemp -d)
cat > config.yaml <<EOF 
# Server related settings
address: 127.0.0.1
port: 8080
auth: false
tls: false
prefix: /

scope: .
modify: true
rules: []
EOF

webdav -p 8080 --auth=false

下载/构建/安装/等 cadaver (一个用于运行webdav命令的简单工具)
运行 cadaver http://localhost:8080
在其命令提示符下运行以下命令:
A

lock foo.yaml
mv foo.yaml foo.yaml.2

然后运行:
B

lock foo.yaml.2
mv foo.yaml foo.yaml.2

你期望看到什么?

A应该成功 -- foo.yaml 应该被重命名为 foo.yaml.2 :

dav:/> lock foo.yaml
Locking `foo.yaml': succeeded.
dav:/> mv foo.yaml foo.yaml.2
Moving `/foo.yaml' to `/foo.yaml.2':  succeeded.

你看到了什么?

A失败了,但B成功了:

dav:/> lock foo.yaml
Locking `foo.yaml': succeeded.
dav:/> mv foo.yaml foo.yaml.2
Moving `/foo.yaml' to `/foo.yaml.2':  failed:
412 Precondition Failed
dav:/> lock foo.yaml.2
Locking `foo.yaml.2': succeeded.
dav:/> mv foo.yaml foo.yaml.2
Moving `/foo.yaml' to `/foo.yaml.2':  succeeded.
dav:/>
pepwfjgg

pepwfjgg1#

一些后续思考/评论:
我的发现表明,您只能将源移动到锁定的目标,这是不正确的。锁定的资源应该简单地重命名,根据webdav RFC丢弃锁:

A successful MOVE request on a write locked resource MUST NOT move
   the write lock with the resource.  However, if there is an existing
   lock at the destination, the server MUST add the moved resource to
   the destination lock scope.  For example, if the MOVE makes the
   resource a child of a collection that has a depth-infinity lock, then
   the resource will be added to that collection's lock.  Additionally,
   if a resource with a depth-infinity lock is moved to a destination
   that is within the scope of the same lock (e.g., within the URL
   namespace tree covered by the lock), the moved resource will again be
   added to the lock.  In both these examples, as specified in
   Section 7.5, an If header must be submitted containing a lock token
   for both the source and destination.

通过检查代码,看起来锁定子系统接受一个可选的src/dst参数。如果两者都设置了,它会尝试在两个资源上加锁。如果只设置了一个,它只会对那个资源加锁。如果两者都没有设置,它会暂时加锁以保持与其他客户端的锁定一致性。
在移动处理程序中,由于存在src和dst,它会在两个地方查找锁,即使dst不存在或未解锁:

release, status, err := h.confirmLocks(r, src, dst)

因此,尽管我们只锁定了src,而dst不存在,请求仍会失败,因为我们没有在dst上获得有效的锁。
实际上,检查应该是“对于给定的资源,如果没有条件,就对其加临时锁”,而不是“如果没有条件,就对所有资源加临时锁”。
如果有兴趣,我可以研究实现修复这个问题的方法(以及 #42839 )。这两个问题目前都在阻碍我们,所以我们需要尽快找到解决方案(即接下来的几周)。我可以研究提交带有修复的PR。我不介意那些对这个代码库有经验的人提供一些指导,特别是针对这个问题,因为我认为修复可能不像 #42839 那么简单。

cqoc49vn

cqoc49vn3#

我有一个潜在的解决方案。我会等待我的CLA通过,但欢迎大家随时查看。

ws51t4hk

ws51t4hk4#

https://golang.org/cl/285754提到了这个问题:webdav: only require locks when necessary

相关问题