aboutsummaryrefslogtreecommitdiffstats
path: root/web/web_bench_test.go
diff options
context:
space:
mode:
authorClaude <noreply@anthropic.com>2026-02-18 21:33:02 +0000
committerClaude <noreply@anthropic.com>2026-02-18 21:33:02 +0000
commitc585d7873e9b4bfd9f6efd30f9ce08aed8a0d92b (patch)
tree807539911d272878d65b79cccc72e8589cdc599f /web/web_bench_test.go
parenta74885d269d2fddb21be5db402e70ac1a41a0e23 (diff)
downloadneko-claude/improve-image-proxy-5iY78.tar.gz
neko-claude/improve-image-proxy-5iY78.tar.bz2
neko-claude/improve-image-proxy-5iY78.zip
Improve image proxy: streaming, size limits, Content-Type validationclaude/improve-image-proxy-5iY78
Rewrites the image proxy handler to address several issues: - Stream responses with io.Copy instead of buffering entire image in memory - Add 25MB size limit via io.LimitReader to prevent memory exhaustion - Close resp.Body (was previously leaked on every request) - Validate Content-Type is an image, rejecting HTML/JS/etc - Forward Content-Type and Content-Length from upstream - Use http.NewRequestWithContext to propagate client cancellation - Check upstream status codes, returning 502 for non-2xx - Fix ETag: use proper quoted format, remove bogus Etag request header check - Increase timeout from 5s to 30s for slow image servers - Use proper HTTP status codes (400 for bad input, 502 for upstream errors) - Add Cache-Control max-age directive alongside Expires header Tests: comprehensive coverage for Content-Type filtering, upstream errors, streaming, ETag validation, User-Agent forwarding, and Content-Length. Benchmarks: cache hit path and streaming at 1KB/64KB/1MB/5MB sizes. https://claude.ai/code/session_01CZcDDVmF6wNs2YjdhvCppy
Diffstat (limited to 'web/web_bench_test.go')
-rw-r--r--web/web_bench_test.go48
1 files changed, 48 insertions, 0 deletions
diff --git a/web/web_bench_test.go b/web/web_bench_test.go
index 7897fc7..068fd55 100644
--- a/web/web_bench_test.go
+++ b/web/web_bench_test.go
@@ -1,8 +1,11 @@
package web
import (
+ "encoding/base64"
+ "fmt"
"net/http"
"net/http/httptest"
+ "net/url"
"strings"
"testing"
@@ -90,3 +93,48 @@ func BenchmarkFullMiddlewareStack(b *testing.B) {
handler.ServeHTTP(rr, req)
}
}
+
+// --- Image proxy benchmarks ---
+
+func BenchmarkImageProxyCacheHit(b *testing.B) {
+ encoded := base64.URLEncoding.EncodeToString([]byte("https://example.com/image.jpg"))
+ etag := `"` + encoded + `"`
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ req := httptest.NewRequest("GET", "/"+encoded, nil)
+ req.Header.Set("If-None-Match", etag)
+ rr := httptest.NewRecorder()
+ imageProxyHandler(rr, req)
+ }
+}
+
+func benchmarkImageProxySize(b *testing.B, size int) {
+ data := make([]byte, size)
+ for i := range data {
+ data[i] = byte(i % 256)
+ }
+
+ ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.Header().Set("Content-Type", "image/jpeg")
+ w.Header().Set("Content-Length", fmt.Sprintf("%d", size))
+ w.Write(data)
+ }))
+ defer ts.Close()
+
+ encoded := base64.URLEncoding.EncodeToString([]byte(ts.URL + "/img.jpg"))
+
+ b.ResetTimer()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ req := httptest.NewRequest("GET", "/"+encoded, nil)
+ req.URL = &url.URL{Path: encoded}
+ rr := httptest.NewRecorder()
+ imageProxyHandler(rr, req)
+ }
+}
+
+func BenchmarkImageProxy_1KB(b *testing.B) { benchmarkImageProxySize(b, 1<<10) }
+func BenchmarkImageProxy_64KB(b *testing.B) { benchmarkImageProxySize(b, 64<<10) }
+func BenchmarkImageProxy_1MB(b *testing.B) { benchmarkImageProxySize(b, 1<<20) }
+func BenchmarkImageProxy_5MB(b *testing.B) { benchmarkImageProxySize(b, 5<<20) }