mirror of
https://github.com/rclone/rclone.git
synced 2024-12-23 07:29:35 +01:00
serve http/webdav/restic: implement --prefix - fixes #3398
--prefix enables the servers to serve from a non root prefix. This enables easier proxying.
This commit is contained in:
parent
d51a970932
commit
02eb747d71
@ -68,7 +68,7 @@ func newServer(f fs.Fs, opt *httplib.Options) *server {
|
||||
f: f,
|
||||
vfs: vfs.New(f, &vfsflags.Opt),
|
||||
}
|
||||
mux.HandleFunc("/", s.handler)
|
||||
mux.HandleFunc(s.Opt.Prefix+"/", s.handler)
|
||||
return s
|
||||
}
|
||||
|
||||
@ -93,7 +93,10 @@ func (s *server) handler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
w.Header().Set("Server", "rclone/"+fs.Version)
|
||||
|
||||
urlPath := r.URL.Path
|
||||
urlPath, ok := s.Path(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
isDir := strings.HasSuffix(urlPath, "/")
|
||||
remote := strings.Trim(urlPath, "/")
|
||||
if isDir {
|
||||
|
@ -26,6 +26,9 @@ func AddFlagsPrefix(flagSet *pflag.FlagSet, prefix string, Opt *httplib.Options)
|
||||
flags.StringVarP(flagSet, &Opt.Realm, prefix+"realm", "", Opt.Realm, "realm for authentication")
|
||||
flags.StringVarP(flagSet, &Opt.BasicUser, prefix+"user", "", Opt.BasicUser, "User name for authentication.")
|
||||
flags.StringVarP(flagSet, &Opt.BasicPass, prefix+"pass", "", Opt.BasicPass, "Password for authentication.")
|
||||
if prefix == "" {
|
||||
flags.StringVarP(flagSet, &Opt.Prefix, prefix+"prefix", "", Opt.Prefix, "Prefix for URLs.")
|
||||
}
|
||||
}
|
||||
|
||||
// AddFlags adds flags for the httplib
|
||||
|
@ -44,6 +44,11 @@ for a transfer.
|
||||
--max-header-bytes controls the maximum number of bytes the server will
|
||||
accept in the HTTP header.
|
||||
|
||||
--prefix controls the URL prefix that rclone serves from. By default
|
||||
rclone will serve from the root. If you used --prefix "rclone" then
|
||||
rclone would serve from a URL starting with "/rclone/". This is
|
||||
useful if you wish to proxy rclone serve.
|
||||
|
||||
#### Authentication
|
||||
|
||||
By default this will serve files without needing a login.
|
||||
@ -81,6 +86,7 @@ certificate authority certificate.
|
||||
// Options contains options for the http Server
|
||||
type Options struct {
|
||||
ListenAddr string // Port to listen on
|
||||
Prefix string // prefix to strip from URLs
|
||||
ServerReadTimeout time.Duration // Timeout for server reading data
|
||||
ServerWriteTimeout time.Duration // Timeout for server writing data
|
||||
MaxHeaderBytes int // Maximum size of request header
|
||||
@ -190,6 +196,14 @@ func NewServer(handler http.Handler, opt *Options) *Server {
|
||||
log.Fatalf("Need both -cert and -key to use SSL")
|
||||
}
|
||||
|
||||
// If a Path is set then serve from there
|
||||
if strings.HasSuffix(s.Opt.Prefix, "/") {
|
||||
s.Opt.Prefix = s.Opt.Prefix[:len(s.Opt.Prefix)-1]
|
||||
}
|
||||
if s.Opt.Prefix != "" && !strings.HasPrefix(s.Opt.Prefix, "/") {
|
||||
s.Opt.Prefix = "/" + s.Opt.Prefix
|
||||
}
|
||||
|
||||
// FIXME make a transport?
|
||||
s.httpServer = &http.Server{
|
||||
Addr: s.Opt.ListenAddr,
|
||||
@ -299,10 +313,27 @@ func (s *Server) URL() string {
|
||||
// (i.e. port assigned by operating system)
|
||||
addr = s.listener.Addr().String()
|
||||
}
|
||||
return fmt.Sprintf("%s://%s/", proto, addr)
|
||||
return fmt.Sprintf("%s://%s%s/", proto, addr, s.Opt.Prefix)
|
||||
}
|
||||
|
||||
// UsingAuth returns true if authentication is required
|
||||
func (s *Server) UsingAuth() bool {
|
||||
return s.usingAuth
|
||||
}
|
||||
|
||||
// Path returns the current path with the Prefix stripped
|
||||
//
|
||||
// If it returns false, then the path was invalid and the handler
|
||||
// should exit as the error response has already been sent
|
||||
func (s *Server) Path(w http.ResponseWriter, r *http.Request) (Path string, ok bool) {
|
||||
Path = r.URL.Path
|
||||
if s.Opt.Prefix == "" {
|
||||
return Path, true
|
||||
}
|
||||
if !strings.HasPrefix(Path, s.Opt.Prefix+"/") {
|
||||
http.Error(w, http.StatusText(http.StatusNotFound), http.StatusNotFound)
|
||||
return Path, false
|
||||
}
|
||||
Path = Path[len(s.Opt.Prefix):]
|
||||
return Path, true
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ func newServer(f fs.Fs, opt *httplib.Options) *server {
|
||||
Server: httplib.NewServer(mux, opt),
|
||||
f: f,
|
||||
}
|
||||
mux.HandleFunc("/", s.handler)
|
||||
mux.HandleFunc(s.Opt.Prefix+"/", s.handler)
|
||||
return s
|
||||
}
|
||||
|
||||
@ -211,7 +211,10 @@ func (s *server) handler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Accept-Ranges", "bytes")
|
||||
w.Header().Set("Server", "rclone/"+fs.Version)
|
||||
|
||||
path := r.URL.Path
|
||||
path, ok := s.Path(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
remote := makeRemote(path)
|
||||
fs.Debugf(s.f, "%s %s", r.Method, path)
|
||||
|
||||
|
@ -114,18 +114,22 @@ func newWebDAV(f fs.Fs, opt *httplib.Options) *WebDAV {
|
||||
f: f,
|
||||
vfs: vfs.New(f, &vfsflags.Opt),
|
||||
}
|
||||
w.Server = httplib.NewServer(http.HandlerFunc(w.handler), opt)
|
||||
webdavHandler := &webdav.Handler{
|
||||
Prefix: w.Server.Opt.Prefix,
|
||||
FileSystem: w,
|
||||
LockSystem: webdav.NewMemLS(),
|
||||
Logger: w.logRequest, // FIXME
|
||||
}
|
||||
w.webdavhandler = webdavHandler
|
||||
w.Server = httplib.NewServer(http.HandlerFunc(w.handler), opt)
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *WebDAV) handler(rw http.ResponseWriter, r *http.Request) {
|
||||
urlPath := r.URL.Path
|
||||
urlPath, ok := w.Path(rw, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
isDir := strings.HasSuffix(urlPath, "/")
|
||||
remote := strings.Trim(urlPath, "/")
|
||||
if !disableGETDir && (r.Method == "GET" || r.Method == "HEAD") && isDir {
|
||||
|
Loading…
Reference in New Issue
Block a user