Compare commits
2 Commits
6e5c4dc623
...
76dcb8721a
| Author | SHA1 | Date | |
|---|---|---|---|
| 76dcb8721a | |||
| cefa33c00d |
@@ -407,9 +407,20 @@ func (h *FileHandler) GetContent(c *gin.Context) {
|
|||||||
if c.Query("inline") == "1" {
|
if c.Query("inline") == "1" {
|
||||||
disposition = "inline"
|
disposition = "inline"
|
||||||
}
|
}
|
||||||
|
name := ""
|
||||||
if res.OriginalName != nil {
|
if res.OriginalName != nil {
|
||||||
|
name = *res.OriginalName
|
||||||
c.Header("Content-Disposition",
|
c.Header("Content-Disposition",
|
||||||
fmt.Sprintf("%s; filename=%q", disposition, *res.OriginalName))
|
fmt.Sprintf("%s; filename=%q", disposition, name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve with byte-range support when the body is seekable (it is for the
|
||||||
|
// disk store): http.ServeContent advertises Accept-Ranges and answers Range
|
||||||
|
// requests with 206 Partial Content, which is what lets the browser scrub and
|
||||||
|
// seek within audio/video. Fall back to a plain stream otherwise.
|
||||||
|
if seeker, ok := res.Body.(io.ReadSeeker); ok {
|
||||||
|
http.ServeContent(c.Writer, c.Request, name, time.Time{}, seeker)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
c.Status(http.StatusOK)
|
c.Status(http.StatusOK)
|
||||||
io.Copy(c.Writer, res.Body) //nolint:errcheck
|
io.Copy(c.Writer, res.Body) //nolint:errcheck
|
||||||
|
|||||||
@@ -955,6 +955,34 @@ func TestImportFromFolder(t *testing.T) {
|
|||||||
assert.True(t, ct.Equal(mtime), "content_datetime %v should equal mtime %v", ct, mtime)
|
assert.True(t, ct.Equal(mtime), "content_datetime %v should equal mtime %v", ct, mtime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestContentRangeRequests verifies the original-content endpoint answers a
|
||||||
|
// byte-range request with 206 Partial Content (so the browser can seek within
|
||||||
|
// audio/video) rather than streaming the whole body.
|
||||||
|
func TestContentRangeRequests(t *testing.T) {
|
||||||
|
if testing.Short() {
|
||||||
|
t.Skip("skipping integration test in short mode")
|
||||||
|
}
|
||||||
|
h := setupSuite(t)
|
||||||
|
token := h.login("admin", "admin")
|
||||||
|
file := h.uploadJPEG(token, "clip.jpg")
|
||||||
|
id := file["id"].(string)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", h.url("/files/"+id+"/content?inline=1"), nil)
|
||||||
|
require.NoError(t, err)
|
||||||
|
req.Header.Set("Authorization", "Bearer "+token)
|
||||||
|
req.Header.Set("Range", "bytes=0-9")
|
||||||
|
resp, err := h.client.Do(req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer resp.Body.Close()
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
assert.Equal(t, http.StatusPartialContent, resp.StatusCode)
|
||||||
|
assert.Equal(t, "bytes", resp.Header.Get("Accept-Ranges"))
|
||||||
|
assert.Regexp(t, `^bytes 0-9/\d+$`, resp.Header.Get("Content-Range"))
|
||||||
|
require.Len(t, body, 10)
|
||||||
|
assert.Equal(t, minimalJPEG()[:10], body)
|
||||||
|
}
|
||||||
|
|
||||||
// TestBlockRevokesActiveSessions verifies that blocking a user immediately
|
// TestBlockRevokesActiveSessions verifies that blocking a user immediately
|
||||||
// invalidates their outstanding access tokens.
|
// invalidates their outstanding access tokens.
|
||||||
func TestBlockRevokesActiveSessions(t *testing.T) {
|
func TestBlockRevokesActiveSessions(t *testing.T) {
|
||||||
|
|||||||
@@ -353,6 +353,9 @@
|
|||||||
const anchor = page.url.searchParams.get('anchor');
|
const anchor = page.url.searchParams.get('anchor');
|
||||||
if (anchor) {
|
if (anchor) {
|
||||||
scrollToFile(anchor);
|
scrollToFile(anchor);
|
||||||
|
// Pre-focus the anchor file so keyboard navigation resumes from it.
|
||||||
|
focusedId = anchor;
|
||||||
|
kbActive = true;
|
||||||
consumeAnchor();
|
consumeAnchor();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -709,6 +712,10 @@
|
|||||||
const target = lastOverlayId;
|
const target = lastOverlayId;
|
||||||
lastOverlayId = null;
|
lastOverlayId = null;
|
||||||
scrollToFile(target);
|
scrollToFile(target);
|
||||||
|
// Land the keyboard roving-focus on the file we came back from, so arrow
|
||||||
|
// navigation continues from there (and the ring marks where you were).
|
||||||
|
focusedId = target;
|
||||||
|
kbActive = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user