diff --git a/cmd/serve/http/http.go b/cmd/serve/http/http.go index f199c9fce..c10019480 100644 --- a/cmd/serve/http/http.go +++ b/cmd/serve/http/http.go @@ -43,7 +43,7 @@ control the stats printing. cmd.CheckArgs(1, 1, command, args) f := cmd.NewFsSrc(args) cmd.Run(false, true, command, func() error { - s := NewServer(f, &httpflags.Opt) + s := newServer(f, &httpflags.Opt) err := s.Serve() if err != nil { return err @@ -54,29 +54,28 @@ control the stats printing. }, } -// Server contains everything to run the Server -type Server struct { +// server contains everything to run the server +type server struct { *httplib.Server f fs.Fs vfs *vfs.VFS } -// NewServer creates a new http server -func NewServer(f fs.Fs, opt *httplib.Options) *Server { +func newServer(f fs.Fs, opt *httplib.Options) *server { mux := http.NewServeMux() - s := &Server{ + s := &server{ Server: httplib.NewServer(mux, opt), f: f, vfs: vfs.New(f, &vfsflags.Opt), } - mux.HandleFunc("/", s.Handler) + mux.HandleFunc("/", s.handler) return s } -// Serve runs the http Server in the background. +// Serve runs the http server in the background. // -// Use s.Close() and s.Wait() to shutdown Server -func (s *Server) Serve() error { +// Use s.Close() and s.Wait() to shutdown server +func (s *server) Serve() error { err := s.Server.Serve() if err != nil { return err @@ -85,8 +84,8 @@ func (s *Server) Serve() error { return nil } -// Handler reads incoming requests and dispatches them -func (s *Server) Handler(w http.ResponseWriter, r *http.Request) { +// handler reads incoming requests and dispatches them +func (s *server) handler(w http.ResponseWriter, r *http.Request) { if r.Method != "GET" && r.Method != "HEAD" { http.Error(w, "Method not allowed", http.StatusMethodNotAllowed) return @@ -105,7 +104,7 @@ func (s *Server) Handler(w http.ResponseWriter, r *http.Request) { } // serveDir serves a directory index at dirRemote -func (s *Server) serveDir(w http.ResponseWriter, r *http.Request, dirRemote string) { +func (s *server) serveDir(w http.ResponseWriter, r *http.Request, dirRemote string) { // List the directory node, err := s.vfs.Stat(dirRemote) if err == vfs.ENOENT { @@ -136,7 +135,7 @@ func (s *Server) serveDir(w http.ResponseWriter, r *http.Request, dirRemote stri } // serveFile serves a file object at remote -func (s *Server) serveFile(w http.ResponseWriter, r *http.Request, remote string) { +func (s *server) serveFile(w http.ResponseWriter, r *http.Request, remote string) { node, err := s.vfs.Stat(remote) if err == vfs.ENOENT { fs.Infof(remote, "%s: File not found", r.RemoteAddr) diff --git a/cmd/serve/http/http_test.go b/cmd/serve/http/http_test.go index d6616f5e1..e43aeed3b 100644 --- a/cmd/serve/http/http_test.go +++ b/cmd/serve/http/http_test.go @@ -19,7 +19,7 @@ import ( var ( updateGolden = flag.Bool("updategolden", false, "update golden files for regression test") - httpServer *Server + httpServer *server testURL string ) @@ -30,7 +30,7 @@ const ( func startServer(t *testing.T, f fs.Fs) { opt := httplib.DefaultOpt opt.ListenAddr = testBindAddress - httpServer = NewServer(f, &opt) + httpServer = newServer(f, &opt) assert.NoError(t, httpServer.Serve()) testURL = httpServer.Server.URL() diff --git a/cmd/serve/webdav/webdav.go b/cmd/serve/webdav/webdav.go index 795ecceb2..bee8e0c5e 100644 --- a/cmd/serve/webdav/webdav.go +++ b/cmd/serve/webdav/webdav.go @@ -9,9 +9,9 @@ import ( "strings" "github.com/ncw/rclone/cmd" - rhttp "github.com/ncw/rclone/cmd/serve/http" "github.com/ncw/rclone/cmd/serve/httplib" "github.com/ncw/rclone/cmd/serve/httplib/httpflags" + "github.com/ncw/rclone/cmd/serve/httplib/serve" "github.com/ncw/rclone/fs" "github.com/ncw/rclone/fs/hash" "github.com/ncw/rclone/fs/log" @@ -41,8 +41,8 @@ var Command = &cobra.Command{ Long: ` rclone serve webdav implements a basic webdav server to serve the remote over HTTP via the webdav protocol. This can be viewed with a -webdav client or you can make a remote of type webdav to read and -write it. +webdav client, through a web browser, or you can make a remote of +type webdav to read and write it. ### Webdav options @@ -103,7 +103,6 @@ type WebDAV struct { f fs.Fs vfs *vfs.VFS webdavhandler *webdav.Handler - httpserver *rhttp.Server } // check interface @@ -121,21 +120,53 @@ func newWebDAV(f fs.Fs, opt *httplib.Options) *WebDAV { Logger: w.logRequest, // FIXME } w.webdavhandler = webdavHandler - if !disableGETDir { - w.httpserver = rhttp.NewServer(f, opt) - } w.Server = httplib.NewServer(http.HandlerFunc(w.handler), opt) return w } func (w *WebDAV) handler(rw http.ResponseWriter, r *http.Request) { - if !disableGETDir && (r.Method == "GET" || r.Method == "HEAD") && strings.HasSuffix(r.URL.Path, "/") { - w.httpserver.Handler(rw, r) + urlPath := r.URL.Path + isDir := strings.HasSuffix(urlPath, "/") + remote := strings.Trim(urlPath, "/") + if !disableGETDir && (r.Method == "GET" || r.Method == "HEAD") && isDir { + w.serveDir(rw, r, remote) return } w.webdavhandler.ServeHTTP(rw, r) } +// serveDir serves a directory index at dirRemote +// This is similar to serveDir in serve http. +func (w *WebDAV) serveDir(rw http.ResponseWriter, r *http.Request, dirRemote string) { + // List the directory + node, err := w.vfs.Stat(dirRemote) + if err == vfs.ENOENT { + http.Error(rw, "Directory not found", http.StatusNotFound) + return + } else if err != nil { + serve.Error(dirRemote, rw, "Failed to list directory", err) + return + } + if !node.IsDir() { + http.Error(rw, "Not a directory", http.StatusNotFound) + return + } + dir := node.(*vfs.Dir) + dirEntries, err := dir.ReadDirAll() + if err != nil { + serve.Error(dirRemote, rw, "Failed to list directory", err) + return + } + + // Make the entries for display + directory := serve.NewDirectory(dirRemote, w.HTMLTemplate) + for _, node := range dirEntries { + directory.AddEntry(node.Path(), node.IsDir()) + } + + directory.Serve(rw, r) +} + // serve runs the http server in the background. // // Use s.Close() and s.Wait() to shutdown server