browser(firefox): properly handle HSTS redirects (#7391)

When Firefox decides to perform an http->https redirect based on HSTS
information, it issues an "internal" redirect and cancels the http request.

Since there is no response for the http request, we forge 307 redirect
in this case, following Chromium lead.

The relevant code is in nsHttpChannel::StartRedirectChannelToHttps.
This commit is contained in:
Dmitry Gozman 2021-06-30 12:59:27 -07:00 committed by GitHub
parent 8f2bfed659
commit fca965cb98
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 38 deletions

View file

@ -1,2 +1,2 @@
1266
Changed: max@schmitt.mx Tue Jun 29 22:44:52 UTC 2021
1267
Changed: dgozman@gmail.com Tue Jun 30 16:15:40 PDT 2021

View file

@ -123,15 +123,8 @@ class NetworkRequest {
this.requestId = httpChannel.channelId + '';
this.navigationId = httpChannel.isMainDocumentChannel ? this.requestId : undefined;
const internalCauseType = this.httpChannel.loadInfo ? this.httpChannel.loadInfo.internalContentPolicyType : Ci.nsIContentPolicy.TYPE_OTHER;
this._redirectedIndex = 0;
const ignoredRedirect = redirectedFrom && !redirectedFrom._sentOnResponse;
if (ignoredRedirect) {
// We just ignore redirect that did not hit the network before being redirected.
// This happens, for example, for automatic http->https redirects.
this.navigationId = redirectedFrom.navigationId;
} else if (redirectedFrom) {
if (redirectedFrom) {
this.redirectedFromId = redirectedFrom.requestId;
this._redirectedIndex = redirectedFrom._redirectedIndex + 1;
this.requestId = this.requestId + '-redirect' + this._redirectedIndex;
@ -513,7 +506,7 @@ class NetworkRequest {
}, this._frameId);
}
_sendOnResponse(fromCache) {
_sendOnResponse(fromCache, opt_statusCode, opt_statusText) {
if (this._sentOnResponse) {
// We can come here twice because of internal redirects, e.g. service workers.
return;
@ -537,8 +530,8 @@ class NetworkRequest {
};
const headers = [];
let status = 0;
let statusText = '';
let status = opt_statusCode || 0;
let statusText = opt_statusText || '';
try {
status = this.httpChannel.responseStatus;
statusText = this.httpChannel.responseStatusText;
@ -666,14 +659,21 @@ class NetworkObserver {
return;
const oldHttpChannel = oldChannel.QueryInterface(Ci.nsIHttpChannel);
const newHttpChannel = newChannel.QueryInterface(Ci.nsIHttpChannel);
if (!(flags & Ci.nsIChannelEventSink.REDIRECT_INTERNAL)) {
const previous = this._channelToRequest.get(oldHttpChannel);
if (previous)
this._expectRedirect(newHttpChannel.channelId + '', previous);
} else {
const request = this._channelToRequest.get(oldHttpChannel);
const request = this._channelToRequest.get(oldHttpChannel);
if (flags & Ci.nsIChannelEventSink.REDIRECT_INTERNAL) {
if (request)
request._onInternalRedirect(newHttpChannel);
} else if (flags & Ci.nsIChannelEventSink.REDIRECT_STS_UPGRADE) {
if (request) {
// This is an internal HSTS upgrade. The original http request is canceled, and a new
// equivalent https request is sent. We forge 307 redirect to follow Chromium here:
// https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_http_job.cc;l=211
request._sendOnResponse(false, 307, 'Temporary Redirect');
this._expectRedirect(newHttpChannel.channelId + '', request);
}
} else {
if (request)
this._expectRedirect(newHttpChannel.channelId + '', request);
}
}

View file

@ -1,2 +1,2 @@
1273
Changed: max@schmitt.mx Tue Jun 29 22:39:37 UTC 2021
1274
Changed: dgozman@gmail.com Tue Jun 30 16:15:40 PDT 2021

View file

@ -123,15 +123,8 @@ class NetworkRequest {
this.requestId = httpChannel.channelId + '';
this.navigationId = httpChannel.isMainDocumentChannel ? this.requestId : undefined;
const internalCauseType = this.httpChannel.loadInfo ? this.httpChannel.loadInfo.internalContentPolicyType : Ci.nsIContentPolicy.TYPE_OTHER;
this._redirectedIndex = 0;
const ignoredRedirect = redirectedFrom && !redirectedFrom._sentOnResponse;
if (ignoredRedirect) {
// We just ignore redirect that did not hit the network before being redirected.
// This happens, for example, for automatic http->https redirects.
this.navigationId = redirectedFrom.navigationId;
} else if (redirectedFrom) {
if (redirectedFrom) {
this.redirectedFromId = redirectedFrom.requestId;
this._redirectedIndex = redirectedFrom._redirectedIndex + 1;
this.requestId = this.requestId + '-redirect' + this._redirectedIndex;
@ -513,7 +506,7 @@ class NetworkRequest {
}, this._frameId);
}
_sendOnResponse(fromCache) {
_sendOnResponse(fromCache, opt_statusCode, opt_statusText) {
if (this._sentOnResponse) {
// We can come here twice because of internal redirects, e.g. service workers.
return;
@ -537,8 +530,8 @@ class NetworkRequest {
};
const headers = [];
let status = 0;
let statusText = '';
let status = opt_statusCode || 0;
let statusText = opt_statusText || '';
try {
status = this.httpChannel.responseStatus;
statusText = this.httpChannel.responseStatusText;
@ -666,14 +659,21 @@ class NetworkObserver {
return;
const oldHttpChannel = oldChannel.QueryInterface(Ci.nsIHttpChannel);
const newHttpChannel = newChannel.QueryInterface(Ci.nsIHttpChannel);
if (!(flags & Ci.nsIChannelEventSink.REDIRECT_INTERNAL)) {
const previous = this._channelToRequest.get(oldHttpChannel);
if (previous)
this._expectRedirect(newHttpChannel.channelId + '', previous);
} else {
const request = this._channelToRequest.get(oldHttpChannel);
const request = this._channelToRequest.get(oldHttpChannel);
if (flags & Ci.nsIChannelEventSink.REDIRECT_INTERNAL) {
if (request)
request._onInternalRedirect(newHttpChannel);
} else if (flags & Ci.nsIChannelEventSink.REDIRECT_STS_UPGRADE) {
if (request) {
// This is an internal HSTS upgrade. The original http request is canceled, and a new
// equivalent https request is sent. We forge 307 redirect to follow Chromium here:
// https://source.chromium.org/chromium/chromium/src/+/main:net/url_request/url_request_http_job.cc;l=211
request._sendOnResponse(false, 307, 'Temporary Redirect');
this._expectRedirect(newHttpChannel.channelId + '', request);
}
} else {
if (request)
this._expectRedirect(newHttpChannel.channelId + '', request);
}
}