import http from "http" ; import https from "https" ; import * as shimmer from "shimmer" ; import { parse , URL } from "url" ; import { TraceContextService } from "./trace-context-service" ; type RequestCallback = ( res : http . IncomingMessage ) => void ; param contextService export function patchHttp ( contextService ) { patchMethod ( http , "request" , contextService ) ; patchMethod ( http , "get" , contextService ) ; patchMethod ( https , "request" , contextService ) ; patchMethod ( https , "get" , contextService ) ; } /**
 * Removes http patching to add DataDog's tracing headers.
 */ export function unpatchHttp ( ) { unpatchMethod ( http , "request" ) ; unpatchMethod ( http , "get" ) ; unpatchMethod ( https , "request" ) ; unpatchMethod ( https , "get" ) ; } function patchMethod ( mod , method , contextService ) { shimmer . wrap ( mod , method , ( original ) => { const fn = ( arg1 , arg2 , arg3 ) => { [ arg1 , arg2 , arg3 ] = addTraceContextToArgs ( contextService , arg1 , arg2 , arg3 ) ; if ( arg3 === undefined || arg3 === null ) { return original ( arg1 , arg2 ) ; } else { return original ( arg1 , arg2 , arg3 ) ; } } ; return fn as any ; } ) ; } function unpatchMethod ( mod , method ) { if ( mod [ method ] . __wrapped !== undefined ) { shimmer . unwrap ( mod , method ) ; } } /**
 * Finds the RequestOptions in the args and injects context into headers
 */ function addTraceContextToArgs ( contextService , arg1 , arg2 ? , arg3 ? ) { let requestOpts ; if ( typeof arg1 === "string" || arg1 instanceof URL ) { if ( arg2 === undefined || arg2 === null ) { requestOpts = { method : "GET" , } ; requestOpts = getRequestOptionsWithTraceContext ( requestOpts , contextService ) ; return [ arg1 , requestOpts , arg3 ] ; } else if ( typeof arg2 === "function" ) { requestOpts = { method : "GET" , } ; requestOpts = getRequestOptionsWithTraceContext ( requestOpts , contextService ) ; return [ arg1 , requestOpts , arg2 ] ; } else { requestOpts = arg2 as http . RequestOptions ; requestOpts = getRequestOptionsWithTraceContext ( requestOpts , contextService ) ; return [ arg1 , requestOpts , arg3 ] ; } } else { requestOpts = getRequestOptionsWithTraceContext ( arg1 , contextService ) ; return [ requestOpts , arg2 , arg3 ] ; } } function getRequestOptionsWithTraceContext ( options , traceService ) { let { headers } = options ; if ( headers === undefined ) { headers = { } ; } const traceHeaders = traceService . currentTraceHeaders ; headers = { ... headers , ... traceHeaders , } ; const requestOpts = { ... options , headers , } ; if ( isIntegrationTest ( ) ) { _logHttpRequest ( requestOpts ) ; } return requestOpts ; } function isIntegrationTest ( ) { const integrationTestEnvVar = process . env . DD_INTEGRATION_TEST ; if ( typeof integrationTestEnvVar !== "string" ) { return false ; } return integrationTestEnvVar . toLowerCase ( ) === "true" ; } param options function _logHttpRequest ( options ) { let headerMessage = "Headers: []" ; if ( options . headers ) { const headerStrings = Object . entries ( options . headers ) . map ( ( [ name , value ] ) => `${ name }:${ value }` ) ; headerStrings . sort ( ) ; headerMessage = `Headers: ${ JSON . stringify ( headerStrings ) }` ; } const url = `${ options . protocol }//${ options . host || options . hostname }${ options . path }` ; const requestMessage = `HTTP ${ options . method } ${ url } ${ headerMessage }\n` ; process . stdout . write ( requestMessage ) ; }