Skip to content

Commit d881df9

Browse files
committed
Merge branch 'feature/2.4.3'
2 parents a5a9822 + fe187d3 commit d881df9

File tree

10 files changed

+114
-37
lines changed

10 files changed

+114
-37
lines changed

CHANGELOG

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
Version 2.4.3 (2015-04-15)
2+
--------------------------
3+
Added License button to README (#357)
4+
Set the ID cookie as soon as the tracker loads (#358)
5+
Updated the session count as soon as the tracker loads (#361)
6+
Made single events exceeding the maximum POST request size attempt to fire exactly once (#359)
7+
Fixed querystring decoration for links with inner elements (#360)
8+
19
Version 2.4.2 (2015-04-07)
210
--------------------------
311
Set a maximum size for POST requests (#353)

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
[ ![Selenium Test Status] [saucelabs-button-image]][saucelabs]
55
[ ![Code Climate] [codeclimate-image] ] [codeclimate]
66
[ ![Built with Grunt] [grunt-image] ] [grunt]
7+
[ ![License] [license-image] ] [bsd]
78

89
## Overview
910

@@ -77,3 +78,4 @@ Licensed under the [Simplified BSD] [bsd] license.
7778
[saucelabs]: https://saucelabs.com/u/snowplow
7879
[saucelabs-button-image]: https://saucelabs.com/buildstatus/snowplow
7980
[saucelabs-matrix-image]: https://saucelabs.com/browser-matrix/snowplow.svg
81+
[license-image]: http://img.shields.io/badge/license-simplified--bsd-blue.svg?style=flat

examples/ads/async.html

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ <h1>Asynchronous ad tracking examples for snowplow.js</h1>
3838
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
3939
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
4040
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
41-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","adTracker"));
41+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js","adTracker"));
4242

4343
window.adTracker('newTracker', rnd, 'd3rkrsqld9gmqf.cloudfront.net', {
4444
'encodeBase64': false
@@ -110,7 +110,7 @@ <h1>Asynchronous ad tracking examples for snowplow.js</h1>
110110
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
111111
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
112112
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
113-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","adTracker"));
113+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js","adTracker"));
114114

115115
window.adTracker('newTracker', rnd, 'd3rkrsqld9gmqf.cloudfront.net', {
116116
'encodeBase64': false
@@ -141,7 +141,7 @@ <h1>Asynchronous ad tracking examples for snowplow.js</h1>
141141
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
142142
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
143143
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
144-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","adTracker"));
144+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js","adTracker"));
145145

146146
window.adTracker('newTracker', rnd, 'd3rkrsqld9gmqf.cloudfront.net', {
147147
'encodeBase64': false

examples/web/async-large.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
2424
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
2525
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
26-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","snowplow_1"));
26+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js","snowplow_1"));
2727

2828
window.snowplow_1('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', { // Initialise a tracker
2929
encodeBase64: false, // Default is true
@@ -82,7 +82,7 @@
8282
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
8383
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
8484
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
85-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","snowplow_2"));
85+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js","snowplow_2"));
8686

8787
window.snowplow_2('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', { // Initialise a tracker
8888
encodeBase64: false, // Default is true

examples/web/async-medium.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
2525
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
2626
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
27-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","new_name_here"));
27+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js","new_name_here"));
2828

2929
window.new_name_here('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', {
3030
encodeBase64: false,

examples/web/async-small.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
;(function(p,l,o,w,i,n,g){if(!p[i]){p.GlobalSnowplowNamespace=p.GlobalSnowplowNamespace||[];
2424
p.GlobalSnowplowNamespace.push(i);p[i]=function(){(p[i].q=p[i].q||[]).push(arguments)
2525
};p[i].q=p[i].q||[];n=l.createElement(o);g=l.getElementsByTagName(o)[0];n.async=1;
26-
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js","snowplow"));
26+
n.src=w;g.parentNode.insertBefore(n,g)}}(window,document,"script","//d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js","snowplow"));
2727

2828
window.snowplow('newTracker', 'cf', 'd3rkrsqld9gmqf.cloudfront.net', { // Initialise a tracker
2929
encodeBase64: false, // Default is true

examples/web/sync.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
<!-- Snowplow starts plowing -->
2121
<script type="text/javascript">
22-
var spSrc = ('https:' == document.location.protocol ? 'https' : 'http') + '://d1fc8wv8zag5ca.cloudfront.net/2.4.2/sp.js';
22+
var spSrc = ('https:' == document.location.protocol ? 'https' : 'http') + '://d1fc8wv8zag5ca.cloudfront.net/2.4.3/sp.js';
2323
document.write(unescape("%3Cscript src='" + spSrc + "' type='text/javascript'%3E%3C/script%3E"));
2424
</script>
2525
<script type="text/javascript">

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "snowplow-tracker",
3-
"version": "2.4.2",
3+
"version": "2.4.3",
44
"devDependencies": {
55
"JSON": "~1.0.0",
66
"browser-cookie-lite": "~0.3.1",

src/js/out_queue.js

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -173,18 +173,20 @@
173173
*/
174174
function enqueueRequest (request, url) {
175175

176+
configCollectorUrl = url + path;
176177
if (usePost) {
177178
var body = getBody(request);
178179
if (body.bytes >= maxPostBytes) {
179180
helpers.warn("Event of size " + body.bytes + " is too long - the maximum size is " + maxPostBytes);
181+
var xhr = initializeXMLHttpRequest(configCollectorUrl);
182+
xhr.send(encloseInPayloadDataEnvelope([body.evt]));
180183
return;
181184
} else {
182185
outQueue.push(body);
183186
}
184187
} else {
185188
outQueue.push(getQuerystring(request));
186189
}
187-
configCollectorUrl = url + path;
188190
var savedToLocalStorage = false;
189191
if (useLocalStorage) {
190192
savedToLocalStorage = helpers.attemptWriteLocalStorage(queueName, json2.stringify(outQueue));
@@ -222,9 +224,7 @@
222224

223225
if (usePost) {
224226

225-
var xhr = new XMLHttpRequest();
226-
xhr.open('POST', configCollectorUrl, true);
227-
xhr.withCredentials = true;
227+
var xhr = initializeXMLHttpRequest(configCollectorUrl);
228228

229229
// Time out POST requests after 5 seconds
230230
var xhrTimeout = setTimeout(function () {
@@ -265,16 +265,11 @@
265265
}
266266
};
267267

268-
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
269268
var batch = lodash.map(outQueue.slice(0, numberToSend), function (x) {
270269
return x.evt;
271270
});
272-
var batchRequest = {
273-
schema: 'iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-2',
274-
data: batch
275-
};
276271
if (batch.length > 0) {
277-
xhr.send(json2.stringify(batchRequest));
272+
xhr.send(encloseInPayloadDataEnvelope(batch));
278273
}
279274

280275
} else {
@@ -295,7 +290,33 @@
295290

296291
image.src = configCollectorUrl + nextRequest;
297292
}
293+
}
298294

295+
/**
296+
* Open an XMLHttpRequest for a given endpoint with the correct credentials and header
297+
*
298+
* @param string url The destination URL
299+
* @return object The XMLHttpRequest
300+
*/
301+
function initializeXMLHttpRequest(url) {
302+
var xhr = new XMLHttpRequest();
303+
xhr.open('POST', url, true);
304+
xhr.withCredentials = true;
305+
xhr.setRequestHeader('Content-Type', 'application/json; charset=UTF-8');
306+
return xhr;
307+
}
308+
309+
/**
310+
* Enclose an array of events in a self-describing payload_data JSON string
311+
*
312+
* @param array events Batch of events
313+
* @return string payload_data self-describing JSON
314+
*/
315+
function encloseInPayloadDataEnvelope(events) {
316+
return json2.stringify({
317+
schema: 'iglu:com.snowplowanalytics.snowplow/payload_data/jsonschema/1-0-2',
318+
data: events
319+
});
299320
}
300321

301322
return {

src/js/tracker.js

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -299,12 +299,10 @@
299299
* @param event e The event targeting the link
300300
*/
301301
function linkDecorationHandler(e) {
302-
var duid = loadDomainUserIdCookie()[1];
303302
var tstamp = new Date().getTime();
304-
var initialQsParams = '_sp=' + duid + '.' + tstamp;
305-
var elt = e.target;
306-
if (elt.href) {
307-
elt.href = helpers.decorateQuerystring(elt.href, '_sp', duid + '.' + tstamp);
303+
var initialQsParams = '_sp=' + domainUserId + '.' + tstamp;
304+
if (this.href) {
305+
this.href = helpers.decorateQuerystring(this.href, '_sp', domainUserId + '.' + tstamp);
308306
}
309307
}
310308

@@ -319,8 +317,8 @@
319317
for (var i=0; i<document.links.length; i++) {
320318
var elt = document.links[i];
321319
if (!elt.spDecorationEnabled && crossDomainLinker(elt)) {
322-
helpers.addEventListener(elt, 'click', linkDecorationHandler);
323-
helpers.addEventListener(elt, 'mousedown', linkDecorationHandler);
320+
helpers.addEventListener(elt, 'click', linkDecorationHandler, true);
321+
helpers.addEventListener(elt, 'mousedown', linkDecorationHandler, true);
324322

325323
// Don't add event listeners more than once
326324
elt.spDecorationEnabled = true;
@@ -503,6 +501,13 @@
503501
}
504502
}
505503

504+
/*
505+
* Sets or renews the session cookie
506+
*/
507+
function setSessionCookie() {
508+
cookie.cookie(getSnowplowCookieName('ses'), '*', configSessionCookieTimeout, configCookiePath, configCookieDomain);
509+
}
510+
506511
/*
507512
* Sets the Visitor ID cookie: either the first time loadDomainUserIdCookie is called
508513
* or when there is a new visit or a new page view
@@ -511,6 +516,55 @@
511516
cookie.cookie(getSnowplowCookieName('id'), _domainUserId + '.' + createTs + '.' + visitCount + '.' + nowTs + '.' + lastVisitTs, configVisitorCookieTimeout, configCookiePath, configCookieDomain);
512517
}
513518

519+
/**
520+
* Generate a pseudo-unique ID to fingerprint this user
521+
* Note: this isn't a RFC4122-compliant UUID
522+
*/
523+
function createNewDomainUserId() {
524+
return hash(
525+
(navigatorAlias.userAgent || '') +
526+
(navigatorAlias.platform || '') +
527+
json2.stringify(browserFeatures) + Math.round(new Date().getTime() / 1000)
528+
).slice(0, 16); // 16 hexits = 64 bits
529+
}
530+
531+
/*
532+
* Generate a new domainUserId and write it to a cookie
533+
*/
534+
function generateNewDomainUserId() {
535+
domainUserId = createNewDomainUserId();
536+
if (configUseCookies && configWriteCookies) {
537+
var nowTs = Math.round(new Date().getTime() / 1000);
538+
setDomainUserIdCookie(domainUserId, nowTs, 0, nowTs, nowTs);
539+
}
540+
}
541+
542+
/*
543+
* Try to load the domainUserId from the cookie
544+
* If this fails, generate a new one
545+
* If there is no session cookie, set one and increment the visit count
546+
*/
547+
function initializeDomainUserId() {
548+
var idCookieValue;
549+
if (configUseCookies) {
550+
idCookieValue = getSnowplowCookieValue('id');
551+
}
552+
if (idCookieValue) {
553+
domainUserId = idCookieValue.split('.')[0];
554+
} else {
555+
generateNewDomainUserId();
556+
}
557+
if (configUseCookies && configWriteCookies) {
558+
if (!getSnowplowCookieValue('ses')) {
559+
var idCookie = loadDomainUserIdCookie();
560+
idCookie[3] ++;
561+
idCookie.shift();
562+
setDomainUserIdCookie.apply(null, idCookie);
563+
}
564+
setSessionCookie();
565+
}
566+
}
567+
514568
/*
515569
* Load visitor ID cookie
516570
*/
@@ -528,15 +582,6 @@
528582
// New visitor set to 0 now
529583
tmpContainer.unshift('0');
530584
} else {
531-
// Domain - generate a pseudo-unique ID to fingerprint this user;
532-
// Note: this isn't a RFC4122-compliant UUID
533-
if (!domainUserId) {
534-
domainUserId = hash(
535-
(navigatorAlias.userAgent || '') +
536-
(navigatorAlias.platform || '') +
537-
json2.stringify(browserFeatures) + nowTs
538-
).slice(0, 16); // 16 hexits = 64 bits
539-
}
540585

541586
tmpContainer = [
542587
// New visitor
@@ -602,11 +647,10 @@
602647
// Add the page URL last as it may take us over the IE limit (and we don't always need it)
603648
sb.add('url', purify(configCustomUrl || locationHrefAlias));
604649

605-
606650
// Update cookies
607651
if (configUseCookies && configWriteCookies) {
608652
setDomainUserIdCookie(_domainUserId, createTs, visitCount, nowTs, lastVisitTs);
609-
cookie.cookie(sesname, '*', configSessionCookieTimeout, configCookiePath, configCookieDomain);
653+
setSessionCookie();
610654
}
611655
}
612656

@@ -910,6 +954,8 @@
910954
*/
911955
updateDomainHash();
912956

957+
initializeDomainUserId();
958+
913959
if (argmap.crossDomainLinker) {
914960
decorateLinks(argmap.crossDomainLinker);
915961
}

0 commit comments

Comments
 (0)