Files
fm_be/internal/app/api/compress_wopi_test.go
2026-07-16 22:16:45 +07:00

132 lines
4.6 KiB
Go

package api
import (
"archive/zip"
"bytes"
"io"
"net/http/httptest"
"testing"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/compress"
)
// buildTinyXLSX returns a minimal but structurally valid .xlsx (ZIP) payload.
func buildTinyXLSX(t *testing.T) []byte {
t.Helper()
var buf bytes.Buffer
zw := zip.NewWriter(&buf)
entries := map[string]string{
"[Content_Types].xml": `<?xml version="1.0"?><Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types"><Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/><Default Extension="xml" ContentType="application/xml"/><Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/></Types>`,
"_rels/.rels": `<?xml version="1.0"?><Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships"><Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/></Relationships>`,
"xl/workbook.xml": `<?xml version="1.0"?><workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"><sheets><sheet name="Sheet1" sheetId="1" r:id="rId1"/></sheets></workbook>`,
}
for name, content := range entries {
w, err := zw.Create(name)
if err != nil {
t.Fatalf("zip create %s: %v", name, err)
}
if _, err := io.WriteString(w, content); err != nil {
t.Fatalf("zip write %s: %v", name, err)
}
}
if err := zw.Close(); err != nil {
t.Fatalf("zip close: %v", err)
}
return buf.Bytes()
}
func assertValidZip(t *testing.T, b []byte) {
t.Helper()
if _, err := zip.NewReader(bytes.NewReader(b), int64(len(b))); err != nil {
t.Fatalf("payload is not a valid zip: %v", err)
}
}
func TestIsWOPIRequest(t *testing.T) {
app := fiber.New()
cases := []struct {
path string
want bool
}{
{"/wopi/files/123/contents", true},
{"/wopi/files/123", true},
{"/api/file-manager/files", false},
{"/wopimirror/x", false},
{"/", false},
}
for _, tc := range cases {
app.Get(tc.path, func(c *fiber.Ctx) error {
if got := isWOPIRequest(c); got != tc.want {
t.Errorf("isWOPIRequest(%q) = %v, want %v", tc.path, got, tc.want)
}
return c.SendStatus(fiber.StatusOK)
})
resp, err := app.Test(httptest.NewRequest("GET", tc.path, nil), -1)
if err != nil {
t.Fatalf("app.Test(%q): %v", tc.path, err)
}
_ = resp.Body.Close()
}
}
// Regression for the "template .xlsx always corrupt via WOPI" bug: the global
// gzip compress middleware must NOT compress WOPI file-content responses.
// Collabora saves the response body verbatim as the document, so a gzip stream
// there is a guaranteed-corrupt file.
func TestCompressMiddleware_SkipsWOPIContents(t *testing.T) {
src := buildTinyXLSX(t)
assertValidZip(t, src)
app := fiber.New()
// Mirror the production compress wiring (UseDefaultMiddlewares).
app.Use(compress.New(compress.Config{
Level: compress.LevelBestSpeed,
Next: func(c *fiber.Ctx) bool {
return isEventStreamRequest(c) || isWOPIRequest(c)
},
}))
streamXLSX := func(c *fiber.Ctx) error {
c.Set(fiber.HeaderContentType, "application/octet-stream")
c.Status(fiber.StatusOK)
c.Context().Response.SetBodyStream(io.NopCloser(bytes.NewReader(src)), len(src))
return nil
}
app.Get("/wopi/files/:id/contents", streamXLSX)
// Negative control: a non-WOPI route with a compressible body must still gzip.
app.Get("/api/echo", func(c *fiber.Ctx) error {
c.Set(fiber.HeaderContentType, "application/octet-stream")
return c.Send(bytes.Repeat([]byte("A"), 4096))
})
// WOPI content download with gzip offered must come back raw + valid.
req := httptest.NewRequest("GET", "/wopi/files/abc/contents", nil)
req.Header.Set("Accept-Encoding", "gzip")
resp, err := app.Test(req, -1)
if err != nil {
t.Fatalf("app.Test wopi: %v", err)
}
if enc := resp.Header.Get("Content-Encoding"); enc != "" {
t.Fatalf("WOPI content unexpectedly encoded: Content-Encoding=%q", enc)
}
got, _ := io.ReadAll(resp.Body)
_ = resp.Body.Close()
assertValidZip(t, got)
if !bytes.Equal(got, src) {
t.Fatalf("WOPI content body mutated: got %d bytes, want %d", len(got), len(src))
}
// Sanity: prove compression is actually active for non-excluded routes.
req2 := httptest.NewRequest("GET", "/api/echo", nil)
req2.Header.Set("Accept-Encoding", "gzip")
resp2, err := app.Test(req2, -1)
if err != nil {
t.Fatalf("app.Test echo: %v", err)
}
if enc := resp2.Header.Get("Content-Encoding"); enc != "gzip" {
t.Fatalf("expected gzip on non-WOPI route, got Content-Encoding=%q (compress not active - test invalid)", enc)
}
_ = resp2.Body.Close()
}