fix(cas): cap upstream streams and read-ahead on the shared endpoint

Merged
MA
14h ago
+41-4

Summary

The shared CAS endpoint proxies every tenant's native gRPC through a single net/http HTTP/2 client to the private gRPC server. That server advertises no MaxConcurrentStreams, so the client funnels all streams onto one upstream connection whose ~1 GiB HTTP/2 flow-control window becomes a shared, exhaustible resource: a client that opens many streams and stops reading can exhaust the window and stall gRPC responses for every tenant on the endpoint. It is reachable unauthenticated via gRPC reflection, or with any valid downloader token via ByteStream/Read.

This change caps the private server at 100 concurrent streams, so the proxy's HTTP/2 client spreads streams across several upstream connections — each with its own flow-control window — instead of exhausting one shared window. It also bounds the proxy transport's per-stream read-ahead to 256 KiB so a stalled reader pins far less already-received data. The otel stats handler is folded into the single grpc.Options call, since kratos's grpc.Options replaces rather than appends.

Only the private loopback server behind the proxy is affected; the legacy direct gRPC listener is unchanged.