Commit 97b29c8fac

97b29c8fac7e5810a15a895c333482e925cc3f50

parent: a582e3d398

Verified · cmc

cmc <hello@cleberg.net> · 2026-09-23 05:51 UTC

httpd: gzipWriter passes a flush through

Ref #250
internal/httpd/compress.go +14
@@ -83,3 +83,17 @@ func (g *gzipWriter) Close() {
8383 g.gz.Close()
8484 }
8585}
86
87// Flush sends what the gzip stream holds, then flushes the connection, so
88// a streamed page reaches the browser as it is written.
89func (g *gzipWriter) Flush() {
90 if !g.decided {
91 g.decide(http.StatusOK)
92 }
93 if g.gz != nil {
94 g.gz.Flush()
95 }
96 http.NewResponseController(g.ResponseWriter).Flush()
97}
98
99func (g *gzipWriter) Unwrap() http.ResponseWriter { return g.ResponseWriter }
internal/httpd/compress_test.go +29
@@ -6,6 +6,7 @@ import (
66 "io"
77 "net/http"
88 "net/http/httptest"
9 "strings"
910 "testing"
1011
1112 "gitbay.org/gitbay/internal/config"
@@ -79,3 +80,31 @@ func TestBinaryResponsesPassThrough(t *testing.T) {
7980 t.Fatalf("git transport touched: %q %q", rec.Header().Get("Content-Encoding"), rec.Body.String())
8081 }
8182}
83
84// A flush mid-response reaches the connection with what was written so
85// far decodable, which is what lets a page stream through gzip.
86func TestGzipWriterFlushes(t *testing.T) {
87 rec := httptest.NewRecorder()
88 h := compressed(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
89 w.Header().Set("Content-Type", "text/html; charset=utf-8")
90 io.WriteString(w, "<p>first</p>")
91 if err := http.NewResponseController(w).Flush(); err != nil {
92 t.Fatalf("flush: %v", err)
93 }
94 if !rec.Flushed {
95 t.Fatal("the flush did not reach the connection")
96 }
97 zr, err := gzip.NewReader(bytes.NewReader(rec.Body.Bytes()))
98 if err != nil {
99 t.Fatalf("gzip header: %v", err)
100 }
101 got, _ := io.ReadAll(zr) // no trailer yet: ends in ErrUnexpectedEOF
102 if !strings.Contains(string(got), "<p>first</p>") {
103 t.Fatalf("flushed body decodes to %q", got)
104 }
105 io.WriteString(w, "<p>second</p>")
106 }))
107 req := httptest.NewRequest("GET", "/", nil)
108 req.Header.Set("Accept-Encoding", "gzip")
109 h.ServeHTTP(rec, req)
110}