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 import { RemotePageChild } from "resource://gre/actors/RemotePageChild.sys.mjs";
14 export class NetErrorChild extends RemotePageChild {
18 // If you add a new function, remember to add it to RemotePageAccessManager.sys.mjs
19 // to allow content-privileged about:neterror or about:certerror to use it.
20 const exportableFunctions = [
24 "RPMRecordTelemetryEvent",
25 "RPMCheckAlternateHostAvailable",
26 "RPMGetHttpResponseHeader",
27 "RPMIsTRROnlyFailure",
29 "RPMIsNativeFallbackFailure",
31 "RPMGetTRRSkipReason",
33 "RPMIsSiteSpecificTRRError",
34 "RPMSetTRRDisabledLoadFlags",
35 "RPMGetCurrentTRRMode",
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();
194 Services.dns.currentTrrMode === Ci.nsIDNSService.MODE_TRRFIRST &&
195 skipReason === Ci.nsITRRSkipReason.TRR_NOT_CONFIRMED
200 const warningReasons = new Set([
201 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_GOOGLE_SAFESEARCH,
202 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_YOUTUBE_SAFESEARCH,
203 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ZSCALER_CANARY,
204 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_CANARY,
205 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_MODIFIED_ROOTS,
206 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PARENTAL_CONTROLS,
207 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_THIRD_PARTY_ROOTS,
208 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_ENTERPRISE_POLICY,
209 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_VPN,
210 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_PROXY,
211 Ci.nsITRRSkipReason.TRR_HEURISTIC_TRIPPED_NRPT,
215 Services.dns.currentTrrMode === Ci.nsIDNSService.MODE_NATIVEONLY &&
216 warningReasons.has(skipReason)
220 RPMGetTRRSkipReason() {
221 let skipReason = this._getTRRSkipReason();
222 return Services.dns.getTRRSkipReasonName(skipReason);
226 return Services.dns.trrDomain;
229 RPMIsSiteSpecificTRRError() {
230 let skipReason = this._getTRRSkipReason();
231 switch (skipReason) {
232 case Ci.nsITRRSkipReason.TRR_NXDOMAIN:
233 case Ci.nsITRRSkipReason.TRR_RCODE_FAIL:
234 case Ci.nsITRRSkipReason.TRR_NO_ANSWERS:
240 RPMSetTRRDisabledLoadFlags() {
241 this.contentWindow.docShell.browsingContext.defaultLoadFlags |=
242 Ci.nsIRequest.LOAD_TRR_DISABLED_MODE;