mirror of
https://github.com/tailscale/tailscale.git
synced 2025-09-21 05:31:36 +02:00
drive: fix StatCache mishandling of paths with spaces
Fix "file not found" errors when WebDAV clients access files/dirs inside directories with spaces. The issue occurred because StatCache was mixing URL-escaped and unescaped paths, causing cache key mismatches. Specifically, StatCache.set() parsed WebDAV responses containing URL-escaped paths (ex. "Dir%20Space/file1.txt") and stored them alongside unescaped cache keys (ex. "Dir Space/file1.txt"). This mismatch prevented StatCache.get() from correctly determining whether a child file existed. See https://github.com/tailscale/tailscale/issues/13632#issuecomment-3243522449 for the full explanation of the issue. The decision to keep all paths references unescaped inside the StatCache is consistent with net/http.Request.URL.Path and rewrite.go (sole consumer) Update unit test to detect this directory space mishandling. Fixes tailscale#13632 Signed-off-by: Craig Hesling <craig@hesling.com>
This commit is contained in:
parent
0f3598b467
commit
2b9d055101
@ -8,6 +8,7 @@ import (
|
|||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -165,7 +166,12 @@ func (c *StatCache) set(name string, depth int, ce *cacheEntry) {
|
|||||||
children = make(map[string]*cacheEntry, len(ms.Responses)-1)
|
children = make(map[string]*cacheEntry, len(ms.Responses)-1)
|
||||||
for i := 0; i < len(ms.Responses); i++ {
|
for i := 0; i < len(ms.Responses); i++ {
|
||||||
response := ms.Responses[i]
|
response := ms.Responses[i]
|
||||||
name := shared.Normalize(response.Href)
|
name, err := url.PathUnescape(response.Href)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("statcache.set child parse error: %s", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
name = shared.Normalize(name)
|
||||||
raw := marshalMultiStatus(response)
|
raw := marshalMultiStatus(response)
|
||||||
entry := newCacheEntry(ce.Status, raw)
|
entry := newCacheEntry(ce.Status, raw)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
|
@ -16,12 +16,12 @@ import (
|
|||||||
"tailscale.com/tstest"
|
"tailscale.com/tstest"
|
||||||
)
|
)
|
||||||
|
|
||||||
var parentPath = "/parent"
|
var parentPath = "/parent with spaces"
|
||||||
|
|
||||||
var childPath = "/parent/child.txt"
|
var childPath = "/parent with spaces/child.txt"
|
||||||
|
|
||||||
var parentResponse = `<D:response>
|
var parentResponse = `<D:response>
|
||||||
<D:href>/parent/</D:href>
|
<D:href>/parent%20with%20spaces/</D:href>
|
||||||
<D:propstat>
|
<D:propstat>
|
||||||
<D:prop>
|
<D:prop>
|
||||||
<D:getlastmodified>Mon, 29 Apr 2024 19:52:23 GMT</D:getlastmodified>
|
<D:getlastmodified>Mon, 29 Apr 2024 19:52:23 GMT</D:getlastmodified>
|
||||||
@ -36,7 +36,7 @@ var parentResponse = `<D:response>
|
|||||||
|
|
||||||
var childResponse = `
|
var childResponse = `
|
||||||
<D:response>
|
<D:response>
|
||||||
<D:href>/parent/child.txt</D:href>
|
<D:href>/parent%20with%20spaces/child.txt</D:href>
|
||||||
<D:propstat>
|
<D:propstat>
|
||||||
<D:prop>
|
<D:prop>
|
||||||
<D:getlastmodified>Mon, 29 Apr 2024 19:52:23 GMT</D:getlastmodified>
|
<D:getlastmodified>Mon, 29 Apr 2024 19:52:23 GMT</D:getlastmodified>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user