orchard
mirrorEvery 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
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}