Files
warpbox/lib/server/downloads_test.go

121 lines
4.0 KiB
Go
Raw Normal View History

package server
import (
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
"github.com/gin-gonic/gin"
"warpbox/lib/boxstore"
"warpbox/lib/config"
"warpbox/lib/models"
)
const downloadTestBoxID = "abcdefabcdefabcdefabcdefabcdefab"
func TestDownloadFileServesEmbeddableMediaInlineWithRangeSupport(t *testing.T) {
app := setupDownloadFileTest(t, "clip.mp4", []byte("0123456789"))
response := performDownloadFile(app, http.MethodGet, "/box/"+downloadTestBoxID+"/files/clip.mp4", map[string]string{
"Range": "bytes=0-3",
})
if response.Code != http.StatusPartialContent {
t.Fatalf("expected ranged download to return 206, got %d", response.Code)
}
if got := response.Header().Get("Content-Disposition"); !strings.HasPrefix(got, "inline;") || !strings.Contains(got, "filename=clip.mp4") {
t.Fatalf("expected inline content disposition for embeddable media, got %q", got)
}
if got := response.Header().Get("Content-Type"); !strings.HasPrefix(got, "video/mp4") {
t.Fatalf("expected video content type, got %q", got)
}
if got := response.Header().Get("Content-Range"); got != "bytes 0-3/10" {
t.Fatalf("expected byte range header, got %q", got)
}
if got := response.Body.String(); got != "0123" {
t.Fatalf("expected ranged body, got %q", got)
}
}
func TestDownloadFileServesUnsafeInlineTypesAsAttachments(t *testing.T) {
app := setupDownloadFileTest(t, "page.html", []byte("<!doctype html><script>alert(1)</script>"))
response := performDownloadFile(app, http.MethodGet, "/box/"+downloadTestBoxID+"/files/page.html", nil)
if response.Code != http.StatusOK {
t.Fatalf("expected download to return 200, got %d", response.Code)
}
if got := response.Header().Get("Content-Disposition"); !strings.HasPrefix(got, "attachment;") || !strings.Contains(got, "filename=page.html") {
t.Fatalf("expected attachment content disposition for html, got %q", got)
}
}
func TestDownloadFileSupportsHeadRequests(t *testing.T) {
app := setupDownloadFileTest(t, "clip.mp4", []byte("0123456789"))
response := performDownloadFile(app, http.MethodHead, "/box/"+downloadTestBoxID+"/files/clip.mp4", nil)
if response.Code != http.StatusOK {
t.Fatalf("expected HEAD download to return 200, got %d", response.Code)
}
if got := response.Header().Get("Content-Disposition"); !strings.HasPrefix(got, "inline;") {
t.Fatalf("expected inline content disposition for HEAD request, got %q", got)
}
if response.Body.Len() != 0 {
t.Fatalf("expected HEAD response body to be empty, got %d bytes", response.Body.Len())
}
}
func setupDownloadFileTest(t *testing.T, filename string, body []byte) *App {
t.Helper()
gin.SetMode(gin.TestMode)
restoreUploadRoot := boxstore.UploadRoot()
t.Cleanup(func() { boxstore.SetUploadRoot(restoreUploadRoot) })
boxstore.SetUploadRoot(t.TempDir())
if err := os.MkdirAll(boxstore.BoxPath(downloadTestBoxID), 0755); err != nil {
t.Fatalf("MkdirAll returned error: %v", err)
}
path, ok := boxstore.SafeBoxFilePath(downloadTestBoxID, filename)
if !ok {
t.Fatal("SafeBoxFilePath rejected test file")
}
if err := os.WriteFile(path, body, 0644); err != nil {
t.Fatalf("WriteFile returned error: %v", err)
}
manifest := models.BoxManifest{
Files: []models.BoxFile{{
ID: "0123456789abcdef",
Name: filename,
Size: int64(len(body)),
MimeType: "",
Status: models.FileStatusReady,
}},
CreatedAt: time.Now().UTC(),
}
if err := boxstore.WriteManifest(downloadTestBoxID, manifest); err != nil {
t.Fatalf("WriteManifest returned error: %v", err)
}
return &App{config: &config.Config{}}
}
func performDownloadFile(app *App, method string, path string, headers map[string]string) *httptest.ResponseRecorder {
router := gin.New()
router.GET("/box/:id/files/:filename", app.handleDownloadFile)
router.HEAD("/box/:id/files/:filename", app.handleDownloadFile)
request := httptest.NewRequest(method, path, nil)
for key, value := range headers {
request.Header.Set(key, value)
}
response := httptest.NewRecorder()
router.ServeHTTP(response, request)
return response
}