|
|
'use strict'
const UUID_REG = /^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu const URN_REG = /([\da-z][\d\-a-z]{0,31}):((?:[\w!$'()*+,\-.:;=@]|%[\da-f]{2})+)/iu
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
|