1 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 ChromeUtils.defineESModuleGetters(lazy, {
9 AppInfo: "chrome://remote/content/shared/AppInfo.sys.mjs",
12 const { RemotePageChild } = ChromeUtils.import(
13 "resource://gre/actors/RemotePageChild.jsm"
16 export class NetErrorChild extends RemotePageChild {
20 // If you add a new function, remember to add it to RemotePageAccessManager.sys.mjs
21 // to allow content-privileged about:neterror or about:certerror to use it.
22 const exportableFunctions = [
26 "RPMRecordTelemetryEvent",
27 "RPMCheckAlternateHostAvailable",
28 "RPMGetHttpResponseHeader",
29 "RPMIsTRROnlyFailure",
31 "RPMIsNativeFallbackFailure",
33 "RPMGetTRRSkipReason",
35 "RPMIsSiteSpecificTRRError",
37 this.exportFunctions(exportableFunctions);
40 getFailedCertChain(docShell) {
42 docShell.failedChannel && docShell.failedChannel.securityInfo;
46 return securityInfo.failedCertChain.map(cert => cert.getBase64DERString());
50 // Documents have a null ownerDocument.
51 let doc = aEvent.originalTarget.ownerDocument || aEvent.originalTarget;
53 switch (aEvent.type) {
55 let elem = aEvent.originalTarget;
56 if (elem.id == "viewCertificate") {
57 // Call through the superclass to avoid the security check.
58 this.sendAsyncMessage("Browser:CertExceptionError", {
59 location: doc.location.href,
61 failedCertChain: this.getFailedCertChain(doc.defaultView.docShell),
68 RPMGetInnerMostURI(uriString) {
69 let uri = Services.io.newURI(uriString);
70 if (uri instanceof Ci.nsINestedURI) {
71 uri = uri.QueryInterface(Ci.nsINestedURI).innermostURI;
78 return Services.appinfo.appBuildID;
81 RPMAddToHistogram(histID, bin) {
82 Services.telemetry.getHistogramById(histID).add(bin);
85 RPMRecordTelemetryEvent(category, event, object, value, extra) {
86 Services.telemetry.recordEvent(category, event, object, value, extra);
89 RPMCheckAlternateHostAvailable() {
90 const host = this.contentWindow.location.host.trim();
92 // Adapted from UrlbarUtils::looksLikeSingleWordHost
93 // https://searchfox.org/mozilla-central/rev/a26af613a476fafe6c3eba05a81bef63dff3c9f1/browser/components/urlbar/UrlbarUtils.sys.mjs#893
94 const REGEXP_SINGLE_WORD = /^[^\s@:/?#]+(:\d+)?$/;
95 if (!REGEXP_SINGLE_WORD.test(host)) {
99 let info = Services.uriFixup.forceHttpFixup(
100 this.contentWindow.location.href
103 if (!info.fixupCreatedAlternateURI && !info.fixupChangedProtocol) {
107 let { displayHost, displaySpec, pathQueryRef } = info.fixedURI;
109 if (pathQueryRef.endsWith("/")) {
110 pathQueryRef = pathQueryRef.slice(0, pathQueryRef.length - 1);
113 let weakDoc = Cu.getWeakReference(this.contentWindow.document);
114 let onLookupCompleteListener = {
115 onLookupComplete(request, record, status) {
116 let doc = weakDoc.get();
117 if (!doc || !Components.isSuccessCode(status)) {
121 let link = doc.createElement("a");
122 link.href = displaySpec;
123 link.setAttribute("data-l10n-name", "website");
125 let span = doc.createElement("span");
126 span.appendChild(link);
127 doc.l10n.setAttributes(span, "neterror-dns-not-found-with-suggestion", {
128 hostAndPath: displayHost + pathQueryRef,
131 const shortDesc = doc.getElementById("errorShortDesc");
132 shortDesc.textContent += " ";
133 shortDesc.appendChild(span);
137 Services.uriFixup.checkHost(
139 onLookupCompleteListener,
140 this.document.nodePrincipal.originAttributes
144 // Get the header from the http response of the failed channel. This function
145 // is used in the 'about:neterror' page.
146 RPMGetHttpResponseHeader(responseHeader) {
147 let channel = this.contentWindow.docShell.failedChannel;
152 let httpChannel = channel.QueryInterface(Ci.nsIHttpChannel);
158 return httpChannel.getResponseHeader(responseHeader);
164 RPMIsTRROnlyFailure() {
165 // We will only show this in Firefox because the options may direct users to settings only available on Firefox Desktop
166 let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface(
167 Ci.nsIHttpChannelInternal
172 return channel.effectiveTRRMode == Ci.nsIRequest.TRR_ONLY_MODE;
176 return lazy.AppInfo.isFirefox;
179 _getTRRSkipReason() {
180 let channel = this.contentWindow?.docShell?.failedChannel?.QueryInterface(
181 Ci.nsIHttpChannelInternal
183 return channel?.trrSkipReason ?? Ci.nsITRRSkipReason.TRR_UNSET;
186 RPMIsNativeFallbackFailure() {
187 if (!this.contentWindow?.navigator.onLine) {
191 let skipReason = this._getTRRSkipReason();
193 const warningReasons = new Set([
194 Ci.nsITRRSkipReason.TRR_NOT_CONFIRMED,
195 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH,
196 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH,
197 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY,
198 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_CANARY,
199 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS,
200 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS,
201 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS,
202 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY,
203 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_VPN,
204 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PROXY,
205 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_NRPT,
209 Services.dns.currentTrrMode == Ci.nsIRequest.TRR_FIRST_MODE &&
210 warningReasons.has(skipReason)
214 RPMGetTRRSkipReason() {
215 let skipReason = this._getTRRSkipReason();
216 return Services.dns.getTRRSkipReasonName(skipReason);
220 return Services.dns.trrDomain;
223 RPMIsSiteSpecificTRRError() {
224 let skipReason = this._getTRRSkipReason();
225 switch (skipReason) {
226 case Ci.nsITRRSkipReason.TRR_NXDOMAIN:
227 case Ci.nsITRRSkipReason.TRR_RCODE_FAIL:
228 case Ci.nsITRRSkipReason.TRR_NO_ANSWERS: