repos
/ orchard main

orchard

mirror

Every site I host, in one repo, along with the Cloudflare Tunnel and Caddy that front them. It's all Go, Vite, and SQLite, and it runs on a desktop at home with nothing listening on an inbound port.

blogbuncaddycloudflare-tunneldockergogolanghomelabhtml-templatemonorepoself-hostedseosqlitestatic-sitetypstuptime-monitoringviteweb-analytics

1.7 KB · 61 lines · Go Raw History
 1package web
 2
 3import (
 4	"bufio"
 5	"context"
 6	"net/http"
 7	"net/http/httptest"
 8	"strings"
 9	"testing"
10	"time"
11)
12
13// The wrappers here embed http.ResponseWriter, so a handler asserting
14// w.(http.Flusher) sees the wrapper and fails. Every SSE endpoint has to reach
15// the real writer through ResponseController instead, and this is the check
16// that the chain still lets it.
17func TestChainKeepsTheWriterFlushable(t *testing.T) {
18	handler := Chain(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
19		rc := http.NewResponseController(w)
20		if err := rc.SetWriteDeadline(time.Time{}); err != nil {
21			http.Error(w, "streaming unsupported", http.StatusInternalServerError)
22			return
23		}
24		w.Header().Set("Content-Type", "text/event-stream")
25		w.Write([]byte("event: status\ndata: {}\n\n"))
26		if err := rc.Flush(); err != nil {
27			t.Errorf("flush through the chain: %v", err)
28		}
29		<-r.Context().Done()
30	}), Recovered, Logged)
31
32	srv := httptest.NewServer(handler)
33	defer srv.Close()
34
35	req, err := http.NewRequest(http.MethodGet, srv.URL+"/stream", nil)
36	if err != nil {
37		t.Fatal(err)
38	}
39	ctx, cancel := context.WithTimeout(req.Context(), 5*time.Second)
40	defer cancel()
41	resp, err := http.DefaultClient.Do(req.WithContext(ctx))
42	if err != nil {
43		t.Fatal(err)
44	}
45	defer resp.Body.Close()
46
47	if resp.StatusCode != http.StatusOK {
48		t.Fatalf("status %d, want 200: the writer lost its flusher", resp.StatusCode)
49	}
50
51	// Reading a frame before the handler returns is the whole point, since a
52	// buffered response would arrive only at close.
53	line, err := bufio.NewReader(resp.Body).ReadString('\n')
54	if err != nil {
55		t.Fatalf("reading the first frame: %v", err)
56	}
57	if !strings.HasPrefix(line, "event: status") {
58		t.Fatalf("first frame %q, want an event", line)
59	}
60}