Implement Page.setRequestInterceptor
This patch: - introduces Request class. - implements Page.setRequestInterceptor method. The method allows to install a callback which will be called for every request with a |Request| object as a single parameter. The callback is free to override certain request's properties and then either continue or abort it. - implements request interception api for phantom-shim and unskips the module/webpage/abort-network-request.js phantomjs test References #1
This commit is contained in:
parent
9bdf9ed5de
commit
e274c26e8b
20
lib/Page.js
20
lib/Page.js
@ -18,6 +18,7 @@ var fs = require('fs');
|
|||||||
var EventEmitter = require('events');
|
var EventEmitter = require('events');
|
||||||
var helpers = require('./helpers');
|
var helpers = require('./helpers');
|
||||||
var mime = require('mime');
|
var mime = require('mime');
|
||||||
|
var Request = require('./Request');
|
||||||
|
|
||||||
class Page extends EventEmitter {
|
class Page extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
@ -56,16 +57,35 @@ class Page extends EventEmitter {
|
|||||||
this._scriptIdToPageCallback = new Map();
|
this._scriptIdToPageCallback = new Map();
|
||||||
/** @type {!Array<string>} */
|
/** @type {!Array<string>} */
|
||||||
this._blockedURLs = [];
|
this._blockedURLs = [];
|
||||||
|
/** @type {?function(!Request)} */
|
||||||
|
this._requestInterceptor = null;
|
||||||
|
|
||||||
client.on('Debugger.paused', event => this._onDebuggerPaused(event));
|
client.on('Debugger.paused', event => this._onDebuggerPaused(event));
|
||||||
client.on('Debugger.scriptParsed', event => this._onScriptParsed(event));
|
client.on('Debugger.scriptParsed', event => this._onScriptParsed(event));
|
||||||
client.on('Network.responseReceived', event => this.emit(Page.Events.ResponseReceived, event.response));
|
client.on('Network.responseReceived', event => this.emit(Page.Events.ResponseReceived, event.response));
|
||||||
client.on('Network.loadingFailed', event => this.emit(Page.Events.ResourceLoadingFailed, event));
|
client.on('Network.loadingFailed', event => this.emit(Page.Events.ResourceLoadingFailed, event));
|
||||||
|
client.on('Network.requestIntercepted', event => this._onRequestIntercepted(event));
|
||||||
client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
|
client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
|
||||||
client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
|
client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
|
||||||
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
|
client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {?function(!Request)} interceptor
|
||||||
|
*/
|
||||||
|
async setRequestInterceptor(interceptor) {
|
||||||
|
this._requestInterceptor = interceptor;
|
||||||
|
await this._client.send('Network.enableRequestInterception', {enabled: !!interceptor});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Object} event
|
||||||
|
*/
|
||||||
|
_onRequestIntercepted(event) {
|
||||||
|
var request = new Request(this._client, event.InterceptionId, event.request);
|
||||||
|
this._requestInterceptor(request);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {!Array<string>} patterns
|
* @param {!Array<string>} patterns
|
||||||
* @return {!Promise}
|
* @return {!Promise}
|
||||||
|
123
lib/Request.js
Normal file
123
lib/Request.js
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class Request {
|
||||||
|
/**
|
||||||
|
* @param {!Connection} client
|
||||||
|
* @param {string} interceptionId
|
||||||
|
* @param {!Object} payload
|
||||||
|
*/
|
||||||
|
constructor(client, interceptionId, payload) {
|
||||||
|
this._client = client;
|
||||||
|
this._interceptionId = interceptionId;
|
||||||
|
this._url = payload.url;
|
||||||
|
this._method = payload.method;
|
||||||
|
this._headers = payload.headers;
|
||||||
|
this._postData = payload.postData;
|
||||||
|
|
||||||
|
this._urlOverride = undefined;
|
||||||
|
this._methodOverride = undefined;
|
||||||
|
this._postDataOverride = undefined;
|
||||||
|
|
||||||
|
this._handled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
url() {
|
||||||
|
return this._urlOverride || this._url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} url
|
||||||
|
*/
|
||||||
|
setUrl(url) {
|
||||||
|
this._urlOverride = url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
method() {
|
||||||
|
return this._methodOverride || this._method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} method
|
||||||
|
*/
|
||||||
|
setMethod(method) {
|
||||||
|
this._methodOverride = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {!Object}
|
||||||
|
*/
|
||||||
|
headers() {
|
||||||
|
return Object.assign({}, this._headersOverride || this._headers);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Object} headers
|
||||||
|
*/
|
||||||
|
setHeaders(headers) {
|
||||||
|
this._headersOverride = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {(string|undefined)}
|
||||||
|
*/
|
||||||
|
postData() {
|
||||||
|
return this._postDataOverride || this._postData;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {(string|undefined)}
|
||||||
|
*/
|
||||||
|
setPostData(data) {
|
||||||
|
this._postDataOverride = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
abort() {
|
||||||
|
console.assert(!this._handled, 'This request is already handled!');
|
||||||
|
this._handled = true;
|
||||||
|
this._client.send('Network.continueInterceptedRequest', {
|
||||||
|
interceptionId: this._interceptionId,
|
||||||
|
errorReason: 'Aborted'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
continue() {
|
||||||
|
console.assert(!this._handled, 'This request is already handled!');
|
||||||
|
this._handled = true;
|
||||||
|
this._client.send('Network.continueInterceptedRequest', {
|
||||||
|
interceptionId: this._interceptionId,
|
||||||
|
url: this._urlOverride,
|
||||||
|
method: this._methodOverride,
|
||||||
|
postData: this._postDataOverride,
|
||||||
|
headers: this._headersOverride
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
handled() {
|
||||||
|
return this._handled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Request;
|
@ -52,6 +52,7 @@ class WebPage {
|
|||||||
|
|
||||||
this.libraryPath = path.dirname(scriptPath);
|
this.libraryPath = path.dirname(scriptPath);
|
||||||
|
|
||||||
|
this._onResourceRequestedCallback = undefined;
|
||||||
this._onConfirmCallback = undefined;
|
this._onConfirmCallback = undefined;
|
||||||
this._onAlertCallback = undefined;
|
this._onAlertCallback = undefined;
|
||||||
this._onError = noop;
|
this._onError = noop;
|
||||||
@ -65,6 +66,34 @@ class WebPage {
|
|||||||
this._pageEvents.on(PageEvents.Exception, (exception, stack) => (this._onError || noop).call(null, exception, stack));
|
this._pageEvents.on(PageEvents.Exception, (exception, stack) => (this._onError || noop).call(null, exception, stack));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {?function(!Object, !Request)}
|
||||||
|
*/
|
||||||
|
get onResourceRequested() {
|
||||||
|
return this._onResourceRequestedCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {?function(!Object, !Request)} callback
|
||||||
|
*/
|
||||||
|
set onResourceRequested(callback) {
|
||||||
|
this._onResourceRequestedCallback = callback;
|
||||||
|
this._page.setRequestInterceptor(callback ? resourceInterceptor : null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {!Request} request
|
||||||
|
*/
|
||||||
|
function resourceInterceptor(request) {
|
||||||
|
var requestData = {
|
||||||
|
url: request.url(),
|
||||||
|
headers: request.headers()
|
||||||
|
};
|
||||||
|
callback(requestData, request);
|
||||||
|
if (!request.handled())
|
||||||
|
request.continue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_onResponseReceived(response) {
|
_onResponseReceived(response) {
|
||||||
if (!this.onResourceReceived)
|
if (!this.onResourceReceived)
|
||||||
return;
|
return;
|
||||||
|
23
test/test.js
23
test/test.js
@ -84,6 +84,29 @@ describe('Puppeteer', function() {
|
|||||||
expect(result).toBe(15);
|
expect(result).toBe(15);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Page.setRequestInterceptor', function() {
|
||||||
|
it('should work', SX(async function() {
|
||||||
|
page.setRequestInterceptor(request => {
|
||||||
|
expect(request.url()).toContain('empty.html');
|
||||||
|
expect(request.headers()['User-Agent']).toBeTruthy();
|
||||||
|
expect(request.method()).toBe('GET');
|
||||||
|
expect(request.postData()).toBe(undefined);
|
||||||
|
request.continue();
|
||||||
|
});
|
||||||
|
var success = await page.navigate(EMPTY_PAGE);
|
||||||
|
}));
|
||||||
|
it('should show extraHTTPHeaders', SX(async function() {
|
||||||
|
await page.setExtraHTTPHeaders({
|
||||||
|
foo: 'bar'
|
||||||
|
});
|
||||||
|
page.setRequestInterceptor(request => {
|
||||||
|
expect(request.headers()['foo']).toBe('bar');
|
||||||
|
request.continue();
|
||||||
|
});
|
||||||
|
var success = await page.navigate(EMPTY_PAGE);
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// Since Jasmine doesn't like async functions, they should be wrapped
|
// Since Jasmine doesn't like async functions, they should be wrapped
|
||||||
|
@ -23,4 +23,4 @@ page.open(address, function(status) {
|
|||||||
console.log('Unable to load the address!');
|
console.log('Unable to load the address!');
|
||||||
phantom.exit();
|
phantom.exit();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
//! unsupported
|
|
||||||
var webpage = require('webpage');
|
var webpage = require('webpage');
|
||||||
|
|
||||||
async_test(function () {
|
async_test(function () {
|
||||||
|
Loading…
Reference in New Issue
Block a user