feat(net): make passive request/response callbacks detachable (#416)
on_request/on_response stored callbacks in append-only Vecs with no way to remove one, so a crawler that installed a response-body capture hook for one phase could never detach it: it fired for the shared client's whole lifetime, re-registering across navigations piled up duplicates, and (because the client is shared per context) it saw sibling pages' requests too. Tag each callback with a stable id. on_request/on_response now return the id and off_request/off_response (remove_on_request/remove_on_response on the client) detach a specific one. Storage is Vec<(u64, Callback)>; all fire sites destructure the tuple. Closes #408.
This commit is contained in:
1 parent
d0b6fc4ffd
commit
99ece0e12d
5 files changed
+147
-23
No files matched your search
@@ -1652,19 +1652,32 @@ impl Page {
|
||||
/// Register a passive callback fired for every JS `fetch()`/XHR (and
|
||||
/// navigation) request, once the method/headers/body are known and before it
|
||||
/// is sent. Non-blocking; use `enable_interception` to mutate or block.
|
||||
pub fn on_request(&mut self, cb: RequestCallback) {
|
||||
if let Ok(mut v) = self.http_client.on_request.try_write() {
|
||||
v.push(cb);
|
||||
}
|
||||
/// Register a passive request observer, returning a stable id. Pass the id
|
||||
/// to `off_request` to detach it (issue #408). Note the observer lives on
|
||||
/// the context's shared http client, so it also sees requests from sibling
|
||||
/// pages in the same context; detach it when the capturing phase ends.
|
||||
pub fn on_request(&mut self, cb: RequestCallback) -> u64 {
|
||||
self.http_client.register_on_request(cb)
|
||||
}
|
||||
|
||||
/// Register a passive callback fired with every JS `fetch()`/XHR (and
|
||||
/// navigation) response, including its body. Non-blocking. The main path for
|
||||
/// crawlers that need to capture API response payloads.
|
||||
pub fn on_response(&mut self, cb: ResponseCallback) {
|
||||
if let Ok(mut v) = self.http_client.on_response.try_write() {
|
||||
v.push(cb);
|
||||
}
|
||||
/// navigation) response, including its body. Non-blocking. Returns a stable
|
||||
/// id for `off_response`. The main path for crawlers that need to capture
|
||||
/// API response payloads. Shared across the context like `on_request`.
|
||||
pub fn on_response(&mut self, cb: ResponseCallback) -> u64 {
|
||||
self.http_client.register_on_response(cb)
|
||||
}
|
||||
|
||||
/// Detach a request observer registered with `on_request`. Returns true if
|
||||
/// one was removed.
|
||||
pub fn off_request(&mut self, id: u64) -> bool {
|
||||
self.http_client.remove_on_request(id)
|
||||
}
|
||||
|
||||
/// Detach a response observer registered with `on_response`. Returns true if
|
||||
/// one was removed.
|
||||
pub fn off_response(&mut self, id: u64) -> bool {
|
||||
self.http_client.remove_on_response(id)
|
||||
}
|
||||
|
||||
pub async fn process_pending_navigation(&mut self) -> Result<bool, PageError> {
|
||||
|
||||
Reference in new issue
Block a user