1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 * This module consolidates various code and data update requests, so flags
7 * can be set, Telemetry collected, etc. in a central place.
10 import { XPCOMUtils } from "resource://gre/modules/XPCOMUtils.sys.mjs";
14 XPCOMUtils.defineLazyServiceGetter(
17 "@mozilla.org/network/protocol-proxy-service;1",
18 "nsIProtocolProxyService"
21 ChromeUtils.defineESModuleGetters(lazy, {
22 ExtensionPreferencesManager:
23 "resource://gre/modules/ExtensionPreferencesManager.sys.mjs",
26 XPCOMUtils.defineLazyServiceGetter(
28 "CaptivePortalService",
29 "@mozilla.org/network/captive-portal-service;1",
30 "nsICaptivePortalService"
33 XPCOMUtils.defineLazyServiceGetter(
35 "gNetworkLinkService",
36 "@mozilla.org/network/network-link-service;1",
37 "nsINetworkLinkService"
40 const PROXY_CONFIG_TYPES = [
44 "unused", // nsIProtocolProxyService.idl skips index 3.
49 function recordEvent(service, source = {}) {
51 Services.telemetry.setEventRecordingEnabled("service_request", true);
52 Services.telemetry.recordEvent(
60 // If the telemetry throws just log the error so it doesn't break any
66 // If proxy.settings is used to change the proxy, an extension will
67 // be "in control". This returns the id of that extension.
68 async function getControllingExtension() {
70 !WebExtensionPolicy.getActiveExtensions().some(p =>
71 p.permissions.includes("proxy")
76 // Is this proxied by an extension that set proxy prefs?
77 let setting = await lazy.ExtensionPreferencesManager.getSetting(
83 async function getProxySource(proxyInfo) {
84 // sourceId is set when using proxy.onRequest
85 if (proxyInfo.sourceId) {
87 source: proxyInfo.sourceId,
91 let type = PROXY_CONFIG_TYPES[lazy.ProxyService.proxyConfigType] || "unknown";
93 // If we have a policy it will have set the prefs.
96 Services.policies.status === Services.policies.ACTIVE
98 let policies = Services.policies.getActivePolicies()?.filter(p => p.Proxy);
99 if (policies?.length) {
107 let source = await getControllingExtension();
109 source: source || "prefs",
115 * ServiceRequest is intended to be a drop-in replacement for current users
118 * @param {Object} options - Options for underlying XHR, e.g. { mozAnon: bool }
120 export class ServiceRequest extends XMLHttpRequest {
121 constructor(options) {
125 * Opens an XMLHttpRequest, and sets the NSS "beConservative" flag.
126 * Requests are always async.
128 * @param {String} method - HTTP method to use, e.g. "GET".
129 * @param {String} url - URL to open.
130 * @param {Object} options - Additional options { bypassProxy: bool }.
132 open(method, url, options) {
133 super.open(method, url, true);
135 if (super.channel instanceof Ci.nsIHttpChannelInternal) {
136 let internal = super.channel.QueryInterface(Ci.nsIHttpChannelInternal);
137 // Disable cutting edge features, like TLS 1.3, where middleboxes might brick us
138 internal.beConservative = true;
139 // Disable use of proxy for this request if necessary.
140 if (options?.bypassProxy && this.bypassProxyEnabled) {
141 internal.bypassProxy = true;
147 let { channel } = this;
148 return channel.QueryInterface(Ci.nsIHttpChannelInternal).bypassProxy;
152 let { channel } = this;
153 return !!(channel instanceof Ci.nsIProxiedChannel && channel.proxyInfo);
156 get bypassProxyEnabled() {
157 return Services.prefs.getBoolPref("network.proxy.allow_bypass", true);
160 static async logProxySource(channel, service) {
161 if (channel.proxyInfo) {
162 let source = await getProxySource(channel.proxyInfo);
163 recordEvent(service, source);
167 static get isOffline() {
170 Services.io.offline ||
171 lazy.CaptivePortalService.state ==
172 lazy.CaptivePortalService.LOCKED_PORTAL ||
173 !lazy.gNetworkLinkService.isLinkUp
176 // we cannot get state, assume the best.