MCPcopy Index your code
hub / github.com/subtrace/subtrace / proxyOptimistic

Method proxyOptimistic

cmd/run/socket/proxy.go:207–315  ·  view source on GitHub ↗

proxyOptimistic peeks at buffered bytes available on the client side to guess the protocol. If a known protocol is found, it passes control to that protocol's handler. Otherwise, it falls back to the raw handler.

(cli, srv *bufConn)

Source from the content-addressed store, hash-verified

205// guess the protocol. If a known protocol is found, it passes control to that
206// protocol's handler. Otherwise, it falls back to the raw handler.
207func (p *proxy) proxyOptimistic(cli, srv *bufConn) error {
208 slog.Debug("starting proxyOptimistic", "proxy", p)
209
210 errs := make(chan error, 2)
211
212 // While we need to sample client's TCP bytes to see if it's HTTP and/or TLS
213 // or something else, we can't synchronously wait for the client's first
214 // bytes. Doing so would break protocols that expect the server side to
215 // talk first. HTTP and TLS don't behave this way, but since those are not
216 // the only protocols we'll be proxying (we intercept all TCP connections at
217 // the socket level), the sampling strategy needs to be robust.
218 var race atomic.Bool
219
220 go func() {
221 if _, err := srv.peekSample(); err != nil {
222 if race.Load() {
223 errs <- fmt.Errorf("server: peek sample: %w", err)
224 } else {
225 errs <- nil
226 }
227 return
228 }
229
230 if isHTTP2Enabled {
231 // Give the client up to few hundred milliseconds to catch up so it has a
232 // better chance of winning the race in situations where the first server
233 // bytes arrive fractions of a millisecond before the first client bytes
234 // (e.g. when a HTTP/2 server pushes a SETTINGS frame before the client
235 // sends its first frame). Doing this greatly increases wire protocol
236 // guess accuracy. While this admittedly adds upto 1ms latency in obscure
237 // protocols where the server is required to talk first, the trade-off is
238 // well worth it because Subtrace is not designed for those protocols.
239 start := time.Now()
240 for i := 0; ; i++ {
241 if race.Load() {
242 break
243 }
244 if i&15 == 15 {
245 time.Sleep(20 * time.Microsecond)
246 }
247 if race.Load() {
248 break
249 }
250 if time.Since(start) >= 1000*time.Microsecond {
251 break
252 }
253 if race.Load() {
254 break
255 }
256 runtime.Gosched()
257 if race.Load() {
258 break
259 }
260 }
261 }
262
263 if winner := race.CompareAndSwap(false, true); !winner {
264 errs <- nil

Callers 2

startMethod · 0.95
proxyTLSMethod · 0.95

Calls 7

proxyFallbackMethod · 0.95
proxyTLSMethod · 0.95
proxyHTTP1Method · 0.95
proxyHTTP2Method · 0.95
guessProtocolFunction · 0.85
peekSampleMethod · 0.80
LoadMethod · 0.80

Tested by

no test coverage detected