mirror of
https://github.com/tailscale/tailscale.git
synced 2024-11-26 11:35:35 +00:00
50fb8b9123
Instead of modeling remote WebDAV servers as actual webdav.FS instances, we now just proxy traffic to them. This not only simplifies the code, but it also allows WebDAV locking to work correctly by making sure locks are handled by the servers that need to (i.e. the ones actually serving the files). Updates tailscale/corp#16827 Signed-off-by: Percy Wegmann <percy@tailscale.com>
94 lines
2.6 KiB
Go
94 lines
2.6 KiB
Go
// Copyright (c) Tailscale Inc & AUTHORS
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
// Package tailfsimpl provides an implementation of package tailfs.
|
|
package tailfsimpl
|
|
|
|
import (
|
|
"log"
|
|
"net"
|
|
"net/http"
|
|
"time"
|
|
|
|
"tailscale.com/tailfs"
|
|
"tailscale.com/tailfs/tailfsimpl/compositedav"
|
|
"tailscale.com/tailfs/tailfsimpl/dirfs"
|
|
"tailscale.com/types/logger"
|
|
)
|
|
|
|
const (
|
|
// statCacheTTL causes the local WebDAV proxy to cache file metadata to
|
|
// avoid excessive network roundtrips. This is similar to the
|
|
// DirectoryCacheLifetime setting of Windows' built-in SMB client,
|
|
// see https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-7/ff686200(v=ws.10)
|
|
statCacheTTL = 10 * time.Second
|
|
)
|
|
|
|
// NewFileSystemForLocal starts serving a filesystem for local clients.
|
|
// Inbound connections must be handed to HandleConn.
|
|
func NewFileSystemForLocal(logf logger.Logf) *FileSystemForLocal {
|
|
if logf == nil {
|
|
logf = log.Printf
|
|
}
|
|
fs := &FileSystemForLocal{
|
|
logf: logf,
|
|
h: &compositedav.Handler{
|
|
Logf: logf,
|
|
StatCache: &compositedav.StatCache{TTL: statCacheTTL},
|
|
},
|
|
listener: newConnListener(),
|
|
}
|
|
fs.startServing()
|
|
return fs
|
|
}
|
|
|
|
// FileSystemForLocal is the TailFS filesystem exposed to local clients. It
|
|
// provides a unified WebDAV interface to remote TailFS shares on other nodes.
|
|
type FileSystemForLocal struct {
|
|
logf logger.Logf
|
|
h *compositedav.Handler
|
|
listener *connListener
|
|
}
|
|
|
|
func (s *FileSystemForLocal) startServing() {
|
|
hs := &http.Server{Handler: s.h}
|
|
go func() {
|
|
err := hs.Serve(s.listener)
|
|
if err != nil {
|
|
// TODO(oxtoacart): should we panic or something different here?
|
|
log.Printf("serve: %v", err)
|
|
}
|
|
}()
|
|
}
|
|
|
|
// HandleConn handles connections from local WebDAV clients
|
|
func (s *FileSystemForLocal) HandleConn(conn net.Conn, remoteAddr net.Addr) error {
|
|
return s.listener.HandleConn(conn, remoteAddr)
|
|
}
|
|
|
|
// SetRemotes sets the complete set of remotes on the given tailnet domain
|
|
// using a map of name -> url. If transport is specified, that transport
|
|
// will be used to connect to these remotes.
|
|
func (s *FileSystemForLocal) SetRemotes(domain string, remotes []*tailfs.Remote, transport http.RoundTripper) {
|
|
children := make([]*compositedav.Child, 0, len(remotes))
|
|
for _, remote := range remotes {
|
|
children = append(children, &compositedav.Child{
|
|
Child: &dirfs.Child{
|
|
Name: remote.Name,
|
|
Available: remote.Available,
|
|
},
|
|
BaseURL: remote.URL,
|
|
Transport: transport,
|
|
})
|
|
}
|
|
|
|
s.h.SetChildren(domain, children...)
|
|
}
|
|
|
|
// Close() stops serving the WebDAV content
|
|
func (s *FileSystemForLocal) Close() error {
|
|
err := s.listener.Close()
|
|
s.h.Close()
|
|
return err
|
|
}
|