Skip to content

responseWriter doesn't track headers #27

@nic-osullivan-gravwell

Description

@nic-osullivan-gravwell

A follow up in a way to #22 I dug in more and found our compression issue only occurs when the response is read from the cache, not the first time when the response is directly pulled from further up the chain. What looks to be happening is that the with the removal of the recorder the new response writer is not tracking the headers that are only from further up the chain.

Our scenario is using a gzip lib to apply compression to responses by providing another wrapped response writer. During this gzip Write call it adds the compression headers. Then after this write is done the cache captures the headers and stores them. When returning a cache result it attaches the Content-Encoding header which causes the gzip lib to consider the body already gziped, which it is not.

Here is a minimum(ish) repro using the same gzip lib.

package main

import (
	"fmt"
	"math/rand"
	"net/http"
	"time"

	"github.com/klauspost/compress/gzhttp"
	cache "github.com/victorspringer/http-cache"
	"github.com/victorspringer/http-cache/adapter/memory"
)

const mb = 1024 * 1024

func cacheWrap(next http.Handler) http.Handler {
	mcc, _ := memory.NewAdapter(
		memory.AdapterWithAlgorithm(memory.LRU),
		memory.AdapterWithStorageCapacity(4*mb),
	)
	cc, _ := cache.NewClient(
		cache.ClientWithAdapter(mcc),
		cache.ClientWithTTL(time.Minute),
		cache.ClientWithMethods([]string{http.MethodGet}),
	)
	return cc.Middleware(next)
}

func main() {
	var content = randString(1024)
	fmt.Println(string(content))
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/plain")
		w.Write(content)
	})

	http.Handle("/", gzhttp.GzipHandler(cacheWrap(handler)))
	http.ListenAndServe("0.0.0.0:8000", nil)
}

func randString(length int) []byte {
	b := make([]byte, length)
	for i := range b {
		b[i] = byte(64 + rand.Intn(60))
	}
	return b
}

The behavior I would expect here is to only consider the headers set by the next handler. I've tried swapping the order of the middleware and that just results in no response, but I haven't looked into why, I currently suspect the bug fixed in #24, but haven't confirmed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions