Repository: go
Issue: x/net/webdav: Etags in WebDAV "If" header conditions are ignored (fails litmus test)
Labels: NeedsInvestigation

<!--
Please answer these questions before submitting your issue. Thanks!
For questions please use one of our forums: https://github.com/golang/go/wiki/Questions
-->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.15.6 linux/amd64
</pre>

### Does this issue reproduce with the latest release?

yes

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/jbe/.cache/go-build"
GOENV="/home/jbe/.config/go/env"
GOEXE=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/jbe/go/pkg/mod"
GONOPROXY="redacted"
GONOSUMDB="redacted"
GOOS="linux"
GOPATH="/home/jbe/go"
GOPRIVATE="redacted"
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/lib/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/lib/go/pkg/tool/linux_amd64"
GCCGO="gccgo"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD=""
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-build221351055=/tmp/go-build -gno-record-gcc-switches"

</pre></details>

### What did you do?

<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
-->
Run the [litmus WebDAV testsuite](http://www.webdav.org/neon/litmus/) against the x/net/webdav test server at https://github.com/golang/net/blob/master/webdav/litmus_test_server.go:

```
$ go run webdav/litmus_test_server.go &
$ cd <litmus download dir>
$ make URL=http://localhost:9999/ check
```

The following playground can also be used  https://play.golang.org/p/FHdp-wHU4me.

### What did you expect to see?

Expected lock test `20. fail_complex_cond_put` to succeed.

### What did you see instead?
Test failed:
`20. fail_complex_cond_put. FAIL (PUT with complex bogus conditional should fail with 412: 201 Created)`


The `fail_complex_cond_put` test sends a conditional PUT request using the header `If: (<1613993752> ["16660e5ed893542e30"]) (Not <DAV:no-lock> ["16660e5ed893542e30"])` where `<1613993752>` is the valid lock token for the resource and `"16660e5ed893542e30"` is a corrupted etag of the resource (the second to last digit is incremented, i.e. changed from `"...20"`->`"...30"`). 
Note: The token/tag values are arbitrary and exact values are only used in the example tin order o avoid confusion arising from the `If:` header syntax.

This condition means the following:
`IF (resource_is_locked_ by(<lock-tok>) AND resource_matches(<invalid etag>)) OR (NOT (resource_is_not_locked()) AND resource_matches(<invalid etag>))`.
The webdav library implements full parsing for `If` headers but only validates the locked_by portions of conditions.
The comment at https://github.com/golang/net/blob/5f55cee0dc0dc168ce29222f077fe7fcd4be72c5/webdav/lock.go#L193 seems to imply that, in addition to Etag conditions, negation is also not implemented at all.

See https://tools.ietf.org/html/rfc4918#section-10.4 for the definition of the `If` header in the WebDAV RFC.