Skip to content
quarry Artifact [1deece8809]
Login

Artifact [1deece8809]

Artifact 1deece880964a327ae3e0fcc1fdfadeec10a582d8d6beb25575739fb43ae1388:


package web

import (
	"compress/gzip"
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"
)

func serve(t *testing.T, accept string, h http.HandlerFunc) *http.Response {
	t.Helper()
	req := httptest.NewRequest("GET", "/", nil)
	if accept != "" {
		req.Header.Set("Accept-Encoding", accept)
	}
	rec := httptest.NewRecorder()
	Compress(h).ServeHTTP(rec, req)
	return rec.Result()
}

// The whole point: a timeline page was 309,584 bytes and gzips to
// 36,599, and before this nothing was compressed at all.
func TestHTMLIsCompressed(t *testing.T) {
	body := strings.Repeat("<div class=\"row\">quarry</div>\n", 400)
	res := serve(t, "gzip", func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "text/html; charset=utf-8")
		io.WriteString(w, body)
	})
	if res.Header.Get("Content-Encoding") != "gzip" {
		t.Fatalf("not compressed: %q", res.Header.Get("Content-Encoding"))
	}
	if res.Header.Get("Vary") == "" {
		t.Error("no Vary: a cache will serve gzip to a client that cannot read it")
	}
	zr, err := gzip.NewReader(res.Body)
	if err != nil {
		t.Fatal(err)
	}
	got, err := io.ReadAll(zr)
	if err != nil || string(got) != body {
		t.Fatalf("body did not survive the round trip (err %v)", err)
	}
}

// SSE must NOT be compressed. quarry has 22 stream writers and gzip
// buffers until it has something worth emitting, so a compressed stream
// delivers its first event late or never — and the failure mode is
// silence, which is the kind that ships.
func TestEventStreamIsNeverCompressed(t *testing.T) {
	res := serve(t, "gzip", func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "text/event-stream")
		w.WriteHeader(http.StatusOK)
		io.WriteString(w, "event: datastar-patch-elements\ndata: elements <p>x</p>\n\n")
		if f, ok := w.(http.Flusher); ok {
			f.Flush()
		}
	})
	if enc := res.Header.Get("Content-Encoding"); enc != "" {
		t.Fatalf("an event stream was encoded as %q; live updates would stall", enc)
	}
	got, _ := io.ReadAll(res.Body)
	if !strings.Contains(string(got), "datastar-patch-elements") {
		t.Errorf("the event did not arrive intact: %q", got)
	}
}

// A wrapped writer that does not forward Flush would stall streaming
// even when it declines to compress.
func TestFlushReachesTheUnderlyingWriter(t *testing.T) {
	req := httptest.NewRequest("GET", "/", nil)
	req.Header.Set("Accept-Encoding", "gzip")
	rec := httptest.NewRecorder()
	Compress(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "text/event-stream")
		w.WriteHeader(http.StatusOK)
		io.WriteString(w, "data: one\n\n")
		f, ok := w.(http.Flusher)
		if !ok {
			t.Error("the wrapper is not a Flusher; SSE cannot work through it")
			return
		}
		f.Flush()
	})).ServeHTTP(rec, req)
	if !rec.Flushed {
		t.Error("Flush did not reach the underlying writer")
	}
}

// Already-compressed bytes only grow, and a client that did not ask
// must get plain bytes.
func TestSkipsWhatItShouldSkip(t *testing.T) {
	png := serve(t, "gzip", func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "image/png")
		w.Write(make([]byte, 4096))
	})
	if png.Header.Get("Content-Encoding") != "" {
		t.Error("a PNG was gzipped")
	}
	plain := serve(t, "", func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.Repeat("x", 4096))
	})
	if plain.Header.Get("Content-Encoding") != "" {
		t.Error("compressed for a client that never asked")
	}
	// "gzip;q=0" is a refusal, and a substring search reads it as a yes.
	refused := serve(t, "gzip;q=0", func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "text/html")
		io.WriteString(w, strings.Repeat("x", 4096))
	})
	if refused.Header.Get("Content-Encoding") != "" {
		t.Error("q=0 means no, and was read as yes")
	}
}

// A stale Content-Length describes the plain body and would truncate
// or hang the client.
func TestContentLengthIsDroppedWhenEncoding(t *testing.T) {
	body := strings.Repeat("y", 8192)
	res := serve(t, "gzip", func(w http.ResponseWriter, _ *http.Request) {
		w.Header().Set("Content-Type", "text/plain")
		w.Header().Set("Content-Length", "8192")
		w.WriteHeader(http.StatusOK)
		io.WriteString(w, body)
	})
	if res.Header.Get("Content-Encoding") != "gzip" {
		t.Fatal("not compressed")
	}
	if cl := res.Header.Get("Content-Length"); cl == "8192" {
		t.Error("the plain-body length survived; the client will truncate")
	}
}