Skip to content

Commit 71474e8

Browse files
committed
0.4.5 - Don't redirect already-redirected requests
Server-initiated redirects are certainly not caused by user-generated navigations, so don't try to force HTTPS for redirected requests. Test case: https://github.com/Rob--W/https-by-default/issues/20#issuecomment-375569458 (=navigate to a HTTP page whose HTTPS page redirects to another HTTP page, and expect that this request is not upgraded to HTTPS).
1 parent ea019c0 commit 71474e8

File tree

2 files changed

+44
-9
lines changed

2 files changed

+44
-9
lines changed

firefox/background.js

+43-8
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ browser.webRequest.onBeforeRequest.addListener(async (details) => {
8181
// so we will rewrite any non-web-initiated navigation,
8282
// including bookmarks, auto-completed URLs and full URLs with "http:" prefix.
8383

84-
let {tabId, url: requestedUrl} = details;
84+
let {tabId, url: requestedUrl, requestedId} = details;
8585

8686
if (!prefsReady) {
8787
await prefsReadyPromise;
@@ -146,6 +146,11 @@ browser.webRequest.onBeforeRequest.addListener(async (details) => {
146146

147147
if (tabCreationTimes.has(tabId)) {
148148
var pendingRedirectInfo = tabPendingRedirectInfos.get(tabId);
149+
if (pendingRedirectInfo && pendingRedirectInfo.redirectedRequestId === requestedId) {
150+
// Don't rewrite redirects. Redirects are triggered by a server response, and
151+
// are certainly not the result of a manually typed URL.
152+
return;
153+
}
149154
if (pendingRedirectInfo && pendingRedirectInfo.url === requestedUrl &&
150155
currentTab && currentTab.status === 'loading') {
151156
// The previous HTTP->HTTPS navigation hasn't started, and the HTTP navigation is
@@ -283,21 +288,54 @@ function isDerivedURL(currentUrl, requestedUrl) {
283288
//
284289
// The caller should make sure that tabId refers to a valid tab.
285290
function registerRedirectInfo(tabId, requestedUrl) {
291+
let redirectInfo = {
292+
url: requestedUrl,
293+
redirectedRequestId: null,
294+
unregister,
295+
};
286296
function unregister() {
287-
browser.webRequest.onHeadersReceived.removeListener(unregister);
297+
browser.webRequest.onHeadersReceived.removeListener(onHeadersReceived);
298+
browser.webRequest.onResponseStarted.removeListener(unregister);
288299
browser.webRequest.onErrorOccurred.removeListener(unregister);
289300
tabPendingRedirectInfos.delete(tabId);
290301
}
291302

303+
function onHeadersReceived({requestedId, statusCode}) {
304+
if (statusCode !== 301 && statusCode !== 302 && statusCode !== 303 &&
305+
statusCode !== 307 && statusCode !== 308) {
306+
unregister();
307+
return;
308+
}
309+
if (tabPendingRedirectInfos.get(tabId) !== redirectInfo) {
310+
// unregister() has been invoked between the queued webRequest event and the
311+
// actual dispatch. This is not expected to happen, but can happen in theory.
312+
// Exit now to avoid registering and leaking a webRequest event handler.
313+
return;
314+
}
315+
316+
// When a request is restarted, the requestedId is preserved.
317+
redirectInfo.redirectedRequestId = requestedId;
318+
319+
// If the response did not have a valid Location header, the request won't be restarted.
320+
// Detect the successful response body via webRequest.onResponseStarted.
321+
// The onHeadersReceived event can fire multiple times throughout a request, but it is safe
322+
// to call addListener because the event handler won't be registered twice.
323+
browser.webRequest.onResponseStarted.addListener(unregister, {
324+
urls: ['*://*/*'],
325+
types: ['main_frame'],
326+
tabId,
327+
});
328+
}
329+
292330
unregisterRedirectInfo(tabId);
293331

294332
// A request was successfully received for the main frame, so clear the registered redirection
295333
// URL. This is not necessarily a response for |requestedUrl|, any response will do.
296-
browser.webRequest.onHeadersReceived.addListener(unregister, {
334+
browser.webRequest.onHeadersReceived.addListener(onHeadersReceived, {
297335
urls: ['*://*/*'],
298336
types: ['main_frame'],
299337
tabId,
300-
});
338+
}, ['blocking']);
301339

302340
// The server is not reachable via HTTPs, and the URL can be unregistered because
303341
// tab.url will show the URL of the attempted navigation:
@@ -309,10 +347,7 @@ function registerRedirectInfo(tabId, requestedUrl) {
309347

310348
// Expose the unregister function so that if somehow neither of the above events happen,
311349
// that the listener is removed when the tab is removed (via tabs.onRemoved):
312-
tabPendingRedirectInfos.set(tabId, {
313-
url: requestedUrl,
314-
unregister,
315-
});
350+
tabPendingRedirectInfos.set(tabId, redirectInfo);
316351
}
317352

318353
function unregisterRedirectInfo(tabId) {

firefox/manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "HTTPS by default",
33
"description": "Request websites over secure https by default from the location bar instead of insecure http. Exceptions can be added at the add-on's preferences page (to not use HTTPS by default for some sites).",
4-
"version": "0.4.4",
4+
"version": "0.4.5",
55
"manifest_version": 2,
66
"background": {
77
"scripts": ["background.js"]

0 commit comments

Comments
 (0)