121 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  * @param {{ protocol?: string, auth?: string, hostname?: string, port?: string, pathname?: string, search?: string, hash?: string, slashes?: boolean }} objURL
 | |
|  * @returns {string}
 | |
|  */
 | |
| function format(objURL) {
 | |
|   var protocol = objURL.protocol || "";
 | |
|   if (protocol && protocol.substr(-1) !== ":") {
 | |
|     protocol += ":";
 | |
|   }
 | |
|   var auth = objURL.auth || "";
 | |
|   if (auth) {
 | |
|     auth = encodeURIComponent(auth);
 | |
|     auth = auth.replace(/%3A/i, ":");
 | |
|     auth += "@";
 | |
|   }
 | |
|   var host = "";
 | |
|   if (objURL.hostname) {
 | |
|     host = auth + (objURL.hostname.indexOf(":") === -1 ? objURL.hostname : "[".concat(objURL.hostname, "]"));
 | |
|     if (objURL.port) {
 | |
|       host += ":".concat(objURL.port);
 | |
|     }
 | |
|   }
 | |
|   var pathname = objURL.pathname || "";
 | |
|   if (objURL.slashes) {
 | |
|     host = "//".concat(host || "");
 | |
|     if (pathname && pathname.charAt(0) !== "/") {
 | |
|       pathname = "/".concat(pathname);
 | |
|     }
 | |
|   } else if (!host) {
 | |
|     host = "";
 | |
|   }
 | |
|   var search = objURL.search || "";
 | |
|   if (search && search.charAt(0) !== "?") {
 | |
|     search = "?".concat(search);
 | |
|   }
 | |
|   var hash = objURL.hash || "";
 | |
|   if (hash && hash.charAt(0) !== "#") {
 | |
|     hash = "#".concat(hash);
 | |
|   }
 | |
|   pathname = pathname.replace(/[?#]/g,
 | |
|   /**
 | |
|    * @param {string} match
 | |
|    * @returns {string}
 | |
|    */
 | |
|   function (match) {
 | |
|     return encodeURIComponent(match);
 | |
|   });
 | |
|   search = search.replace("#", "%23");
 | |
|   return "".concat(protocol).concat(host).concat(pathname).concat(search).concat(hash);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * @param {URL & { fromCurrentScript?: boolean }} parsedURL
 | |
|  * @returns {string}
 | |
|  */
 | |
| function createSocketURL(parsedURL) {
 | |
|   var hostname = parsedURL.hostname;
 | |
| 
 | |
|   // Node.js module parses it as `::`
 | |
|   // `new URL(urlString, [baseURLString])` parses it as '[::]'
 | |
|   var isInAddrAny = hostname === "0.0.0.0" || hostname === "::" || hostname === "[::]";
 | |
| 
 | |
|   // why do we need this check?
 | |
|   // hostname n/a for file protocol (example, when using electron, ionic)
 | |
|   // see: https://github.com/webpack/webpack-dev-server/pull/384
 | |
|   if (isInAddrAny && self.location.hostname && self.location.protocol.indexOf("http") === 0) {
 | |
|     hostname = self.location.hostname;
 | |
|   }
 | |
|   var socketURLProtocol = parsedURL.protocol || self.location.protocol;
 | |
| 
 | |
|   // When https is used in the app, secure web sockets are always necessary because the browser doesn't accept non-secure web sockets.
 | |
|   if (socketURLProtocol === "auto:" || hostname && isInAddrAny && self.location.protocol === "https:") {
 | |
|     socketURLProtocol = self.location.protocol;
 | |
|   }
 | |
|   socketURLProtocol = socketURLProtocol.replace(/^(?:http|.+-extension|file)/i, "ws");
 | |
|   var socketURLAuth = "";
 | |
| 
 | |
|   // `new URL(urlString, [baseURLstring])` doesn't have `auth` property
 | |
|   // Parse authentication credentials in case we need them
 | |
|   if (parsedURL.username) {
 | |
|     socketURLAuth = parsedURL.username;
 | |
| 
 | |
|     // Since HTTP basic authentication does not allow empty username,
 | |
|     // we only include password if the username is not empty.
 | |
|     if (parsedURL.password) {
 | |
|       // Result: <username>:<password>
 | |
|       socketURLAuth = socketURLAuth.concat(":", parsedURL.password);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   // In case the host is a raw IPv6 address, it can be enclosed in
 | |
|   // the brackets as the brackets are needed in the final URL string.
 | |
|   // Need to remove those as url.format blindly adds its own set of brackets
 | |
|   // if the host string contains colons. That would lead to non-working
 | |
|   // double brackets (e.g. [[::]]) host
 | |
|   //
 | |
|   // All of these web socket url params are optionally passed in through resourceQuery,
 | |
|   // so we need to fall back to the default if they are not provided
 | |
|   var socketURLHostname = (hostname || self.location.hostname || "localhost").replace(/^\[(.*)\]$/, "$1");
 | |
|   var socketURLPort = parsedURL.port;
 | |
|   if (!socketURLPort || socketURLPort === "0") {
 | |
|     socketURLPort = self.location.port;
 | |
|   }
 | |
| 
 | |
|   // If path is provided it'll be passed in via the resourceQuery as a
 | |
|   // query param so it has to be parsed out of the querystring in order for the
 | |
|   // client to open the socket to the correct location.
 | |
|   var socketURLPathname = "/ws";
 | |
|   if (parsedURL.pathname && !parsedURL.fromCurrentScript) {
 | |
|     socketURLPathname = parsedURL.pathname;
 | |
|   }
 | |
|   return format({
 | |
|     protocol: socketURLProtocol,
 | |
|     auth: socketURLAuth,
 | |
|     hostname: socketURLHostname,
 | |
|     port: socketURLPort,
 | |
|     pathname: socketURLPathname,
 | |
|     slashes: true
 | |
|   });
 | |
| }
 | |
| export default createSocketURL; |