From 724fa512cf8b234ff594e41f273799a1900a9f95 Mon Sep 17 00:00:00 2001 From: Andrey Lushnikov Date: Thu, 31 May 2018 17:38:30 -0700 Subject: [PATCH] feat(network): introduce Request.isNavigationRequest() method (#2633) This patch introduces `Request.isNavigationRequest()` method. Fixes #2627, #1132. --- docs/api.md | 6 ++++++ lib/NetworkManager.js | 25 ++++++++++++++++++------- test/network.spec.js | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 7 deletions(-) diff --git a/docs/api.md b/docs/api.md index 66c9e3b995a..5d3ecae0dde 100644 --- a/docs/api.md +++ b/docs/api.md @@ -231,6 +231,7 @@ * [request.failure()](#requestfailure) * [request.frame()](#requestframe) * [request.headers()](#requestheaders) + * [request.isNavigationRequest()](#requestisnavigationrequest) * [request.method()](#requestmethod) * [request.postData()](#requestpostdata) * [request.redirectChain()](#requestredirectchain) @@ -2649,6 +2650,11 @@ page.on('requestfailed', request => { #### request.headers() - returns: <[Object]> An object with HTTP headers associated with the request. All header names are lower-case. +#### request.isNavigationRequest() +- returns: <[boolean]> + +Whether this request is driving frame's navigation. + #### request.method() - returns: <[string]> Request's method (GET, POST, etc.) diff --git a/lib/NetworkManager.js b/lib/NetworkManager.js index 493aacf1235..af850aca2e3 100644 --- a/lib/NetworkManager.js +++ b/lib/NetworkManager.js @@ -155,7 +155,7 @@ class NetworkManager extends EventEmitter { const request = this._interceptionIdToRequest.get(event.interceptionId); if (request) { this._handleRequestRedirect(request, event.responseStatusCode, event.responseHeaders, false /* fromDiskCache */, false /* fromServiceWorker */, null /* securityDetails */); - this._handleRequestStart(request._requestId, event.interceptionId, event.redirectUrl, event.resourceType, event.request, event.frameId, request._redirectChain); + this._handleRequestStart(request._requestId, event.interceptionId, event.redirectUrl, event.isNavigationRequest, event.resourceType, event.request, event.frameId, request._redirectChain); } return; } @@ -163,10 +163,10 @@ class NetworkManager extends EventEmitter { const requestId = this._requestHashToRequestIds.firstValue(requestHash); if (requestId) { this._requestHashToRequestIds.delete(requestHash, requestId); - this._handleRequestStart(requestId, event.interceptionId, event.request.url, event.resourceType, event.request, event.frameId, []); + this._handleRequestStart(requestId, event.interceptionId, event.request.url, event.isNavigationRequest, event.resourceType, event.request, event.frameId, []); } else { this._requestHashToInterceptionIds.set(requestHash, event.interceptionId); - this._handleRequestStart(null, event.interceptionId, event.request.url, event.resourceType, event.request, event.frameId, []); + this._handleRequestStart(null, event.interceptionId, event.request.url, event.isNavigationRequest, event.resourceType, event.request, event.frameId, []); } } @@ -203,16 +203,17 @@ class NetworkManager extends EventEmitter { * @param {?string} requestId * @param {?string} interceptionId * @param {string} url + * @param {boolean} isNavigationRequest * @param {string} resourceType * @param {!Protocol.Network.Request} requestPayload * @param {?string} frameId * @param {!Array} redirectChain */ - _handleRequestStart(requestId, interceptionId, url, resourceType, requestPayload, frameId, redirectChain) { + _handleRequestStart(requestId, interceptionId, url, isNavigationRequest, resourceType, requestPayload, frameId, redirectChain) { let frame = null; if (frameId) frame = this._frameManager.frame(frameId); - const request = new Request(this._client, requestId, interceptionId, this._userRequestInterceptionEnabled, url, resourceType, requestPayload, frame, redirectChain); + const request = new Request(this._client, requestId, interceptionId, isNavigationRequest, this._userRequestInterceptionEnabled, url, resourceType, requestPayload, frame, redirectChain); if (requestId) this._requestIdToRequest.set(requestId, request); if (interceptionId) @@ -249,7 +250,8 @@ class NetworkManager extends EventEmitter { redirectChain = request._redirectChain; } } - this._handleRequestStart(event.requestId, null, event.request.url, event.type, event.request, event.frameId, redirectChain); + const isNavigationRequest = event.requestId === event.loaderId && event.type === 'Document'; + this._handleRequestStart(event.requestId, null, event.request.url, isNavigationRequest, event.type, event.request, event.frameId, redirectChain); } /** @@ -307,6 +309,7 @@ class Request { * @param {!Puppeteer.CDPSession} client * @param {?string} requestId * @param {string} interceptionId + * @param {boolean} isNavigationRequest * @param {boolean} allowInterception * @param {string} url * @param {string} resourceType @@ -314,9 +317,10 @@ class Request { * @param {?Puppeteer.Frame} frame * @param {!Array} redirectChain */ - constructor(client, requestId, interceptionId, allowInterception, url, resourceType, payload, frame, redirectChain) { + constructor(client, requestId, interceptionId, isNavigationRequest, allowInterception, url, resourceType, payload, frame, redirectChain) { this._client = client; this._requestId = requestId; + this._isNavigationRequest = isNavigationRequest; this._interceptionId = interceptionId; this._allowInterception = allowInterception; this._interceptionHandled = false; @@ -385,6 +389,13 @@ class Request { return this._frame; } + /** + * @return {boolean} + */ + isNavigationRequest() { + return this._isNavigationRequest; + } + /** * @return {!Array} */ diff --git a/test/network.spec.js b/test/network.spec.js index 08e0a2672c2..8d38848cdd1 100644 --- a/test/network.spec.js +++ b/test/network.spec.js @@ -199,6 +199,41 @@ module.exports.addTests = function({testRunner, expect}) { }); }); + describe('Request.isNavigationRequest', () => { + it('should work', async({page, server}) => { + const requests = new Map(); + page.on('request', request => requests.set(request.url().split('/').pop(), request)); + server.setRedirect('/rrredirect', '/frames/one-frame.html'); + await page.goto(server.PREFIX + '/rrredirect'); + expect(requests.get('rrredirect').isNavigationRequest()).toBe(true); + expect(requests.get('one-frame.html').isNavigationRequest()).toBe(true); + expect(requests.get('frame.html').isNavigationRequest()).toBe(true); + expect(requests.get('script.js').isNavigationRequest()).toBe(false); + expect(requests.get('style.css').isNavigationRequest()).toBe(false); + }); + it('should work with request interception', async({page, server}) => { + const requests = new Map(); + page.on('request', request => { + requests.set(request.url().split('/').pop(), request); + request.continue(); + }); + await page.setRequestInterception(true); + server.setRedirect('/rrredirect', '/frames/one-frame.html'); + await page.goto(server.PREFIX + '/rrredirect'); + expect(requests.get('rrredirect').isNavigationRequest()).toBe(true); + expect(requests.get('one-frame.html').isNavigationRequest()).toBe(true); + expect(requests.get('frame.html').isNavigationRequest()).toBe(true); + expect(requests.get('script.js').isNavigationRequest()).toBe(false); + expect(requests.get('style.css').isNavigationRequest()).toBe(false); + }); + it('should work when navigating to image', async({page, server}) => { + const requests = []; + page.on('request', request => requests.push(request)); + await page.goto(server.PREFIX + '/pptr.png'); + expect(requests[0].isNavigationRequest()).toBe(true); + }); + }); + describe('Page.setRequestInterception', function() { it('should intercept', async({page, server}) => { await page.setRequestInterception(true); @@ -207,6 +242,7 @@ module.exports.addTests = function({testRunner, expect}) { expect(request.headers()['user-agent']).toBeTruthy(); expect(request.method()).toBe('GET'); expect(request.postData()).toBe(undefined); + expect(request.isNavigationRequest()).toBe(true); expect(request.resourceType()).toBe('document'); expect(request.frame() === page.mainFrame()).toBe(true); expect(request.frame().url()).toBe('about:blank'); @@ -327,6 +363,7 @@ module.exports.addTests = function({testRunner, expect}) { expect(redirectChain[2].url()).toContain('/non-existing-page-3.html'); for (let i = 0; i < redirectChain.length; ++i) { const request = redirectChain[i]; + expect(request.isNavigationRequest()).toBe(true); expect(request.redirectChain().indexOf(request)).toBe(i); } });