Merge pull request #5823 from Rob--W/preserve-http-referer
[Chrome extension] Add Referer request header if needed
This commit is contained in:
commit
8aa1c8102e
@ -16,6 +16,7 @@ limitations under the License.
|
||||
-->
|
||||
<script src="chrome.tabs.executeScriptInFrame.js"></script>
|
||||
<script src="feature-detect.js"></script>
|
||||
<script src="preserve-referer.js"></script>
|
||||
<script src="pdfHandler.js"></script>
|
||||
<script src="extension-router.js"></script>
|
||||
<script src="pdfHandler-v2.js"></script>
|
||||
|
@ -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, Features */
|
||||
/* globals chrome, Features, saveReferer */
|
||||
|
||||
'use strict';
|
||||
|
||||
@ -113,6 +113,9 @@ chrome.webRequest.onHeadersReceived.addListener(
|
||||
|
||||
var viewerUrl = getViewerURL(details.url);
|
||||
|
||||
// Implemented in preserve-referer.js
|
||||
saveReferer(details);
|
||||
|
||||
// Replace frame with viewer
|
||||
if (Features.webRequestRedirectUrl) {
|
||||
return { redirectUrl: viewerUrl };
|
||||
|
143
extensions/chromium/preserve-referer.js
Normal file
143
extensions/chromium/preserve-referer.js
Normal file
@ -0,0 +1,143 @@
|
||||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
|
||||
/*
|
||||
Copyright 2015 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, getHeaderFromHeaders */
|
||||
/* exported saveReferer */
|
||||
|
||||
'use strict';
|
||||
/**
|
||||
* This file is one part of the Referer persistency implementation. The other
|
||||
* part resides in chromecom.js.
|
||||
*
|
||||
* This file collects request headers for every http(s) request, and temporarily
|
||||
* stores the request headers in a dictionary. Upon completion of the request
|
||||
* (success or failure), the headers are discarded.
|
||||
* pdfHandler.js will call saveReferer(details) when it is about to redirect to
|
||||
* the viewer. Upon calling saveReferer, the Referer header is extracted from
|
||||
* the request headers and saved.
|
||||
*
|
||||
* When the viewer is opened, it opens a port ("chromecom-referrer"). This port
|
||||
* is used to set up the webRequest listeners that stick the Referer headers to
|
||||
* the HTTP requests created by this extension. When the port is disconnected,
|
||||
* the webRequest listeners and the referrer information is discarded.
|
||||
*
|
||||
* See setReferer in chromecom.js for more explanation of this logic.
|
||||
*/
|
||||
|
||||
// Remembers the request headers for every http(s) page request for the duration
|
||||
// of the request.
|
||||
var g_requestHeaders = {};
|
||||
// g_referrers[tabId][frameId] = referrer of PDF frame.
|
||||
var g_referrers = {};
|
||||
|
||||
(function() {
|
||||
var requestFilter = {
|
||||
urls: ['*://*/*'],
|
||||
types: ['main_frame', 'sub_frame']
|
||||
};
|
||||
chrome.webRequest.onSendHeaders.addListener(function(details) {
|
||||
g_requestHeaders[details.requestId] = details.requestHeaders;
|
||||
}, requestFilter, ['requestHeaders']);
|
||||
chrome.webRequest.onBeforeRedirect.addListener(forgetHeaders, requestFilter);
|
||||
chrome.webRequest.onCompleted.addListener(forgetHeaders, requestFilter);
|
||||
chrome.webRequest.onErrorOccurred.addListener(forgetHeaders, requestFilter);
|
||||
function forgetHeaders(details) {
|
||||
delete g_requestHeaders[details.requestId];
|
||||
}
|
||||
})();
|
||||
|
||||
/**
|
||||
* @param {object} details - onHeadersReceived event data.
|
||||
*/
|
||||
function saveReferer(details) {
|
||||
var referer = g_requestHeaders[details.requestId] &&
|
||||
getHeaderFromHeaders(g_requestHeaders[details.requestId], 'referer');
|
||||
referer = referer && referer.value || '';
|
||||
if (!g_referrers[details.tabId]) {
|
||||
g_referrers[details.tabId] = {};
|
||||
}
|
||||
g_referrers[details.tabId][details.frameId] = referer;
|
||||
}
|
||||
|
||||
chrome.tabs.onRemoved.addListener(function(tabId) {
|
||||
delete g_referrers[tabId];
|
||||
});
|
||||
|
||||
// This method binds a webRequest event handler which adds the Referer header
|
||||
// to matching PDF resource requests (only if the Referer is non-empty). The
|
||||
// handler is removed as soon as the PDF viewer frame is unloaded.
|
||||
chrome.runtime.onConnect.addListener(function onReceivePort(port) {
|
||||
if (port.name !== 'chromecom-referrer') {
|
||||
return;
|
||||
}
|
||||
// Note: sender.frameId is only set in Chrome 41+.
|
||||
if (!('frameId' in port.sender)) {
|
||||
port.disconnect();
|
||||
return;
|
||||
}
|
||||
var tabId = port.sender.tab.id;
|
||||
var frameId = port.sender.frameId;
|
||||
|
||||
// If the PDF is viewed for the first time, then the referer will be set here.
|
||||
var referer = g_referrers[tabId] && g_referrers[tabId][frameId] || '';
|
||||
port.onMessage.addListener(function(data) {
|
||||
// If the viewer was opened directly (without opening a PDF URL first), then
|
||||
// the background script does not know about g_referrers, but the viewer may
|
||||
// know about the referer if stored in the history state (see chromecom.js).
|
||||
if (data.referer) {
|
||||
referer = data.referer;
|
||||
}
|
||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
if (referer) {
|
||||
// Only add a blocking request handler if the referer has to be rewritten.
|
||||
chrome.webRequest.onBeforeSendHeaders.addListener(onBeforeSendHeaders, {
|
||||
urls: [data.requestUrl],
|
||||
types: ['xmlhttprequest'],
|
||||
tabId: tabId
|
||||
}, ['blocking', 'requestHeaders']);
|
||||
}
|
||||
// Acknowledge the message, and include the latest referer for this frame.
|
||||
port.postMessage(referer);
|
||||
});
|
||||
|
||||
// The port is only disconnected when the other end reloads.
|
||||
port.onDisconnect.addListener(function() {
|
||||
if (g_referrers[tabId]) {
|
||||
delete g_referrers[tabId][frameId];
|
||||
}
|
||||
chrome.webRequest.onBeforeSendHeaders.removeListener(onBeforeSendHeaders);
|
||||
});
|
||||
|
||||
function onBeforeSendHeaders(details) {
|
||||
if (details.frameId !== frameId) {
|
||||
return;
|
||||
}
|
||||
var headers = details.requestHeaders;
|
||||
var refererHeader = getHeaderFromHeaders(headers, 'referer');
|
||||
if (!refererHeader) {
|
||||
refererHeader = {name: 'Referer'};
|
||||
headers.push(refererHeader);
|
||||
} else if (refererHeader.value &&
|
||||
refererHeader.value.lastIndexOf('chrome-extension:', 0) !== 0) {
|
||||
// Sanity check. If the referer is set, and the value is not the URL of
|
||||
// this extension, then the request was not initiated by this extension.
|
||||
return;
|
||||
}
|
||||
refererHeader.value = referer;
|
||||
return {requestHeaders: headers};
|
||||
}
|
||||
});
|
@ -104,8 +104,70 @@ var ChromeCom = (function ChromeComClosure() {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (/^https?:/.test(file)) {
|
||||
// Assumption: The file being opened is the file that was requested.
|
||||
// There is no UI to input a different URL, so this assumption will hold
|
||||
// for now.
|
||||
setReferer(file, function() {
|
||||
PDFViewerApplication.open(file, 0);
|
||||
});
|
||||
return;
|
||||
}
|
||||
PDFViewerApplication.open(file, 0);
|
||||
});
|
||||
};
|
||||
|
||||
// This port is used for several purposes:
|
||||
// 1. When disconnected, the background page knows that the frame has unload.
|
||||
// 2. When the referrer was saved in history.state.chromecomState, it is sent
|
||||
// to the background page.
|
||||
// 3. When the background page knows the referrer of the page, the referrer is
|
||||
// saved in history.state.chromecomState.
|
||||
var port;
|
||||
// Set the referer for the given URL.
|
||||
// 0. Background: If loaded via a http(s) URL: Save referer.
|
||||
// 1. Page -> background: send URL and referer from history.state
|
||||
// 2. Background: Bind referer to URL (via webRequest).
|
||||
// 3. Background -> page: Send latest referer and save to history.
|
||||
// 4. Page: Invoke callback.
|
||||
function setReferer(url, callback) {
|
||||
if (!port) {
|
||||
// The background page will accept the port, and keep adding the Referer
|
||||
// request header to requests to |url| until the port is disconnected.
|
||||
port = chrome.runtime.connect({name: 'chromecom-referrer'});
|
||||
}
|
||||
port.onDisconnect.addListener(onDisconnect);
|
||||
port.onMessage.addListener(onMessage);
|
||||
// Initiate the information exchange.
|
||||
port.postMessage({
|
||||
referer: window.history.state && window.history.state.chromecomState,
|
||||
requestUrl: url
|
||||
});
|
||||
|
||||
function onMessage(referer) {
|
||||
if (referer) {
|
||||
// The background extracts the Referer from the initial HTTP request for
|
||||
// the PDF file. When the viewer is reloaded or when the user navigates
|
||||
// back and forward, the background page will not observe a HTTP request
|
||||
// with Referer. To make sure that the Referer is preserved, store it in
|
||||
// history.state, which is preserved accross reloads/navigations.
|
||||
var state = window.history.state || {};
|
||||
state.chromecomState = referer;
|
||||
window.history.replaceState(state, '');
|
||||
}
|
||||
onCompleted();
|
||||
}
|
||||
function onDisconnect() {
|
||||
// When the connection fails, ignore the error and call the callback.
|
||||
port = null;
|
||||
onCompleted();
|
||||
}
|
||||
function onCompleted() {
|
||||
port.onDisconnect.removeListener(onDisconnect);
|
||||
port.onMessage.removeListener(onMessage);
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
return ChromeCom;
|
||||
})();
|
||||
|
@ -135,6 +135,10 @@ var PDFHistory = (function () {
|
||||
});
|
||||
},
|
||||
|
||||
clearHistoryState: function pdfHistory_clearHistoryState() {
|
||||
this._pushOrReplaceState(null, true);
|
||||
},
|
||||
|
||||
_isStateObjectDefined: function pdfHistory_isStateObjectDefined(state) {
|
||||
return (state && state.uid >= 0 &&
|
||||
state.fingerprint && this.fingerprint === state.fingerprint &&
|
||||
@ -143,6 +147,13 @@ var PDFHistory = (function () {
|
||||
|
||||
_pushOrReplaceState: function pdfHistory_pushOrReplaceState(stateObj,
|
||||
replace) {
|
||||
//#if CHROME
|
||||
// history.state.chromecomState is managed by chromecom.js.
|
||||
if (window.history.state && 'chromecomState' in window.history.state) {
|
||||
stateObj = stateObj || {};
|
||||
stateObj.chromecomState = window.history.state.chromecomState;
|
||||
}
|
||||
//#endif
|
||||
if (replace) {
|
||||
//#if (GENERIC || CHROME)
|
||||
window.history.replaceState(stateObj, '', document.URL);
|
||||
|
@ -795,8 +795,8 @@ var PDFViewerApplication = {
|
||||
if (!PDFJS.disableHistory && !self.isViewerEmbedded) {
|
||||
// The browsing history is only enabled when the viewer is standalone,
|
||||
// i.e. not when it is embedded in a web page.
|
||||
if (!self.preferenceShowPreviousViewOnLoad && window.history.state) {
|
||||
window.history.replaceState(null, '');
|
||||
if (!self.preferenceShowPreviousViewOnLoad) {
|
||||
PDFHistory.clearHistoryState();
|
||||
}
|
||||
self.pdfHistory.initialize(self.documentFingerprint);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user