diff --git a/CHANGELOG.md b/CHANGELOG.md index 988b9293..eef7ab0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,6 @@ +* v2.17.0 + - Add inital support for users to set the client IP address + * v2.16.1 - Fix promise rejection errors when trying to retrieve fetch response text in network-tracking module diff --git a/README.md b/README.md index a49bfd11..eb40d1cd 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,8 @@ objects (for partial matches). Each should match the hostname or TLD that you wa `apiEndpoint` - A string URI containing the protocol, domain and port (optional) where all payloads will be sent to. This can be used to proxy payloads to the Raygun API through your own server. When not set this defaults internally to the Raygun API, and for most usages you won't need to set this. +`clientIp` - A string containing the client's IP address. RUM requests will be associated to this IP address when set. Particularally useful when proxying payloads to the Raygun API using the `apiEndpoint` option and maintaining RUM's geographic lookup feature. + `pulseMaxVirtualPageDuration` - The maximum time a virtual page can be considered viewed, in milliseconds (defaults to 30 minutes). `pulseIgnoreUrlCasing` - Ignore URL casing when sending data to Pulse. diff --git a/bower.json b/bower.json index 99129dd5..aaef9a2e 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "raygun4js", - "version": "2.16.1", + "version": "2.17.0", "homepage": "http://raygun.io", "authors": [ "Mindscape " diff --git a/package.json b/package.json index 5c31eb21..7e052153 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ ], "title": "Raygun4js", "description": "Raygun.io plugin for JavaScript", - "version": "2.16.1", + "version": "2.17.0", "homepage": "https://github.com/MindscapeHQ/raygun4js", "author": { "name": "MindscapeHQ", diff --git a/raygun4js.nuspec b/raygun4js.nuspec index 9653832d..3241b05e 100644 --- a/raygun4js.nuspec +++ b/raygun4js.nuspec @@ -2,7 +2,7 @@ raygun4js - 2.16.1 + 2.17.0 Raygun4js Mindscape Limited Mindscape Limited diff --git a/src/raygun.js b/src/raygun.js index ba50a011..32ee0f83 100644 --- a/src/raygun.js +++ b/src/raygun.js @@ -66,6 +66,7 @@ var raygunFactory = function(window, $, undefined) { $document, _captureUnhandledRejections = true, _setCookieAsSecure = false, + _clientIp, detachPromiseRejectionFunction; var rand = Math.random(); @@ -144,6 +145,10 @@ var raygunFactory = function(window, $, undefined) { if (options.from) { _loadedFrom = options.from; } + + if(options.clientIp) { + _clientIp = options.clientIp; + } } ensureUser(); @@ -362,6 +367,11 @@ var raygunFactory = function(window, $, undefined) { } } }, + + setClientIp: function(ip) { + _clientIp = ip; + }, + recordBreadcrumb: function() { _breadcrumbs.recordBreadcrumb.apply(_breadcrumbs, arguments); }, @@ -1019,6 +1029,10 @@ var raygunFactory = function(window, $, undefined) { var xhr = createCORSRequest('POST', url, data); if (typeof xhr.setRequestHeader === 'function') { xhr.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8'); + + if(typeof _clientIp !== "undefined") { + xhr.setRequestHeader('X-Remote-Address', _clientIp); + } } if (typeof _beforeXHRCallback === 'function') { diff --git a/src/raygun.loader.js b/src/raygun.loader.js index 8c5f07da..f4b1949a 100644 --- a/src/raygun.loader.js +++ b/src/raygun.loader.js @@ -195,6 +195,9 @@ case 'logContentsOfXhrCalls': rg.setBreadcrumbOption('logXhrContents', pair[1]); break; + case 'clientIp': + rg.setClientIp(value); + break; case 'captureUnhandledRejections': captureUnhandledRejections = value; break; diff --git a/tests/fixtures/common/instrumentXHRs.js b/tests/fixtures/common/instrumentXHRs.js index 91a6c775..33def691 100644 --- a/tests/fixtures/common/instrumentXHRs.js +++ b/tests/fixtures/common/instrumentXHRs.js @@ -2,9 +2,30 @@ window.__requestPayloads = []; window.__inFlightXHRs = []; window.__completedXHRs = []; + window.__sentXHRs = []; var origOpen = XMLHttpRequest.prototype.open; var origSend = XMLHttpRequest.prototype.send; + + var origSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader; + + XMLHttpRequest.prototype.setRequestHeader = function() { + if(!this.__headers) { + this.__headers = {}; + } + this.__headers[arguments[0]] = arguments[1]; + + origSetRequestHeader.apply(this, arguments); + }; + + XMLHttpRequest.prototype.getRequestHeader = function() { + if(!this.__headers) { + this.__headers = {}; + } + + var header = arguments[0]; + return this.__headers[header] || null; + }; XMLHttpRequest.prototype.open = function() { @@ -29,8 +50,13 @@ window.__requestPayloads.push(json); } + window.__sentXHRs.push({ + xhr: this, + clientIp: this.getRequestHeader('X-Remote-Address') + }); + origSend.apply(this, arguments); - } + }; if (window.XDomainRequest) { var origXOpen = XDomainRequest.prototype.open; @@ -58,6 +84,6 @@ window.__requestPayloads.push(JSON.parse(arguments[0])); origXSend.apply(this, arguments); - } + }; } })() diff --git a/tests/fixtures/v2/withClientIpSet.html b/tests/fixtures/v2/withClientIpSet.html new file mode 100644 index 00000000..2a9e59f5 --- /dev/null +++ b/tests/fixtures/v2/withClientIpSet.html @@ -0,0 +1,27 @@ + + + + + Raygun4JS with Client IP + + + + + + + + diff --git a/tests/fixtures/v2/withoutClientIpSet.html b/tests/fixtures/v2/withoutClientIpSet.html new file mode 100644 index 00000000..edd179c4 --- /dev/null +++ b/tests/fixtures/v2/withoutClientIpSet.html @@ -0,0 +1,26 @@ + + + + + Raygun4JS without Client IP + + + + + + + + diff --git a/tests/specs/v2/clientIp.js b/tests/specs/v2/clientIp.js new file mode 100644 index 00000000..fe819819 --- /dev/null +++ b/tests/specs/v2/clientIp.js @@ -0,0 +1,38 @@ +/* globals describe, beforeEach, it, expect, browser, window */ + +var _ = require('underscore'); + +describe("ClientIp", function() { + + it("X-Remote-Address is null when not set", function () { + browser.url('http://localhost:4567/fixtures/v2/withoutClientIpSet.html'); + + browser.pause(4000); + + var sentXhrs = browser.execute(function () { + return window.__sentXHRs; + }); + + var remoteAddressIsUndefined = _.every(sentXhrs.value, function (req) { + return req.clientIp === null; + }); + + expect(remoteAddressIsUndefined).toBe(true); + }); + + it("X-Remote-Address is equal to '192.168.0.12'", function () { + browser.url('http://localhost:4567/fixtures/v2/withClientIpSet.html'); + + browser.pause(4000); + + var sentXhrs = browser.execute(function () { + return window.__sentXHRs; + }); + + var remoteAddressIsSet = _.every(sentXhrs.value, function (req) { + return req.clientIp === "192.168.0.12"; + }); + + expect(remoteAddressIsSet).toBe(true); + }); +});