-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support for transport plugins #183
Changes from all commits
c043afe
e0bb8ef
c33201a
e0126b4
e893c65
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/** | ||
* Chrome/V8 XHR Post plugin | ||
* | ||
* Allows raven-js to send log entries using XHR and CORS for | ||
* environments where the Origin and Referer headers are missing (e.g Chrome plugins). | ||
* | ||
* Usage: Raven.config('https+post://...'); | ||
* */ | ||
|
||
;(function(window, Raven, undefined){ | ||
'use strict'; | ||
var V8Transport = window.V8Transport = { | ||
setup: function(dsn, triggerEvent){ | ||
if(!this.hasCORS() && window.console && console.error){ | ||
console.error('This browser lacks support for CORS. Falling back to the default transport'); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. |
||
delete dsn.pass; | ||
HTTPGetTransport.setup(dsn); | ||
return HTTPGetTransport; | ||
} | ||
|
||
if(!dsn.pass) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd recommend also checking if the user wants https here so they could also use http+post if(!dsn.pass && dsn.protocol == 'https+post') |
||
throw new RavenConfigError('The https+post V8 transport needs the private key to be set in the DSN.'); | ||
|
||
this.triggerEvent = triggerEvent; | ||
this.dsn = dsn; | ||
return this; | ||
}, | ||
|
||
hasCORS: function(){ | ||
return 'withCredentials' in new XMLHttpRequest(); | ||
}, | ||
|
||
getAuthString: function(){ | ||
if (this.cachedAuth) return this.cachedAuth; | ||
|
||
var qs = [ | ||
'sentry_version=4', | ||
'sentry_client=raven-js/' + Raven.VERSION, | ||
'sentry_key=' + this.dsn.user, | ||
'sentry_secret=' + this.dsn.pass | ||
]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd make pass optional for people who just want http. var qs = [
'sentry_version=4',
'sentry_client=raven-js/' + Raven.VERSION,
'sentry_key=' + this.dsn.user
];
if (this.dsn.pass) {
qs.push('sentry_secret=' + this.dsn.pass);
} |
||
|
||
return this.cachedAuth = 'Sentry ' + qs.join(','); | ||
}, | ||
|
||
send: function(data, endpoint){ | ||
var xhr = new XMLHttpRequest(), | ||
triggerEvent = this.triggerEvent; | ||
|
||
|
||
xhr.open('POST', endpoint, true); | ||
xhr.setRequestHeader('X-Sentry-Auth', this.getAuthString()); | ||
xhr.setRequestHeader('Content-Type', 'application/json; charset=utf-8'); | ||
|
||
xhr.onload = function success() { | ||
triggerEvent('success', { | ||
data: data, | ||
src: endpoint | ||
}); | ||
}; | ||
xhr.onerror = xhr.onabort = function failure() { | ||
triggerEvent('failure', { | ||
data: data, | ||
src: endpoint | ||
}); | ||
}; | ||
|
||
xhr.send(JSON.stringify(data)); | ||
} | ||
} | ||
|
||
Raven.registerTransport('https+post', V8Transport); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And I would add Raven.registerTransport('http+post', V8Transport); |
||
}(this, Raven)); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,49 @@ | ||
'use strict'; | ||
|
||
/* | ||
* Default transport. | ||
* */ | ||
var HTTPGetTransport = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. .. and this one ImageTransport? |
||
setup: function(dsn, triggerEvent){ | ||
if (dsn.pass) | ||
throw new RavenConfigError('Do not specify your private key in the DSN!'); | ||
this.dsn = dsn; | ||
this.triggerEvent = triggerEvent; | ||
}, | ||
send: function(data, endpoint){ | ||
var img = new Image(), | ||
triggerEvent = this.triggerEvent, | ||
src = endpoint + this.getAuthQueryString() + '&sentry_data=' + encodeURIComponent(JSON.stringify(data)); | ||
|
||
img.onload = function success() { | ||
triggerEvent('success', { | ||
data: data, | ||
src: src | ||
}); | ||
}; | ||
img.onerror = img.onabort = function failure() { | ||
triggerEvent('failure', { | ||
data: data, | ||
src: src | ||
}); | ||
}; | ||
img.src = src; | ||
}, | ||
|
||
getAuthQueryString: function() { | ||
if (this.cachedAuth) return this.cachedAuth; | ||
var qs = [ | ||
'sentry_version=4', | ||
'sentry_client=raven-js/' + Raven.VERSION | ||
]; | ||
if (globalKey) { | ||
qs.push('sentry_key=' + this.dsn.user); | ||
} | ||
|
||
return this.cachedAuth = '?' + qs.join('&'); | ||
} | ||
}; | ||
|
||
// First, check for JSON support | ||
// If there is no JSON, we no-op the core features of Raven | ||
// since JSON is required to encode the payload | ||
|
@@ -10,6 +54,8 @@ var _Raven = window.Raven, | |
globalUser, | ||
globalKey, | ||
globalProject, | ||
globalTransports = { 'default': HTTPGetTransport }, | ||
globalTransport = null, | ||
globalOptions = { | ||
logger: 'javascript', | ||
ignoreErrors: [], | ||
|
@@ -21,6 +67,7 @@ var _Raven = window.Raven, | |
extra: {} | ||
}; | ||
|
||
|
||
/* | ||
* The core Raven singleton | ||
* | ||
|
@@ -95,7 +142,9 @@ var Raven = { | |
'/' + path + 'api/' + globalProject + '/store/'; | ||
|
||
if (uri.protocol) { | ||
globalServer = uri.protocol + ':' + globalServer; | ||
// Only use the first part of the url if it contains | ||
// a plugin identifier, e.g https+post -> https | ||
globalServer = uri.protocol.split('+')[0] + ':' + globalServer; | ||
} | ||
|
||
if (globalOptions.fetchContext) { | ||
|
@@ -108,6 +157,13 @@ var Raven = { | |
|
||
TraceKit.collectWindowErrors = !!globalOptions.collectWindowErrors; | ||
|
||
globalTransport = uri.protocol && globalTransports[uri.protocol] ? globalTransports[uri.protocol] : globalTransports['default']; | ||
|
||
// Allow transports to fall back to other transport protocols, | ||
// if the chosen one isn't supported | ||
var transport = globalTransport.setup(uri, triggerEvent); | ||
globalTransport = transport ? transport : globalTransport; | ||
|
||
// return for chaining | ||
return Raven; | ||
}, | ||
|
@@ -128,6 +184,23 @@ var Raven = { | |
return Raven; | ||
}, | ||
|
||
|
||
|
||
/* | ||
* Register a transport plugin for pushing data into Sentry. | ||
* Transport plugins are chosen based upon the DSN passed into Raven.configure, | ||
* e.g Raven.configure('http://...') will use the plugin registered for 'http'. | ||
* | ||
* @param {string} protocol A protocol identifier in the DSN, e.g http or https+post | ||
* @param {object} transport An implementation of the transport. Must implement the `setup(dsn)` and `send(data, endpoint)` methods. | ||
*/ | ||
registerTransport: function(protocol, transport){ | ||
if(globalTransports[protocol]) throw new RavenConfigError('Protocol ' + protocol + ' already has a registered transport method'); | ||
|
||
globalTransports[protocol] = transport; | ||
return Raven; | ||
}, | ||
|
||
/* | ||
* Wrap code within a context so Raven can capture errors | ||
* reliably across domains that is executed immediately. | ||
|
@@ -321,7 +394,7 @@ function triggerEvent(eventType, options) { | |
} | ||
|
||
var dsnKeys = 'source protocol user pass host port path'.split(' '), | ||
dsnPattern = /^(?:(\w+):)?\/\/(\w+)(:\w+)?@([\w\.-]+)(?::(\d+))?(\/.*)/; | ||
dsnPattern = /^(?:(\w+|\w+\+\w+)?:)?\/\/(\w+)(?::(\w+))?@([\w\.-]+)(?::(\d+))?(\/.*)/; | ||
|
||
function RavenConfigError(message) { | ||
this.name = 'RavenConfigError'; | ||
|
@@ -334,17 +407,14 @@ RavenConfigError.prototype.constructor = RavenConfigError; | |
function parseDSN(str) { | ||
var m = dsnPattern.exec(str), | ||
dsn = {}, | ||
i = 7; | ||
i = dsnKeys.length; | ||
|
||
try { | ||
while (i--) dsn[dsnKeys[i]] = m[i] || ''; | ||
} catch(e) { | ||
throw new RavenConfigError('Invalid DSN: ' + str); | ||
} | ||
|
||
if (dsn.pass) | ||
throw new RavenConfigError('Do not specify your private key in the DSN!'); | ||
|
||
return dsn; | ||
} | ||
|
||
|
@@ -395,23 +465,6 @@ function each(obj, callback) { | |
} | ||
} | ||
|
||
var cachedAuth; | ||
|
||
function getAuthQueryString() { | ||
if (cachedAuth) return cachedAuth; | ||
|
||
var qs = [ | ||
'sentry_version=4', | ||
'sentry_client=raven-js/' + Raven.VERSION | ||
]; | ||
if (globalKey) { | ||
qs.push('sentry_key=' + globalKey); | ||
} | ||
|
||
cachedAuth = '?' + qs.join('&'); | ||
return cachedAuth; | ||
} | ||
|
||
function handleStackInfo(stackInfo, options) { | ||
var frames = []; | ||
|
||
|
@@ -619,22 +672,7 @@ function send(data) { | |
|
||
|
||
function makeRequest(data) { | ||
var img = new Image(), | ||
src = globalServer + getAuthQueryString() + '&sentry_data=' + encodeURIComponent(JSON.stringify(data)); | ||
|
||
img.onload = function success() { | ||
triggerEvent('success', { | ||
data: data, | ||
src: src | ||
}); | ||
}; | ||
img.onerror = img.onabort = function failure() { | ||
triggerEvent('failure', { | ||
data: data, | ||
src: src | ||
}); | ||
}; | ||
img.src = src; | ||
globalTransport.send(data, globalServer); | ||
} | ||
|
||
function isSetup() { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not call this one XHRTransport?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because sadly, this doesn't just work everywhere that XHR is accepted, so this is specific to V8.