diff --git a/background.js b/background.js index 76f97b7..fbf1f80 100644 --- a/background.js +++ b/background.js @@ -1,3 +1,4 @@ +(function() { /** * A dictionary of header settings, keyed using the URLs supplied in the Options page */ @@ -18,6 +19,11 @@ var alteredCount = 0; */ var displayCount = true; +/** + * Cache with of request specific data + */ +var requestIds; + /** * Returns the index of a given header object in the provided array * @param headerArray The Array to search in @@ -36,18 +42,31 @@ function getHeaderIndex(headerArray, newHeader) { return -1; } -function mergeNewHeaders(originalHeaders, newHeaders) { +function mergeNewHeaders(originalHeaders, newHeaders, origin) { //copy the headers for our own usage var mergedHeaders = originalHeaders.slice(); for (var i = 0, len = newHeaders.length; i < len; i++) { - var index = getHeaderIndex(mergedHeaders, newHeaders[i]); - - //if a matching header is defined, replace it - //if not, add the new header to the end - if (index > -1) { - mergedHeaders[index] = newHeaders[i]; - } else { - mergedHeaders.push(newHeaders[i]); + var thisHeader = newHeaders[i]; + + //skip if both are blank + if (thisHeader.name || thisHeader.value) { + var index = getHeaderIndex(mergedHeaders, thisHeader); + + //issue #9 - fix - use new object to not over-write passed in reference + if (thisHeader.value === "HTTP_ORIGIN") { + thisHeader = { + name: thisHeader.name, + value: origin + }; + } + + //if a matching header is defined, replace it + //if not, add the new header to the end + if (index > -1) { + mergedHeaders[index] = thisHeader; + } else { + mergedHeaders.push(thisHeader); + } } } @@ -101,8 +120,80 @@ function onHeadersReceivedHandler(info) { chrome.browserAction.setBadgeText({ text:(++alteredCount).toString()}); } - return { responseHeaders:mergeNewHeaders(info.responseHeaders, desiredHeaders) }; + var request = getRequestAndCleanUp(info); + var origin = request ? request.origin : "*"; // default to all if nothing is found + return { responseHeaders: mergeNewHeaders(info.responseHeaders, desiredHeaders, origin) }; +} + +/** + * Responds to Chrome's onBeforeSendHeaders event and finds 'origin' or 'referer' header for use later + * @param info {Object} Contains the request info + * @see http://code.google.com/chrome/extensions/webRequest.html#event-onBeforeSendHeaders + */ +function onBeforeSendHeadersHandler(info) { + var origin = null; + + for (var i = 0, len = info.requestHeaders.length; i < len; i++) { + var header = info.requestHeaders[i]; + if (header.name === "Origin") { // be done + origin = header.value; + break; + } + if (header.name === "Referer") { // keep going + origin = header.value; + } + } + + //push on to stack + if (origin) { + requestIds.push({ + requestId: info.requestId, + origin: origin, + expiration: Math.round(info.timeStamp) + 10E3 + }); + } + + return {requestHeaders: info.requestHeaders}; +}; + +/** + * Find the request and garbage collect the other requests. This should clean up orphan requests. + * @param info {Object} Contains the request info + */ +function getRequestAndCleanUp(info) { + + var requestId = info.requestId; + var now = Math.ceil(info.timeStamp); + + var request = null; + + // Array.prototype.filter method + // - callback ~ return true (keep) or false (remove) + // - finds the current element - fitlered + // - return true (keep) if now is less than expiration + // + requestIds = requestIds.filter(function(elem) { + if (elem.requestId === requestId) { + request = elem; + return false; + } + return (now < elem.expiration); + }); + + return request; +} + +/** + * Responds to Chrome's onErrorOccurred event + * @param info {Object} Contains the request info + * @see http://code.google.com/chrome/extensions/webRequest.html#event-onErrorOccurred + */ +function onErrorOccurredHandler(info) { + //still works but Chrome still complains ... this is the only property that is different from a normal request + if (info.type !== "xmlhttprequest") { + console.log('ForceCORS was unable to modify headers for: '+info.url +' - '+info.error); + } } /** @@ -116,8 +207,6 @@ function showOptionsPage() { ); } - - /** * Initializes the background page by retrieving settings and establishing the onHeadersReceived listener. * This method is called upon initialization, and also when the user changes settings on the Options page. @@ -127,6 +216,7 @@ function init() { var settings = retrieveSettings(); headersPerUrl = {}; urlsToAlter = []; + requestIds = []; if (settings) { for (var l = settings.length, i = 0; i < l; i++) { @@ -150,29 +240,26 @@ function init() { if (chrome.webRequest.onHeadersReceived.hasListener(onHeadersReceivedHandler)) { chrome.webRequest.onHeadersReceived.removeListener(onHeadersReceivedHandler) } + chrome.webRequest.onHeadersReceived.addListener(onHeadersReceivedHandler, {urls: urlsToAlter}, ["blocking", "responseHeaders"]); - chrome.webRequest.onHeadersReceived.addListener( - onHeadersReceivedHandler, - // filters - { - urls:urlsToAlter - }, - // extraInfoSpec - ["blocking", "responseHeaders"] - ); + //same logic + if (chrome.webRequest.onBeforeSendHeaders.hasListener(onBeforeSendHeadersHandler)) { + chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeadersHandler) + } + chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeadersHandler, {urls: urlsToAlter}, ["requestHeaders"]); - chrome.webRequest.onErrorOccurred.addListener( - function(info){console.log('ForceCORS was unable to modify headers for: '+info.url +' - '+info.error)}, - { - urls:urlsToAlter - } - ); + //dido + if (chrome.webRequest.onErrorOccurred.hasListener(onErrorOccurredHandler)) { + chrome.webRequest.onErrorOccurred.removeListener(onErrorOccurredHandler); + } + chrome.webRequest.onErrorOccurred.addListener(onErrorOccurredHandler, {urls: urlsToAlter}); + //let chrome know chrome.webRequest.handlerBehaviorChanged(); } //establish a listener to respond to changes from the Options page -chrome.extension.onRequest.addListener(function (request, sender, sendResponse) { +chrome.extension.onRequest.addListener(function (request_not_used, sender_not_used, sendResponse) { //retrigger the init method to load the new settings init(); @@ -180,6 +267,7 @@ chrome.extension.onRequest.addListener(function (request, sender, sendResponse) sendResponse(); }); - //make rocket go now! -init(); \ No newline at end of file +init(); + +})(); \ No newline at end of file