Skip to content

HAR: capture client↔proxy RTT to make 'wait' fully client-perceived #283

@jonathaneoliver

Description

@jonathaneoliver

Goal

The HAR's `timings.wait` after #(downstream-timings PR) measures server-side processing only — time from request received by go-proxy to first response byte sent. The true client-perceived wait includes the network RTT in both directions:

```
true_wait = RTT/2 (client → proxy)
+ server_processing (the new ClientWaitMs)
+ RTT/2 (first response byte ← proxy)
```

On LAN / loopback the RTTs are negligible and `server_wait ≈ true_wait`. On wifi / cellular / shaped paths the RTT can dominate, and a HAR that under-reports wait makes the network look healthier than it is to anyone reading it.

Approach

Option A: server-side via `TCP_INFO` (preferred)

Linux exposes the kernel's smoothed RTT estimator per established TCP connection via `getsockopt(TCP_INFO)`. Go can reach it through `net.TCPConn.SyscallConn().Control`. Sample on every request from the connection associated with that `*http.Request`, store on the `NetworkLogEntry` as `ClientRTTMs`. Map into HAR as:

  • Add `ClientRTTMs` to `NetworkLogEntry`.
  • Augment `_extensions.upstream` with a sibling `_extensions.client_rtt` block carrying `{rtt_ms, samples_seen}`.
  • The HAR's main `timings.wait` stays as server processing for compatibility with viewers, but the extension block tells you "true wait ≈ wait + rtt_ms".

Cost: ~50 lines of `syscall` plumbing in the proxy handler. No client work.

Option B: client-reported RTT

Player samples `URLSessionTaskMetrics` (Apple) / OkHttp `EventListener.connectStart→connectEnd` (Android), POSTs the latest RTT in the existing heartbeat. More accurate (real client→server measurement, not kernel estimate), but more code on three platforms.

Recommendation

Land Option A first as the cheap baseline. Option B can layer on later if Option A's smoothed-RTT estimate proves too lossy under packet loss / heavy shaping.

Out of scope

Estimated points: 5

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions