mirror of
https://github.com/drakkan/sftpgo.git
synced 2025-12-06 14:20:55 +03:00
177 lines
4.9 KiB
Go
177 lines
4.9 KiB
Go
// Package webdavd implements the WebDAV protocol
|
|
package webdavd
|
|
|
|
import (
|
|
"fmt"
|
|
"path/filepath"
|
|
|
|
"github.com/drakkan/sftpgo/common"
|
|
"github.com/drakkan/sftpgo/logger"
|
|
"github.com/drakkan/sftpgo/utils"
|
|
)
|
|
|
|
type ctxReqParams int
|
|
|
|
const (
|
|
requestIDKey ctxReqParams = iota
|
|
requestStartKey
|
|
)
|
|
|
|
const (
|
|
logSender = "webdavd"
|
|
)
|
|
|
|
var (
|
|
server *webDavServer
|
|
)
|
|
|
|
// ServiceStatus defines the service status
|
|
type ServiceStatus struct {
|
|
IsActive bool `json:"is_active"`
|
|
Bindings []Binding `json:"bindings"`
|
|
}
|
|
|
|
// Cors configuration
|
|
type Cors struct {
|
|
AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"`
|
|
AllowedMethods []string `json:"allowed_methods" mapstructure:"allowed_methods"`
|
|
AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"`
|
|
ExposedHeaders []string `json:"exposed_headers" mapstructure:"exposed_headers"`
|
|
AllowCredentials bool `json:"allow_credentials" mapstructure:"allow_credentials"`
|
|
Enabled bool `json:"enabled" mapstructure:"enabled"`
|
|
MaxAge int `json:"max_age" mapstructure:"max_age"`
|
|
}
|
|
|
|
// UsersCacheConfig defines the cache configuration for users
|
|
type UsersCacheConfig struct {
|
|
ExpirationTime int `json:"expiration_time" mapstructure:"expiration_time"`
|
|
MaxSize int `json:"max_size" mapstructure:"max_size"`
|
|
}
|
|
|
|
// MimeCacheConfig defines the cache configuration for mime types
|
|
type MimeCacheConfig struct {
|
|
Enabled bool `json:"enabled" mapstructure:"enabled"`
|
|
MaxSize int `json:"max_size" mapstructure:"max_size"`
|
|
}
|
|
|
|
// Cache configuration
|
|
type Cache struct {
|
|
Users UsersCacheConfig `json:"users" mapstructure:"users"`
|
|
MimeTypes MimeCacheConfig `json:"mime_types" mapstructure:"mime_types"`
|
|
}
|
|
|
|
// Binding defines the configuration for a network listener
|
|
type Binding struct {
|
|
// The address to listen on. A blank value means listen on all available network interfaces.
|
|
Address string `json:"address" mapstructure:"address"`
|
|
// The port used for serving requests
|
|
Port int `json:"port" mapstructure:"port"`
|
|
// you also need to provide a certificate for enabling HTTPS
|
|
EnableHTTPS bool `json:"enable_https" mapstructure:"enable_https"`
|
|
}
|
|
|
|
// GetAddress returns the binding address
|
|
func (b *Binding) GetAddress() string {
|
|
return fmt.Sprintf("%s:%d", b.Address, b.Port)
|
|
}
|
|
|
|
// IsValid returns true if the binding port is > 0
|
|
func (b *Binding) IsValid() bool {
|
|
return b.Port > 0
|
|
}
|
|
|
|
// Configuration defines the configuration for the WevDAV server
|
|
type Configuration struct {
|
|
// Addresses and ports to bind to
|
|
Bindings []Binding `json:"bindings" mapstructure:"bindings"`
|
|
// Deprecated: please use Bindings
|
|
BindPort int `json:"bind_port" mapstructure:"bind_port"`
|
|
// Deprecated: please use Bindings
|
|
BindAddress string `json:"bind_address" mapstructure:"bind_address"`
|
|
// If files containing a certificate and matching private key for the server are provided the server will expect
|
|
// HTTPS connections.
|
|
// Certificate and key files can be reloaded on demand sending a "SIGHUP" signal on Unix based systems and a
|
|
// "paramchange" request to the running service on Windows.
|
|
CertificateFile string `json:"certificate_file" mapstructure:"certificate_file"`
|
|
CertificateKeyFile string `json:"certificate_key_file" mapstructure:"certificate_key_file"`
|
|
// CORS configuration
|
|
Cors Cors `json:"cors" mapstructure:"cors"`
|
|
// Cache configuration
|
|
Cache Cache `json:"cache" mapstructure:"cache"`
|
|
}
|
|
|
|
// GetStatus returns the server status
|
|
func GetStatus() ServiceStatus {
|
|
if server == nil {
|
|
return ServiceStatus{}
|
|
}
|
|
return server.status
|
|
}
|
|
|
|
// ShouldBind returns true if there is at least a valid binding
|
|
func (c *Configuration) ShouldBind() bool {
|
|
for _, binding := range c.Bindings {
|
|
if binding.IsValid() {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Initialize configures and starts the WebDAV server
|
|
func (c *Configuration) Initialize(configDir string) error {
|
|
var err error
|
|
logger.Debug(logSender, "", "initializing WebDAV server with config %+v", *c)
|
|
mimeTypeCache = mimeCache{
|
|
maxSize: c.Cache.MimeTypes.MaxSize,
|
|
mimeTypes: make(map[string]string),
|
|
}
|
|
if !c.Cache.MimeTypes.Enabled {
|
|
mimeTypeCache.maxSize = 0
|
|
}
|
|
if !c.ShouldBind() {
|
|
return common.ErrNoBinding
|
|
}
|
|
server, err = newServer(c, configDir)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
server.status.Bindings = nil
|
|
|
|
exitChannel := make(chan error, 1)
|
|
|
|
for _, binding := range c.Bindings {
|
|
if !binding.IsValid() {
|
|
continue
|
|
}
|
|
|
|
go func(binding Binding) {
|
|
exitChannel <- server.listenAndServe(binding)
|
|
}(binding)
|
|
}
|
|
|
|
server.status.IsActive = true
|
|
|
|
return <-exitChannel
|
|
}
|
|
|
|
// ReloadTLSCertificate reloads the TLS certificate and key from the configured paths
|
|
func ReloadTLSCertificate() error {
|
|
if server != nil && server.certMgr != nil {
|
|
return server.certMgr.LoadCertificate(logSender)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func getConfigPath(name, configDir string) string {
|
|
if !utils.IsFileInputValid(name) {
|
|
return ""
|
|
}
|
|
if len(name) > 0 && !filepath.IsAbs(name) {
|
|
return filepath.Join(configDir, name)
|
|
}
|
|
return name
|
|
}
|