Skip to content

Instantly share code, notes, and snippets.

@kasparsd
Created August 19, 2016 18:55
Show Gist options
  • Save kasparsd/8c14bf83d5c9d98d860988cc29ffa901 to your computer and use it in GitHub Desktop.
Save kasparsd/8c14bf83d5c9d98d860988cc29ffa901 to your computer and use it in GitHub Desktop.
Source code of the Headerbid Expert Chrome extension
<!DOCTYPE html>
<body>
<script src="bidderPatterns.js"></script>
<script src="background.js"></script>
/**
* Authors: julien delhommeau
* Description: chrome extension background.js file
* used to filter ad calls and look for known patterns for both prebid and class 1 ad servers
**/
// class 1 ad server and urls patterns to look for for each known tag types
// var class1Ads = [
// {name: "OAS", shortName: "O", tagTypes: [{name: "MJX", patterns: ["\/4\/.*@", "RealMedia/ads/adstream_mjx.ads"]}, {name: "JX", patterns: ["\/3\/.*@", "RealMedia/ads/adstream_jx.ads"]}, {name: "SX", patterns: ["\/2\/.*@", "RealMedia/ads/adstream_sx.ads"]}, {name: "DX", patterns: ["\/jp\/.*@"]}]},
// {name: "DFP", shortName: "D", tagTypes: [{name: "GPT", patterns: ["g\.doubleclick\.net\/gampad\/ads\?"]}]},
// {name: "Smart", shortName: "S", tagTypes: [{name: "Standard", patterns: ["www6.smartadserver.com//ac?"]}]},
// {name: "AdTech", shortName: "A", tagTypes: [{name: "Standard", patterns: ["adserver\.adtech\.de\/addyn", "adserver\.adtechus\.com\/addyn"]}]}
// ];
/* {
'.adnxs.com/jpt': 'appnexus',
...
}
*/
var patternsToBidders = {};
// ["*://*.adnxs.com/jpt*"]
var reqPatterns = [];
for (var b in bidderPatterns) {
var patterns = bidderPatterns[b];
for (var i = 0; i < patterns.length; i++) {
var p = patterns[i];
patternsToBidders[p] = b;
// .adnxs.com/jpt would become *.adnxs.com/jpt
// and ad.crwdcntrl.net/ will remain as it is
if (p[0] === '.') p = '*' + p;
var urlPattern = '*://' + p + '*';
reqPatterns.push(urlPattern);
}
}
/*
{
"frameId": 0,
"method": "GET",
"parentFrameId": -1,
"requestId": "153729",
"tabId": 2452,
"timeStamp": 1449356123237.1,
"type": "script",
"url": "http:\/\/ib.adnxs.com\/jpt?callback=pbjs.handleCB&callback_uid=1f4c1ca09&psa=0&size=728x90&promo_sizes=970x90&referrer=http%3A%2F%2Flocal%2Fexamples%2Fpbjs_full_example.html"
}
*/
function getBidderFromURL(url) {
if (!url) return;
for (var p in patternsToBidders) {
var urlRegex;
var wildcard = p.indexOf('*');
// '*' in a bidder pattern will match urls provided by Chrome API, but not
// the patternsToBidders map using regex syntax. It will match as a regex
// by placing '.' before the '*', meaning any character 0 or more times
if (wildcard !== -1) {
urlRegex = new RegExp(p.slice(0, wildcard) + '.' + p.slice(wildcard));
}
if (url.indexOf(p) != -1 || (urlRegex && urlRegex.test(url))) {
return patternsToBidders[p];
}
}
}
/* Example:
{
2452: { // tab ID
'153729': { // request ID
bidder: 'appnexus',
start: 1449357588485.302,
end: 1449357588666.545,
},
'234324': ...
}
}
*/
var bidReqs = {};
/* Track the number of bidders in each tab for the icon badge.
Example:
{ tabId: bidders
2452: ['appnexus', 'openx', ...]
} */
var bidders = {};
// https://developer.chrome.com/extensions/match_patterns
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if (!details) return;
// Find the bidder
var bidder = getBidderFromURL(details.url);
if (!bidder) return;
var tabId = details.tabId;
// Make sure the tabId objects are in bidders and bidReqs
if (!(tabId in bidders)) return;
if (!(tabId in bidReqs)) return;
var tabBidReqs = bidReqs[tabId];
// Record the request ID and the start timestamp
tabBidReqs[details.requestId] = {
bidder: bidder,
start: details.timeStamp,
tabId: tabId
}
// Increment bidders for showing in badge
var tabBidders = bidders[tabId];
if (tabBidders && tabBidders.indexOf(bidder) == -1) {
tabBidders.push(bidder);
var count = tabBidders.length;
chrome.browserAction.setBadgeText({text: '' + count, tabId: tabId});
}
}, {
urls: reqPatterns
}
);
chrome.webRequest.onCompleted.addListener(
function(details) {
if (!details) return;
var reqId = details.requestId;
var tabId = details.tabId;
if (!(tabId in bidReqs)) return;
var tabBidReqs = bidReqs[tabId];
// Find the request based on the request ID. Record the end timestamp
if (reqId in tabBidReqs) {
tabBidReqs[reqId].end = details.timeStamp;
}
}, {
urls: reqPatterns
}
);
// Users installed this login to understand latency data.
// If prebid partners' latency are found, log their latency data.
// The server will display the latency data by prebid partner in a UI.
// A demo of such latency data are available at: http://api.prebid.org/
function logTabBidReq(tabId, loadId, referrer) {
setTimeout(function() {
if (!(tabId in bidReqs)) return;
var tabBidReqs = bidReqs[tabId];
// If no bidder latency is found, do not log.
if (Object.keys(tabBidReqs).length == 0) return;
var data = {
"loadId": loadId,
"referrer": referrer,
"bidReqs": tabBidReqs
}
var xhr = new XMLHttpRequest();
xhr.open('POST', LOG_LOC, true);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.send(JSON.stringify(data));
}, LOG_WAIT_TIME);
}
// reset table when tab is refreshed
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if (changeInfo.status == "loading") {
bidders[tabId] = [];
bidReqs[tabId] = {};
chrome.browserAction.setBadgeText({text: "" + 0, tabId: tabId});
var loadId = '' + new Date().getTime();
loadId += Math.floor(Math.random() * 100000);
logTabBidReq(tabId, loadId, tab.url);
}
})
// clean table when tab is closed
chrome.tabs.onRemoved.addListener(function(tabId, removeInfo) {
delete bidders[tabId];
delete bidReqs[tabId];
})
var bidderPatterns = {
'AppNexus': [
'.adnxs.com/jpt'
],
'Openx': [
//'.servedbyopenx.com/w/1.0/jstag', //CDN
'.servedbyopenx.com/w/1.0/acj',
'.openx.net/w/1.0/acj'
],
'Pubmatic': [
//'.pubmatic.com/AdServer/js/gshowad.js', //CDN
'.pubmatic.com/AdServer/AdCallAggregator',
'.pubmatic.com/AdServer/AdServerServlet'
],
'Rubicon': [
//'.rubiconproject.com/ad/9707.js', //CDN
'.rubiconproject.com/a/api/fastlane.json',
'.rubiconproject.com/a/api/ads.json'
],
'Criteo': [
'.criteo.com/delivery/rta/rta.js'
],
'Amazon': [
//'.amazon-adsystem.com/aax2/amzn_ads.js', //CDN
'.amazon-adsystem.com/e/dtb/bid'
],
'AOL': [
'.adtechus.com/pubapi*cmd=bid'
],
'Sovrn': [
'.lijit.com/rtb/bid'
],
'Yieldbot': [
//'.yldbt.com/js/yieldbot.intent.js', //CDN
'.yldbt.com/m/'
],
'Sonobi': [
'.sonobi.com/trinity.js'
],
'Index': [
'.casalemedia.com/cygnus',
'.casalemedia.com/headertag'
],
'Proximic': [
'.zqtk.net/'
],
'Lotame': [
'ad.crwdcntrl.net/'
],
'AudienceS': [
'.revsci.net/pql'
],
'Adform': [
'adx.adform.net/adx/?rp=4'
],
'DFP': [
'.doubleclick.net/gampad/ads'
]
};
var LOG_WAIT_TIME = 6000;
//var LOG_LOC = 'http://localhost:3000/log';
var LOG_LOC = 'http://api.prebid.org/log';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment