You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					189 lines
				
				4.6 KiB
			
		
		
			
		
	
	
					189 lines
				
				4.6 KiB
			| 
											3 years ago
										 | 'use strict' | ||
|  | 
 | ||
|  | const UUID_REG = /^[0-9a-fA-F]{8}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{4}\b-[0-9a-fA-F]{12}$/ | ||
|  | const URN_REG = /([A-Za-z0-9][A-Za-z0-9-]{0,31}):(([A-Za-z0-9()+,\-.:=@;$_!*']|%[0-9A-Fa-f]{2})+)/ | ||
|  | 
 | ||
|  | function isSecure (wsComponents) { | ||
|  |   return typeof wsComponents.secure === 'boolean' ? wsComponents.secure : String(wsComponents.scheme).toLowerCase() === 'wss' | ||
|  | } | ||
|  | 
 | ||
|  | function httpParse (components) { | ||
|  |   if (!components.host) { | ||
|  |     components.error = components.error || 'HTTP URIs must have a host.' | ||
|  |   } | ||
|  | 
 | ||
|  |   return components | ||
|  | } | ||
|  | 
 | ||
|  | function httpSerialize (components) { | ||
|  |   const secure = String(components.scheme).toLowerCase() === 'https' | ||
|  | 
 | ||
|  |   // normalize the default port
 | ||
|  |   if (components.port === (secure ? 443 : 80) || components.port === '') { | ||
|  |     components.port = undefined | ||
|  |   } | ||
|  | 
 | ||
|  |   // normalize the empty path
 | ||
|  |   if (!components.path) { | ||
|  |     components.path = '/' | ||
|  |   } | ||
|  | 
 | ||
|  |   // NOTE: We do not parse query strings for HTTP URIs
 | ||
|  |   // as WWW Form Url Encoded query strings are part of the HTML4+ spec,
 | ||
|  |   // and not the HTTP spec.
 | ||
|  | 
 | ||
|  |   return components | ||
|  | } | ||
|  | 
 | ||
|  | function wsParse (wsComponents) { | ||
|  | // indicate if the secure flag is set
 | ||
|  |   wsComponents.secure = isSecure(wsComponents) | ||
|  | 
 | ||
|  |   // construct resouce name
 | ||
|  |   wsComponents.resourceName = (wsComponents.path || '/') + (wsComponents.query ? '?' + wsComponents.query : '') | ||
|  |   wsComponents.path = undefined | ||
|  |   wsComponents.query = undefined | ||
|  | 
 | ||
|  |   return wsComponents | ||
|  | } | ||
|  | 
 | ||
|  | function wsSerialize (wsComponents) { | ||
|  | // normalize the default port
 | ||
|  |   if (wsComponents.port === (isSecure(wsComponents) ? 443 : 80) || wsComponents.port === '') { | ||
|  |     wsComponents.port = undefined | ||
|  |   } | ||
|  | 
 | ||
|  |   // ensure scheme matches secure flag
 | ||
|  |   if (typeof wsComponents.secure === 'boolean') { | ||
|  |     wsComponents.scheme = (wsComponents.secure ? 'wss' : 'ws') | ||
|  |     wsComponents.secure = undefined | ||
|  |   } | ||
|  | 
 | ||
|  |   // reconstruct path from resource name
 | ||
|  |   if (wsComponents.resourceName) { | ||
|  |     const [path, query] = wsComponents.resourceName.split('?') | ||
|  |     wsComponents.path = (path && path !== '/' ? path : undefined) | ||
|  |     wsComponents.query = query | ||
|  |     wsComponents.resourceName = undefined | ||
|  |   } | ||
|  | 
 | ||
|  |   // forbid fragment component
 | ||
|  |   wsComponents.fragment = undefined | ||
|  | 
 | ||
|  |   return wsComponents | ||
|  | } | ||
|  | 
 | ||
|  | function urnParse (urnComponents, options) { | ||
|  |   if (!urnComponents.path) { | ||
|  |     urnComponents.error = 'URN can not be parsed' | ||
|  |     return urnComponents | ||
|  |   } | ||
|  |   const matches = urnComponents.path.match(URN_REG) | ||
|  |   if (matches) { | ||
|  |     const scheme = options.scheme || urnComponents.scheme || 'urn' | ||
|  |     urnComponents.nid = matches[1].toLowerCase() | ||
|  |     urnComponents.nss = matches[2] | ||
|  |     const urnScheme = `${scheme}:${options.nid || urnComponents.nid}` | ||
|  |     const schemeHandler = SCHEMES[urnScheme] | ||
|  |     urnComponents.path = undefined | ||
|  | 
 | ||
|  |     if (schemeHandler) { | ||
|  |       urnComponents = schemeHandler.parse(urnComponents, options) | ||
|  |     } | ||
|  |   } else { | ||
|  |     urnComponents.error = urnComponents.error || 'URN can not be parsed.' | ||
|  |   } | ||
|  | 
 | ||
|  |   return urnComponents | ||
|  | } | ||
|  | 
 | ||
|  | function urnSerialize (urnComponents, options) { | ||
|  |   const scheme = options.scheme || urnComponents.scheme || 'urn' | ||
|  |   const nid = urnComponents.nid.toLowerCase() | ||
|  |   const urnScheme = `${scheme}:${options.nid || nid}` | ||
|  |   const schemeHandler = SCHEMES[urnScheme] | ||
|  | 
 | ||
|  |   if (schemeHandler) { | ||
|  |     urnComponents = schemeHandler.serialize(urnComponents, options) | ||
|  |   } | ||
|  | 
 | ||
|  |   const uriComponents = urnComponents | ||
|  |   const nss = urnComponents.nss | ||
|  |   uriComponents.path = `${nid || options.nid}:${nss}` | ||
|  | 
 | ||
|  |   options.skipEscape = true | ||
|  |   return uriComponents | ||
|  | } | ||
|  | 
 | ||
|  | function urnuuidParse (urnComponents, options) { | ||
|  |   const uuidComponents = urnComponents | ||
|  |   uuidComponents.uuid = uuidComponents.nss | ||
|  |   uuidComponents.nss = undefined | ||
|  | 
 | ||
|  |   if (!options.tolerant && (!uuidComponents.uuid || !UUID_REG.test(uuidComponents.uuid))) { | ||
|  |     uuidComponents.error = uuidComponents.error || 'UUID is not valid.' | ||
|  |   } | ||
|  | 
 | ||
|  |   return uuidComponents | ||
|  | } | ||
|  | 
 | ||
|  | function urnuuidSerialize (uuidComponents) { | ||
|  |   const urnComponents = uuidComponents | ||
|  |   // normalize UUID
 | ||
|  |   urnComponents.nss = (uuidComponents.uuid || '').toLowerCase() | ||
|  |   return urnComponents | ||
|  | } | ||
|  | 
 | ||
|  | const http = { | ||
|  |   scheme: 'http', | ||
|  |   domainHost: true, | ||
|  |   parse: httpParse, | ||
|  |   serialize: httpSerialize | ||
|  | } | ||
|  | 
 | ||
|  | const https = { | ||
|  |   scheme: 'https', | ||
|  |   domainHost: http.domainHost, | ||
|  |   parse: httpParse, | ||
|  |   serialize: httpSerialize | ||
|  | } | ||
|  | 
 | ||
|  | const ws = { | ||
|  |   scheme: 'ws', | ||
|  |   domainHost: true, | ||
|  |   parse: wsParse, | ||
|  |   serialize: wsSerialize | ||
|  | } | ||
|  | 
 | ||
|  | const wss = { | ||
|  |   scheme: 'wss', | ||
|  |   domainHost: ws.domainHost, | ||
|  |   parse: ws.parse, | ||
|  |   serialize: ws.serialize | ||
|  | } | ||
|  | 
 | ||
|  | const urn = { | ||
|  |   scheme: 'urn', | ||
|  |   parse: urnParse, | ||
|  |   serialize: urnSerialize, | ||
|  |   skipNormalize: true | ||
|  | } | ||
|  | 
 | ||
|  | const urnuuid = { | ||
|  |   scheme: 'urn:uuid', | ||
|  |   parse: urnuuidParse, | ||
|  |   serialize: urnuuidSerialize, | ||
|  |   skipNormalize: true | ||
|  | } | ||
|  | 
 | ||
|  | const SCHEMES = { | ||
|  |   http, | ||
|  |   https, | ||
|  |   ws, | ||
|  |   wss, | ||
|  |   urn, | ||
|  |   'urn:uuid': urnuuid | ||
|  | } | ||
|  | 
 | ||
|  | module.exports = SCHEMES |