Use tab-specific stream storage
Also: - Use webNavigation.getAllFrames to find out whether the navigation has already started. This is (at least) needed for top-level navigation to a stream. The webNavigation.onErrorOccurred event has become obsolete, and has been removed.
This commit is contained in:
parent
32313b9149
commit
94ba01c8aa
@ -19,7 +19,11 @@ limitations under the License.
|
|||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
// Hash map of "<pdf url>": "<stream url>"
|
//
|
||||||
|
// Stream URL storage manager
|
||||||
|
//
|
||||||
|
|
||||||
|
// Hash map of "<tab id>": { "<pdf url>": ["<stream url>", ...], ... }
|
||||||
var urlToStream = {};
|
var urlToStream = {};
|
||||||
|
|
||||||
// Note: Execution of this script stops when the streamsPrivate API is
|
// Note: Execution of this script stops when the streamsPrivate API is
|
||||||
@ -28,18 +32,56 @@ var urlToStream = {};
|
|||||||
// when the streamsPrivate API is unavailable.
|
// when the streamsPrivate API is unavailable.
|
||||||
chrome.streamsPrivate.onExecuteMimeTypeHandler.addListener(handleStream);
|
chrome.streamsPrivate.onExecuteMimeTypeHandler.addListener(handleStream);
|
||||||
|
|
||||||
|
// Chrome before 27 does not support tabIds on stream events.
|
||||||
|
var streamSupportsTabId = true;
|
||||||
|
// "tabId" used for Chrome before 27.
|
||||||
|
var STREAM_NO_TABID = 0;
|
||||||
|
|
||||||
|
function hasStream(tabId, pdfUrl) {
|
||||||
|
var streams = urlToStream[streamSupportsTabId ? tabId : STREAM_NO_TABID];
|
||||||
|
return streams && streams[pdfUrl] && streams[pdfUrl].length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get stream URL for a given tabId and PDF url. The retrieved stream URL
|
||||||
|
* will be removed from the list.
|
||||||
|
* @return {string|undefined} The blob:-URL
|
||||||
|
*/
|
||||||
|
function getStream(tabId, pdfUrl) {
|
||||||
|
if (!streamSupportsTabId) tabId = STREAM_NO_TABID;
|
||||||
|
if (hasStream(tabId, pdfUrl)) {
|
||||||
|
var streamUrl = urlToStream[tabId][pdfUrl].shift();
|
||||||
|
if (urlToStream[tabId][pdfUrl].length === 0) {
|
||||||
|
delete urlToStream[tabId][pdfUrl];
|
||||||
|
if (Object.keys(urlToStream[tabId]).length === 0) {
|
||||||
|
delete urlToStream[tabId];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return streamUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setStream(tabId, pdfUrl, streamUrl) {
|
||||||
|
tabId = tabId || STREAM_NO_TABID;
|
||||||
|
if (!urlToStream[tabId]) urlToStream[tabId] = {};
|
||||||
|
if (!urlToStream[tabId][pdfUrl]) urlToStream[tabId][pdfUrl] = [];
|
||||||
|
urlToStream[tabId][pdfUrl].push(streamUrl);
|
||||||
|
}
|
||||||
|
|
||||||
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
||||||
if (message && message.action === 'getPDFStream') {
|
if (message && message.action === 'getPDFStream') {
|
||||||
var pdfUrl = message.data;
|
var pdfUrl = message.data;
|
||||||
var streamUrl = urlToStream[pdfUrl];
|
var streamUrl = getStream(sender.tab.id, pdfUrl);
|
||||||
// The stream can be used only once.
|
|
||||||
delete urlToStream[pdfUrl];
|
|
||||||
sendResponse({
|
sendResponse({
|
||||||
streamUrl: streamUrl
|
streamUrl: streamUrl
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// PDF detection and activation of PDF viewer.
|
||||||
|
//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for when we receive a stream
|
* Callback for when we receive a stream
|
||||||
*
|
*
|
||||||
@ -52,12 +94,51 @@ chrome.runtime.onMessage.addListener(function(message, sender, sendResponse) {
|
|||||||
function handleStream(mimeType, pdfUrl, streamUrl, tabId) {
|
function handleStream(mimeType, pdfUrl, streamUrl, tabId) {
|
||||||
console.log('Intercepted ' + mimeType + ' in tab ' + tabId + ' with URL ' +
|
console.log('Intercepted ' + mimeType + ' in tab ' + tabId + ' with URL ' +
|
||||||
pdfUrl + '\nAvailable as: ' + streamUrl);
|
pdfUrl + '\nAvailable as: ' + streamUrl);
|
||||||
urlToStream[pdfUrl] = streamUrl;
|
streamSupportsTabId = typeof tabId === 'number';
|
||||||
|
|
||||||
|
setStream(tabId, pdfUrl, streamUrl);
|
||||||
|
|
||||||
|
if (!tabId) { // Chrome doesn't set the tabId before v27
|
||||||
|
// PDF.js targets Chrome 28+ because of fatal bugs in incognito mode
|
||||||
|
// for older versions of Chrome. So, don't bother implementing a fallback.
|
||||||
|
// For those who are interested, either loop through all tabs, or use the
|
||||||
|
// webNavigation.onBeforeNavigate event to map pdfUrls to tab + frame IDs.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the frame has already been rendered.
|
||||||
|
chrome.webNavigation.getAllFrames({
|
||||||
|
tabId: tabId
|
||||||
|
}, function(details) {
|
||||||
|
if (details) {
|
||||||
|
details = details.filter(function(frame) {
|
||||||
|
return frame.url === pdfUrl;
|
||||||
|
});
|
||||||
|
if (details.length > 0) {
|
||||||
|
if (details.length !== 1) {
|
||||||
|
// (Rare case) Multiple frames with same URL.
|
||||||
|
// TODO(rob): Find a better way to handle this case.
|
||||||
|
console.warn('More than one frame found for tabId ' + tabId +
|
||||||
|
' with URL ' + pdfUrl + '. Using first frame.');
|
||||||
|
}
|
||||||
|
details = details[0];
|
||||||
|
details = {
|
||||||
|
tabId: tabId,
|
||||||
|
frameId: details.frameId,
|
||||||
|
url: details.url
|
||||||
|
};
|
||||||
|
handleWebNavigation(details);
|
||||||
|
} else {
|
||||||
|
console.warn('No webNavigation frames found for tabId ' + tabId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('Unable to get frame information for tabId ' + tabId);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback for when a navigation error has occurred.
|
* This method is called when the chrome.streamsPrivate API has intercepted
|
||||||
* This event is triggered when the chrome.streamsPrivate API has intercepted
|
|
||||||
* the PDF stream. This method detects such streams, finds the frame where
|
* the PDF stream. This method detects such streams, finds the frame where
|
||||||
* the request was made, and loads the viewer in that frame.
|
* the request was made, and loads the viewer in that frame.
|
||||||
*
|
*
|
||||||
@ -67,18 +148,17 @@ function handleStream(mimeType, pdfUrl, streamUrl, tabId) {
|
|||||||
* @param details.frameId {number} 0 indicates the navigation happens in the tab
|
* @param details.frameId {number} 0 indicates the navigation happens in the tab
|
||||||
* content window; a positive value indicates
|
* content window; a positive value indicates
|
||||||
* navigation in a subframe.
|
* navigation in a subframe.
|
||||||
* @param details.error {string}
|
|
||||||
*/
|
*/
|
||||||
function webNavigationOnErrorOccurred(details) {
|
function handleWebNavigation(details) {
|
||||||
var tabId = details.tabId;
|
var tabId = details.tabId;
|
||||||
var frameId = details.frameId;
|
var frameId = details.frameId;
|
||||||
var pdfUrl = details.url;
|
var pdfUrl = details.url;
|
||||||
|
|
||||||
if (details.error === 'net::ERR_ABORTED') {
|
if (!hasStream(tabId, pdfUrl)) {
|
||||||
if (!urlToStream[pdfUrl]) {
|
console.log('No PDF stream found in tab ' + tabId + ' for ' + pdfUrl);
|
||||||
console.log('No saved PDF stream found for ' + pdfUrl);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var viewerUrl = getViewerURL(pdfUrl);
|
var viewerUrl = getViewerURL(pdfUrl);
|
||||||
|
|
||||||
if (frameId === 0) { // Main frame
|
if (frameId === 0) { // Main frame
|
||||||
@ -100,6 +180,3 @@ function webNavigationOnErrorOccurred(details) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
chrome.webNavigation.onErrorOccurred.addListener(webNavigationOnErrorOccurred);
|
|
||||||
|
Loading…
Reference in New Issue
Block a user