mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-30 05:25:35 +00:00
7209c4f91e
Clients often perform a PROPFIND for the parent directory before performing PROPFIND for specific children within that directory. The PROPFIND for the parent directory is usually done at depth 1, meaning that we already have information for all of the children. By immediately adding that to the cache, we save a roundtrip to the remote peer on the PROPFIND for the specific child. Updates tailscale/corp#19779 Signed-off-by: Percy Wegmann <percy@tailscale.com>
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package shared
|
|
|
|
import (
|
|
"net/url"
|
|
"path"
|
|
"strings"
|
|
)
|
|
|
|
// This file provides utility functions for working with URL paths. These are
|
|
// similar to functions in package path in the standard library, but differ in
|
|
// ways that are documented on the relevant functions.
|
|
|
|
const (
|
|
sepString = "/"
|
|
sepStringAndDot = "/."
|
|
sep = '/'
|
|
)
|
|
|
|
// CleanAndSplit cleans the provided path p and splits it into its constituent
|
|
// parts. This is different from path.Split which just splits a path into prefix
|
|
// and suffix.
|
|
func CleanAndSplit(p string) []string {
|
|
return strings.Split(strings.Trim(path.Clean(p), sepStringAndDot), sepString)
|
|
}
|
|
|
|
// Normalize normalizes the given path (e.g. dropping trailing slashes).
|
|
func Normalize(p string) string {
|
|
return Join(CleanAndSplit(p)...)
|
|
}
|
|
|
|
// Parent extracts the parent of the given path.
|
|
func Parent(p string) string {
|
|
parts := CleanAndSplit(p)
|
|
return Join(parts[:len(parts)-1]...)
|
|
}
|
|
|
|
// Join behaves like path.Join() but also includes a leading slash.
|
|
func Join(parts ...string) string {
|
|
fullParts := make([]string, 0, len(parts))
|
|
fullParts = append(fullParts, sepString)
|
|
for _, part := range parts {
|
|
fullParts = append(fullParts, part)
|
|
}
|
|
return path.Join(fullParts...)
|
|
}
|
|
|
|
// JoinEscaped is like Join but path escapes each part.
|
|
func JoinEscaped(parts ...string) string {
|
|
fullParts := make([]string, 0, len(parts))
|
|
fullParts = append(fullParts, sepString)
|
|
for _, part := range parts {
|
|
fullParts = append(fullParts, url.PathEscape(part))
|
|
}
|
|
return path.Join(fullParts...)
|
|
}
|
|
|
|
// IsRoot determines whether a given path p is the root path, defined as either
|
|
// empty or "/".
|
|
func IsRoot(p string) bool {
|
|
return p == "" || p == sepString
|
|
}
|
|
|
|
// Base is like path.Base except that it returns "" for the root folder
|
|
func Base(p string) string {
|
|
if IsRoot(p) {
|
|
return ""
|
|
}
|
|
return path.Base(p)
|
|
}
|