diff --git a/.github/workflows/server-test.yaml b/.github/workflows/server-test.yaml index 667e969f7..0e92f023e 100644 --- a/.github/workflows/server-test.yaml +++ b/.github/workflows/server-test.yaml @@ -103,7 +103,7 @@ jobs: cache-dependency-path: server/go.sum - name: Run CDP telemetry browser regressions - run: go test -race ./lib/cdpmonitor -run '^(TestNetworkCapture|TestTelemetryConnection|TestProxyErrorE2E)' -count=1 -v + run: go test -race ./lib/cdpmonitor -run '^(TestNetworkCapture|TestNetworkWireCapture|TestNetworkBodiesSurviveNavigation|TestNetworkExtensionAttribution|TestTelemetryConnection|TestProxyErrorE2E)' -count=1 -v working-directory: server env: KERNEL_CDPMONITOR_CHROME_E2E: "1" diff --git a/server/lib/cdpmonitor/README.md b/server/lib/cdpmonitor/README.md index 1480cc4bf..807cf56b6 100644 --- a/server/lib/cdpmonitor/README.md +++ b/server/lib/cdpmonitor/README.md @@ -64,8 +64,8 @@ startup, telemetry toggles, and shutdown. Additional regressions delay a cleanup command while PUT/PATCH/GET continue, fence old capture across coalesced revisions, and recover page/frame listeners after socket loss or failed cleanup. They check future navigations and the independent user CDP connection as well. Extension -background pages are included in discovery but are not validated by a real extension -fixture here. A delayed-Network-reply regression also verifies that pending +service-worker and page attribution are covered by an unpacked-extension browser +fixture. A delayed-Network-reply regression also verifies that pending attachments finish recovery before optional instrumentation starts, and that click events arrive without navigation through subsequent telemetry toggles. @@ -109,6 +109,83 @@ and fresh sessions after reconnect. Without the environment variable these tests skip, matching the other real-Chromium tests in this package. They exercise settled targets, not requests issued before their capture domains finish initializing. +## Network capture fidelity + +Top-level navigation retains requests until their terminal events. Only requests +belonging to the new loader seed its pending count; completions from the previous +navigation cannot make the new navigation idle. Same-process frame requests still +participate in their page's network-idle accounting. + +The collector joins `requestWillBeSentExtraInfo` to requests +by session, request ID, and redirect hop. Cached hops without ExtraInfo do not +consume the next hop's headers. A `network_request` waits at most one second for +wire headers, then uses the base headers so a hanging request remains visible. +`network_response.request_headers` retains wire request headers that arrive after +that initial event. After body retrieval, response capture waits up to one second +for request headers. Missing or invalid request headers fall back to the base +headers on the request event and are omitted from the response. Capture remains +best-effort when Chrome omits events or a target disconnects. Redirects emit a +response for each hop, without a body. Request IDs remain the same across a +redirect chain. + +Network event timestamps record wall-clock time when the CDP event is observed, +before header collection, body retrieval, or publication waits. Response events +use observation of `loadingFinished`, or the redirect notification for redirects. +Timestamp differences therefore retain request duration despite delayed delivery. +Other event types may publish during these waits, so timestamps need not increase +in stream order. + +Responses, failures, and proxy errors for tracked requests publish after their +request event. Each redirect response publishes before the next hop's request. +Header waits run concurrently across hops and remain bounded by one second; +publication dependencies drain in order even when capture is canceled. +Header correlation stays active for pending redirect responses after the final +request completes or fails, until their capture finishes. + +`network_response.status`, `status_text`, and `headers` retain Chrome's effective +response, including custom reason phrases and retained cache headers. A +revalidated cached response has `status: 200` and may carry Chrome's cached body. +Body capture is limited to selected textual resources and remains subject to +truncation and retrieval errors. + +While optional telemetry is enabled, `Network.enable` requests durable body +storage with `maxTotalBufferSize` set to 10 MiB on each attached session. Disabling +telemetry stops new durable capture without disabling the Network domain used by +counters. Chrome may keep already-buffered bodies until eviction or disconnection. +Unsupported configuration is logged and ordinary capture continues. Bodies can +still be evicted under buffer pressure; `body_error` reports retrieval/decoding +failures separately from intentionally excluded or empty bodies. The 8 KiB/4 KiB +output caps are unchanged. + +Extension-target events carry `source.metadata.extension_id` and +`source.metadata.kernel_extension` (`"true"` or `"false"`). The latter identifies +the bundled extensions loaded from their fixed installation paths. Consumers can +filter these sources while retaining application workers and custom extensions. +Network events snapshot the request's document origin, falling back to the target +URL, so navigating into or out of an extension page does not relabel pending +requests. Content-script requests made through an ordinary page document are not +attributed to an extension. Attribution is a telemetry aid, not a security boundary. + +Run the browser regressions with: + +```sh +KERNEL_CDPMONITOR_CHROME_E2E=1 go test -race ./lib/cdpmonitor \ + -run '^TestNetwork(WireCapture|BodiesSurviveNavigation|ExtensionAttribution)$' -count=1 +``` + +Bundled-extension attribution also has a browser regression that loads an actual +installed bundle and checks its Chromium-assigned ID. Run it once for each bundled +path (`/home/kernel/extensions/kernel` and `/home/kernel/extensions/capmonster`): + +```sh +KERNEL_CDPMONITOR_BUNDLED_EXTENSION_PATH=/home/kernel/extensions/kernel \ + go test -race ./lib/cdpmonitor -run '^TestNetworkBundledExtensionAttribution$' -count=1 +``` + +This requires the bundle at its installation path, with its normal manifest and +assets. It is separate from the general Chromium suite because the bundles are +not included in this source tree. An explicit path that cannot load fails the test. + ## Event taxonomy **CDP-derived** (1-to-1 with a CDP notification): `console_log`, `console_error`, `network_request`, `network_response`, `network_loading_failed`, `proxy_error` (classified from a branded 502 or 403 response carrying the `X-Kernel-Proxy-Error` header), `page_tab_opened`, `page_navigation`, `page_dom_content_loaded`, `page_load`, `page_layout_shift`, `page_lcp`. `proxy_error` is an opt-in per-session/per-URL refinement of the raw `network` events: it is only observable while the network category (CDP collector) is running, so it is not a default-on alerting signal. @@ -360,7 +437,7 @@ Unless otherwise noted, events also include the nav context fields described abo | Event | Fields | | --- | --- | | `network_request` | `request_id`, `loader_id`, `frame_id`, `document_url`, `method`, `url`, `headers`, `initiator_type`. Optional: `post_data`, `resource_type`, `is_redirect` + `redirect_url`. | -| `network_response` | `request_id`, `loader_id`, `frame_id`, `method`, `url`, `status`, `headers`. Optional: `status_text`, `mime_type`, `resource_type`, `body` (truncated text body for textual MIME types). | +| `network_response` | `request_id`, `loader_id`, `frame_id`, `method`, `url`, `status`, `headers`. Optional: `status_text`, `mime_type`, `resource_type`, `body` (truncated text body for textual MIME types), `body_error`, `request_headers`. | | `network_loading_failed` | `request_id`, `error_text`, `canceled`. Optional (absent when the request record was not found): `url`, `loader_id`, `frame_id`, `resource_type`. | | `proxy_error` | `request_id`, `code` (typed enum matching the metro header values), `status` (502, or 403 when the session's network policy blocks the destination). Optional: `raw_code` (sanitized original value when `code` is `unknown`), `url`, `loader_id`, `frame_id`, `method`, `resource_type`. Emitted when a 502 or 403 response carries the `X-Kernel-Proxy-Error` header. Unrecognized values are reported as `unknown`; all such values share one rate-limit slot. Emission is sampled to at most one per session+code+resource_type per second. WebSocket handshakes are not classified (documented non-goal). A CONNECT the proxy refuses outright, such as a `network_policy_denied` CONNECT to a port other than 443, is not classified either: Chromium does not expose the refusal, so it appears only as `network_loading_failed` with `net::ERR_TUNNEL_CONNECTION_FAILED`. | diff --git a/server/lib/cdpmonitor/cdp_proto.go b/server/lib/cdpmonitor/cdp_proto.go index 75fd2a86e..7fc374b36 100644 --- a/server/lib/cdpmonitor/cdp_proto.go +++ b/server/lib/cdpmonitor/cdp_proto.go @@ -162,6 +162,17 @@ type cdpNetworkRequestWillBeSentParams struct { RenderBlockingBehavior string `json:"renderBlockingBehavior,omitempty"` } +// cdpNetworkRequestWillBeSentExtraInfoParams mirrors Network.requestWillBeSentExtraInfo. +type cdpNetworkRequestWillBeSentExtraInfoParams struct { + RequestID string `json:"requestId"` + AssociatedCookies json.RawMessage `json:"associatedCookies"` + Headers json.RawMessage `json:"headers"` + ConnectTiming json.RawMessage `json:"connectTiming"` + ClientSecurityState json.RawMessage `json:"clientSecurityState,omitempty"` + SiteHasCookieInOtherPartition bool `json:"siteHasCookieInOtherPartition,omitempty"` + AppliedNetworkConditionsID string `json:"appliedNetworkConditionsId,omitempty"` +} + // cdpNetworkResponseReceivedParams mirrors Network.responseReceived params. type cdpNetworkResponseReceivedParams struct { RequestID string `json:"requestId"` diff --git a/server/lib/cdpmonitor/cdp_proto_test.go b/server/lib/cdpmonitor/cdp_proto_test.go index 7a9d04900..87df22d6d 100644 --- a/server/lib/cdpmonitor/cdp_proto_test.go +++ b/server/lib/cdpmonitor/cdp_proto_test.go @@ -29,6 +29,7 @@ func TestLayer1Roundtrip(t *testing.T) { {"Runtime.exceptionThrown", "Runtime_exceptionThrown.json", func() any { return new(cdpRuntimeExceptionThrownParams) }}, {"Runtime.bindingCalled", "Runtime_bindingCalled.json", func() any { return new(cdpRuntimeBindingCalledParams) }}, {"Network.requestWillBeSent", "Network_requestWillBeSent.json", func() any { return new(cdpNetworkRequestWillBeSentParams) }}, + {"Network.requestWillBeSentExtraInfo", "Network_requestWillBeSentExtraInfo.json", func() any { return new(cdpNetworkRequestWillBeSentExtraInfoParams) }}, {"Network.responseReceived", "Network_responseReceived.json", func() any { return new(cdpNetworkResponseReceivedParams) }}, {"Network.loadingFinished", "Network_loadingFinished.json", func() any { return new(cdpNetworkLoadingFinishedParams) }}, {"Network.loadingFailed", "Network_loadingFailed.json", func() any { return new(cdpNetworkLoadingFailedParams) }}, diff --git a/server/lib/cdpmonitor/cdp_test.go b/server/lib/cdpmonitor/cdp_test.go index 11096facd..6694445aa 100644 --- a/server/lib/cdpmonitor/cdp_test.go +++ b/server/lib/cdpmonitor/cdp_test.go @@ -390,10 +390,7 @@ func simulateRequest(m *Monitor, id string) { }, "s1") } -// simulateFinished stores minimal state and sends Network.loadingFinished. +// simulateFinished completes the request without replacing its captured state. func simulateFinished(m *Monitor, id string) { - m.pendReqMu.Lock() - m.pendingRequests[networkRequestKey{"s1", id}] = networkReqState{sessionID: "s1", method: "GET", url: "https://example.com/" + id} - m.pendReqMu.Unlock() m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: id}, "s1") } diff --git a/server/lib/cdpmonitor/computed.go b/server/lib/cdpmonitor/computed.go index 07ebfc474..1c5f8510d 100644 --- a/server/lib/cdpmonitor/computed.go +++ b/server/lib/cdpmonitor/computed.go @@ -138,8 +138,7 @@ func (s *computedState) stop() { // resetOnNavigation resets all state machines. Called on Page.frameNavigated. // Increments navSeq so any AfterFunc callbacks already running will discard their results. -// inflight seeds netPending; callers pass 0 because each session only tracks its -// own requests and starts fresh on navigation. +// inflight seeds netPending with requests already observed for the new loader. func (s *computedState) resetOnNavigation(inflight int, ctx navContext) error { s.mu.Lock() defer s.mu.Unlock() @@ -159,11 +158,8 @@ func (s *computedState) resetOnNavigation(inflight int, ctx navContext) error { return err } s.navData = navData - s.navMeta = map[string]string{ - MetadataKeyCDPSessionID: ctx.sessionID, - MetadataKeyTargetID: ctx.targetID, - MetadataKeyTargetType: ctx.targetType, - } + s.navMeta = targetMetadata(targetInfo{targetID: ctx.targetID, targetType: ctx.targetType, url: ctx.url}) + s.navMeta[MetadataKeyCDPSessionID] = ctx.sessionID stopTimer(s.netTimer) s.netTimer = nil diff --git a/server/lib/cdpmonitor/domains.go b/server/lib/cdpmonitor/domains.go index b2aa7e853..72f264288 100644 --- a/server/lib/cdpmonitor/domains.go +++ b/server/lib/cdpmonitor/domains.go @@ -133,9 +133,10 @@ func (m *Monitor) disableOptionalDomains(ctx context.Context, sessionID, scriptI if !exists { return nil } - var cleanupErr error + cleanupErr := m.configureBodyCapture(ctx, sessionID, false) if scriptID != "" { - _, cleanupErr = m.send(ctx, "Page.removeScriptToEvaluateOnNewDocument", map[string]any{"identifier": scriptID}, sessionID) + _, err := m.send(ctx, "Page.removeScriptToEvaluateOnNewDocument", map[string]any{"identifier": scriptID}, sessionID) + cleanupErr = errors.Join(cleanupErr, err) } if isPageLikeTarget(info.targetType) { if dirty { diff --git a/server/lib/cdpmonitor/extension_source.go b/server/lib/cdpmonitor/extension_source.go new file mode 100644 index 000000000..151a49483 --- /dev/null +++ b/server/lib/cdpmonitor/extension_source.go @@ -0,0 +1,36 @@ +package cdpmonitor + +import ( + "crypto/sha256" + "encoding/hex" + "net/url" + "strconv" + "strings" +) + +// These bundled extensions are loaded unpacked at fixed paths without a manifest +// key. Chromium derives their IDs from the first 128 bits of SHA-256(path). +var bundledExtensionIDs = map[string]bool{ + unpackedExtensionID("/home/kernel/extensions/kernel"): true, + unpackedExtensionID("/home/kernel/extensions/capmonster"): true, +} + +func unpackedExtensionID(path string) string { + sum := sha256.Sum256([]byte(path)) + return strings.Map(func(r rune) rune { + if r <= '9' { + return 'a' + r - '0' + } + return 'k' + r - 'a' + }, hex.EncodeToString(sum[:16])) +} + +func targetMetadata(info targetInfo) map[string]string { + metadata := map[string]string{MetadataKeyTargetID: info.targetID, MetadataKeyTargetType: info.targetType} + origin, err := url.Parse(info.url) + if err == nil && origin.Scheme == "chrome-extension" && origin.Host != "" { + metadata["extension_id"] = origin.Host + metadata["kernel_extension"] = strconv.FormatBool(bundledExtensionIDs[origin.Host]) + } + return metadata +} diff --git a/server/lib/cdpmonitor/handlers.go b/server/lib/cdpmonitor/handlers.go index 230c95ec5..7a672dd85 100644 --- a/server/lib/cdpmonitor/handlers.go +++ b/server/lib/cdpmonitor/handlers.go @@ -61,6 +61,10 @@ func (m *Monitor) logUnmarshalErr(method string, err error) { // publishEvent stamps common fields and publishes an event. func (m *Monitor) publishEvent(eventType string, category oapi.TelemetryEventCategory, source oapi.BrowserEventSource, sourceEvent string, data json.RawMessage, sessionID string) { + m.publishEventAt(time.Now(), eventType, category, source, sourceEvent, data, sessionID) +} + +func (m *Monitor) publishEventAt(observedAt time.Time, eventType string, category oapi.TelemetryEventCategory, source oapi.BrowserEventSource, sourceEvent string, data json.RawMessage, sessionID string) { src := source src.Event = &sourceEvent if sessionID != "" { @@ -71,15 +75,19 @@ func (m *Monitor) publishEvent(eventType string, category oapi.TelemetryEventCat } } meta[MetadataKeyCDPSessionID] = sessionID - m.sessionsMu.RLock() - info := m.sessions[sessionID] - m.sessionsMu.RUnlock() - meta[MetadataKeyTargetID] = info.targetID - meta[MetadataKeyTargetType] = info.targetType + // Asynchronous network events carry the origin observed at request time. + if _, snapshotted := meta[MetadataKeyTargetID]; !snapshotted { + m.sessionsMu.RLock() + info := m.sessions[sessionID] + m.sessionsMu.RUnlock() + for k, v := range targetMetadata(info) { + meta[k] = v + } + } src.Metadata = &meta } m.publish(events.Event{ - Ts: time.Now().UnixMicro(), + Ts: observedAt.UnixMicro(), Type: eventType, Category: category, Source: src, @@ -144,6 +152,11 @@ func (m *Monitor) dispatchEvent(msg cdpMessage) { if m.decodeParams(msg.Method, msg.Params, &p) { m.handleNetworkRequest(p, msg.SessionID) } + case "Network.requestWillBeSentExtraInfo": + var p cdpNetworkRequestWillBeSentExtraInfoParams + if m.decodeParams(msg.Method, msg.Params, &p) { + m.handleRequestExtraInfo(p, msg.SessionID) + } case "Network.responseReceived": var p cdpNetworkResponseReceivedParams if m.decodeParams(msg.Method, msg.Params, &p) { @@ -425,6 +438,7 @@ func (m *Monitor) handleTimelineEvent(p cdpPerformanceTimelineEventAddedParams, // This mirrors what CDP/DevTools itself exposes. Consumers should treat the // event stream as privileged data; opt-in redaction can be added later. func (m *Monitor) handleNetworkRequest(p cdpNetworkRequestWillBeSentParams, sessionID string) { + observedAt := time.Now() // Extract only the initiator type; the stack trace is too verbose and dominates event size. var initiatorType string var raw struct { @@ -439,8 +453,10 @@ func (m *Monitor) handleNetworkRequest(p cdpNetworkRequestWillBeSentParams, sess m.sessionsMu.RUnlock() cs := m.computedFor(sessionID) var navSeq int64 + countedNavSeq := -1 if cs != nil { - navSeq = int64(cs.currentNavSeq()) + countedNavSeq = cs.currentNavSeq() + navSeq = int64(countedNavSeq) } // Redirects reuse the same requestId and fire additional requestWillBeSent @@ -455,18 +471,21 @@ func (m *Monitor) handleNetworkRequest(p cdpNetworkRequestWillBeSentParams, sess addedAt = time.Now() } else { navSeq = existing.navSeq + countedNavSeq = existing.countedNavSeq + m.resolveNetworkHeadersLocked(existing.hop, p.RedirectHasExtraInfo) } m.pendingRequests[key] = networkReqState{ - sessionID: sessionID, - method: p.Request.Method, - url: p.Request.URL, - headers: p.Request.Headers, - postData: p.Request.PostData, - resourceType: p.Type, - loaderID: p.LoaderID, - frameID: p.FrameID, - navSeq: navSeq, - addedAt: addedAt, + sessionID: sessionID, + method: p.Request.Method, + url: p.Request.URL, + headers: p.Request.Headers, + postData: p.Request.PostData, + resourceType: p.Type, + loaderID: p.LoaderID, + frameID: p.FrameID, + navSeq: navSeq, + countedNavSeq: countedNavSeq, + addedAt: addedAt, } m.pendReqMu.Unlock() var hdrs oapi.BrowserHttpHeaders @@ -495,14 +514,33 @@ func (m *Monitor) handleNetworkRequest(p cdpNetworkRequestWillBeSentParams, sess payload.IsRedirect = ptrOf(true) payload.RedirectUrl = ptrOf(existing.url) } - data, _ := json.Marshal(payload) - m.publishEvent(EventNetworkRequest, events.Network, oapi.BrowserEventSource{Kind: oapi.Cdp}, "Network.requestWillBeSent", data, sessionID) + m.pendReqMu.Lock() + requestInfo := info + if p.DocumentURL != "" { + requestInfo.url = p.DocumentURL + } + hop := m.queueNetworkRequestLocked(key, payload, requestInfo, observedAt) + state := m.pendingRequests[key] + state.hop = hop + m.pendingRequests[key] = state + m.pendReqMu.Unlock() + var redirectPublished <-chan struct{} + if isRedirect && len(p.RedirectResponse) != 0 { + var response cdpNetworkResponse + if json.Unmarshal(p.RedirectResponse, &response) == nil { + existing.status, existing.statusText = response.Status, response.StatusText + existing.resHeaders, existing.mimeType = response.Headers, response.MimeType + redirectPublished = m.emitNetworkResponse(m.telemetryCtx, observedAt, key, existing, info, true) + } + } + m.publishNetworkRequest(m.telemetryCtx, key, hop, redirectPublished) if !isRedirect && cs != nil { cs.onRequest() } } func (m *Monitor) handleResponseReceived(p cdpNetworkResponseReceivedParams, sessionID string) { + observedAt := time.Now() key := networkRequestKey{sessionID, p.RequestID} m.pendReqMu.Lock() var ( @@ -514,6 +552,7 @@ func (m *Monitor) handleResponseReceived(p cdpNetworkResponseReceivedParams, ses st.statusText = p.Response.StatusText st.resHeaders = p.Response.Headers st.mimeType = p.Response.MimeType + m.resolveNetworkHeadersLocked(st.hop, p.HasExtraInfo) m.pendingRequests[key] = st state, ok = st, true } @@ -554,10 +593,21 @@ func (m *Monitor) handleResponseReceived(p cdpNetworkResponseReceivedParams, ses navSeq = int64(cs.currentNavSeq()) } } - m.publishProxyError(sessionID, p.RequestID, code, p.Response.Status, navSeq, method, resType, url, frame, loader) + source := oapi.BrowserEventSource{Kind: oapi.Cdp} + if state.hop != nil { + source = state.hop.source + } + // Detaching a target removes its session while publication may still be waiting. + m.sessionsMu.RLock() + info := m.sessions[sessionID] + m.sessionsMu.RUnlock() + m.publishAfterNetworkRequest(state.hop, func() { + m.publishProxyError(observedAt, source, info, sessionID, p.RequestID, code, p.Response.Status, navSeq, method, resType, url, frame, loader) + }) } func (m *Monitor) handleLoadingFinished(ctx context.Context, p cdpNetworkLoadingFinishedParams, sessionID string) { + observedAt := time.Now() key := networkRequestKey{sessionID, p.RequestID} m.pendReqMu.Lock() state, ok := m.pendingRequests[key] @@ -571,79 +621,47 @@ func (m *Monitor) handleLoadingFinished(ctx context.Context, p cdpNetworkLoading m.sessionsMu.RLock() info := m.sessions[sessionID] m.sessionsMu.RUnlock() - if cs := m.computedFor(state.sessionID); cs != nil { - cs.onLoadingFinished() - } - // Fetch response body async to avoid blocking readLoop; binary types are skipped. - m.telemetryWg.Go(func() { - body := m.fetchResponseBody(ctx, p.RequestID, sessionID, state) - var hdrs oapi.BrowserHttpHeaders - _ = json.Unmarshal(state.resHeaders, &hdrs) - resPayload := oapi.BrowserNetworkResponseEventData{ - SessionId: sessionID, - TargetId: info.targetID, - TargetType: oapi.BrowserTargetType(info.targetType), - FrameId: ptrOf(state.frameID), - LoaderId: ptrOf(state.loaderID), - Url: ptrOf(state.url), - NavSeq: state.navSeq, - RequestId: p.RequestID, - Method: state.method, - Status: state.status, - Headers: hdrs, - } - if state.statusText != "" { - resPayload.StatusText = ptrOf(state.statusText) - } - if state.mimeType != "" { - resPayload.MimeType = ptrOf(state.mimeType) - } - if state.resourceType != "" { - resPayload.ResourceType = ptrOf(state.resourceType) - } - if body != "" { - resPayload.Body = ptrOf(body) - } - data, _ := json.Marshal(resPayload) - m.publishEvent(EventNetworkResponse, events.Network, oapi.BrowserEventSource{Kind: oapi.Cdp}, "Network.loadingFinished", data, sessionID) - }) + m.finishNetworkRequest(state) + m.emitNetworkResponse(ctx, observedAt, key, state, info, false) } // fetchResponseBody retrieves and truncates the response body for textual resources. -func (m *Monitor) fetchResponseBody(ctx context.Context, requestID, sessionID string, state networkReqState) string { +func (m *Monitor) fetchResponseBody(ctx context.Context, requestID, sessionID string, state networkReqState) (string, error) { if !isTextualResource(state.resourceType, state.mimeType) { - return "" + return "", nil } result, err := m.send(ctx, "Network.getResponseBody", map[string]any{ "requestId": requestID, }, sessionID) if err != nil { - return "" + return "", err } var resp struct { Body string `json:"body"` Base64Encoded bool `json:"base64Encoded"` } - if json.Unmarshal(result, &resp) != nil { - return "" + if err := json.Unmarshal(result, &resp); err != nil { + return "", err } body := resp.Body if resp.Base64Encoded { decoded, err := base64.StdEncoding.DecodeString(body) if err != nil { - return "" + return "", err } body = string(decoded) } - return events.TruncateCaptured(body, bodyCapFor(state.mimeType)) + return events.TruncateCaptured(body, bodyCapFor(state.mimeType)), nil } func (m *Monitor) handleLoadingFailed(p cdpNetworkLoadingFailedParams, sessionID string) { + observedAt := time.Now() key := networkRequestKey{sessionID, p.RequestID} m.pendReqMu.Lock() state, ok := m.pendingRequests[key] if ok { delete(m.pendingRequests, key) + m.resolveFailedHeadersLocked(state.hop) } m.pendReqMu.Unlock() @@ -677,12 +695,16 @@ func (m *Monitor) handleLoadingFailed(p cdpNetworkLoadingFailedParams, sessionID } } data, _ := json.Marshal(failPayload) - m.publishEvent(EventNetworkLoadingFailed, events.Network, oapi.BrowserEventSource{Kind: oapi.Cdp}, "Network.loadingFailed", data, sessionID) + source := oapi.BrowserEventSource{Kind: oapi.Cdp} + if state.hop != nil { + source = state.hop.source + } + m.publishAfterNetworkRequest(state.hop, func() { + m.publishEventAt(observedAt, EventNetworkLoadingFailed, events.Network, source, "Network.loadingFailed", data, sessionID) + }) if ok { - if cs := m.computedFor(state.sessionID); cs != nil { - cs.onLoadingFinished() - } + m.finishNetworkRequest(state) } } @@ -742,7 +764,7 @@ func (m *Monitor) proxyErrorRateLimited(sessionID, code, resourceType string) bo // the published enum lists it. The metro egress proxy gains codes on its own // release cadence, so a value this image does not know is reported as unknown // with the sanitized header value in raw_code rather than dropped. -func (m *Monitor) publishProxyError(sessionID, requestID, code string, status int, navSeq int64, method, resourceType string, url, frameID, loaderID *string) { +func (m *Monitor) publishProxyError(observedAt time.Time, source oapi.BrowserEventSource, info targetInfo, sessionID, requestID, code string, status int, navSeq int64, method, resourceType string, url, frameID, loaderID *string) { var rawCode *string if code == proxyErrorUnknownCode || !oapi.BrowserProxyErrorEventDataCode(code).Valid() { raw := sanitizeProxyErrorRawCode(code) @@ -753,9 +775,6 @@ func (m *Monitor) publishProxyError(sessionID, requestID, code string, status in if m.proxyErrorRateLimited(sessionID, code, resourceType) { return } - m.sessionsMu.RLock() - info := m.sessions[sessionID] - m.sessionsMu.RUnlock() data, _ := json.Marshal(oapi.BrowserProxyErrorEventData{ SessionId: sessionID, TargetId: info.targetID, @@ -771,16 +790,22 @@ func (m *Monitor) publishProxyError(sessionID, requestID, code string, status in RawCode: rawCode, ResourceType: optPtr(resourceType), }) - m.publishEvent(EventProxyError, events.Network, oapi.BrowserEventSource{Kind: oapi.Cdp}, "Network.responseReceived", data, sessionID) + m.publishEventAt(observedAt, EventProxyError, events.Network, source, "Network.responseReceived", data, sessionID) } func (m *Monitor) handleFrameNavigated(p cdpPageFrameNavigatedParams, sessionID string) { // Pre-fetch target info and computedState before acquiring pendReqMu to // avoid a pendReqMu → sessionsMu ordering cycle. - m.sessionsMu.RLock() - info := m.sessions[sessionID] + m.sessionsMu.Lock() + info, tracked := m.sessions[sessionID] cs := m.computedStates[sessionID] - m.sessionsMu.RUnlock() + // Chromium uses an OOPIF's root frame ID as its target ID; that root can + // still have a parentId, unlike a top-level page's root. + if tracked && (p.Frame.ParentID == "" || p.Frame.ID == info.targetID) { + info.url = p.Frame.URL + m.sessions[sessionID] = info + } + m.sessionsMu.Unlock() if info.targetType == "iframe" && p.Frame.ParentID == "" { p.Frame.ParentID = info.parentFrameID @@ -811,18 +836,24 @@ func (m *Monitor) handleFrameNavigated(p cdpPageFrameNavigatedParams, sessionID } m.pendReqMu.Lock() - for id, req := range m.pendingRequests { - if req.sessionID == sessionID { - delete(m.pendingRequests, id) + inflight := 0 + nextSeq := -1 + if cs != nil { + nextSeq = cs.currentNavSeq() + 1 + } + for key, req := range m.pendingRequests { + if req.sessionID != sessionID { + continue + } + req.countedNavSeq = -1 + if cs != nil && req.loaderID == p.Frame.LoaderID { + req.countedNavSeq = nextSeq + inflight++ } + m.pendingRequests[key] = req } - // Reset while holding pendReqMu so new requests arriving concurrently - // can't increment netPending before the reset completes. - // inflight=0: remaining pendingRequests belong to other target sessions; - // their loadingFinished events decrement those sessions' own state machines, - // not this one, so we start fresh. if cs != nil { - if err := cs.resetOnNavigation(0, navCtx); err != nil { + if err := cs.resetOnNavigation(inflight, navCtx); err != nil { m.log.Error("cdpmonitor: failed to build nav event payload", "err", err) } } @@ -950,5 +981,10 @@ func (m *Monitor) handleDetachedFromTarget(p cdpTargetDetachedFromTargetParams) delete(m.pendingRequests, key) } } + for key := range m.networkExchanges { + if key.sessionID == p.SessionID { + delete(m.networkExchanges, key) + } + } m.pendReqMu.Unlock() } diff --git a/server/lib/cdpmonitor/handlers_test.go b/server/lib/cdpmonitor/handlers_test.go index 02e4ff6e0..467bff971 100644 --- a/server/lib/cdpmonitor/handlers_test.go +++ b/server/lib/cdpmonitor/handlers_test.go @@ -410,8 +410,8 @@ func TestNetworkEvents(t *testing.T) { func TestProxyErrorUnknownCodesShareRateLimit(t *testing.T) { collector := newEventCollector() monitor := New(newTestUpstream(""), collector.publishFn(), 0, discardLogger, nil) - monitor.publishProxyError("sess", "req-a", "future_a", 502, 0, "GET", "Document", nil, nil, nil) - monitor.publishProxyError("sess", "req-b", "future_b", 502, 0, "GET", "Document", nil, nil, nil) + monitor.publishProxyError(time.Now(), oapi.BrowserEventSource{Kind: oapi.Cdp}, targetInfo{}, "sess", "req-a", "future_a", 502, 0, "GET", "Document", nil, nil, nil) + monitor.publishProxyError(time.Now(), oapi.BrowserEventSource{Kind: oapi.Cdp}, targetInfo{}, "sess", "req-b", "future_b", 502, 0, "GET", "Document", nil, nil, nil) collector.mu.Lock() defer collector.mu.Unlock() diff --git a/server/lib/cdpmonitor/monitor.go b/server/lib/cdpmonitor/monitor.go index 4e2cfa63d..f66e7809a 100644 --- a/server/lib/cdpmonitor/monitor.go +++ b/server/lib/cdpmonitor/monitor.go @@ -68,8 +68,9 @@ type Monitor struct { sessions map[string]targetInfo // sessionID → targetInfo mainSessionID atomic.Value // string; set on first top-level frameNavigated, cleared on reconnect - pendReqMu sync.Mutex - pendingRequests map[networkRequestKey]networkReqState + pendReqMu sync.Mutex + pendingRequests map[networkRequestKey]networkReqState + networkExchanges map[networkRequestKey]*networkExchange computedStates map[string]*computedState // sessionID → state machine; guarded by sessionsMu @@ -114,6 +115,7 @@ func New(upstreamMgr UpstreamProvider, publish PublishFunc, displayNum int, log sessions: make(map[string]targetInfo), computedStates: make(map[string]*computedState), pendingRequests: make(map[networkRequestKey]networkReqState), + networkExchanges: make(map[networkRequestKey]*networkExchange), bindingLastSeen: make(map[string]time.Time), proxyLastEmit: make(map[string]time.Time), lifecycleCtx: context.Background(), @@ -292,6 +294,21 @@ func (m *Monitor) handleSurfaceEvent(conn *monitorConnection, event browsersurfa case browsersurface.EventSessionRemoved: m.handleDetachedFromTarget(cdpTargetDetachedFromTargetParams{SessionID: event.SessionID}) case browsersurface.EventProtocol: + if event.Message.Method == "Target.targetInfoChanged" { + var p struct { + TargetInfo cdpTargetTargetInfo `json:"targetInfo"` + } + if json.Unmarshal(event.Message.Params, &p) == nil { + m.sessionsMu.Lock() + for id, info := range m.sessions { + if info.targetID == p.TargetInfo.TargetID { + info.url, info.title = p.TargetInfo.URL, p.TargetInfo.Title + m.sessions[id] = info + } + } + m.sessionsMu.Unlock() + } + } if event.Message.Method == "Target.targetDestroyed" { var p struct { TargetID string `json:"targetId"` @@ -345,6 +362,7 @@ func (m *Monitor) clearState() { m.mainSessionID.Store(mainSessionUnset) m.pendReqMu.Lock() m.pendingRequests = make(map[networkRequestKey]networkReqState) + clear(m.networkExchanges) m.pendReqMu.Unlock() m.bindingRateMu.Lock() m.bindingLastSeen = make(map[string]time.Time) @@ -374,11 +392,14 @@ func (m *Monitor) sweepPendingRequests(ctx context.Context) { toSweep = append(toSweep, state) } } + for key, exchange := range m.networkExchanges { + if now.Sub(exchange.addedAt) > pendingRequestTTL { + delete(m.networkExchanges, key) + } + } m.pendReqMu.Unlock() for _, state := range toSweep { - if cs := m.computedFor(state.sessionID); cs != nil { - cs.onLoadingFinished() - } + m.finishNetworkRequest(state) } } } diff --git a/server/lib/cdpmonitor/network_capture.go b/server/lib/cdpmonitor/network_capture.go new file mode 100644 index 000000000..192b6e7b6 --- /dev/null +++ b/server/lib/cdpmonitor/network_capture.go @@ -0,0 +1,275 @@ +package cdpmonitor + +import ( + "context" + "encoding/json" + "time" + + "github.com/kernel/kernel-images/server/lib/events" + "github.com/kernel/kernel-images/server/lib/oapi" +) + +const ( + networkHeaderWait = time.Second + maxNetworkExchanges = 8192 + maxExtraInfoPerExchange = 64 + durableBodyBufferSize = 10 * 1024 * 1024 +) + +// Chrome emits base events and ExtraInfo on independent streams. Redirects reuse +// request IDs; only hops whose response advertises ExtraInfo consume the header queue. +// All exchange and hop fields are protected by pendReqMu. +type networkExchange struct { + addedAt time.Time + hops []*networkHop + requests []json.RawMessage + terminal bool + publications int // request/response publishers still using this exchange +} + +type networkHop struct { + exchange *networkExchange + request oapi.BrowserNetworkRequestEventData + source oapi.BrowserEventSource + observedAt time.Time + known bool + hasExtra bool + requestHeaders json.RawMessage + requestReady chan struct{} + requestMatched bool + requestPublished chan struct{} +} + +func (m *Monitor) exchangeLocked(key networkRequestKey) *networkExchange { + e := m.networkExchanges[key] + if e == nil { + e = &networkExchange{addedAt: time.Now()} + m.networkExchanges[key] = e + } + return e +} + +func (m *Monitor) queueNetworkRequestLocked(key networkRequestKey, request oapi.BrowserNetworkRequestEventData, info targetInfo, observedAt time.Time) *networkHop { + e := m.exchangeLocked(key) + metadata := targetMetadata(info) + h := &networkHop{ + exchange: e, + request: request, + source: oapi.BrowserEventSource{Kind: oapi.Cdp, Metadata: &metadata}, + observedAt: observedAt, + requestReady: make(chan struct{}), + requestPublished: make(chan struct{}), + } + e.hops = append(e.hops, h) + e.publications++ + return h +} + +func (m *Monitor) handleRequestExtraInfo(p cdpNetworkRequestWillBeSentExtraInfoParams, sessionID string) { + key := networkRequestKey{sessionID, p.RequestID} + m.pendReqMu.Lock() + defer m.pendReqMu.Unlock() + if m.networkExchanges[key] == nil && len(m.networkExchanges) >= maxNetworkExchanges { + return + } + e := m.exchangeLocked(key) + if len(e.requests) >= maxExtraInfoPerExchange { + return + } + e.requests = append(e.requests, p.Headers) + e.matchHeaders() +} + +func (m *Monitor) resolveNetworkHeadersLocked(h *networkHop, hasExtra bool) { + if h == nil { + return + } + h.known, h.hasExtra = true, hasExtra + h.exchange.matchHeaders() +} + +func (m *Monitor) resolveFailedHeadersLocked(h *networkHop) { + if h == nil { + return + } + h.exchange.terminal = true + // CORS failures can have ExtraInfo without a responseReceived event. + if !h.known { + h.known, h.hasExtra = true, true + } + h.exchange.matchHeaders() + m.cleanupNetworkExchangeLocked(networkRequestKey{h.request.SessionId, h.request.RequestId}, h.exchange) +} + +func (m *Monitor) cleanupNetworkExchangeLocked(key networkRequestKey, e *networkExchange) { + if e.terminal && e.publications == 0 && m.networkExchanges[key] == e { + delete(m.networkExchanges, key) + } +} + +func (m *Monitor) finishNetworkPublication(key networkRequestKey, e *networkExchange) { + m.pendReqMu.Lock() + defer m.pendReqMu.Unlock() + e.publications-- + m.cleanupNetworkExchangeLocked(key, e) +} + +func (e *networkExchange) matchHeaders() { + for _, h := range e.hops { + if !h.known { + break + } + if h.requestMatched { + continue + } + if h.hasExtra { + if len(e.requests) == 0 { + break + } + h.requestHeaders, e.requests = e.requests[0], e.requests[1:] + } + h.requestMatched = true + close(h.requestReady) + } +} + +func waitNetworkHeaders(ctx context.Context, ready <-chan struct{}) { + timer := time.NewTimer(networkHeaderWait) + defer timer.Stop() + select { + case <-ready: + case <-ctx.Done(): + case <-timer.C: + } +} + +func (m *Monitor) publishNetworkRequest(ctx context.Context, key networkRequestKey, h *networkHop, redirectPublished <-chan struct{}) { + m.telemetryWg.Go(func() { + defer m.finishNetworkPublication(key, h.exchange) + defer close(h.requestPublished) + waitNetworkHeaders(ctx, h.requestReady) + if redirectPublished != nil { + <-redirectPublished + } + m.pendReqMu.Lock() + payload := h.request + if h.requestHeaders != nil { + var headers oapi.BrowserHttpHeaders + if json.Unmarshal(h.requestHeaders, &headers) == nil && headers != nil { + payload.Headers = headers + } + } + m.pendReqMu.Unlock() + data, _ := json.Marshal(payload) + m.publishEventAt(h.observedAt, EventNetworkRequest, events.Network, h.source, "Network.requestWillBeSent", data, key.sessionID) + }) +} + +// The request publisher always drains, including on cancellation. Wait for its +// publication, not just header readiness, to preserve per-request event order. +func (m *Monitor) publishAfterNetworkRequest(h *networkHop, publish func()) { + if h == nil { + publish() + return + } + m.telemetryWg.Go(func() { + <-h.requestPublished + publish() + }) +} + +func (m *Monitor) emitNetworkResponse(ctx context.Context, observedAt time.Time, key networkRequestKey, state networkReqState, info targetInfo, redirect bool) <-chan struct{} { + published := make(chan struct{}) + h := state.hop + if h != nil { + m.pendReqMu.Lock() + h.exchange.publications++ + if !redirect { + h.exchange.terminal = true + } + m.pendReqMu.Unlock() + } + m.telemetryWg.Go(func() { + defer close(published) + if h != nil { + defer m.finishNetworkPublication(key, h.exchange) + } + // Fetch before waiting for ExtraInfo so header ordering cannot delay retrieval. + var body string + var bodyErr error + if !redirect { + body, bodyErr = m.fetchResponseBody(ctx, key.requestID, key.sessionID, state) + } + if h != nil { + waitNetworkHeaders(ctx, h.requestReady) + <-h.requestPublished + } + var headers oapi.BrowserHttpHeaders + _ = json.Unmarshal(state.resHeaders, &headers) + // Use Chrome's effective status and headers with its captured body. A wire + // 304 can omit cached headers; a separate wire response view is intentionally + // not exposed by browser telemetry. + payload := oapi.BrowserNetworkResponseEventData{ + SessionId: key.sessionID, + TargetId: info.targetID, + TargetType: oapi.BrowserTargetType(info.targetType), + FrameId: ptrOf(state.frameID), + LoaderId: ptrOf(state.loaderID), + Url: ptrOf(state.url), + NavSeq: state.navSeq, + RequestId: key.requestID, + Method: state.method, + Status: state.status, + Headers: headers, + StatusText: optPtr(state.statusText), + MimeType: optPtr(state.mimeType), + ResourceType: optPtr(state.resourceType), + Body: optPtr(body), + } + if bodyErr != nil { + payload.BodyError = ptrOf(bodyErr.Error()) + } + metadata := targetMetadata(info) + source := oapi.BrowserEventSource{Kind: oapi.Cdp, Metadata: &metadata} + if h != nil { + source = h.source + m.pendReqMu.Lock() + if h.requestHeaders != nil { + var requestHeaders oapi.BrowserHttpHeaders + if json.Unmarshal(h.requestHeaders, &requestHeaders) == nil && requestHeaders != nil { + payload.RequestHeaders = &requestHeaders + } + } + m.pendReqMu.Unlock() + } + data, _ := json.Marshal(payload) + event := "Network.loadingFinished" + if redirect { + event = "Network.requestWillBeSent" + } + m.publishEventAt(observedAt, EventNetworkResponse, events.Network, source, event, data, key.sessionID) + }) + return published +} + +func (m *Monitor) finishNetworkRequest(state networkReqState) { + if cs := m.computedFor(state.sessionID); cs != nil { + m.pendReqMu.Lock() + defer m.pendReqMu.Unlock() + cs.mu.Lock() + sameNavigation := state.countedNavSeq == cs.navSeq + cs.mu.Unlock() + if sameNavigation { + cs.onLoadingFinished() + } + } +} + +func (m *Monitor) configureBodyCapture(ctx context.Context, sessionID string, enabled bool) error { + size := 0 + if enabled { + size = durableBodyBufferSize + } + _, err := m.send(ctx, "Network.enable", map[string]any{"enableDurableMessages": enabled, "maxTotalBufferSize": size}, sessionID) + return err +} diff --git a/server/lib/cdpmonitor/network_capture_test.go b/server/lib/cdpmonitor/network_capture_test.go new file mode 100644 index 000000000..baf65f51d --- /dev/null +++ b/server/lib/cdpmonitor/network_capture_test.go @@ -0,0 +1,532 @@ +package cdpmonitor + +import ( + "context" + "encoding/json" + "fmt" + "sync" + "testing" + "testing/synctest" + "time" + + "github.com/kernel/kernel-images/server/lib/browsersurface" + "github.com/kernel/kernel-images/server/lib/cdpclient" + "github.com/kernel/kernel-images/server/lib/events" + "github.com/kernel/kernel-images/server/lib/oapi" + "github.com/stretchr/testify/require" +) + +func sendNetworkFixture(t *testing.T, srv *testServer, method string, params any) { + t.Helper() + srv.sendToMonitor(t, map[string]any{"method": method, "params": params}) +} + +func TestNetworkTimestampsReflectObservation(t *testing.T) { + for _, typ := range []string{EventNetworkResponse, EventNetworkLoadingFailed, EventProxyError} { + t.Run(typ, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + requestAt := time.Now().UnixMicro() + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/slow"}}, "s") + time.Sleep(400 * time.Millisecond) + terminalAt := time.Now().UnixMicro() + switch typ { + case EventNetworkResponse: + m.handleResponseReceived(cdpNetworkResponseReceivedParams{RequestID: "r", HasExtraInfo: true, Response: cdpNetworkResponse{Status: 200}}, "s") + m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: "r"}, "s") + case EventNetworkLoadingFailed: + m.handleLoadingFailed(cdpNetworkLoadingFailedParams{RequestID: "r", ErrorText: "net::ERR_ABORTED", Canceled: true}, "s") + case EventProxyError: + m.handleResponseReceived(cdpNetworkResponseReceivedParams{RequestID: "r", HasExtraInfo: true, Response: cdpNetworkResponse{Status: 502, Headers: json.RawMessage(`{"x-kernel-proxy-error":"proxy_connect_failed"}`)}}, "s") + } + time.Sleep(2 * time.Second) + synctest.Wait() + require.Equal(t, requestAt, ec.waitFor(t, EventNetworkRequest, time.Second).Ts) + require.Equal(t, terminalAt, ec.waitFor(t, typ, time.Second).Ts) + }) + }) + } +} + +func TestNetworkRedirectHopsPublishInOrder(t *testing.T) { + for _, mode := range []string{"late_headers", "missing_headers", "canceled"} { + t.Run(mode, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + m.telemetryCtx = ctx + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/start"}}, "s") + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: "r", RedirectHasExtraInfo: true, RedirectResponse: json.RawMessage(`{"status":302}`), Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/end"}}, "s") + m.handleResponseReceived(cdpNetworkResponseReceivedParams{RequestID: "r", Response: cdpNetworkResponse{Status: 200}}, "s") + m.handleLoadingFinished(ctx, cdpNetworkLoadingFinishedParams{RequestID: "r"}, "s") + time.Sleep(200 * time.Millisecond) + if mode == "late_headers" { + m.handleRequestExtraInfo(cdpNetworkRequestWillBeSentExtraInfoParams{RequestID: "r", Headers: json.RawMessage(`{}`)}, "s") + } else if mode == "canceled" { + cancel() + } + time.Sleep(2 * time.Second) + synctest.Wait() + ec.mu.Lock() + defer ec.mu.Unlock() + var sequence []string + for _, event := range ec.events { + var payload struct { + URL string `json:"url"` + } + require.NoError(t, json.Unmarshal(event.Data, &payload)) + sequence = append(sequence, event.Type+" "+payload.URL) + } + require.Equal(t, []string{ + EventNetworkRequest + " https://example.com/start", + EventNetworkResponse + " https://example.com/start", + EventNetworkRequest + " https://example.com/end", + EventNetworkResponse + " https://example.com/end", + }, sequence) + }) + }) + } +} + +func TestNetworkHeadersFollowRedirectHops(t *testing.T) { + for _, order := range []string{"extras_first", "extras_last", "interleaved"} { + t.Run(order, func(t *testing.T) { + srv := newTestServer(t) + defer srv.close() + _, ec, cleanup := startMonitor(t, srv, nil) + defer cleanup() + send := func(method string, params any) { sendNetworkFixture(t, srv, method, params) } + extra := func(index int) { + send("Network.requestWillBeSentExtraInfo", map[string]any{"requestId": "r", "headers": map[string]string{"Cookie": fmt.Sprintf("hop=%d", index)}}) + send("Network.responseReceivedExtraInfo", map[string]any{"requestId": "r", "statusCode": []int{302, 200}[index], "headers": map[string]string{"X-Hop": fmt.Sprint(index)}}) + } + if order == "extras_first" { + extra(0) + extra(1) + } + send("Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/start"}}) + if order == "interleaved" { + extra(0) + } + send("Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", RedirectHasExtraInfo: true, RedirectResponse: json.RawMessage(`{"status":302,"headers":{"Base":"redirect"}}`), Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/cached"}}) + // A cached redirect has no ExtraInfo; it must not consume the next hop's headers. + send("Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", RedirectResponse: json.RawMessage(`{"status":301,"headers":{"Base":"cached"}}`), Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/final"}}) + if order == "interleaved" { + extra(1) + } + send("Network.responseReceived", cdpNetworkResponseReceivedParams{RequestID: "r", HasExtraInfo: true, Response: cdpNetworkResponse{Status: 200, Headers: json.RawMessage(`{"Base":"final"}`)}}) + send("Network.loadingFinished", cdpNetworkLoadingFinishedParams{RequestID: "r"}) + if order == "extras_last" { + extra(0) + extra(1) + } + for _, tc := range []struct { + path, cookie, header string + status int + }{{"start", "hop=0", "redirect", 302}, {"cached", "", "cached", 301}, {"final", "hop=1", "final", 200}} { + req := waitForNetworkURL(t, ec, EventNetworkRequest, "https://example.com/"+tc.path) + var request oapi.BrowserNetworkRequestEventData + require.NoError(t, json.Unmarshal(req.Data, &request)) + res := waitForNetworkURL(t, ec, EventNetworkResponse, "https://example.com/"+tc.path) + var response oapi.BrowserNetworkResponseEventData + require.NoError(t, json.Unmarshal(res.Data, &response)) + require.Equal(t, tc.status, response.Status) + require.Equal(t, tc.header, response.Headers["Base"]) + require.NotContains(t, response.Headers, "X-Hop") + if tc.cookie != "" { + require.Equal(t, tc.cookie, request.Headers["Cookie"]) + require.NotNil(t, response.RequestHeaders) + require.Equal(t, tc.cookie, (*response.RequestHeaders)["Cookie"]) + } else { + require.NotContains(t, request.Headers, "Cookie") + require.Nil(t, response.RequestHeaders) + } + } + }) + } +} + +func TestTerminalRequestPreservesPendingRedirectHeaders(t *testing.T) { + for _, terminal := range []string{EventNetworkLoadingFailed, EventNetworkResponse} { + t.Run(terminal, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/start"}}, "s") + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: "r", RedirectHasExtraInfo: true, RedirectResponse: json.RawMessage(`{"status":302,"headers":{"Base":"redirect"}}`), Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/final"}}, "s") + if terminal == EventNetworkLoadingFailed { + m.handleLoadingFailed(cdpNetworkLoadingFailedParams{RequestID: "r", ErrorText: "net::ERR_ABORTED", Canceled: true}, "s") + } else { + m.handleResponseReceived(cdpNetworkResponseReceivedParams{RequestID: "r", Response: cdpNetworkResponse{Status: 200}}, "s") + m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: "r"}, "s") + } + time.Sleep(200 * time.Millisecond) + m.handleRequestExtraInfo(cdpNetworkRequestWillBeSentExtraInfoParams{RequestID: "r", Headers: json.RawMessage(`{"Cookie":"hop=0"}`)}, "s") + if terminal == EventNetworkLoadingFailed { + m.handleRequestExtraInfo(cdpNetworkRequestWillBeSentExtraInfoParams{RequestID: "r", Headers: json.RawMessage(`{"Cookie":"hop=1"}`)}, "s") + } + synctest.Wait() + event := waitForNetworkURL(t, ec, EventNetworkResponse, "https://example.com/start") + var response oapi.BrowserNetworkResponseEventData + require.NoError(t, json.Unmarshal(event.Data, &response)) + require.Equal(t, "redirect", response.Headers["Base"]) + require.NotNil(t, response.RequestHeaders) + require.Equal(t, "hop=0", (*response.RequestHeaders)["Cookie"]) + waitForNetworkURL(t, ec, terminal, "https://example.com/final") + require.Empty(t, m.networkExchanges, "completed captures must release their header state") + }) + }) + } +} + +func TestCanceledRequestPublishesBeforeFailure(t *testing.T) { + srv := newTestServer(t) + defer srv.close() + _, ec, cleanup := startMonitor(t, srv, nil) + defer cleanup() + sendNetworkFixture(t, srv, "Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/canceled"}}) + sendNetworkFixture(t, srv, "Network.loadingFailed", cdpNetworkLoadingFailedParams{RequestID: "r", ErrorText: "net::ERR_ABORTED", Canceled: true}) + request := ec.waitFor(t, EventNetworkRequest, 2*time.Second) + failure := ec.waitFor(t, EventNetworkLoadingFailed, 2*time.Second) + ec.mu.Lock() + defer ec.mu.Unlock() + var order []string + for _, event := range ec.events { + if event.Category == events.Network { + order = append(order, event.Type) + } + } + require.Equal(t, []string{EventNetworkRequest, EventNetworkLoadingFailed}, order) + require.LessOrEqual(t, request.Ts, failure.Ts) +} + +func TestResponseWaitsForRequestPublication(t *testing.T) { + ec := newEventCollector() + publish := ec.publishFn() + entered, release := make(chan struct{}), make(chan struct{}) + var once sync.Once + unblock := func() { once.Do(func() { close(release) }) } + m := New(newTestUpstream(""), func(event events.Event) (events.Envelope, bool) { + if event.Type == EventNetworkRequest { + close(entered) + <-release + } + return publish(event) + }, 0, discardLogger, nil) + defer m.Stop() + defer unblock() + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/image"}}, "s") + m.handleResponseReceived(cdpNetworkResponseReceivedParams{RequestID: "r", Response: cdpNetworkResponse{Status: 200}}, "s") + select { + case <-entered: + case <-time.After(time.Second): + t.Fatal("request publication did not start") + } + m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: "r"}, "s") + ec.assertNone(t, EventNetworkResponse, 0, 50*time.Millisecond) + unblock() + ec.waitFor(t, EventNetworkResponse, time.Second) + ec.mu.Lock() + defer ec.mu.Unlock() + require.Len(t, ec.events, 2) + require.Equal(t, EventNetworkRequest, ec.events[0].Type) + require.Equal(t, EventNetworkResponse, ec.events[1].Type) +} + +func TestNetworkLateHeadersRemainOnResponse(t *testing.T) { + srv := newTestServer(t) + defer srv.close() + _, ec, cleanup := startMonitor(t, srv, nil) + defer cleanup() + sendNetworkFixture(t, srv, "Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/slow", Headers: json.RawMessage(`{"Base":"value"}`)}}) + // A hanging request is still visible without waiting for a server response. + request := ec.waitFor(t, EventNetworkRequest, 2*time.Second) + var data oapi.BrowserNetworkRequestEventData + require.NoError(t, json.Unmarshal(request.Data, &data)) + require.Equal(t, "value", data.Headers["Base"]) + sendNetworkFixture(t, srv, "Network.requestWillBeSentExtraInfo", map[string]any{"requestId": "r", "headers": map[string]string{"Cookie": "late=true"}}) + sendNetworkFixture(t, srv, "Network.responseReceived", cdpNetworkResponseReceivedParams{RequestID: "r", HasExtraInfo: true, Response: cdpNetworkResponse{Status: 200}}) + sendNetworkFixture(t, srv, "Network.loadingFinished", cdpNetworkLoadingFinishedParams{RequestID: "r"}) + sendNetworkFixture(t, srv, "Network.responseReceivedExtraInfo", map[string]any{"requestId": "r", "headers": map[string]string{"X-Wire": "yes"}, "statusCode": 200}) + response := ec.waitFor(t, EventNetworkResponse, 2*time.Second) + var payload oapi.BrowserNetworkResponseEventData + require.NoError(t, json.Unmarshal(response.Data, &payload)) + require.NotNil(t, payload.RequestHeaders) + require.Equal(t, "late=true", (*payload.RequestHeaders)["Cookie"]) + require.NotContains(t, payload.Headers, "X-Wire") + ec.mu.Lock() + defer ec.mu.Unlock() + count := 0 + for _, event := range ec.events { + if event.Type == EventNetworkRequest { + count++ + } + } + require.Equal(t, 1, count, "late headers must not duplicate the request event") +} + +func TestNetworkMalformedWireHeadersPreserveBaseHeaders(t *testing.T) { + for _, wire := range []string{`[]`, `"invalid"`, `null`} { + t.Run(wire, func(t *testing.T) { + srv := newTestServer(t) + defer srv.close() + _, ec, cleanup := startMonitor(t, srv, nil) + defer cleanup() + sendNetworkFixture(t, srv, "Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/", Headers: json.RawMessage(`{"X-Request":"base"}`)}}) + sendNetworkFixture(t, srv, "Network.requestWillBeSentExtraInfo", cdpNetworkRequestWillBeSentExtraInfoParams{RequestID: "r", Headers: json.RawMessage(wire)}) + sendNetworkFixture(t, srv, "Network.responseReceived", cdpNetworkResponseReceivedParams{RequestID: "r", HasExtraInfo: true, Response: cdpNetworkResponse{Status: 200, Headers: json.RawMessage(`{"X-Response":"base"}`)}}) + sendNetworkFixture(t, srv, "Network.responseReceivedExtraInfo", map[string]any{"requestId": "r", "statusCode": 200, "headers": json.RawMessage(wire)}) + sendNetworkFixture(t, srv, "Network.loadingFinished", cdpNetworkLoadingFinishedParams{RequestID: "r"}) + var request oapi.BrowserNetworkRequestEventData + require.NoError(t, json.Unmarshal(ec.waitFor(t, EventNetworkRequest, time.Second).Data, &request)) + require.Equal(t, "base", request.Headers["X-Request"]) + var response oapi.BrowserNetworkResponseEventData + require.NoError(t, json.Unmarshal(ec.waitFor(t, EventNetworkResponse, time.Second).Data, &response)) + require.Equal(t, "base", response.Headers["X-Response"]) + require.Nil(t, response.RequestHeaders, "invalid wire headers must not be exposed as captured headers") + }) + } +} + +func TestNetworkResponseUsesEffectiveValues(t *testing.T) { + for _, tc := range []struct { + name string + wireStatus *int + }{ + {"revalidated", ptrOf(304)}, + {"unchanged", ptrOf(200)}, + {"no_extra_info", nil}, + } { + t.Run(tc.name, func(t *testing.T) { + srv := newTestServer(t) + defer srv.close() + _, ec, cleanup := startMonitor(t, srv, nil) + defer cleanup() + sendNetworkFixture(t, srv, "Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/"}}) + sendNetworkFixture(t, srv, "Network.responseReceived", cdpNetworkResponseReceivedParams{RequestID: "r", HasExtraInfo: tc.wireStatus != nil, Response: cdpNetworkResponse{Status: 200, StatusText: "Custom OK", Headers: json.RawMessage(`{"ETag":"v1","Content-Type":"application/json","X-Cached":"retained"}`)}}) + if tc.wireStatus != nil { + sendNetworkFixture(t, srv, "Network.requestWillBeSentExtraInfo", cdpNetworkRequestWillBeSentExtraInfoParams{RequestID: "r", Headers: json.RawMessage(`{}`)}) + sendNetworkFixture(t, srv, "Network.responseReceivedExtraInfo", map[string]any{"requestId": "r", "statusCode": *tc.wireStatus, "headers": map[string]string{"ETag": "v1"}}) + } + sendNetworkFixture(t, srv, "Network.loadingFinished", cdpNetworkLoadingFinishedParams{RequestID: "r"}) + var response map[string]any + require.NoError(t, json.Unmarshal(ec.waitFor(t, EventNetworkResponse, time.Second).Data, &response)) + require.Equal(t, float64(200), response["status"]) + require.Equal(t, "Custom OK", response["status_text"]) + require.Equal(t, map[string]any{"ETag": "v1", "Content-Type": "application/json", "X-Cached": "retained"}, response["headers"]) + require.NotContains(t, response, "effective_status") + require.NotContains(t, response, "wire_status") + require.NotContains(t, response, "wire_headers") + }) + } +} + +func TestNetworkBodyErrorsAreObservable(t *testing.T) { + srv := newTestServer(t) + defer srv.close() + _, ec, cleanup := startMonitor(t, srv, func(msg cdpMessage) any { + if msg.Method == "Network.getResponseBody" { + return map[string]any{"id": msg.ID, "error": map[string]any{"code": -32000, "message": "No resource with given identifier found"}} + } + return nil + }) + defer cleanup() + sendNetworkFixture(t, srv, "Network.requestWillBeSent", cdpNetworkRequestWillBeSentParams{RequestID: "r", Type: "Fetch", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/api"}}) + sendNetworkFixture(t, srv, "Network.responseReceived", cdpNetworkResponseReceivedParams{RequestID: "r", Response: cdpNetworkResponse{Status: 200, MimeType: "application/json"}}) + sendNetworkFixture(t, srv, "Network.loadingFinished", cdpNetworkLoadingFinishedParams{RequestID: "r"}) + event := ec.waitFor(t, EventNetworkResponse, time.Second) + var response oapi.BrowserNetworkResponseEventData + require.NoError(t, json.Unmarshal(event.Data, &response)) + require.NotNil(t, response.BodyError) + require.Contains(t, *response.BodyError, "No resource with given identifier found") + require.Nil(t, response.Body) + require.Equal(t, 200, response.Status) +} + +func TestNavigationPreservesPendingResponsesAndIdleAccounting(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + navigateMonitor(m, "https://example.com/old") + request := func(id, loader string) { + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: id, LoaderID: loader, Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/" + id}}, "s1") + } + request("old", "") + request("document", "new-loader") + m.handleResponseReceived(cdpNetworkResponseReceivedParams{RequestID: "document", Response: cdpNetworkResponse{Status: 200}}, "s1") + m.handleFrameNavigated(cdpPageFrameNavigatedParams{Frame: cdpPageFrame{ID: "f1", LoaderID: "new-loader", URL: "https://example.com/new"}}, "s1") + m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: "old"}, "s1") + // Finishing the previous loader must not make the new document idle. + checkpoint := ec.checkpoint() + ec.assertNone(t, EventNetworkIdle, checkpoint, 600*time.Millisecond) + m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: "document"}, "s1") + event := waitForNetworkURL(t, ec, EventNetworkResponse, "https://example.com/document") + var response oapi.BrowserNetworkResponseEventData + require.NoError(t, json.Unmarshal(event.Data, &response)) + require.Equal(t, 200, response.Status) + ec.waitForNew(t, EventNetworkIdle, checkpoint, time.Second) +} + +func TestExtensionSourceIdentifiesBundledAndCustomTargets(t *testing.T) { + for _, tc := range []struct{ url, id, managed string }{ + {"https://example.com/worker.js", "", ""}, + {"chrome-extension://aiefahdofckmjaelnjpjkffghapmnlof/background.js", "aiefahdofckmjaelnjpjkffghapmnlof", "true"}, + {"chrome-extension://" + unpackedExtensionID("/home/kernel/extensions/kernel") + "/background.js", unpackedExtensionID("/home/kernel/extensions/kernel"), "true"}, + {"chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/background.js", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "false"}, + } { + t.Run(tc.url, func(t *testing.T) { + metadata := targetMetadata(targetInfo{url: tc.url, targetType: "service_worker", targetID: "target"}) + require.Equal(t, tc.id, metadata["extension_id"]) + require.Equal(t, tc.managed, metadata["kernel_extension"]) + }) + } +} + +func TestSameProcessFrameRequestsParticipateInNetworkIdle(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + navigateMonitor(m, "https://example.com/") + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{RequestID: "child", LoaderID: "iframe-loader", FrameID: "child", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/child"}}, "s1") + ec.assertNone(t, EventNetworkIdle, 0, 600*time.Millisecond) + m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: "child"}, "s1") + ec.waitFor(t, EventNetworkIdle, time.Second) +} + +func TestNetworkSourceSurvivesOriginChanges(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + navigateMonitor(m, "about:blank") + extension := "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/page.html" + for index, document := range []string{extension, "https://example.com/"} { + id := fmt.Sprint(index) + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{ + RequestID: id, DocumentURL: document, + Request: cdpNetworkRequest{Method: "GET", URL: document}, + }, "s1") + // Publication is delayed until after the next document replaces the target URL. + next := "https://example.com/" + if index == 1 { + next = extension + } + m.handleFrameNavigated(cdpPageFrameNavigatedParams{Frame: cdpPageFrame{ID: "f1", URL: next}}, "s1") + m.handleResponseReceived(cdpNetworkResponseReceivedParams{RequestID: id, Response: cdpNetworkResponse{Status: 200}}, "s1") + m.handleLoadingFinished(context.Background(), cdpNetworkLoadingFinishedParams{RequestID: id}, "s1") + for _, typ := range []string{EventNetworkRequest, EventNetworkResponse} { + event := waitForNetworkURL(t, ec, typ, document) + if index == 0 { + require.Equal(t, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", (*event.Source.Metadata)["extension_id"]) + } else { + require.NotContains(t, *event.Source.Metadata, "extension_id") + require.NotContains(t, *event.Source.Metadata, "kernel_extension") + } + } + } +} + +func TestExtensionSourceTracksTargetAndRootFrameNavigation(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + navigateMonitor(m, "about:blank") + extension := "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/page.html" + m.handleFrameNavigated(cdpPageFrameNavigatedParams{Frame: cdpPageFrame{ID: "f1", URL: extension}}, "s1") + m.handleFrameNavigated(cdpPageFrameNavigatedParams{Frame: cdpPageFrame{ID: "child", ParentID: "f1", URL: "https://example.com/"}}, "s1") + m.handleTargetCrashed("s1") + event := ec.waitFor(t, EventPageCrashed, time.Second) + require.Equal(t, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", (*event.Source.Metadata)["extension_id"], "a child frame must not change the target origin") + + params, err := json.Marshal(map[string]any{"targetInfo": cdpTargetTargetInfo{TargetID: m.sessions["s1"].targetID, URL: "https://example.com/"}}) + require.NoError(t, err) + m.handleSurfaceEvent(nil, browsersurface.Event{Kind: browsersurface.EventProtocol, Message: cdpclient.Message{Method: "Target.targetInfoChanged", Params: params}}) + checkpoint := ec.checkpoint() + m.handleTargetCrashed("s1") + event = ec.waitForNew(t, EventPageCrashed, checkpoint, time.Second) + require.NotContains(t, *event.Source.Metadata, "extension_id") +} + +func TestExtensionSourceTracksOOPIFRootNavigation(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + m.sessions["s1"] = targetInfo{targetID: "child", targetType: "iframe", parentFrameID: "parent"} + m.handleFrameNavigated(cdpPageFrameNavigatedParams{Frame: cdpPageFrame{ID: "child", ParentID: "parent", URL: "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/page.html"}}, "s1") + m.handleFrameNavigated(cdpPageFrameNavigatedParams{Frame: cdpPageFrame{ID: "nested", ParentID: "child", URL: "https://example.com/"}}, "s1") + m.handleTargetCrashed("s1") + event := ec.waitFor(t, EventPageCrashed, time.Second) + require.Equal(t, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", (*event.Source.Metadata)["extension_id"]) +} + +func TestProxyErrorIdentitySurvivesTargetDetach(t *testing.T) { + for _, targetType := range []string{targetTypePage, "service_worker"} { + t.Run(targetType, func(t *testing.T) { + synctest.Test(t, func(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + m.sessions["s1"] = targetInfo{targetID: "test-target", targetType: targetType} + requestAt := time.Now().UnixMicro() + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{ + RequestID: "r", Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/api"}, + }, "s1") + time.Sleep(400 * time.Millisecond) + responseAt := time.Now().UnixMicro() + m.handleResponseReceived(cdpNetworkResponseReceivedParams{ + RequestID: "r", HasExtraInfo: true, + Response: cdpNetworkResponse{Status: 502, Headers: json.RawMessage(`{"x-kernel-proxy-error":"proxy_connect_failed"}`)}, + }, "s1") + synctest.Wait() + require.Zero(t, ec.checkpoint(), "publication must still be waiting for request headers") + m.handleDetachedFromTarget(cdpTargetDetachedFromTargetParams{SessionID: "s1"}) + time.Sleep(time.Second) + synctest.Wait() + + ec.mu.Lock() + defer ec.mu.Unlock() + require.Len(t, ec.events, 2) + require.Equal(t, EventNetworkRequest, ec.events[0].Type) + require.Equal(t, requestAt, ec.events[0].Ts) + event := ec.events[1] + require.Equal(t, EventProxyError, event.Type) + require.Equal(t, responseAt, event.Ts) + var payload oapi.BrowserProxyErrorEventData + require.NoError(t, json.Unmarshal(event.Data, &payload)) + require.Equal(t, "s1", payload.SessionId) + require.Equal(t, "r", payload.RequestId) + require.Equal(t, "test-target", payload.TargetId) + require.Equal(t, oapi.BrowserTargetType(targetType), payload.TargetType) + require.NotNil(t, event.Source.Metadata) + require.Equal(t, payload.TargetId, (*event.Source.Metadata)[MetadataKeyTargetID]) + require.Equal(t, targetType, (*event.Source.Metadata)[MetadataKeyTargetType]) + }) + }) + } +} + +func TestProxyErrorSourceSurvivesOriginChanges(t *testing.T) { + extension := "chrome-extension://aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/page.html" + for _, document := range []string{extension, "https://example.com/"} { + t.Run(document, func(t *testing.T) { + m, ec := newComputedMonitor(t) + defer m.Stop() + navigateMonitor(m, document) + m.handleNetworkRequest(cdpNetworkRequestWillBeSentParams{ + RequestID: "r", DocumentURL: document, + Request: cdpNetworkRequest{Method: "GET", URL: "https://example.com/api"}, + }, "s1") + next := extension + if document == extension { + next = "https://example.com/" + } + navigateMonitor(m, next) + m.handleResponseReceived(cdpNetworkResponseReceivedParams{ + RequestID: "r", Response: cdpNetworkResponse{Status: 403, Headers: json.RawMessage(`{"x-kernel-proxy-error":"network_policy_denied"}`)}, + }, "s1") + event := ec.waitFor(t, EventProxyError, time.Second) + if document == extension { + require.Equal(t, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", (*event.Source.Metadata)["extension_id"]) + } else { + require.NotContains(t, *event.Source.Metadata, "extension_id") + require.NotContains(t, *event.Source.Metadata, "kernel_extension") + } + }) + } +} diff --git a/server/lib/cdpmonitor/network_chrome_e2e_test.go b/server/lib/cdpmonitor/network_chrome_e2e_test.go index f9e8cf44c..552f3d52b 100644 --- a/server/lib/cdpmonitor/network_chrome_e2e_test.go +++ b/server/lib/cdpmonitor/network_chrome_e2e_test.go @@ -199,6 +199,9 @@ func TestNetworkCaptureAcrossFrames(t *testing.T) { require.NotEmpty(t, request.SessionId) require.NotNil(t, request.FrameId) require.NotEmpty(t, *request.FrameId) + if frame.targetType == "iframe" { + require.Equal(t, frame.target, *request.FrameId, "Chromium uses the OOPIF root frame ID as its target ID") + } if aborted { event := waitForNetworkURL(t, ec, EventNetworkLoadingFailed, frame.origin+path) var failure oapi.BrowserNetworkLoadingFailedEventData diff --git a/server/lib/cdpmonitor/network_cleanup_test.go b/server/lib/cdpmonitor/network_cleanup_test.go index 468ffee8e..d9d473166 100644 --- a/server/lib/cdpmonitor/network_cleanup_test.go +++ b/server/lib/cdpmonitor/network_cleanup_test.go @@ -2,13 +2,46 @@ package cdpmonitor import ( "context" + "encoding/json" "sync" + "sync/atomic" "testing" "time" "github.com/stretchr/testify/require" ) +func TestDurableBodyDisableFailureReplacesConnection(t *testing.T) { + srv := newTestServer(t) + defer srv.close() + var failed atomic.Bool + m, _, cleanup := startMonitor(t, srv, func(msg cdpMessage) any { + var params struct { + EnableDurableMessages *bool `json:"enableDurableMessages"` + } + if msg.Method == "Network.enable" && json.Unmarshal(msg.Params, ¶ms) == nil && params.EnableDurableMessages != nil && !*params.EnableDurableMessages { + failed.Store(true) + return map[string]any{"id": msg.ID, "error": map[string]any{"code": -32000, "message": "fixture disable failure"}} + } + return nil + }) + defer cleanup() + srv.sendToMonitor(t, map[string]any{"method": "Target.attachedToTarget", "params": map[string]any{"sessionId": "s", "targetInfo": map[string]any{"targetId": "t", "type": "page"}}}) + require.Eventually(t, func() bool { + m.sessionsMu.RLock() + defer m.sessionsMu.RUnlock() + return m.optionalSessions["s"] == "test-script" + }, time.Second, time.Millisecond) + m.lifeMu.Lock() + old := m.conn + m.lifeMu.Unlock() + require.NoError(t, m.SetTelemetry(false)) + require.Eventually(t, func() bool { return failed.Load() && old.ctx.Err() != nil }, time.Second, time.Millisecond) + waitForTelemetryReconcile(t, m, false) + // A replacement connection releases session-owned body storage. + require.False(t, m.captureEnabled()) +} + func TestTelemetryCleanupAttemptsAllSessionsAfterError(t *testing.T) { srv := newTestServer(t) defer srv.close() diff --git a/server/lib/cdpmonitor/network_fidelity_chrome_e2e_test.go b/server/lib/cdpmonitor/network_fidelity_chrome_e2e_test.go new file mode 100644 index 000000000..ce38a672f --- /dev/null +++ b/server/lib/cdpmonitor/network_fidelity_chrome_e2e_test.go @@ -0,0 +1,369 @@ +package cdpmonitor + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "net/http/httptest" + "os" + "path/filepath" + "strings" + "sync" + "testing" + "time" + + "github.com/kernel/kernel-images/server/lib/cdpclient" + "github.com/kernel/kernel-images/server/lib/oapi" + "github.com/stretchr/testify/require" +) + +func TestNetworkWireCapture(t *testing.T) { + if os.Getenv("KERNEL_CDPMONITOR_CHROME_E2E") == "" { + t.Skip("set KERNEL_CDPMONITOR_CHROME_E2E=1 to run real-Chromium network tests") + } + ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second) + defer cancel() + var mu sync.Mutex + var wireHeaders http.Header + var statuses []int + var cachedRequests int + stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/api": + mu.Lock() + wireHeaders = r.Header.Clone() + wireHeaders.Set("Host", r.Host) + status := 200 + if r.Header.Get("If-None-Match") != "" { + status = 304 + } + statuses = append(statuses, status) + mu.Unlock() + w.Header().Set("ETag", `"v1"`) + w.Header().Set("Cache-Control", "no-cache") + if status == 200 { + w.Header().Set("Content-Type", "application/json") + w.Header().Set("X-Cached", "retained") + } + w.WriteHeader(status) + if status == 200 { + fmt.Fprint(w, `{"ok":true}`) + } + case "/cached": + mu.Lock() + cachedRequests++ + mu.Unlock() + w.Header().Set("Content-Type", "application/json") + w.Header().Set("Cache-Control", "max-age=3600") + w.Header().Set("X-Cached", "fresh") + fmt.Fprint(w, `{"cached":true}`) + default: + w.Header().Set("Content-Type", "text/html") + fmt.Fprint(w, "local reproduction") + } + })) + defer stub.Close() + ws := launchChromium(t, ctx, findChromium(t), "--site-per-process") + driver := dialCDP(t, ctx, ws) + defer driver.close() + target := driver.call(t, ctx, "", "Target.createTarget", map[string]any{"url": "about:blank"}).targetID(t) + session := driver.call(t, ctx, "", "Target.attachToTarget", map[string]any{"targetId": target, "flatten": true}).sessionID(t) + ec := newEventCollector() + m := New(&staticUpstream{url: ws}, ec.publishFn(), 99, discardLogger, nil) + require.NoError(t, m.Start(ctx)) + defer m.Stop() + require.Eventually(t, func() bool { return driver.evalBool(ctx, session, "window.__kernelEventInjected === true") }, 10*time.Second, 20*time.Millisecond) + driver.call(t, ctx, session, "Page.navigate", map[string]any{"url": stub.URL + "/document"}) + require.Eventually(t, func() bool { + return driver.evalBool(ctx, session, fmt.Sprintf(`location.href === %q && document.readyState === "complete"`, stub.URL+"/document")) + }, 10*time.Second, 20*time.Millisecond) + driver.call(t, ctx, session, "Runtime.evaluate", map[string]any{"expression": `document.cookie="test_cookie=present; path=/"`}) + for range 2 { + result := driver.call(t, ctx, session, "Runtime.evaluate", map[string]any{"expression": `fetch("/api").then(r => r.text())`, "awaitPromise": true, "returnByValue": true}) + require.NotContains(t, string(result.raw), "exceptionDetails") + } + snapshot := func(typ, url string) []map[string]any { + ec.mu.Lock() + defer ec.mu.Unlock() + var out []map[string]any + for _, ev := range ec.events { + if ev.Type != typ { + continue + } + var p map[string]any + require.NoError(t, json.Unmarshal(ev.Data, &p)) + if p["url"] == url { + out = append(out, p) + } + } + return out + } + require.Eventually(t, func() bool { return len(snapshot(EventNetworkResponse, stub.URL+"/api")) == 2 }, 5*time.Second, 20*time.Millisecond) + mu.Lock() + require.Equal(t, []int{200, 304}, statuses) + require.Equal(t, "test_cookie=present", wireHeaders.Get("Cookie")) + mu.Unlock() + t.Run("document_response", func(t *testing.T) { + require.Eventually(t, func() bool { return len(snapshot(EventNetworkResponse, stub.URL+"/document")) == 1 }, time.Second, 20*time.Millisecond, "completed document load must emit a response") + }) + t.Run("cookie_header", func(t *testing.T) { + requests := snapshot(EventNetworkRequest, stub.URL+"/api") + require.Len(t, requests, 2) + headers := requests[0]["headers"].(map[string]any) + require.Contains(t, headers, "Cookie", "server received Cookie, telemetry must capture it") + }) + t.Run("effective_response", func(t *testing.T) { + responses := snapshot(EventNetworkResponse, stub.URL+"/api") + for _, response := range responses { + require.Equal(t, float64(200), response["status"]) + require.Equal(t, "OK", response["status_text"]) + headers := response["headers"].(map[string]any) + require.Equal(t, "application/json", headers["Content-Type"]) + require.Equal(t, "retained", headers["X-Cached"]) + require.JSONEq(t, `{"ok":true}`, response["body"].(string)) + require.NotContains(t, response, "effective_status") + require.NotContains(t, response, "wire_status") + require.NotContains(t, response, "wire_headers") + } + }) + t.Run("fresh_cache", func(t *testing.T) { + for range 2 { + result := driver.call(t, ctx, session, "Runtime.evaluate", map[string]any{"expression": `fetch("/cached").then(r => r.text())`, "awaitPromise": true, "returnByValue": true}) + require.NotContains(t, string(result.raw), "exceptionDetails") + } + require.Eventually(t, func() bool { return len(snapshot(EventNetworkResponse, stub.URL+"/cached")) == 2 }, 5*time.Second, 20*time.Millisecond) + mu.Lock() + count := cachedRequests + mu.Unlock() + require.Equal(t, 1, count, "the second fetch must use the cache without contacting the server") + for _, response := range snapshot(EventNetworkResponse, stub.URL+"/cached") { + require.Equal(t, float64(200), response["status"]) + headers := response["headers"].(map[string]any) + require.Equal(t, "application/json", headers["Content-Type"]) + require.Equal(t, "fresh", headers["X-Cached"]) + require.JSONEq(t, `{"cached":true}`, response["body"].(string)) + require.NotContains(t, response, "wire_status") + require.NotContains(t, response, "wire_headers") + } + }) +} + +func TestNetworkBodiesSurviveNavigation(t *testing.T) { + if os.Getenv("KERNEL_CDPMONITOR_CHROME_E2E") == "" { + t.Skip("set KERNEL_CDPMONITOR_CHROME_E2E=1 to run real-Chromium network tests") + } + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/api" { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, `{"body":"retained"}`) + return + } + w.Header().Set("Content-Type", "text/html") + fmt.Fprint(w, "body retention") + })) + defer stub.Close() + ws := launchChromium(t, ctx, findChromium(t), "--site-per-process") + driver := dialCDP(t, ctx, ws) + defer driver.close() + target := driver.call(t, ctx, "", "Target.createTarget", map[string]any{"url": "about:blank"}).targetID(t) + session := driver.call(t, ctx, "", "Target.attachToTarget", map[string]any{"targetId": target, "flatten": true}).sessionID(t) + ec := newEventCollector() + m := New(&staticUpstream{url: ws}, ec.publishFn(), 99, discardLogger, nil) + require.NoError(t, m.Start(ctx)) + defer m.Stop() + require.Eventually(t, func() bool { return driver.evalBool(ctx, session, "window.__kernelEventInjected === true") }, 10*time.Second, 20*time.Millisecond) + driver.call(t, ctx, session, "Page.navigate", map[string]any{"url": stub.URL + "/document"}) + require.Eventually(t, func() bool { + return driver.evalBool(ctx, session, fmt.Sprintf(`location.href === %q && document.readyState === "complete"`, stub.URL+"/document")) + }, 5*time.Second, 20*time.Millisecond) + evaluateNetworkScript(t, ctx, driver, session, `fetch("/api").then(r=>r.text())`) + response := waitForNetworkURL(t, ec, EventNetworkResponse, stub.URL+"/api") + var payload oapi.BrowserNetworkResponseEventData + require.NoError(t, json.Unmarshal(response.Data, &payload)) + require.NotNil(t, payload.Body) + require.JSONEq(t, `{"body":"retained"}`, *payload.Body) + destination := strings.Replace(stub.URL, "127.0.0.1", "localhost", 1) + "/next" + driver.call(t, ctx, session, "Page.navigate", map[string]any{"url": destination}) + require.Eventually(t, func() bool { + return driver.evalBool(ctx, session, fmt.Sprintf(`location.href === %q && document.readyState === "complete"`, destination)) + }, 5*time.Second, 20*time.Millisecond) + // Retrieve through the monitor's own session after the renderer has changed. + body, err := m.fetchResponseBody(ctx, payload.RequestId, payload.SessionId, networkReqState{resourceType: "Fetch", mimeType: "application/json"}) + require.NoError(t, err) + require.JSONEq(t, `{"body":"retained"}`, body) + require.NoError(t, m.SetTelemetry(false)) + waitForTelemetryReconcile(t, m, false) + observer, err := cdpclient.DialWithEvents(ctx, ws) + require.NoError(t, err) + defer observer.Close() + attached, err := observer.Send(ctx, "Target.attachToTarget", map[string]any{"targetId": target, "flatten": true}, "") + require.NoError(t, err) + var observedSession struct { + SessionID string `json:"sessionId"` + } + require.NoError(t, json.Unmarshal(attached, &observedSession)) + _, err = observer.Send(ctx, "Network.enable", nil, observedSession.SessionID) + require.NoError(t, err) + before := m.NetworkSnapshot().Completed + evaluateNetworkScript(t, ctx, driver, session, `fetch("/api?after-disable").then(r=>r.text())`) + require.Eventually(t, func() bool { return m.NetworkSnapshot().Completed > before }, time.Second, 20*time.Millisecond) + var uncapturedRequestID string + for uncapturedRequestID == "" { + select { + case message := <-observer.Events(): + var p cdpNetworkRequestWillBeSentParams + if message.Method == "Network.requestWillBeSent" && json.Unmarshal(message.Params, &p) == nil && strings.HasSuffix(p.Request.URL, "/api?after-disable") { + uncapturedRequestID = p.RequestID + } + case <-ctx.Done(): + t.Fatal("missing request after capture was disabled") + } + } + driver.call(t, ctx, session, "Page.navigate", map[string]any{"url": stub.URL + "/back"}) + require.Eventually(t, func() bool { + return driver.evalBool(ctx, session, fmt.Sprintf(`location.href === %q && document.readyState === "complete"`, stub.URL+"/back")) + }, 5*time.Second, 20*time.Millisecond) + _, err = m.fetchResponseBody(ctx, uncapturedRequestID, payload.SessionId, networkReqState{resourceType: "Fetch", mimeType: "application/json"}) + require.Error(t, err, "disabled capture must not retain new bodies across navigation") +} + +func TestNetworkExtensionAttribution(t *testing.T) { + if os.Getenv("KERNEL_CDPMONITOR_CHROME_E2E") == "" { + t.Skip("set KERNEL_CDPMONITOR_CHROME_E2E=1 to run real-Chromium network tests") + } + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, `{"from":"extension"}`) + })) + defer stub.Close() + dir := t.TempDir() + require.NoError(t, os.WriteFile(filepath.Join(dir, "manifest.json"), []byte(`{"manifest_version":3,"name":"telemetry test","version":"1.0","background":{"service_worker":"background.js"},"host_permissions":["http://127.0.0.1/*"]}`), 0600)) + require.NoError(t, os.WriteFile(filepath.Join(dir, "background.js"), []byte(`chrome.runtime.onInstalled.addListener(() => {});`), 0600)) + require.NoError(t, os.WriteFile(filepath.Join(dir, "page.html"), []byte(`extension page`), 0600)) + ws := launchChromium(t, ctx, findChromium(t), "--enable-unsafe-extension-debugging") + c, err := cdpclient.Dial(ctx, ws) + require.NoError(t, err) + defer c.Close() + ec := newEventCollector() + m := New(&staticUpstream{url: ws}, ec.publishFn(), 99, discardLogger, nil) + require.NoError(t, m.Start(ctx)) + defer m.Stop() + extensionID, err := c.LoadUnpackedExtension(ctx, dir) + require.NoError(t, err) + var target string + require.Eventually(t, func() bool { + raw, err := c.Send(ctx, "Target.getTargets", nil, "") + if err != nil { + return false + } + var p struct { + Targets []cdpTargetTargetInfo `json:"targetInfos"` + } + if json.Unmarshal(raw, &p) != nil { + return false + } + for _, info := range p.Targets { + if info.Type == "service_worker" && strings.HasPrefix(info.URL, "chrome-extension://"+extensionID+"/") { + target = info.TargetID + return true + } + } + return false + }, 5*time.Second, 20*time.Millisecond) + driver := dialCDP(t, ctx, ws) + defer driver.close() + session := driver.call(t, ctx, "", "Target.attachToTarget", map[string]any{"targetId": target, "flatten": true}).sessionID(t) + // Wait for the collector's own attachment before driving the request. + require.Eventually(t, func() bool { + m.sessionsMu.RLock() + defer m.sessionsMu.RUnlock() + for sid, info := range m.sessions { + if info.targetID == target && m.networkReady[sid] { + return true + } + } + return false + }, 5*time.Second, 20*time.Millisecond) + evaluateNetworkScript(t, ctx, driver, session, fmt.Sprintf(`fetch(%q).then(r=>r.json())`, stub.URL+"/extension-api")) + request := waitForNetworkURL(t, ec, EventNetworkRequest, stub.URL+"/extension-api") + response := waitForNetworkURL(t, ec, EventNetworkResponse, stub.URL+"/extension-api") + var p map[string]any + require.NoError(t, json.Unmarshal(request.Data, &p)) + require.Equal(t, "service_worker", p["target_type"]) + require.Equal(t, target, p["target_id"]) + require.Equal(t, extensionID, (*request.Source.Metadata)["extension_id"]) + require.Equal(t, extensionID, (*response.Source.Metadata)["extension_id"]) + require.Equal(t, "false", (*request.Source.Metadata)["kernel_extension"]) + + page := driver.call(t, ctx, "", "Target.createTarget", map[string]any{"url": "about:blank"}).targetID(t) + pageSession := driver.call(t, ctx, "", "Target.attachToTarget", map[string]any{"targetId": page, "flatten": true}).sessionID(t) + require.Eventually(t, func() bool { return driver.evalBool(ctx, pageSession, "window.__kernelEventInjected === true") }, 5*time.Second, 20*time.Millisecond) + for index, destination := range []string{"chrome-extension://" + extensionID + "/page.html", stub.URL + "/page"} { + driver.call(t, ctx, pageSession, "Page.navigate", map[string]any{"url": destination}) + require.Eventually(t, func() bool { + return driver.evalBool(ctx, pageSession, fmt.Sprintf(`location.href === %q && document.readyState === "complete"`, destination)) + }, 5*time.Second, 20*time.Millisecond) + url := fmt.Sprintf("%s/page-api-%d", stub.URL, index) + evaluateNetworkScript(t, ctx, driver, pageSession, fmt.Sprintf(`fetch(%q).then(r=>r.json())`, url)) + for _, typ := range []string{EventNetworkRequest, EventNetworkResponse} { + event := waitForNetworkURL(t, ec, typ, url) + if index == 0 { + require.Equal(t, extensionID, (*event.Source.Metadata)["extension_id"]) + } else { + require.NotContains(t, *event.Source.Metadata, "extension_id") + require.NotContains(t, *event.Source.Metadata, "kernel_extension") + } + } + idle := waitForNetworkURL(t, ec, EventNetworkIdle, destination) + if index == 0 { + require.Equal(t, extensionID, (*idle.Source.Metadata)["extension_id"]) + require.Equal(t, "false", (*idle.Source.Metadata)["kernel_extension"]) + } else { + require.NotContains(t, *idle.Source.Metadata, "extension_id") + require.NotContains(t, *idle.Source.Metadata, "kernel_extension") + } + } +} + +func TestNetworkBundledExtensionAttribution(t *testing.T) { + dir := os.Getenv("KERNEL_CDPMONITOR_BUNDLED_EXTENSION_PATH") + if dir == "" { + t.Skip("set KERNEL_CDPMONITOR_BUNDLED_EXTENSION_PATH to a bundled extension at its installed path") + } + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + stub := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + fmt.Fprint(w, `{"from":"bundled-extension"}`) + })) + defer stub.Close() + ws := launchChromium(t, ctx, findChromium(t), "--enable-unsafe-extension-debugging") + c, err := cdpclient.Dial(ctx, ws) + require.NoError(t, err) + defer c.Close() + extensionID, err := c.LoadUnpackedExtension(ctx, dir) + require.NoError(t, err) + t.Logf("Chromium loaded %s as %s", dir, extensionID) + driver := dialCDP(t, ctx, ws) + defer driver.close() + target := driver.call(t, ctx, "", "Target.createTarget", map[string]any{"url": "chrome-extension://" + extensionID + "/manifest.json"}).targetID(t) + session := driver.call(t, ctx, "", "Target.attachToTarget", map[string]any{"targetId": target, "flatten": true}).sessionID(t) + ec := newEventCollector() + m := New(&staticUpstream{url: ws}, ec.publishFn(), 99, discardLogger, nil) + require.NoError(t, m.Start(ctx)) + defer m.Stop() + require.Eventually(t, func() bool { + return driver.evalBool(ctx, session, fmt.Sprintf(`location.hostname === %q && window.__kernelEventInjected === true`, extensionID)) + }, 5*time.Second, 20*time.Millisecond) + evaluateNetworkScript(t, ctx, driver, session, fmt.Sprintf(`fetch(%q).then(r=>r.json())`, stub.URL+"/bundled-api")) + for _, typ := range []string{EventNetworkRequest, EventNetworkResponse} { + event := waitForNetworkURL(t, ec, typ, stub.URL+"/bundled-api") + require.Equal(t, extensionID, (*event.Source.Metadata)["extension_id"]) + require.Equal(t, "true", (*event.Source.Metadata)["kernel_extension"]) + } +} diff --git a/server/lib/cdpmonitor/surface_events_test.go b/server/lib/cdpmonitor/surface_events_test.go index 72cf925cf..5014597d2 100644 --- a/server/lib/cdpmonitor/surface_events_test.go +++ b/server/lib/cdpmonitor/surface_events_test.go @@ -28,12 +28,13 @@ func TestSurfaceDropsNetworkEventsForUnknownAndRemovedSessions(t *testing.T) { m.sessions["session"] = targetInfo{targetID: "frame", targetType: "iframe"} m.handleSurfaceEvent(nil, event) require.Len(t, m.pendingRequests, 1) - require.Len(t, ec.events, 1) + ec.waitFor(t, EventNetworkRequest, 2*time.Second) + require.Equal(t, 1, ec.checkpoint()) m.handleSurfaceEvent(nil, browsersurface.Event{Kind: browsersurface.EventSessionRemoved, SessionID: "session"}) m.handleSurfaceEvent(nil, event) require.Empty(t, m.pendingRequests) - require.Len(t, ec.events, 1, "a removed session must not resume emitting metadata-free requests") + require.Equal(t, 1, ec.checkpoint(), "a removed session must not resume emitting metadata-free requests") } func TestSurfaceCarriesOOPIFParentFrameIntoNavigation(t *testing.T) { diff --git a/server/lib/cdpmonitor/telemetry.go b/server/lib/cdpmonitor/telemetry.go index 587a4987b..8a9b20dda 100644 --- a/server/lib/cdpmonitor/telemetry.go +++ b/server/lib/cdpmonitor/telemetry.go @@ -94,6 +94,7 @@ func (m *Monitor) applyTelemetry(state uint64) error { m.computedPublishMu.Unlock() m.pendReqMu.Lock() clear(m.pendingRequests) + clear(m.networkExchanges) m.pendReqMu.Unlock() m.mainSessionID.Store(mainSessionUnset) m.bindingRateMu.Lock() @@ -176,6 +177,9 @@ func (m *Monitor) enableOptionalCapture(ctx context.Context, sessionID string, i m.preparePageCapture(sessionID, info) ctx, cancel := context.WithTimeout(ctx, sendTimeout) defer cancel() + if err := m.configureBodyCapture(ctx, sessionID, true); err != nil && ctx.Err() == nil { + m.log.Warn("cdpmonitor: durable body capture unavailable", "session", sessionID, "err", err) + } m.enableDomains(ctx, sessionID, info.targetType) if isPageLikeTarget(info.targetType) { var rejection *cdpclient.Error diff --git a/server/lib/cdpmonitor/testdata/Network_requestWillBeSentExtraInfo.json b/server/lib/cdpmonitor/testdata/Network_requestWillBeSentExtraInfo.json new file mode 100644 index 000000000..0800ffd5a --- /dev/null +++ b/server/lib/cdpmonitor/testdata/Network_requestWillBeSentExtraInfo.json @@ -0,0 +1,9 @@ +{ + "requestId": "149.2", + "associatedCookies": [], + "headers": {"Accept": "*/*", "Cookie": "session=test", "Host": "example.com"}, + "connectTiming": {"requestTime": 123.5}, + "clientSecurityState": {"initiatorIsSecureContext": true, "initiatorIPAddressSpace": "Public", "privateNetworkRequestPolicy": "Allow"}, + "siteHasCookieInOtherPartition": true, + "appliedNetworkConditionsId": "conditions" +} diff --git a/server/lib/cdpmonitor/types.go b/server/lib/cdpmonitor/types.go index 98826012c..f9905c1ad 100644 --- a/server/lib/cdpmonitor/types.go +++ b/server/lib/cdpmonitor/types.go @@ -112,20 +112,22 @@ type networkRequestKey struct { // networkReqState holds request + response metadata until loadingFinished. type networkReqState struct { - sessionID string - method string - url string - headers json.RawMessage - postData string - resourceType string - loaderID string - frameID string - navSeq int64 - status int - statusText string - resHeaders json.RawMessage - mimeType string - addedAt time.Time // for TTL eviction + sessionID string + method string + url string + headers json.RawMessage + postData string + resourceType string + loaderID string + frameID string + navSeq int64 + countedNavSeq int + status int + statusText string + resHeaders json.RawMessage + mimeType string + addedAt time.Time // for TTL eviction + hop *networkHop } // navContext carries the identity of the navigation that owns a computedState. diff --git a/server/lib/oapi/oapi.go b/server/lib/oapi/oapi.go index 1580789eb..e0f6bad81 100644 --- a/server/lib/oapi/oapi.go +++ b/server/lib/oapi/oapi.go @@ -5373,7 +5373,7 @@ type BrowserNetworkRequestEventData struct { // FrameId CDP frame identifier within the target. FrameId *string `json:"frame_id,omitempty"` - // Headers Request headers. + // Headers Request headers reported by Chrome, including browser-added headers available before publication. Headers BrowserHttpHeaders `json:"headers"` // InitiatorType CDP Initiator.type indicating what caused the request, passed through as-is from Chrome. Known values include script, parser, preload, and other. @@ -5416,7 +5416,7 @@ type BrowserNetworkRequestEventData struct { Url *string `json:"url,omitempty"` } -// BrowserNetworkResponseEvent A browser network response received event. Fired after the response body is fully received, not when headers arrive. +// BrowserNetworkResponseEvent A browser network response received event. Fired after the response body is fully received, or when a redirect advances to the next request. type BrowserNetworkResponseEvent struct { Category BrowserNetworkResponseEventCategory `json:"category"` Data *BrowserNetworkResponseEventData `json:"data,omitempty"` @@ -5443,10 +5443,13 @@ type BrowserNetworkResponseEventData struct { // Body Truncated response body, present only for text MIME types. Body *string `json:"body,omitempty"` + // BodyError Response body retrieval or decoding error. Absent for successfully retrieved or intentionally excluded bodies. + BodyError *string `json:"body_error,omitempty"` + // FrameId CDP frame identifier within the target. FrameId *string `json:"frame_id,omitempty"` - // Headers Response headers. + // Headers Effective response headers reported by Chrome, including retained cache headers after revalidation. Headers BrowserHttpHeaders `json:"headers"` // LoaderId CDP document loader identifier, reset on each navigation. @@ -5461,6 +5464,9 @@ type BrowserNetworkResponseEventData struct { // NavSeq Monotonically increasing navigation sequence number, incremented on each top-level navigation within the target. NavSeq int64 `json:"nav_seq"` + // RequestHeaders Captured request headers when available, including browser-added headers that arrived after network_request was published. + RequestHeaders *BrowserHttpHeaders `json:"request_headers,omitempty"` + // RequestId CDP request identifier matching the originating network_request event. RequestId string `json:"request_id"` @@ -5470,7 +5476,7 @@ type BrowserNetworkResponseEventData struct { // SessionId CDP session identifier for the target connection. SessionId string `json:"session_id"` - // Status HTTP response status code. + // Status Effective HTTP response status reported by Chrome, including 200 after successful cache revalidation. Status int `json:"status"` // StatusText HTTP response status text (e.g. OK, Not Found). @@ -27594,758 +27600,755 @@ func (sh *strictHandler) GetWebMCPTools(w http.ResponseWriter, r *http.Request, // Base64 encoded, gzipped, json marshaled Swagger object var swaggerSpec = []string{ - "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", - "dO7Ll/8vAAD//2r2liqB/QMA", + "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", } // GetSwagger returns the content of the embedded swagger specification file diff --git a/server/openapi.yaml b/server/openapi.yaml index a1da52d1a..b4315554f 100644 --- a/server/openapi.yaml +++ b/server/openapi.yaml @@ -2617,7 +2617,7 @@ components: description: URL of the document that initiated the request. headers: $ref: "#/components/schemas/BrowserHttpHeaders" - description: Request headers. + description: Request headers reported by Chrome, including browser-added headers available before publication. resource_type: type: string description: CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. @@ -2669,25 +2669,31 @@ components: description: HTTP method of the original request. status: type: integer - description: HTTP response status code. + description: Effective HTTP response status reported by Chrome, including 200 after successful cache revalidation. status_text: type: string description: HTTP response status text (e.g. OK, Not Found). headers: $ref: "#/components/schemas/BrowserHttpHeaders" - description: Response headers. + description: Effective response headers reported by Chrome, including retained cache headers after revalidation. mime_type: type: string description: MIME type of the response (e.g. text/html, application/json). resource_type: type: string description: CDP Network.ResourceType for the request, passed through as-is from Chrome. Known values include Document, Fetch, XHR, Script, Stylesheet, Image, Media, Font, TextTrack, EventSource, WebSocket, Manifest, Prefetch, Other, and more. + request_headers: + $ref: "#/components/schemas/BrowserHttpHeaders" + description: Captured request headers when available, including browser-added headers that arrived after network_request was published. body: type: string description: Truncated response body, present only for text MIME types. + body_error: + type: string + description: Response body retrieval or decoding error. Absent for successfully retrieved or intentionally excluded bodies. BrowserNetworkResponseEvent: type: object - description: A browser network response received event. Fired after the response body is fully received, not when headers arrive. + description: A browser network response received event. Fired after the response body is fully received, or when a redirect advances to the next request. required: [ts, type, category, source] properties: ts: