webdavd.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Package webdavd implements the WebDAV protocol
  2. package webdavd
  3. import (
  4. "fmt"
  5. "path/filepath"
  6. "github.com/drakkan/sftpgo/common"
  7. "github.com/drakkan/sftpgo/logger"
  8. "github.com/drakkan/sftpgo/utils"
  9. )
  10. type ctxReqParams int
  11. const (
  12. requestIDKey ctxReqParams = iota
  13. requestStartKey
  14. )
  15. const (
  16. logSender = "webdavd"
  17. )
  18. var (
  19. server *webDavServer
  20. )
  21. // ServiceStatus defines the service status
  22. type ServiceStatus struct {
  23. IsActive bool `json:"is_active"`
  24. Bindings []Binding `json:"bindings"`
  25. }
  26. // Cors configuration
  27. type Cors struct {
  28. AllowedOrigins []string `json:"allowed_origins" mapstructure:"allowed_origins"`
  29. AllowedMethods []string `json:"allowed_methods" mapstructure:"allowed_methods"`
  30. AllowedHeaders []string `json:"allowed_headers" mapstructure:"allowed_headers"`
  31. ExposedHeaders []string `json:"exposed_headers" mapstructure:"exposed_headers"`
  32. AllowCredentials bool `json:"allow_credentials" mapstructure:"allow_credentials"`
  33. Enabled bool `json:"enabled" mapstructure:"enabled"`
  34. MaxAge int `json:"max_age" mapstructure:"max_age"`
  35. }
  36. // UsersCacheConfig defines the cache configuration for users
  37. type UsersCacheConfig struct {
  38. ExpirationTime int `json:"expiration_time" mapstructure:"expiration_time"`
  39. MaxSize int `json:"max_size" mapstructure:"max_size"`
  40. }
  41. // MimeCacheConfig defines the cache configuration for mime types
  42. type MimeCacheConfig struct {
  43. Enabled bool `json:"enabled" mapstructure:"enabled"`
  44. MaxSize int `json:"max_size" mapstructure:"max_size"`
  45. }
  46. // Cache configuration
  47. type Cache struct {
  48. Users UsersCacheConfig `json:"users" mapstructure:"users"`
  49. MimeTypes MimeCacheConfig `json:"mime_types" mapstructure:"mime_types"`
  50. }
  51. // Binding defines the configuration for a network listener
  52. type Binding struct {
  53. // The address to listen on. A blank value means listen on all available network interfaces.
  54. Address string `json:"address" mapstructure:"address"`
  55. // The port used for serving requests
  56. Port int `json:"port" mapstructure:"port"`
  57. // you also need to provide a certificate for enabling HTTPS
  58. EnableHTTPS bool `json:"enable_https" mapstructure:"enable_https"`
  59. // set to 1 to require client certificate authentication in addition to basic auth.
  60. // You need to define at least a certificate authority for this to work
  61. ClientAuthType int `json:"client_auth_type" mapstructure:"client_auth_type"`
  62. }
  63. // GetAddress returns the binding address
  64. func (b *Binding) GetAddress() string {
  65. return fmt.Sprintf("%s:%d", b.Address, b.Port)
  66. }
  67. // IsValid returns true if the binding port is > 0
  68. func (b *Binding) IsValid() bool {
  69. return b.Port > 0
  70. }
  71. // Configuration defines the configuration for the WevDAV server
  72. type Configuration struct {
  73. // Addresses and ports to bind to
  74. Bindings []Binding `json:"bindings" mapstructure:"bindings"`
  75. // Deprecated: please use Bindings
  76. BindPort int `json:"bind_port" mapstructure:"bind_port"`
  77. // Deprecated: please use Bindings
  78. BindAddress string `json:"bind_address" mapstructure:"bind_address"`
  79. // If files containing a certificate and matching private key for the server are provided the server will expect
  80. // HTTPS connections.
  81. // Certificate and key files can be reloaded on demand sending a "SIGHUP" signal on Unix based systems and a
  82. // "paramchange" request to the running service on Windows.
  83. CertificateFile string `json:"certificate_file" mapstructure:"certificate_file"`
  84. CertificateKeyFile string `json:"certificate_key_file" mapstructure:"certificate_key_file"`
  85. // CACertificates defines the set of root certificate authorities to use to verify client certificates.
  86. CACertificates []string `json:"ca_certificates" mapstructure:"ca_certificates"`
  87. // CORS configuration
  88. Cors Cors `json:"cors" mapstructure:"cors"`
  89. // Cache configuration
  90. Cache Cache `json:"cache" mapstructure:"cache"`
  91. }
  92. // GetStatus returns the server status
  93. func GetStatus() ServiceStatus {
  94. if server == nil {
  95. return ServiceStatus{}
  96. }
  97. return server.status
  98. }
  99. // ShouldBind returns true if there is at least a valid binding
  100. func (c *Configuration) ShouldBind() bool {
  101. for _, binding := range c.Bindings {
  102. if binding.IsValid() {
  103. return true
  104. }
  105. }
  106. return false
  107. }
  108. // Initialize configures and starts the WebDAV server
  109. func (c *Configuration) Initialize(configDir string) error {
  110. var err error
  111. logger.Debug(logSender, "", "initializing WebDAV server with config %+v", *c)
  112. mimeTypeCache = mimeCache{
  113. maxSize: c.Cache.MimeTypes.MaxSize,
  114. mimeTypes: make(map[string]string),
  115. }
  116. if !c.Cache.MimeTypes.Enabled {
  117. mimeTypeCache.maxSize = 0
  118. }
  119. if !c.ShouldBind() {
  120. return common.ErrNoBinding
  121. }
  122. server, err = newServer(c, configDir)
  123. if err != nil {
  124. return err
  125. }
  126. server.status.Bindings = nil
  127. exitChannel := make(chan error, 1)
  128. for _, binding := range c.Bindings {
  129. if !binding.IsValid() {
  130. continue
  131. }
  132. go func(binding Binding) {
  133. exitChannel <- server.listenAndServe(binding)
  134. }(binding)
  135. }
  136. server.status.IsActive = true
  137. return <-exitChannel
  138. }
  139. // ReloadTLSCertificate reloads the TLS certificate and key from the configured paths
  140. func ReloadTLSCertificate() error {
  141. if server != nil && server.certMgr != nil {
  142. return server.certMgr.LoadCertificate(logSender)
  143. }
  144. return nil
  145. }
  146. func getConfigPath(name, configDir string) string {
  147. if !utils.IsFileInputValid(name) {
  148. return ""
  149. }
  150. if name != "" && !filepath.IsAbs(name) {
  151. return filepath.Join(configDir, name)
  152. }
  153. return name
  154. }