rcserver: set Last-Modified
header for files served by --rc-serve
This commit is contained in:
parent
3d473eb54e
commit
94cdb00eb6
3 changed files with 24 additions and 1 deletions
|
@ -93,13 +93,14 @@ const (
|
||||||
// SeekModes contains all valid SeekMode's
|
// SeekModes contains all valid SeekMode's
|
||||||
var SeekModes = []SeekMode{SeekModeNone, SeekModeRegular, SeekModeRange}
|
var SeekModes = []SeekMode{SeekModeNone, SeekModeRegular, SeekModeRange}
|
||||||
|
|
||||||
// ContentMockObject mocks an fs.Object and has content
|
// ContentMockObject mocks an fs.Object and has content, mod time
|
||||||
type ContentMockObject struct {
|
type ContentMockObject struct {
|
||||||
Object
|
Object
|
||||||
content []byte
|
content []byte
|
||||||
seekMode SeekMode
|
seekMode SeekMode
|
||||||
f fs.Fs
|
f fs.Fs
|
||||||
unknownSize bool
|
unknownSize bool
|
||||||
|
modTime time.Time
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithContent returns an fs.Object with the given content.
|
// WithContent returns an fs.Object with the given content.
|
||||||
|
@ -192,6 +193,18 @@ func (o *ContentMockObject) Hash(ctx context.Context, t hash.Type) (string, erro
|
||||||
return hasher.Sums()[t], nil
|
return hasher.Sums()[t], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ModTime returns the modification date of the file
|
||||||
|
// It should return a best guess if one isn't available
|
||||||
|
func (o *ContentMockObject) ModTime(ctx context.Context) time.Time {
|
||||||
|
return o.modTime
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetModTime sets the metadata on the object to set the modification date
|
||||||
|
func (o *ContentMockObject) SetModTime(ctx context.Context, t time.Time) error {
|
||||||
|
o.modTime = t
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type readCloser struct{ io.Reader }
|
type readCloser struct{ io.Reader }
|
||||||
|
|
||||||
func (r *readCloser) Close() error { return nil }
|
func (r *readCloser) Close() error { return nil }
|
||||||
|
|
|
@ -35,6 +35,10 @@ func Object(w http.ResponseWriter, r *http.Request, o fs.Object) {
|
||||||
w.Header().Set("Content-Type", mimeType)
|
w.Header().Set("Content-Type", mimeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set last modified
|
||||||
|
modTime := o.ModTime(r.Context())
|
||||||
|
w.Header().Set("Last-Modified", modTime.UTC().Format(http.TimeFormat))
|
||||||
|
|
||||||
if r.Method == "HEAD" {
|
if r.Method == "HEAD" {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
package serve
|
package serve
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/rclone/rclone/fstest/mockobject"
|
"github.com/rclone/rclone/fstest/mockobject"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -25,11 +27,13 @@ func TestObjectHEAD(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
r := httptest.NewRequest("HEAD", "http://example.com/aFile", nil)
|
r := httptest.NewRequest("HEAD", "http://example.com/aFile", nil)
|
||||||
o := mockobject.New("aFile").WithContent([]byte("hello"), mockobject.SeekModeNone)
|
o := mockobject.New("aFile").WithContent([]byte("hello"), mockobject.SeekModeNone)
|
||||||
|
_ = o.SetModTime(context.Background(), time.Date(2023, 9, 20, 12, 11, 15, 0, time.FixedZone("", 4*60*60))) // UTC+4
|
||||||
Object(w, r, o)
|
Object(w, r, o)
|
||||||
resp := w.Result()
|
resp := w.Result()
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
assert.Equal(t, "5", resp.Header.Get("Content-Length"))
|
assert.Equal(t, "5", resp.Header.Get("Content-Length"))
|
||||||
assert.Equal(t, "bytes", resp.Header.Get("Accept-Ranges"))
|
assert.Equal(t, "bytes", resp.Header.Get("Accept-Ranges"))
|
||||||
|
assert.Equal(t, "Wed, 20 Sep 2023 08:11:15 GMT", resp.Header.Get("Last-Modified"))
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
assert.Equal(t, "", string(body))
|
assert.Equal(t, "", string(body))
|
||||||
}
|
}
|
||||||
|
@ -38,11 +42,13 @@ func TestObjectGET(t *testing.T) {
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
r := httptest.NewRequest("GET", "http://example.com/aFile", nil)
|
r := httptest.NewRequest("GET", "http://example.com/aFile", nil)
|
||||||
o := mockobject.New("aFile").WithContent([]byte("hello"), mockobject.SeekModeNone)
|
o := mockobject.New("aFile").WithContent([]byte("hello"), mockobject.SeekModeNone)
|
||||||
|
_ = o.SetModTime(context.Background(), time.Date(2023, 9, 20, 12, 11, 15, 0, time.FixedZone("", 2*60*60))) // UTC+2
|
||||||
Object(w, r, o)
|
Object(w, r, o)
|
||||||
resp := w.Result()
|
resp := w.Result()
|
||||||
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
assert.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
assert.Equal(t, "5", resp.Header.Get("Content-Length"))
|
assert.Equal(t, "5", resp.Header.Get("Content-Length"))
|
||||||
assert.Equal(t, "bytes", resp.Header.Get("Accept-Ranges"))
|
assert.Equal(t, "bytes", resp.Header.Get("Accept-Ranges"))
|
||||||
|
assert.Equal(t, "Wed, 20 Sep 2023 10:11:15 GMT", resp.Header.Get("Last-Modified"))
|
||||||
body, _ := io.ReadAll(resp.Body)
|
body, _ := io.ReadAll(resp.Body)
|
||||||
assert.Equal(t, "hello", string(body))
|
assert.Equal(t, "hello", string(body))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue