Spaces:
Paused
Paused
File size: 4,191 Bytes
9ada4bc |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
import { Agent } from 'http'
import { RequestOptions, Agent as HttpsAgent } from 'https'
import { Logger } from '@open-draft/logger'
const logger = new Logger('utils getUrlByRequestOptions')
// Request instance constructed by the "request" library
// has a "self" property that has a "uri" field. This is
// reproducible by performing a "XMLHttpRequest" request in JSDOM.
export interface RequestSelf {
uri?: URL
}
export type ResolvedRequestOptions = RequestOptions & RequestSelf
export const DEFAULT_PATH = '/'
const DEFAULT_PROTOCOL = 'http:'
const DEFAULT_HOSTNAME = 'localhost'
const SSL_PORT = 443
function getAgent(
options: ResolvedRequestOptions
): Agent | HttpsAgent | undefined {
return options.agent instanceof Agent ? options.agent : undefined
}
function getProtocolByRequestOptions(options: ResolvedRequestOptions): string {
if (options.protocol) {
return options.protocol
}
const agent = getAgent(options)
const agentProtocol = (agent as RequestOptions)?.protocol
if (agentProtocol) {
return agentProtocol
}
const port = getPortByRequestOptions(options)
const isSecureRequest = options.cert || port === SSL_PORT
return isSecureRequest ? 'https:' : options.uri?.protocol || DEFAULT_PROTOCOL
}
function getPortByRequestOptions(
options: ResolvedRequestOptions
): number | undefined {
// Use the explicitly provided port.
if (options.port) {
return Number(options.port)
}
// Otherwise, try to resolve port from the agent.
const agent = getAgent(options)
if ((agent as HttpsAgent)?.options.port) {
return Number((agent as HttpsAgent).options.port)
}
if ((agent as RequestOptions)?.defaultPort) {
return Number((agent as RequestOptions).defaultPort)
}
// Lastly, return undefined indicating that the port
// must inferred from the protocol. Do not infer it here.
return undefined
}
interface RequestAuth {
username: string
password: string
}
function getAuthByRequestOptions(
options: ResolvedRequestOptions
): RequestAuth | undefined {
if (options.auth) {
const [username, password] = options.auth.split(':')
return { username, password }
}
}
/**
* Returns true if host looks like an IPv6 address without surrounding brackets
* It assumes any host containing `:` is definitely not IPv4 and probably IPv6,
* but note that this could include invalid IPv6 addresses as well.
*/
function isRawIPv6Address(host: string): boolean {
return host.includes(':') && !host.startsWith('[') && !host.endsWith(']')
}
function getHostname(options: ResolvedRequestOptions): string | undefined {
let host = options.hostname || options.host
if (host) {
if (isRawIPv6Address(host)) {
host = `[${host}]`
}
// Check the presence of the port, and if it's present,
// remove it from the host, returning a hostname.
return new URL(`http://${host}`).hostname
}
return DEFAULT_HOSTNAME
}
/**
* Creates a `URL` instance from a given `RequestOptions` object.
*/
export function getUrlByRequestOptions(options: ResolvedRequestOptions): URL {
logger.info('request options', options)
if (options.uri) {
logger.info(
'constructing url from explicitly provided "options.uri": %s',
options.uri
)
return new URL(options.uri.href)
}
logger.info('figuring out url from request options...')
const protocol = getProtocolByRequestOptions(options)
logger.info('protocol', protocol)
const port = getPortByRequestOptions(options)
logger.info('port', port)
const hostname = getHostname(options)
logger.info('hostname', hostname)
const path = options.path || DEFAULT_PATH
logger.info('path', path)
const credentials = getAuthByRequestOptions(options)
logger.info('credentials', credentials)
const authString = credentials
? `${credentials.username}:${credentials.password}@`
: ''
logger.info('auth string:', authString)
const portString = typeof port !== 'undefined' ? `:${port}` : ''
const url = new URL(`${protocol}//${hostname}${portString}${path}`)
url.username = credentials?.username || ''
url.password = credentials?.password || ''
logger.info('created url:', url)
return url
}
|