diff --git a/drivers/webdav/driver.go b/drivers/webdav/driver.go index 5aedca3d..ce47b0fa 100644 --- a/drivers/webdav/driver.go +++ b/drivers/webdav/driver.go @@ -73,24 +73,14 @@ func (d *WebDav) List(ctx context.Context, dir model.Obj, args model.ListArgs) ( //} func (d *WebDav) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { - callback := func(r *http.Request) { - if args.Header.Get("Range") != "" { - r.Header.Set("Range", args.Header.Get("Range")) - } - if args.Header.Get("If-Range") != "" { - r.Header.Set("If-Range", args.Header.Get("If-Range")) - } - } - reader, header, err := d.client.ReadStream(file.GetPath(), callback) + url, header, err := d.client.Link(file.GetPath()) if err != nil { return nil, err } - link := &model.Link{Data: reader} - if header.Get("Content-Range") != "" { - link.Status = 206 - link.Header = header - } - return link, nil + return &model.Link{ + URL: url, + Header: header, + }, nil } func (d *WebDav) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { diff --git a/drivers/webdav/meta.go b/drivers/webdav/meta.go index a34faf3a..806f582e 100644 --- a/drivers/webdav/meta.go +++ b/drivers/webdav/meta.go @@ -16,7 +16,7 @@ type Addition struct { var config = driver.Config{ Name: "WebDav", LocalSort: true, - OnlyLocal: true, + OnlyProxy: true, DefaultRoot: "/", } diff --git a/pkg/gowebdav/client.go b/pkg/gowebdav/client.go index 0197dccc..1a25b76d 100644 --- a/pkg/gowebdav/client.go +++ b/pkg/gowebdav/client.go @@ -342,6 +342,58 @@ func (c *Client) Read(path string) ([]byte, error) { return buf.Bytes(), nil } +func (c *Client) Link(path string) (string, http.Header, error) { + method := "HEAD" + url := PathEscape(Join(c.root, path)) + r, err := http.NewRequest(method, url, nil) + + if err != nil { + return "", nil, newPathErrorErr("Link", path, err) + } + + for k, vals := range c.headers { + for _, v := range vals { + r.Header.Add(k, v) + } + } + + c.authMutex.Lock() + auth := c.auth + c.authMutex.Unlock() + + auth.Authorize(r, method, path) + + if c.interceptor != nil { + c.interceptor(method, r) + } + + rs, err := c.c.Do(r) + if err != nil { + return "", nil, newPathErrorErr("Link", path, err) + } + + if rs.StatusCode == 401 { + wwwAuthenticateHeader := strings.ToLower(rs.Header.Get("Www-Authenticate")) + if strings.Contains(wwwAuthenticateHeader, "digest") { + c.authMutex.Lock() + c.auth = &DigestAuth{auth.User(), auth.Pass(), digestParts(rs)} + c.auth.Authorize(r, method, path) + c.authMutex.Unlock() + } else if strings.Contains(wwwAuthenticateHeader, "basic") { + c.authMutex.Lock() + c.auth = &BasicAuth{auth.User(), auth.Pass()} + c.auth.Authorize(r, method, path) + c.authMutex.Unlock() + } else { + return "", nil, newPathError("Authorize", c.root, rs.StatusCode) + } + } else if rs.StatusCode > 400 { + return "", nil, newPathError("Authorize", path, rs.StatusCode) + } + + return r.URL.String(), r.Header, nil +} + // ReadStream reads the stream for a given path func (c *Client) ReadStream(path string, callback func(rq *http.Request)) (io.ReadCloser, http.Header, error) { rs, err := c.req("GET", path, nil, callback) diff --git a/server/common/proxy.go b/server/common/proxy.go index 8d0b39e7..21e4cb71 100644 --- a/server/common/proxy.go +++ b/server/common/proxy.go @@ -28,6 +28,8 @@ func Proxy(w http.ResponseWriter, r *http.Request, link *model.Link, file model. w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"; filename*=UTF-8''%s`, file.GetName(), url.QueryEscape(file.GetName()))) w.Header().Set("Content-Length", strconv.FormatInt(file.GetSize(), 10)) if link.Header != nil { + // TODO clean header with blacklist or whitelist + link.Header.Del("set-cookie") for h, val := range link.Header { w.Header()[h] = val } @@ -81,6 +83,8 @@ func Proxy(w http.ResponseWriter, r *http.Request, link *model.Link, file model. _ = res.Body.Close() }() log.Debugf("proxy status: %d", res.StatusCode) + // TODO clean header with blacklist or whitelist + res.Header.Del("set-cookie") for h, v := range res.Header { w.Header()[h] = v } diff --git a/server/webdav/webdav.go b/server/webdav/webdav.go index caac7d61..f8cb8fcf 100644 --- a/server/webdav/webdav.go +++ b/server/webdav/webdav.go @@ -218,7 +218,8 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (sta w.Header().Set("ETag", etag) // Let ServeContent determine the Content-Type header. storage, _ := fs.GetStorage(reqPath) - if storage.GetStorage().WebdavNative() { + downProxyUrl := storage.GetStorage().DownProxyUrl + if storage.GetStorage().WebdavNative() || (storage.GetStorage().WebdavProxy() && downProxyUrl == "") { link, _, err := fs.Link(ctx, reqPath, model.LinkArgs{Header: r.Header}) if err != nil { return http.StatusInternalServerError, err @@ -227,19 +228,19 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request) (sta if err != nil { return http.StatusInternalServerError, err } - } else if storage.Config().MustProxy() || storage.GetStorage().WebdavProxy() { - u := fmt.Sprintf("%s/p%s?sign=%s", - common.GetApiUrl(r), + } else if storage.GetStorage().WebdavProxy() && downProxyUrl != "" { + u := fmt.Sprintf("%s%s?sign=%s", + strings.Split(downProxyUrl, "\n")[0], utils.EncodePath(reqPath, true), sign.Sign(reqPath)) w.Header().Set("Cache-Control", "max-age=0, no-cache, no-store, must-revalidate") - http.Redirect(w, r, u, 302) + http.Redirect(w, r, u, http.StatusFound) } else { link, _, err := fs.Link(ctx, reqPath, model.LinkArgs{IP: utils.ClientIP(r)}) if err != nil { return http.StatusInternalServerError, err } - http.Redirect(w, r, link.URL, 302) + http.Redirect(w, r, link.URL, http.StatusFound) } return 0, nil }