-
Notifications
You must be signed in to change notification settings - Fork 26
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #7 from getstation/fix/mixmax
Add WebRequest API
- Loading branch information
Showing
12 changed files
with
297 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
// Try it with motherfuckingwebsite.com | ||
|
||
chrome.webRequest.onBeforeRequest.addListener(function(details) { | ||
// Fires when a request is about to occur. | ||
// This event is sent before any TCP connection is made and can be used to cancel or redirect requests. | ||
console.log('--- onBeforeRequest details') | ||
console.log(details) | ||
return { | ||
cancel: details.url.indexOf("://evil.com/") !== -1 | ||
}; | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
|
||
|
||
chrome.webRequest.onBeforeSendHeaders.addListener(function(details) { | ||
// Fires when a request is about to occur and the initial headers have been prepared. | ||
// The event is intended to allow extensions to add, modify, and delete request headers (*). | ||
// The onBeforeSendHeaders event is passed to all subscribers, so different subscribers may attempt to modify the request; | ||
// see the Implementation details section for how this is handled. This event can be used to cancel the request. | ||
details.requestHeaders['User-Agent'] = 'My Awesome Agent added onBeforeSendHeaders' | ||
console.log('--- onBeforeSendHeaders details') | ||
console.log(details) | ||
return { | ||
cancel: false, | ||
requestHeaders: details.requestHeaders, | ||
}; | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
|
||
chrome.webRequest.onSendHeaders.addListener(function(details) { | ||
// Fires after all extensions have had a chance to modify the request headers, and presents the final (*) version. | ||
// The event is triggered before the headers are sent to the network. This event is informational and handled asynchronously. | ||
// It does not allow modifying or cancelling the request. | ||
console.log('--- onSendHeaders details') | ||
console.log(details) | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
|
||
chrome.webRequest.onHeadersReceived.addListener(function(details) { | ||
// Fired when HTTP response headers of a request have been received. | ||
details.responseHeaders.push({ | ||
name: 'X-onHeadersReceived', | ||
value: 'ok' | ||
}); | ||
|
||
return { | ||
cancel: false, | ||
responseHeaders: details.responseHeaders, | ||
}; | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
// | ||
// chrome.webRequest.onAuthRequired.addListener(function(details) { | ||
// // not available in electron. We have to implement it. | ||
// }, { | ||
// urls: ['<all_urls>'], | ||
// types: ['main_frame'] | ||
// }); | ||
|
||
chrome.webRequest.onBeforeRedirect.addListener(function(details) { | ||
// Fires when a redirect is about to be executed. A redirection can be triggered by an HTTP response code or by an extension. | ||
// This event is informational and handled asynchronously. | ||
// It does not allow you to modify or cancel the request. | ||
console.log('--- onBeforeRedirect details') | ||
console.log(details) | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
|
||
|
||
chrome.webRequest.onResponseStarted.addListener(function(details) { | ||
// Fires when the first byte of the response body is received. | ||
// For HTTP requests, this means that the status line and response headers are available. | ||
// This event is informational and handled asynchronously. | ||
// It does not allow modifying or cancelling the request. | ||
console.log('--- onResponseStarted details') | ||
console.log(details) | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
|
||
chrome.webRequest.onCompleted.addListener(function(details) { | ||
// Fires when a request has been processed successfully. | ||
console.log('--- onCompleted details') | ||
console.log(details) | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
|
||
chrome.webRequest.onErrorOccurred.addListener(function(details) { | ||
// Fires when a request could not be processed successfully. | ||
console.log('--- onErrorOccurred details') | ||
console.log(details) | ||
}, { | ||
urls: ['<all_urls>'], | ||
types: ['main_frame'] | ||
}); | ||
|
||
const sampleRequest = new XMLHttpRequest(); | ||
sampleRequest.addEventListener('load', function () { | ||
console.log('--- sampleRequest AllResponseHeaders'); | ||
console.log(this.getAllResponseHeaders()); | ||
}); | ||
sampleRequest.open('GET', `http://motherfuckingwebsite.com/?foo=${Date.now()}`); | ||
sampleRequest.send(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
const { session } = require('electron'); | ||
const RCEventController = require('../rc-event-controller'); | ||
|
||
const WEBREQUEST_EVENTS = ['onBeforeRequest', 'onBeforeSendHeaders', 'onSendHeaders', | ||
'onHeadersReceived', 'onAuthRequired', 'onResponseStarted', 'onBeforeRedirect', 'onCompleted', | ||
'onErrorOccurred']; | ||
|
||
const fromElectronHeadersToChromeHeaders = (cbReturn) => { | ||
if (cbReturn && cbReturn.responseHeaders) { | ||
const responseHeaders = {}; | ||
cbReturn.responseHeaders.forEach((header) => responseHeaders[header.name] = [header.value]); | ||
cbReturn.responseHeaders = responseHeaders; | ||
} | ||
|
||
return cbReturn | ||
}; | ||
|
||
const fromChromeHeadersToElectronHeaders = (details) => { | ||
if (details.responseHeaders) | ||
details.responseHeaders = Object.keys(details.responseHeaders).map((k) => | ||
({ name: k, value: details.responseHeaders[k][0]})); | ||
|
||
return details; | ||
}; | ||
|
||
class ChromeWebRequestAPIHandler { | ||
constructor(extensionId) { | ||
this.electronWebRequestApi = session.defaultSession.webRequest; | ||
this.rcEventControllers = []; | ||
|
||
WEBREQUEST_EVENTS.forEach(methodName => { | ||
const controller = new RCEventController(`${extensionId}-webRequest-${methodName}`); | ||
this.rcEventControllers.push(controller); | ||
controller.on('add-listener', (listenerArgs, remoteCallListener) => { | ||
const [filter, extraInfos] = listenerArgs; | ||
this.electronWebRequestApi[methodName](filter, (details, callback) => { | ||
if (callback) | ||
remoteCallListener(fromChromeHeadersToElectronHeaders(details)) | ||
.then(returnedDetails => { | ||
if (!returnedDetails) return callback(details); | ||
return callback(fromElectronHeadersToChromeHeaders(returnedDetails)) | ||
}) | ||
.catch(e => {}) | ||
}) | ||
}) | ||
}); | ||
}; | ||
|
||
release () { | ||
this.rcEventControllers.forEach(c => c.release()) | ||
} | ||
} | ||
|
||
module.exports = ChromeWebRequestAPIHandler; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
const { rpc, RpcIpcManager } = require('electron-simple-rpc'); | ||
const { ipcMain } = require('electron'); | ||
const EventEmitter = require('events'); | ||
|
||
ipcMain.setMaxListeners(100); | ||
|
||
class RCEventController extends EventEmitter { | ||
constructor(eventId) { | ||
super(); | ||
|
||
this.controlerRPCScope = `${eventId}-controller`; | ||
this.eventRPCScope = `${eventId}-event`; | ||
|
||
this.rpcManager = new RpcIpcManager({ | ||
addListener: this._addListener.bind(this) | ||
}, this.controlerRPCScope); | ||
|
||
} | ||
|
||
_addListener(listenerId, listenerArgs) { | ||
const remoteCallListener = (args) => | ||
rpc(this.eventRPCScope, 'triggerListener')(listenerId, args).timeout(2500); | ||
this.emit('add-listener', listenerArgs, remoteCallListener); | ||
} | ||
|
||
release() { | ||
this.rpcManager.release(); | ||
} | ||
} | ||
|
||
module.exports = RCEventController; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,24 +1,28 @@ | ||
class Event { | ||
constructor () { | ||
this.listeners = [] | ||
this.listeners = []; | ||
} | ||
|
||
addListener (callback) { | ||
this.listeners.push(callback) | ||
this.listeners.push(callback); | ||
} | ||
|
||
hasListener (callback) { | ||
return this.listeners.indexOf(callback) !== -1; | ||
} | ||
|
||
removeListener (callback) { | ||
const index = this.listeners.indexOf(callback) | ||
const index = this.listeners.indexOf(callback); | ||
if (index !== -1) { | ||
this.listeners.splice(index, 1) | ||
} | ||
} | ||
|
||
emit (...args) { | ||
for (const listener of this.listeners) { | ||
listener(...args) | ||
listener(...args); | ||
} | ||
} | ||
} | ||
|
||
module.exports = Event | ||
module.exports = Event; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
const { rpc, RpcIpcManager } = require('electron-simple-rpc'); | ||
const uuid = require('uuid/v1'); | ||
|
||
class RCEvent { | ||
constructor(eventId) { | ||
this.listeners = new Map(); | ||
|
||
this.controllerRPCScope = `${eventId}-controller`; | ||
this.eventRPCScope = `${eventId}-event`; | ||
|
||
this.rpcManager = new RpcIpcManager({ | ||
triggerListener: this._triggerListener.bind(this) | ||
}, this.eventRPCScope) | ||
} | ||
|
||
addListener(callback, ...args) { | ||
const listenerId = uuid(); | ||
this.listeners.set(listenerId, callback); | ||
rpc(this.controllerRPCScope, 'addListener')(listenerId, args); | ||
} | ||
|
||
hasListener(callback) { | ||
return !!this._listenerIdFromCallback(callback) | ||
} | ||
|
||
removeListener(callback) { | ||
const [listenerId, cb] = this._listenerIdFromCallback(callback); | ||
this.listeners.delete(listenerId) | ||
} | ||
|
||
_triggerListener(listenerId, args) { | ||
const listener = this.listeners.get(listenerId); | ||
if (!listener) return; | ||
|
||
try { | ||
return listener.call(this, args); | ||
} catch (e) { | ||
console.error(e); | ||
} | ||
} | ||
|
||
_listenerIdFromCallback(callback) { | ||
return this.listeners.entries() | ||
.find(e => e[1] === callback) | ||
} | ||
} | ||
|
||
module.exports = RCEvent; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,22 @@ | ||
const Event = require('./event'); | ||
const { rpc, RpcIpcManager } = require('electron-simple-rpc'); | ||
const capitalize = require('capitalize'); | ||
const Event = require('../../renderer/extensions/event'); | ||
const RCEvent = require('./rc-event'); | ||
|
||
exports.setup = extensionId => { | ||
return { | ||
onBeforeRequest: new Event(), | ||
onBeforeSendHeaders: new Event(), | ||
onSendHeaders: new Event(), | ||
onHeadersReceived: new Event(), | ||
onAuthRequired: new Event(), | ||
onResponseStarted: new Event(), | ||
onBeforeRedirect: new Event(), | ||
onCompleted: new Event(), | ||
onErrorOccurred: new Event(), | ||
handlerBehaviorChanged () {}, | ||
MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES: 10 | ||
const WEBREQUEST_EVENTS = ['onBeforeRequest', 'onBeforeSendHeaders', 'onSendHeaders', | ||
'onHeadersReceived', 'onAuthRequired', 'onResponseStarted', 'onBeforeRedirect', 'onCompleted', | ||
'onErrorOccurred']; | ||
|
||
class ChromeWebRequestAPIClient { | ||
constructor(extensionId) { | ||
this.MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES = 10; | ||
WEBREQUEST_EVENTS.forEach(event => this[event] = new RCEvent(`${extensionId}-webRequest-${event}`)); | ||
} | ||
|
||
handlerBehaviorChanged () { | ||
console.warn('Call not implemented method **handlerBehaviorChanged**'); | ||
return Promise.resolve() | ||
} | ||
} | ||
|
||
exports.setup = extensionId => new ChromeWebRequestAPIClient(extensionId); |
Oops, something went wrong.