Use redirectUrl at onHeadersReceived if available.

http://crbug.com/280464 has been resolved, so we can now use redirectUrl at
onHeadersReceived.
For backwards-compatibility, the code for the original method has not been
removed, and a feature detection script was added that detects whether the
desired feature is available.
This commit is contained in:
Rob Wu 2014-03-30 00:25:37 +01:00
parent d04f81b964
commit ae32f31eb4
2 changed files with 70 additions and 4 deletions

View File

@ -23,6 +23,8 @@ var Features = {
featureDetectLastUA: '', featureDetectLastUA: '',
// Whether ftp: in XMLHttpRequest is allowed // Whether ftp: in XMLHttpRequest is allowed
extensionSupportsFTP: false, extensionSupportsFTP: false,
// Whether redirectUrl at onHeadersReceived is supported.
webRequestRedirectUrl: false,
}; };
chrome.storage.local.get(Features, function(features) { chrome.storage.local.get(Features, function(features) {
@ -31,13 +33,34 @@ chrome.storage.local.get(Features, function(features) {
// Browser not upgraded, so the features did probably not change. // Browser not upgraded, so the features did probably not change.
return; return;
} }
var inconclusiveTestCount = 0;
if (!features.extensionSupportsFTP) { if (!features.extensionSupportsFTP) {
features.extensionSupportsFTP = featureTestFTP(); features.extensionSupportsFTP = featureTestFTP();
} }
Features.featureDetectLastUA = navigator.userAgent; if (!features.webRequestRedirectUrl) {
chrome.storage.local.set(Features); ++inconclusiveTestCount;
// Relatively expensive (and asynchronous) test:
featureTestRedirectOnHeadersReceived(function(result) {
// result = 'yes', 'no' or 'maybe'.
if (result !== 'maybe') {
--inconclusiveTestCount;
}
features.webRequestRedirectUrl = result === 'yes';
checkTestCompletion();
});
}
checkTestCompletion();
function checkTestCompletion() {
// Only stamp the feature detection results when all tests have finished.
if (inconclusiveTestCount === 0) {
Features.featureDetectLastUA = navigator.userAgent;
}
chrome.storage.local.set(Features);
}
}); });
// Tests whether the extension can perform a FTP request. // Tests whether the extension can perform a FTP request.
@ -56,3 +79,43 @@ function featureTestFTP() {
return false; return false;
} }
} }
// Tests whether redirectUrl at the onHeadersReceived stage is functional.
// Feature is supported since Chromium 35.0.1911.0 (r259546).
function featureTestRedirectOnHeadersReceived(callback) {
// The following URL is really going to be accessed via the network.
// It is the only way to feature-detect this feature, because the
// onHeadersReceived event is only triggered for http(s) requests.
var url = 'http://example.com/?feature-detect-' + chrome.runtime.id;
function onHeadersReceived(details) {
// If supported, the request is redirected.
// If not supported, the return value is ignored.
return {
redirectUrl: chrome.runtime.getURL('/manifest.json')
};
}
chrome.webRequest.onHeadersReceived.addListener(onHeadersReceived, {
types: ['xmlhttprequest'],
urls: [url]
}, ['blocking']);
var x = new XMLHttpRequest();
x.open('get', url);
x.onloadend = function() {
chrome.webRequest.onHeadersReceived.removeListener(onHeadersReceived);
if (!x.responseText) {
// Network error? Anyway, can't tell with certainty whether the feature
// is supported.
callback('maybe');
} else if (/^\s*\{/.test(x.responseText)) {
// If the response starts with "{", assume that the redirection to the
// manifest file succeeded, so the feature is supported.
callback('yes');
} else {
// Did not get the content of manifest.json, so the redirect seems not to
// be followed. The feature is not supported.
callback('no');
}
};
x.send();
}

View File

@ -114,8 +114,11 @@ chrome.webRequest.onHeadersReceived.addListener(
var viewerUrl = getViewerURL(details.url); var viewerUrl = getViewerURL(details.url);
// Replace frame with viewer // Replace frame with viewer
// TODO: When http://crbug.com/280464 is fixed, use if (Features.webRequestRedirectUrl) {
// return { redirectUrl: viewerUrl }; return { redirectUrl: viewerUrl };
}
// Aww.. redirectUrl is not yet supported, so we have to use a different
// method as fallback (Chromium <35).
if (details.frameId === 0) { if (details.frameId === 0) {
// Main frame. Just replace the tab and be done! // Main frame. Just replace the tab and be done!