Skip to content

Commit

Permalink
Merge branch 'support-transport-field'
Browse files Browse the repository at this point in the history
  • Loading branch information
keithclark committed Oct 6, 2015
2 parents a98b23e + 55f9355 commit 5e5348d
Show file tree
Hide file tree
Showing 8 changed files with 183 additions and 45 deletions.
Binary file modified dist/gadebugger-2.0.0.crx
Binary file not shown.
Binary file modified dist/gadebugger-2.0.0.xpi
Binary file not shown.
85 changes: 47 additions & 38 deletions src/chrome/js/api.js
Expand Up @@ -82,55 +82,64 @@ var GADebuggerAPI = (function() {
}


function process(url) {
var beacon = GACore.parseBeacon(url),
tracker, item, refNode;
function process(request) {
var url = request.url,
beacon, tracker, item, refNode;

if (beacon) {
tracker = getTrackerByAccount(beacon.account);

// create a tracker list item for this beacon
if (!tracker) {
tracker = {
account: beacon.account,
list: elements.trackerBeaconList.cloneNode(true)
};
UI.ItemList.addItem(
elements.trackerList,
tracker.account + '<i>' + beacon.documentHostname + '</i>',
tracker.account,
true
);
trackerObjects.push(tracker);
if (GACore.isBeaconUrl(url)) {

if (request.method === 'POST') {
url += request.queryString.length ? '&' : '?';
url += request.postData.text;
}

// add the beacon to the trackers beacon list
item = UI.ItemList.addItem(
tracker.list,
beacon.type + ' - ' + GACore.createBeaconHint(beacon),
url
);
beacon = GACore.parseBeacon(url);

if (beacon) {
tracker = getTrackerByAccount(beacon.account);

// create a tracker list item for this beacon
if (!tracker) {
tracker = {
account: beacon.account,
list: elements.trackerBeaconList.cloneNode(true)
};
UI.ItemList.addItem(
elements.trackerList,
tracker.account + '<i>' + beacon.documentHostname + '</i>',
tracker.account,
true
);
trackerObjects.push(tracker);
}

// add the beacon to the trackers beacon list
item = UI.ItemList.addItem(
tracker.list,
beacon.type + ' - ' + GACore.createBeaconHint(beacon),
url
);

item.className = 'beacon beacon--' + beacon.type;
item.className = 'beacon beacon--' + beacon.type;

// ensure transaction items are grouped
if (beacon.type === 'item') {
refNode = tracker.list.querySelector('[tid="' + beacon.transactionItem.transactionId + '"]');
if (refNode) {
refNode = refNode.nextElementSibling;
// ensure transaction items are grouped
if (beacon.type === 'item') {
refNode = tracker.list.querySelector('[tid="' + beacon.transactionItem.transactionId + '"]');
if (refNode) {
refNode = refNode.nextElementSibling;
}
tracker.list.insertBefore(item, refNode);
item.setAttribute('tid', beacon.transactionItem.transactionId);
}
tracker.list.insertBefore(item, refNode);
item.setAttribute('tid', beacon.transactionItem.transactionId);
}

// ensure the transaction header is above any transaction items
if (beacon.type === 'transaction') {
tracker.list.insertBefore(item, tracker.list.querySelector('[tid="' + beacon.transaction.id + '"]'));
// ensure the transaction header is above any transaction items
if (beacon.type === 'transaction') {
tracker.list.insertBefore(item, tracker.list.querySelector('[tid="' + beacon.transaction.id + '"]'));
}
}
}
}


function setProperties(propertyList, props) {
var group = propertyList.parentNode.parentNode;

Expand Down
2 changes: 1 addition & 1 deletion src/chrome/js/devtools.js
Expand Up @@ -13,7 +13,7 @@ chrome.devtools.panels.create('GA Debugger', 'img/icon-48.png', 'index.html', fu
panel.onShown.removeListener(init);

function requestHandler(request) {
panelWindow.GADebugger.process(request.request.url);
panelWindow.GADebugger.process(request.request);
}

captureButton.onClicked.addListener(function() {
Expand Down
9 changes: 9 additions & 0 deletions src/core/api.js
Expand Up @@ -10,6 +10,12 @@ var GACoreAPI = (function() {
'stats.g.doubleclick.net'
];

function isBeaconUrl(url) {
var uri = Utils.parseUri(url);
return uri && HOSTS.indexOf(uri.hostname) > -1 &&
(uri.path === '/collect' || uri.path === '/__utm.gif');
}

function parseBeacon(url) {
var uri = Utils.parseUri(url),
beacon;
Expand Down Expand Up @@ -45,6 +51,9 @@ var GACoreAPI = (function() {
}

return {
isBeaconUrl: function(url) {
return isBeaconUrl(url);
},
parseBeacon: function(url) {
return parseBeacon(url);
},
Expand Down
72 changes: 71 additions & 1 deletion src/firefox/chrome/tool.js
Expand Up @@ -6,6 +6,7 @@ const STRINGS_URI = 'chrome://gadebugger/locale/strings.properties';

const EVENTS = {
NETWORK_EVENT: 'networkEvent',
NETWORK_EVENT_UPDATE: 'networkEventUpdate',
BEACONMONITOR_STARTED: 'GADebugger:BeaconMonitorStarted',
BEACONMONITOR_STOPPED: 'GADebugger:BeaconMonitorStopped',
BEACONMONITOR_BEACON: 'GADebugger:BeaconMonitorBeacon'
Expand Down Expand Up @@ -58,30 +59,99 @@ let BeaconMonitor = {
});

this._onNetworkEvent = this._onNetworkEvent.bind(this);
this._onNetworkEventUpdate = this._onNetworkEventUpdate.bind(this);
},
destroy: function() {
this.client = null;
this.webConsoleClient = null;
},
start: function() {
if (!this.capturing) {
this._activeRequests = {};
this.client.addListener(EVENTS.NETWORK_EVENT, this._onNetworkEvent);
this.client.addListener(EVENTS.NETWORK_EVENT_UPDATE, this._onNetworkEventUpdate);
this._recording = true;
window.emit(EVENTS.BEACONMONITOR_STARTED);
}
},
stop: function() {
if (this.capturing) {
this.client.removeListener(EVENTS.NETWORK_EVENT, this._onNetworkEvent);
this.client.removeListener(EVENTS.NETWORK_EVENT_UPDATE, this._onNetworkEventUpdate);
this._activeRequests = {};
this._recording = false;
window.emit(EVENTS.BEACONMONITOR_STOPPED);
}
},
get capturing() {
return this._recording;
},
/**
* The `networkEvent` message type handler.
*
* Arguments:
* aType string Message type
* aPacket object The network request information
*/
_onNetworkEvent: function(aType, aPacket) {
var beacon = GACore.parseBeacon(aPacket.eventActor.url);
var eventActor = aPacket.eventActor;

if (GACore.isBeaconUrl(eventActor.url)) {
let request = {
method: eventActor.method,
url: eventActor.url
};

// if this is a GET request we can log the beacon now
if (request.method === 'GET') {
this._onNetworkBeaconRequest(request);
}
// for POST requests we need to wait for the `networkEventUpdate` event
else if (request.method === 'POST') {
this._activeRequests[eventActor.actor] = request;
}
}
},
/**
* The `networkEventUpdate` message type handler.
*
* Arguments:
* aType string Message type
* aPacket object The network request information
*/
_onNetworkEventUpdate: function(aType, aPacket) {
var activeRequest = this._activeRequests[aPacket.from];
if (activeRequest) {
if (aPacket.updateType === 'requestPostData') {
this.webConsoleClient.getRequestPostData(aPacket.from, function (aResponse) {
activeRequest.postData = aResponse.postData.text;
this._onNetworkBeaconRequest(activeRequest);
delete this._activeRequests[aPacket.from];
}.bind(this));
}
}
},
/**
* The `networkBeaconRequest` handler.
*
* Called when a network request is determined to be a valid
* GA beacon.
*
* Arguments:
* request object The request object
*/
_onNetworkBeaconRequest: function(request) {
var url = request.url;
var beacon;

// if this is a POST it was either sent using the `xhr`
// or `beacon` transport. For these requests we append
// the post body to the url as a querystring.
if (request.method === 'POST') {
url += '?' + request.postData;
}

beacon = GACore.parseBeacon(url);
if (beacon) {
window.emit(EVENTS.BEACONMONITOR_BEACON, beacon);
if (!TrackerListView.hasTracker(beacon.account)) {
Expand Down
39 changes: 34 additions & 5 deletions test/client-test.html
Expand Up @@ -42,6 +42,7 @@ <h1>Test tool</h1>
<tr>
<th>Tracker</th>
<th>Type</th>
<th>Transport</th>
<th>Data</th>
<th>URL</th>
</tr>
Expand Down Expand Up @@ -73,7 +74,7 @@ <h1>Test tool</h1>
return out;
}

function logRequest(url) {
function logRequest(url, transport) {
var tracker = /__utm.gif?/.test(url) ? "UTM" : "UA",
type = (/[?&](?:utm)?t=([^&]*)/.exec(url) || ['','pageview'])[1],
title = (/[?&](?:utm)?dt=([^&]*)/.exec(url) || ['', ''])[1],
Expand All @@ -83,6 +84,8 @@ <h1>Test tool</h1>
url = url.replace(new RegExp(encodeURIComponent(document.location.host), "g"), encodeURIComponent(SPOOF_HOST));
url = url.replace(new RegExp(encodeURIComponent(document.location.pathname), "g"), encodeURIComponent('/'));

transport = transport || (tracker === 'UA' ? 'image' : '');

// generate the data column value
if (type === "social") {
data = getParams(["utmsn", "utmsa", "utmsid", "sn", "sa", "st"], url)
Expand All @@ -100,12 +103,12 @@ <h1>Test tool</h1>
document.getElementById("results").innerHTML +=
"<tr><td>" + tracker + "</td>" +
"<td>" + type + "</td>" +
"<td>" + transport + "</td>" +
"<td>" + decodeURIComponent(data) + "</td>" +
"<td>" + url + "</td></tr>";
}

var originalImage = window.Image,
originalCreateElement = document.createElement,
var originalCreateElement = document.createElement,
stubbedImage = Object.defineProperties({}, {
src: {
set: function (x) {
Expand All @@ -125,6 +128,27 @@ <h1>Test tool</h1>
}
return elem;
}

// Patch XMLHttpRequest to intercept UA XHR transport beacons
window.XMLHttpRequest = function() {}

window.XMLHttpRequest.prototype = {
withCredentials: true,
setRequestHeader: function() {},
open: function(method, url, async) {
this._url = url;
},
send: function(data) {
logRequest(this._url + '?' + data, 'xhr');
}
}

// Patch navigator.sendBeacon to intercept UA beacon transport beacons
navigator.sendBeacon = function(url, data) {
logRequest(url + '?' + data, 'beacon');
return true;
}

}
}());
</script>
Expand All @@ -145,8 +169,6 @@ <h1>Test tool</h1>
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
</script>



<script>
/* account creation
------------------------------------------------------- */
Expand Down Expand Up @@ -322,6 +344,13 @@ <h1>Test tool</h1>
ga('send', 'pageview', '/screen-name-test');
ga('set', 'screenName', null);


/* Transport (UA only)
------------------------------------------------------- */

ga('send', 'pageview', '/image-transport', {transport: 'image'});
ga('send', 'pageview', '/beacon-transport', {transport: 'beacon'});
ga('send', 'pageview', '/xhr-transport', {transport: 'xhr'});
</script>

</body>
Expand Down
21 changes: 21 additions & 0 deletions test/unit/core/api_test.js
Expand Up @@ -42,5 +42,26 @@ module.exports = {
test.strictEqual(beacon, undefined);
test.done();
},
},
'API.isBeaconUrl': {
'Universal analytics URL': function (test) {
test.strictEqual(GACoreAPI.isBeaconUrl('http://www.google-analytics.com/collect'), true);
test.strictEqual(GACoreAPI.isBeaconUrl('https://www.google-analytics.com/collect'), true);
test.done();
},
'Traditional analytics URL': function (test) {
test.strictEqual(GACoreAPI.isBeaconUrl('http://www.google-analytics.com/__utm.gif'), true);
test.strictEqual(GACoreAPI.isBeaconUrl('https://ssl.google-analytics.com/__utm.gif'), true);
test.done();
},
'Traditional analytics remarketing URL': function (test) {
test.strictEqual(GACoreAPI.isBeaconUrl('http://stats.g.doubleclick.net/__utm.gif'), true);
test.strictEqual(GACoreAPI.isBeaconUrl('https://stats.g.doubleclick.net/__utm.gif'), true);
test.done();
},
'Non-GA URL': function (test) {
test.strictEqual(GACoreAPI.isBeaconUrl('http://my.website.com'), false);
test.done();
}
}
};

0 comments on commit 5e5348d

Please sign in to comment.