diff --git a/extensions/chromium/feature-detect.js b/extensions/chromium/feature-detect.js
new file mode 100644
index 000000000..121672c0a
--- /dev/null
+++ b/extensions/chromium/feature-detect.js
@@ -0,0 +1,121 @@
+/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
+/*
+Copyright 2014 Mozilla Foundation
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+/* globals chrome */
+
+'use strict';
+
+var Features = {
+ featureDetectLastUA: '',
+ // Whether ftp: in XMLHttpRequest is allowed
+ extensionSupportsFTP: false,
+ // Whether redirectUrl at onHeadersReceived is supported.
+ webRequestRedirectUrl: false,
+};
+
+chrome.storage.local.get(Features, function(features) {
+ Features = features;
+ if (features.featureDetectLastUA === navigator.userAgent) {
+ // Browser not upgraded, so the features did probably not change.
+ return;
+ }
+ var inconclusiveTestCount = 0;
+
+ if (!features.extensionSupportsFTP) {
+ features.extensionSupportsFTP = featureTestFTP();
+ }
+
+ if (!features.webRequestRedirectUrl) {
+ ++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.
+// Feature is supported since Chromium 35.0.1888.0 (r256810).
+function featureTestFTP() {
+ var x = new XMLHttpRequest();
+ // The URL does not need to exist, as long as the scheme is ftp:.
+ x.open('GET', 'ftp://ftp.mozilla.org/');
+ try {
+ x.send();
+ // Previous call did not throw error, so the feature is supported!
+ // Immediately abort the request so that the network is not hit at all.
+ x.abort();
+ return true;
+ } catch (e) {
+ 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();
+}
diff --git a/extensions/chromium/pdfHandler-v2.js b/extensions/chromium/pdfHandler-v2.js
index 711c35d6f..9bfbc099a 100644
--- a/extensions/chromium/pdfHandler-v2.js
+++ b/extensions/chromium/pdfHandler-v2.js
@@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-/* globals chrome, URL, getViewerURL */
+/* globals chrome, URL, getViewerURL, Features */
(function() {
'use strict';
@@ -158,7 +158,8 @@ limitations under the License.
var streamInfo = getStream(sender.tab.id, pdfUrl) || {};
sendResponse({
streamUrl: streamInfo.streamUrl,
- contentLength: streamInfo.contentLength
+ contentLength: streamInfo.contentLength,
+ extensionSupportsFTP: Features.extensionSupportsFTP
});
}
});
diff --git a/extensions/chromium/pdfHandler.html b/extensions/chromium/pdfHandler.html
index ffb6c1ae6..c98851363 100644
--- a/extensions/chromium/pdfHandler.html
+++ b/extensions/chromium/pdfHandler.html
@@ -15,6 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
-->
+
diff --git a/extensions/chromium/pdfHandler.js b/extensions/chromium/pdfHandler.js
index 99cdbae0f..5f5465b57 100644
--- a/extensions/chromium/pdfHandler.js
+++ b/extensions/chromium/pdfHandler.js
@@ -15,7 +15,7 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
-/* globals chrome */
+/* globals chrome, Features */
'use strict';
@@ -114,8 +114,11 @@ chrome.webRequest.onHeadersReceived.addListener(
var viewerUrl = getViewerURL(details.url);
// Replace frame with viewer
- // TODO: When http://crbug.com/280464 is fixed, use
- // return { redirectUrl: viewerUrl };
+ if (Features.webRequestRedirectUrl) {
+ 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) {
// Main frame. Just replace the tab and be done!
@@ -172,6 +175,27 @@ chrome.webRequest.onHeadersReceived.addListener(
},
['blocking','responseHeaders']);
+chrome.webRequest.onBeforeRequest.addListener(
+ function onBeforeRequestForFTP(details) {
+ if (!Features.extensionSupportsFTP) {
+ chrome.webRequest.onBeforeRequest.removeListener(onBeforeRequestForFTP);
+ return;
+ }
+ if (isPdfDownloadable(details)) {
+ return;
+ }
+ var viewerUrl = getViewerURL(details.url);
+ return { redirectUrl: viewerUrl };
+ },
+ {
+ urls: [
+ 'ftp://*/*.pdf',
+ 'ftp://*/*.PDF'
+ ],
+ types: ['main_frame', 'sub_frame']
+ },
+ ['blocking']);
+
chrome.webRequest.onBeforeRequest.addListener(
function(details) {
if (isPdfDownloadable(details)) {
diff --git a/web/viewer.js b/web/viewer.js
index 82a662749..6239bd9af 100644
--- a/web/viewer.js
+++ b/web/viewer.js
@@ -1880,9 +1880,10 @@ function webViewerLoad(evt) {
// PDFView.setTitleUsingUrl(file);
// return;
// }
-// if (isFTPFile) {
-// // Stream not found, and it's loaded from FTP. Reload the page, because
-// // it is not possible to get resources over ftp using XMLHttpRequest.
+// if (isFTPFile && !response.extensionSupportsFTP) {
+// // Stream not found, and it's loaded from FTP.
+// // When the browser does not support loading ftp resources over
+// // XMLHttpRequest, just reload the page.
// // NOTE: This will not lead to an infinite redirect loop, because
// // if the file exists, then the streamsPrivate API will capture the
// // stream and send back the response. If the stream does not exist, then