-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by: 117503445 <[email protected]>
- Loading branch information
Showing
5 changed files
with
265 additions
and
88 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package common | ||
|
||
import ( | ||
"os" | ||
) | ||
|
||
// GetProjectRoot returns the root directory of the project, e.g. "/root/project/GoWebDAV/" | ||
func GetProjectRoot() string { | ||
wd, _ := os.Getwd() | ||
// look for parents until we find a directory with a .git folder | ||
for { | ||
if _, err := os.Stat(wd + "/.git"); err == nil { | ||
break | ||
} | ||
wd = wd[:len(wd)-1] | ||
} | ||
|
||
return wd | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
package server | ||
|
||
import ( | ||
"errors" | ||
"net/http" | ||
"os" | ||
"strings" | ||
|
||
"golang.org/x/net/webdav" | ||
) | ||
|
||
type HandlerConfig struct { | ||
Prefix string | ||
PathDir string | ||
Username string | ||
Password string | ||
ReadOnly bool | ||
} | ||
|
||
type handler struct { | ||
handler *webdav.Handler | ||
|
||
prefix string // URL prefix | ||
dirPath string // File system directory | ||
|
||
username string // HTTP Basic Auth Username. if empty, no auth | ||
password string // HTTP Basic Auth Password | ||
|
||
readOnly bool // if true, only allow GET, OPTIONS, PROPFIND, HEAD | ||
} | ||
|
||
func NewHandler(cfg *HandlerConfig) *handler { | ||
return &handler{ | ||
handler: &webdav.Handler{ | ||
FileSystem: webdav.Dir(cfg.PathDir), | ||
LockSystem: webdav.NewMemLS(), | ||
Prefix: cfg.Prefix, | ||
}, | ||
prefix: cfg.Prefix, | ||
dirPath: cfg.PathDir, | ||
username: cfg.Username, | ||
password: cfg.Password, | ||
readOnly: cfg.ReadOnly, | ||
} | ||
} | ||
|
||
func (h *handler) ServeHTTP(w http.ResponseWriter, req *http.Request) { | ||
enableBasicAuth := h.username != "" | ||
if enableBasicAuth { | ||
username, password, ok := req.BasicAuth() | ||
// log.Debug().Str("username", username).Str("password", password).Bool("ok", ok).Msg("BasicAuth Request") | ||
if !ok { | ||
w.Header().Set("WWW-Authenticate", `Basic realm="Restricted"`) | ||
w.WriteHeader(http.StatusUnauthorized) | ||
return | ||
} | ||
|
||
if username != h.username || password != h.password { | ||
w.WriteHeader(http.StatusUnauthorized) | ||
return | ||
} | ||
} | ||
|
||
if h.readOnly { | ||
allowedMethods := map[string]bool{ | ||
"GET": true, | ||
"OPTIONS": true, | ||
"PROPFIND": true, | ||
"HEAD": true, | ||
} | ||
if !allowedMethods[req.Method] { | ||
w.WriteHeader(http.StatusMethodNotAllowed) | ||
return | ||
} | ||
} | ||
|
||
h.handler.ServeHTTP(w, req) | ||
} | ||
|
||
func checkHandlerConfig(cfg *HandlerConfig) error { | ||
// prefix must start with "/", contains only one "/" | ||
if cfg.Prefix == "" || cfg.Prefix[0] != '/' { | ||
return errors.New("prefix must start with /") | ||
} | ||
|
||
// prefix must contain only one "/" | ||
if strings.Count(cfg.Prefix, "/") != 1 { | ||
return errors.New("prefix must contain only one /") | ||
} | ||
|
||
// prefix must not contain not allowed characters | ||
notAllowedChars := []string{"?", "%", "#", "&"} | ||
for _, char := range notAllowedChars { | ||
if strings.Contains(cfg.Prefix, char) { | ||
return errors.New("prefix must not contain " + char) | ||
} | ||
} | ||
|
||
// pathDir must be a valid directory | ||
if fileinfo, err := os.Stat(cfg.PathDir); err != nil { | ||
return err | ||
} else if !fileinfo.IsDir() { | ||
return errors.New("pathDir must be a directory") | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func checkHandlerConfigs(cfgs []*HandlerConfig) error { | ||
for _, cfg := range cfgs { | ||
if err := checkHandlerConfig(cfg); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
prefixs := make(map[string]bool) | ||
for _, cfg := range cfgs { | ||
if _, ok := prefixs[cfg.Prefix]; ok { | ||
return errors.New("prefix " + cfg.Prefix + " is duplicated") | ||
} | ||
prefixs[cfg.Prefix] = true | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
package server | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestHandlerConfig(t *testing.T) { | ||
assert := assert.New(t) | ||
|
||
wd, err := os.Getwd() | ||
assert.Nil(err) | ||
|
||
cases := []struct { | ||
cfg *HandlerConfig | ||
valid bool | ||
}{ | ||
{ | ||
&HandlerConfig{ | ||
Prefix: "/data", | ||
PathDir: wd, | ||
}, | ||
true, | ||
}, { | ||
&HandlerConfig{ | ||
Prefix: "/", | ||
PathDir: wd, | ||
}, | ||
true, | ||
}, { | ||
&HandlerConfig{ | ||
Prefix: "data", | ||
PathDir: wd, | ||
}, | ||
false, | ||
}, { | ||
&HandlerConfig{ | ||
Prefix: "/data/", | ||
PathDir: wd, | ||
}, | ||
false, | ||
}, { | ||
&HandlerConfig{ | ||
Prefix: "/114?514", | ||
PathDir: wd, | ||
}, | ||
false, | ||
}, { | ||
&HandlerConfig{ | ||
Prefix: "/data", | ||
PathDir: "/114514", | ||
}, | ||
false, | ||
}, | ||
} | ||
|
||
for _, c := range cases { | ||
if c.valid { | ||
assert.Nil(checkHandlerConfig(c.cfg), "cfg: %+v should be valid", c.cfg) | ||
} else { | ||
assert.NotNil(checkHandlerConfig(c.cfg), "cfg: %+v should be invalid", c.cfg) | ||
} | ||
} | ||
} | ||
|
||
func TestHandlerConfigs(t *testing.T) { | ||
assert := assert.New(t) | ||
|
||
wd, err := os.Getwd() | ||
assert.Nil(err) | ||
|
||
cases := []struct { | ||
cfgs []*HandlerConfig | ||
valid bool | ||
}{ | ||
{ | ||
[]*HandlerConfig{ | ||
{ | ||
Prefix: "/data1", | ||
PathDir: wd, | ||
}, | ||
{ | ||
Prefix: "/data2", | ||
PathDir: wd, | ||
}, | ||
}, | ||
true, | ||
}, { | ||
[]*HandlerConfig{ | ||
{ | ||
Prefix: "/data1", | ||
PathDir: wd, | ||
}, | ||
{ | ||
Prefix: "/data1", | ||
PathDir: wd, | ||
}, | ||
}, | ||
false, | ||
}, | ||
} | ||
|
||
for _, c := range cases { | ||
if c.valid { | ||
assert.Nil(checkHandlerConfigs(c.cfgs), "cfgs: %+v should be valid", c.cfgs) | ||
} else { | ||
assert.NotNil(checkHandlerConfigs(c.cfgs), "cfgs: %+v should be invalid", c.cfgs) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters