forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			182 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			182 lines
		
	
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* This Source Code Form is subject to the terms of the Mozilla Public
 | |
|  * License, v. 2.0. If a copy of the MPL was not distributed with this
 | |
|  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | |
| 
 | |
| "use strict";
 | |
| 
 | |
| var EXPORTED_SYMBOLS = ["RemoteAgent", "RemoteAgentFactory"];
 | |
| 
 | |
| const { XPCOMUtils } = ChromeUtils.import(
 | |
|   "resource://gre/modules/XPCOMUtils.jsm"
 | |
| );
 | |
| 
 | |
| XPCOMUtils.defineLazyModuleGetters(this, {
 | |
|   Services: "resource://gre/modules/Services.jsm",
 | |
| 
 | |
|   CDP: "chrome://remote/content/cdp/CDP.jsm",
 | |
|   HttpServer: "chrome://remote/content/server/HTTPD.jsm",
 | |
|   Log: "chrome://remote/content/shared/Log.jsm",
 | |
|   Preferences: "resource://gre/modules/Preferences.jsm",
 | |
|   RecommendedPreferences:
 | |
|     "chrome://remote/content/cdp/RecommendedPreferences.jsm",
 | |
| });
 | |
| 
 | |
| XPCOMUtils.defineLazyGetter(this, "logger", () => Log.get());
 | |
| 
 | |
| const PREF_ACTIVE_PROTOCOLS = "remote.active-protocols";
 | |
| const PREF_FORCE_LOCAL = "remote.force-local";
 | |
| 
 | |
| // const BIDI_ACTIVE = 0x1;
 | |
| const CDP_ACTIVE = 0x2;
 | |
| 
 | |
| const LOOPBACKS = ["localhost", "127.0.0.1", "[::1]"];
 | |
| 
 | |
| class RemoteAgentClass {
 | |
|   constructor() {
 | |
|     this.cdp = null;
 | |
|     this.server = null;
 | |
| 
 | |
|     this.alteredPrefs = new Set();
 | |
| 
 | |
|     const protocols = Services.prefs.getIntPref(PREF_ACTIVE_PROTOCOLS);
 | |
|     if (protocols < 1 || protocols > 3) {
 | |
|       throw Error(`Invalid remote protocol identifier: ${protocols}`);
 | |
|     }
 | |
|     this.activeProtocols = protocols;
 | |
|   }
 | |
| 
 | |
|   get listening() {
 | |
|     return !!this.server && !this.server.isStopped();
 | |
|   }
 | |
| 
 | |
|   get debuggerAddress() {
 | |
|     if (!this.server) {
 | |
|       return "";
 | |
|     }
 | |
| 
 | |
|     return `${this.host}:${this.port}`;
 | |
|   }
 | |
| 
 | |
|   listen(url) {
 | |
|     if (Services.appinfo.processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT) {
 | |
|       throw Components.Exception(
 | |
|         "May only be instantiated in parent process",
 | |
|         Cr.NS_ERROR_LAUNCHED_CHILD_PROCESS
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     if (this.listening) {
 | |
|       return Promise.resolve();
 | |
|     }
 | |
| 
 | |
|     if (!(url instanceof Ci.nsIURI)) {
 | |
|       url = Services.io.newURI(url);
 | |
|     }
 | |
| 
 | |
|     let { host, port } = url;
 | |
|     if (Preferences.get(PREF_FORCE_LOCAL) && !LOOPBACKS.includes(host)) {
 | |
|       throw Components.Exception(
 | |
|         "Restricted to loopback devices",
 | |
|         Cr.NS_ERROR_ILLEGAL_VALUE
 | |
|       );
 | |
|     }
 | |
| 
 | |
|     // nsIServerSocket uses -1 for atomic port allocation
 | |
|     if (port === 0) {
 | |
|       port = -1;
 | |
|     }
 | |
| 
 | |
|     for (let [k, v] of RecommendedPreferences) {
 | |
|       if (!Preferences.isSet(k)) {
 | |
|         logger.debug(`Setting recommended pref ${k} to ${v}`);
 | |
|         Preferences.set(k, v);
 | |
|         this.alteredPrefs.add(k);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     this.server = new HttpServer();
 | |
| 
 | |
|     if ((this.activeProtocols & CDP_ACTIVE) === CDP_ACTIVE) {
 | |
|       this.cdp = new CDP(this.server);
 | |
|     }
 | |
| 
 | |
|     return this.asyncListen(host, port);
 | |
|   }
 | |
| 
 | |
|   async asyncListen(host, port) {
 | |
|     try {
 | |
|       this.server._start(port, host);
 | |
| 
 | |
|       await this.cdp?.start();
 | |
|     } catch (e) {
 | |
|       await this.close();
 | |
|       logger.error(`Unable to start remote agent: ${e.message}`, e);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   close() {
 | |
|     try {
 | |
|       for (let k of this.alteredPrefs) {
 | |
|         logger.debug(`Resetting recommended pref ${k}`);
 | |
|         Preferences.reset(k);
 | |
|       }
 | |
|       this.alteredPrefs.clear();
 | |
| 
 | |
|       // Stop the CDP support before stopping the server.
 | |
|       // Otherwise the HTTP server will fail to stop.
 | |
|       this.cdp?.stop();
 | |
| 
 | |
|       if (this.listening) {
 | |
|         return this.server.stop();
 | |
|       }
 | |
|     } catch (e) {
 | |
|       // this function must never fail
 | |
|       logger.error("unable to stop listener", e);
 | |
|     } finally {
 | |
|       this.cdp = null;
 | |
|       this.server = null;
 | |
|     }
 | |
| 
 | |
|     return Promise.resolve();
 | |
|   }
 | |
| 
 | |
|   get scheme() {
 | |
|     if (!this.server) {
 | |
|       return null;
 | |
|     }
 | |
|     return this.server.identity.primaryScheme;
 | |
|   }
 | |
| 
 | |
|   get host() {
 | |
|     if (!this.server) {
 | |
|       return null;
 | |
|     }
 | |
| 
 | |
|     // Bug 1675471: When using the nsIRemoteAgent interface the HTTPd server's
 | |
|     // primary identity ("this.server.identity.primaryHost") is lazily set.
 | |
|     return this.server._host;
 | |
|   }
 | |
| 
 | |
|   get port() {
 | |
|     if (!this.server) {
 | |
|       return null;
 | |
|     }
 | |
| 
 | |
|     // Bug 1675471: When using the nsIRemoteAgent interface the HTTPd server's
 | |
|     // primary identity ("this.server.identity.primaryPort") is lazily set.
 | |
|     return this.server._port;
 | |
|   }
 | |
| 
 | |
|   // XPCOM
 | |
| 
 | |
|   get QueryInterface() {
 | |
|     return ChromeUtils.generateQI(["nsIRemoteAgent"]);
 | |
|   }
 | |
| }
 | |
| 
 | |
| var RemoteAgent = new RemoteAgentClass();
 | |
| 
 | |
| // This is used by the XPCOM codepath which expects a constructor
 | |
| var RemoteAgentFactory = function() {
 | |
|   return RemoteAgent;
 | |
| };
 | 
