import { URL } from 'url' ; import { isIPv6 } from 'net' ; import tls , { ConnectionOptions } from 'tls' ; import http , { ClientRequest , ClientRequestArgs } from 'http' ; import https from 'https' ; interface AgentOptions extends http . AgentOptions { proxy : string | URL ; disableConnect ? : boolean ; } const initialize = ( self , options ) => { self . proxy = typeof options . proxy === 'string' ? new URL ( options . proxy ) : options . proxy ; } ; const getBasic = ( url ) : string => { let basic = '' ; if ( url . username || url . password ) { const username = decodeURIComponent ( url . username ) ; const password = decodeURIComponent ( url . password ) ; basic = Buffer . from ( `${ username }:${ password }` ) . toString ( 'base64' ) ; return `Basic ${ basic }` ; } return basic ; } ; export class HttpRegularProxyAgent extends http . Agent { proxy ! : URL ; constructor ( options ) { super ( options ) ; initialize ( this , options ) ; } addRequest ( request , options ) { if ( options . socketPath ) { super . addRequest ( request , options ) ; return ; } let hostport = `${ options . host }:${ options . port }` ; if ( isIPv6 ( options . host ! ) ) { hostport = `[${ options . host }]:${ options . port }` ; } const url = new URL ( `${ request . protocol }//${ hostport }${ request . path }` ) ; options = { ... options , host : this . proxy . hostname , port : this . proxy . port , } ; request . path = url . href ; const basic = getBasic ( this . proxy ) ; if ( basic ) { request . setHeader ( 'proxy-authorization' , basic ) ; } super . addRequest ( request , options ) ; } } export class HttpProxyAgent extends http . Agent { proxy ! : URL ; constructor ( options ) { super ( options ) ; initialize ( this , options ) ; } createConnection ( options , callback ) { if ( options . path ) { super . createConnection ( options , callback ) ; return ; } const fn = this . proxy . protocol === 'https:' ? https . request : http . request ; let hostport = `${ options . host }:${ options . port }` ; if ( isIPv6 ( options . host ! ) ) { hostport = `[${ options . host }]:${ options . port }` ; } const headers = { host : hostport , } ; const basic = getBasic ( this . proxy ) ; if ( basic ) { headers [ 'proxy-authorization' ] = basic ; headers . authorization = basic ; } const connectRequest = fn ( this . proxy , { method : 'CONNECT' , headers , path : hostport , agent : false , rejectUnauthorized : false , } ) ; connectRequest . once ( 'connect' , ( response , socket , head ) => { if ( head . length > 0 || response . statusCode !== 200 ) { socket . destroy ( ) ; const error = new Error ( `The proxy responded with ${ response . statusCode }: ${ head . toString ( ) }` ) ; callback ( error ) ; return ; } if ( ( options as any ) . protocol === 'https:' ) { callback ( undefined , tls . connect ( { ... options , socket , } ) ) ; return ; } callback ( undefined , socket ) ; } ) ; connectRequest . once ( 'error' , ( error ) => { callback ( error ) ; } ) ; connectRequest . end ( ) ; } } export class HttpsProxyAgent extends https . Agent { proxy ! : URL ; constructor ( options ) { super ( options ) ; initialize ( this , options ) ; } createConnection ( options , callback ) { HttpProxyAgent . prototype . createConnection . call ( this , options , callback ) ; } }