2018-10-28 14:08:20 +00:00
|
|
|
package serve
|
|
|
|
|
|
|
|
import (
|
2019-09-22 20:31:11 +00:00
|
|
|
"bytes"
|
2018-10-28 14:08:20 +00:00
|
|
|
"fmt"
|
|
|
|
"html/template"
|
|
|
|
"net/http"
|
|
|
|
"net/url"
|
|
|
|
"path"
|
|
|
|
|
2019-07-28 17:47:38 +00:00
|
|
|
"github.com/rclone/rclone/fs"
|
|
|
|
"github.com/rclone/rclone/fs/accounting"
|
|
|
|
"github.com/rclone/rclone/lib/rest"
|
2018-10-28 14:08:20 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// DirEntry is a directory entry
|
|
|
|
type DirEntry struct {
|
|
|
|
remote string
|
|
|
|
URL string
|
|
|
|
Leaf string
|
|
|
|
}
|
|
|
|
|
|
|
|
// Directory represents a directory
|
|
|
|
type Directory struct {
|
2018-12-23 00:16:50 +00:00
|
|
|
DirRemote string
|
|
|
|
Title string
|
|
|
|
Entries []DirEntry
|
|
|
|
Query string
|
|
|
|
HTMLTemplate *template.Template
|
2018-10-28 14:08:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewDirectory makes an empty Directory
|
2018-12-23 00:16:50 +00:00
|
|
|
func NewDirectory(dirRemote string, htmlTemplate *template.Template) *Directory {
|
2018-10-28 14:08:20 +00:00
|
|
|
d := &Directory{
|
2018-12-23 00:16:50 +00:00
|
|
|
DirRemote: dirRemote,
|
|
|
|
Title: fmt.Sprintf("Directory listing of /%s", dirRemote),
|
|
|
|
HTMLTemplate: htmlTemplate,
|
2018-10-28 14:08:20 +00:00
|
|
|
}
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetQuery sets the query parameters for each URL
|
|
|
|
func (d *Directory) SetQuery(queryParams url.Values) *Directory {
|
|
|
|
d.Query = ""
|
|
|
|
if len(queryParams) > 0 {
|
|
|
|
d.Query = "?" + queryParams.Encode()
|
|
|
|
}
|
|
|
|
return d
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddEntry adds an entry to that directory
|
|
|
|
func (d *Directory) AddEntry(remote string, isDir bool) {
|
|
|
|
leaf := path.Base(remote)
|
|
|
|
if leaf == "." {
|
|
|
|
leaf = ""
|
|
|
|
}
|
|
|
|
urlRemote := leaf
|
|
|
|
if isDir {
|
|
|
|
leaf += "/"
|
|
|
|
urlRemote += "/"
|
|
|
|
}
|
|
|
|
d.Entries = append(d.Entries, DirEntry{
|
|
|
|
remote: remote,
|
|
|
|
URL: rest.URLPathEscape(urlRemote) + d.Query,
|
|
|
|
Leaf: leaf,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-09-22 20:31:11 +00:00
|
|
|
// Error logs the error and if a ResponseWriter is given it writes a http.StatusInternalServerError
|
2018-10-28 14:08:20 +00:00
|
|
|
func Error(what interface{}, w http.ResponseWriter, text string, err error) {
|
2019-11-18 14:13:02 +00:00
|
|
|
err = fs.CountError(err)
|
2018-10-28 14:08:20 +00:00
|
|
|
fs.Errorf(what, "%s: %v", text, err)
|
2019-09-22 20:31:11 +00:00
|
|
|
if w != nil {
|
|
|
|
http.Error(w, text+".", http.StatusInternalServerError)
|
|
|
|
}
|
2018-10-28 14:08:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Serve serves a directory
|
|
|
|
func (d *Directory) Serve(w http.ResponseWriter, r *http.Request) {
|
|
|
|
// Account the transfer
|
2019-07-18 10:13:54 +00:00
|
|
|
tr := accounting.Stats(r.Context()).NewTransferRemoteSize(d.DirRemote, -1)
|
2019-07-16 11:56:20 +00:00
|
|
|
defer tr.Done(nil)
|
2018-10-28 14:08:20 +00:00
|
|
|
|
|
|
|
fs.Infof(d.DirRemote, "%s: Serving directory", r.RemoteAddr)
|
2018-12-23 00:16:50 +00:00
|
|
|
|
2019-09-22 20:31:11 +00:00
|
|
|
buf := &bytes.Buffer{}
|
|
|
|
err := d.HTMLTemplate.Execute(buf, d)
|
2018-10-28 14:08:20 +00:00
|
|
|
if err != nil {
|
|
|
|
Error(d.DirRemote, w, "Failed to render template", err)
|
|
|
|
return
|
|
|
|
}
|
2019-09-22 20:31:11 +00:00
|
|
|
_, err = buf.WriteTo(w)
|
|
|
|
if err != nil {
|
|
|
|
Error(d.DirRemote, nil, "Failed to drain template buffer", err)
|
|
|
|
}
|
2018-10-28 14:08:20 +00:00
|
|
|
}
|