Skip to content
quarry Artifact [94d57ac623]
Login

Artifact [94d57ac623]

Artifact 94d57ac623bae3c833b5bbe292d1fc16a509ab6f0f04832dfa37a50c0da92a42:


package xfer

import (
	"bytes"
	"compress/zlib"
	"context"
	"encoding/binary"
	"net/http"
	"net/http/httptest"
	"runtime"
	"strings"
	"testing"
)

// zeros is a container of n compressed zero bytes claiming the length
// claim: a few hundred KiB on the wire for every 100 MiB inflated.
func zeros(n int, claim uint32) []byte {
	var buf bytes.Buffer
	var head [4]byte
	binary.BigEndian.PutUint32(head[:], claim)
	buf.Write(head[:])
	zw, _ := zlib.NewWriterLevel(&buf, zlib.BestCompression)
	chunk := make([]byte, 1<<20)
	for i := 0; i < n>>20; i++ {
		zw.Write(chunk)
	}
	zw.Close()
	return buf.Bytes()
}

// heapGrowth runs f and reports how far the heap grew.
func heapGrowth(f func()) uint64 {
	var before, after runtime.MemStats
	runtime.GC()
	runtime.ReadMemStats(&before)
	f()
	runtime.ReadMemStats(&after)
	return after.TotalAlloc - before.TotalAlloc
}

// Exchange refuses a reply that inflates past its MaxReply.
func TestUVExchangeRefusesABomb(t *testing.T) {
	bomb := zeros(64<<20, 64<<20)
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/x-fossil")
		w.Write(bomb)
	}))
	defer srv.Close()
	var err error
	grew := heapGrowth(func() {
		_, err = UVUpstream{URL: srv.URL, MaxReply: 1 << 20}.Exchange(context.Background(), "uvgimme a\n")
	})
	if err == nil || grew > 16<<20 {
		t.Fatalf("FAIL: a reply inflating to 64 MiB under a 1 MiB cap: %v, heap grew %d", err, grew)
	}
	t.Logf("ok: refused (%v), heap grew %d bytes", strings.SplitN(err.Error(), ";", 2)[0], grew)
}