Browse Source
This patch adds the Referer request header to PDF requests if the original PDF request included the Referer header.
6 changed files with 223 additions and 3 deletions
@ -0,0 +1,143 @@
@@ -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}; |
||||
} |
||||
}); |
Loading…
Reference in new issue