rcserver: set ModTime for dirs and files served by --rc-serve

This commit is contained in:
Nikita Shoshin 2023-09-25 22:03:38 +04:00 committed by Nick Craig-Wood
parent 08bf5228a7
commit 92368f6d2b
10 changed files with 66 additions and 8 deletions

1
.gitignore vendored
View File

@ -7,6 +7,7 @@ docs/public
rclone.iml rclone.iml
.idea .idea
.history .history
.vscode
*.test *.test
*.iml *.iml
fuzz-build.zip fuzz-build.zip

View File

@ -281,6 +281,7 @@ Flags to control the Remote Control API.
--rc-realm string Realm for authentication --rc-realm string Realm for authentication
--rc-salt string Password hashing salt (default "dlPL2MqE") --rc-salt string Password hashing salt (default "dlPL2MqE")
--rc-serve Enable the serving of remote objects --rc-serve Enable the serving of remote objects
--rc-serve-no-modtime Don't read the modification time (can speed things up)
--rc-server-read-timeout Duration Timeout for server reading data (default 1h0m0s) --rc-server-read-timeout Duration Timeout for server reading data (default 1h0m0s)
--rc-server-write-timeout Duration Timeout for server writing data (default 1h0m0s) --rc-server-write-timeout Duration Timeout for server writing data (default 1h0m0s)
--rc-template string User-specified template --rc-template string User-specified template

View File

@ -77,6 +77,12 @@ remotes using this syntax http://127.0.0.1:5572/[remote:path]/path/to/object
Default Off. Default Off.
### --rc-serve-no-modtime
Set this flag to skip reading the modification time (can speed things up).
Default Off.
### --rc-files /path/to/directory ### --rc-files /path/to/directory
Path to local files to serve on the HTTP server. Path to local files to serve on the HTTP server.

View File

@ -23,6 +23,7 @@ type Options struct {
Template libhttp.TemplateConfig Template libhttp.TemplateConfig
Enabled bool // set to enable the server Enabled bool // set to enable the server
Serve bool // set to serve files from remotes Serve bool // set to serve files from remotes
ServeNoModTime bool // don't read the modification time
Files string // set to enable serving files locally Files string // set to enable serving files locally
NoAuth bool // set to disable auth checks on AuthRequired methods NoAuth bool // set to disable auth checks on AuthRequired methods
WebUI bool // set to launch the web ui WebUI bool // set to launch the web ui

View File

@ -21,6 +21,7 @@ func AddFlags(flagSet *pflag.FlagSet) {
flags.BoolVarP(flagSet, &Opt.Enabled, "rc", "", false, "Enable the remote control server", "RC") flags.BoolVarP(flagSet, &Opt.Enabled, "rc", "", false, "Enable the remote control server", "RC")
flags.StringVarP(flagSet, &Opt.Files, "rc-files", "", "", "Path to local files to serve on the HTTP server", "RC") flags.StringVarP(flagSet, &Opt.Files, "rc-files", "", "", "Path to local files to serve on the HTTP server", "RC")
flags.BoolVarP(flagSet, &Opt.Serve, "rc-serve", "", false, "Enable the serving of remote objects", "RC") flags.BoolVarP(flagSet, &Opt.Serve, "rc-serve", "", false, "Enable the serving of remote objects", "RC")
flags.BoolVarP(flagSet, &Opt.ServeNoModTime, "rc-serve-no-modtime", "", false, "Don't read the modification time (can speed things up)", "RC")
flags.BoolVarP(flagSet, &Opt.NoAuth, "rc-no-auth", "", false, "Don't require auth for certain methods", "RC") flags.BoolVarP(flagSet, &Opt.NoAuth, "rc-no-auth", "", false, "Don't require auth for certain methods", "RC")
flags.BoolVarP(flagSet, &Opt.WebUI, "rc-web-gui", "", false, "Launch WebGUI on localhost", "RC") flags.BoolVarP(flagSet, &Opt.WebUI, "rc-web-gui", "", false, "Launch WebGUI on localhost", "RC")
flags.BoolVarP(flagSet, &Opt.WebGUIUpdate, "rc-web-gui-update", "", false, "Check and update to latest version of web gui", "RC") flags.BoolVarP(flagSet, &Opt.WebGUIUpdate, "rc-web-gui-update", "", false, "Check and update to latest version of web gui", "RC")

View File

@ -340,8 +340,11 @@ func (s *Server) serveRemote(w http.ResponseWriter, r *http.Request, path string
directory := serve.NewDirectory(path, s.server.HTMLTemplate()) directory := serve.NewDirectory(path, s.server.HTMLTemplate())
for _, entry := range entries { for _, entry := range entries {
_, isDir := entry.(fs.Directory) _, isDir := entry.(fs.Directory)
//directory.AddHTMLEntry(entry.Remote(), isDir, entry.Size(), entry.ModTime(r.Context())) var modTime time.Time
directory.AddHTMLEntry(entry.Remote(), isDir, entry.Size(), time.Time{}) if !s.opt.ServeNoModTime {
modTime = entry.ModTime(r.Context())
}
directory.AddHTMLEntry(entry.Remote(), isDir, entry.Size(), modTime)
} }
sortParm := r.URL.Query().Get("sort") sortParm := r.URL.Query().Get("sort")
orderParm := r.URL.Query().Get("order") orderParm := r.URL.Query().Get("order")

View File

@ -8,6 +8,7 @@ import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"os" "os"
"path/filepath"
"regexp" "regexp"
"strings" "strings"
"testing" "testing"
@ -23,10 +24,10 @@ import (
) )
const ( const (
testBindAddress = "localhost:0" testBindAddress = "localhost:0"
testTemplate = "testdata/golden/testindex.html" defaultTestTemplate = "testdata/golden/testindex.html"
testFs = "testdata/files" testFs = "testdata/files"
remoteURL = "[" + testFs + "]/" // initial URL path to fetch from that remote remoteURL = "[" + testFs + "]/" // initial URL path to fetch from that remote
) )
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -49,7 +50,7 @@ func TestMain(m *testing.M) {
func TestRcServer(t *testing.T) { func TestRcServer(t *testing.T) {
opt := rc.DefaultOpt opt := rc.DefaultOpt
opt.HTTP.ListenAddr = []string{testBindAddress} opt.HTTP.ListenAddr = []string{testBindAddress}
opt.Template.Path = testTemplate opt.Template.Path = defaultTestTemplate
opt.Enabled = true opt.Enabled = true
opt.Serve = true opt.Serve = true
opt.Files = testFs opt.Files = testFs
@ -102,15 +103,21 @@ type testRun struct {
// Run a suite of tests // Run a suite of tests
func testServer(t *testing.T, tests []testRun, opt *rc.Options) { func testServer(t *testing.T, tests []testRun, opt *rc.Options) {
t.Helper()
ctx := context.Background() ctx := context.Background()
configfile.Install() configfile.Install()
opt.Template.Path = testTemplate if opt.Template.Path == "" {
opt.Template.Path = defaultTestTemplate
}
rcServer, err := newServer(ctx, opt, http.DefaultServeMux) rcServer, err := newServer(ctx, opt, http.DefaultServeMux)
require.NoError(t, err) require.NoError(t, err)
testURL := rcServer.server.URLs()[0] testURL := rcServer.server.URLs()[0]
mux := rcServer.server.Router() mux := rcServer.server.Router()
for _, test := range tests { for _, test := range tests {
t.Run(test.Name, func(t *testing.T) { t.Run(test.Name, func(t *testing.T) {
t.Helper()
method := test.Method method := test.Method
if method == "" { if method == "" {
method = "GET" method = "GET"
@ -172,6 +179,7 @@ func TestFileServing(t *testing.T) {
Expected: `<pre> Expected: `<pre>
<a href="dir/">dir/</a> <a href="dir/">dir/</a>
<a href="file.txt">file.txt</a> <a href="file.txt">file.txt</a>
<a href="modtime/">modtime/</a>
</pre> </pre>
`, `,
}, { }, {
@ -243,6 +251,7 @@ func TestRemoteServing(t *testing.T) {
<body> <body>
<h1>Directory listing of /</h1> <h1>Directory listing of /</h1>
<a href="dir/">dir/</a><br /> <a href="dir/">dir/</a><br />
<a href="modtime/">modtime/</a><br />
<a href="file.txt">file.txt</a><br /> <a href="file.txt">file.txt</a><br />
</body> </body>
</html> </html>
@ -804,3 +813,37 @@ func TestRCDebug(t *testing.T) {
opt.Files = "" opt.Files = ""
testServer(t, tests, &opt) testServer(t, tests, &opt)
} }
func TestServeModTime(t *testing.T) {
for file, mtime := range map[string]time.Time{
"dir": time.Date(2023, 4, 12, 21, 15, 17, 0, time.UTC),
"modtime.txt": time.Date(2021, 1, 18, 5, 2, 28, 0, time.UTC),
} {
path := filepath.Join(testFs, "modtime", file)
err := os.Chtimes(path, mtime, mtime)
require.NoError(t, err)
}
opt := newTestOpt()
opt.Serve = true
opt.Template.Path = "testdata/golden/testmodtime.html"
tests := []testRun{{
Name: "modtime",
Method: "GET",
URL: remoteURL + "modtime/",
Status: http.StatusOK,
Expected: "* dir/ - 2023-04-12T21:15:17Z\n* modtime.txt - 2021-01-18T05:02:28Z\n",
}}
testServer(t, tests, &opt)
opt.ServeNoModTime = true
tests = []testRun{{
Name: "no modtime",
Method: "GET",
URL: remoteURL + "modtime/",
Status: http.StatusOK,
Expected: "* dir/ - 0001-01-01T00:00:00Z\n* modtime.txt - 0001-01-01T00:00:00Z\n",
}}
testServer(t, tests, &opt)
}

View File

View File

View File

@ -0,0 +1,2 @@
{{ range .Entries }}* {{ .Leaf }} - {{ .ModTime.UTC.Format "2006-01-02T15:04:05Z07:00" }}
{{ end }}