import * as http from 'http' ; import * as https from 'https' ; import { createLogger , ErrorWithCause , pickIgnoreCase , unixEOL } from '@sap-cloud-sdk/util' ; import axios , { AxiosRequestConfig } from 'axios' ; import { buildHeadersForDestination , Destination , DestinationFetchOptions , toDestinationNameUrl , useOrFetchDestination , getAgentConfig } from '@sap-cloud-sdk/connectivity' ; import { DestinationHttpRequestConfig , ExecuteHttpRequestFn , HttpRequest , HttpRequestConfig , HttpRequestConfigWithOrigin , HttpRequestOptions , HttpResponse } from './http-client-types' ; import { buildHttpRequestConfig } from './http-request-config' ; import { buildCsrfHeaders } from './csrf-token-header' ; const logger = createLogger ( { package : 'http-client' , messageContext : 'http-client' } ) ; param destination param customHeaders returns export async function buildHttpRequest ( destination , customHeaders ? ) { if ( customHeaders ) { logger . info ( `The following custom headers will overwrite headers created by the SDK:\n${ Object . keys ( customHeaders ) . map ( key => `  - "${ key }"` ) . join ( '\n' ) }` ) ; } const resolvedDestination = await resolveDestination ( destination ) ; if ( ! resolvedDestination ) { throw Error ( `Failed to resolve the destination '${ toDestinationNameUrl ( destination ) }'.` ) ; } const headers = await buildHeaders ( resolvedDestination , customHeaders ) ; return buildDestinationHttpRequestConfig ( resolvedDestination , headers ) ; } param destination param requestConfig returns internal export function addDestinationToRequestConfig < T extends HttpRequestConfig > ( destination , requestConfig ) { return buildHttpRequest ( destination ) . then ( destinationConfig => merge ( destinationConfig , requestConfig ) ) ; } param executeFn returns internal export function execute < ReturnT > ( executeFn ) { return async function < T extends HttpRequestConfig > ( destination , requestConfig , options ? ) : Promise < ReturnT > { const destinationRequestConfig = await buildHttpRequest ( destination , requestConfig . headers ) ; const request = merge ( destinationRequestConfig , requestConfig ) ; request . headers = await addCsrfTokenToHeader ( destination , request , options ) ; logRequestInformation ( request ) ; return executeFn ( request ) ; } ; } function logRequestInformation ( request ) { const basicRequestInfo = `Execute '${ request . method }' request with target: ${ request . url }.` ; if ( request . headers ) { const headerText = Object . keys ( request . headers ) . reduce ( ( previous , key ) => { if ( key . toLowerCase ( ) . includes ( 'authentication' ) || key . toLowerCase ( ) . includes ( 'authorization' ) ) { return `${ previous }${ unixEOL }${ key }:*******` ; } return `${ previous }${ unixEOL }${ key }:${ request . headers ! [ key ] }` ; } , 'The headers of the request are:' ) ; logger . debug ( `${ basicRequestInfo }${ unixEOL }${ headerText }` ) ; } } experimental param destination param requestConfig internal export async function buildAxiosRequestConfig < T extends HttpRequestConfig > ( destination , requestConfig ? ) { const destinationRequestConfig = await buildHttpRequest ( destination , requestConfig ?. headers ) ; const request = requestConfig ? merge ( destinationRequestConfig , requestConfig ) : destinationRequestConfig ; return { ... getAxiosConfigWithDefaultsWithoutMethod ( ) , ... request } ; } param destination param requestConfig param options returns export function executeHttpRequest < T extends HttpRequestConfig > ( destination , requestConfig , options ? ) { return execute ( executeWithAxios ) ( destination , requestConfig , options ) ; } param destination param requestConfig param options returns export function executeHttpRequestWithOrigin < T extends HttpRequestConfigWithOrigin > ( destination , requestConfig , options ? ) { return execute ( executeWithAxios ) ( destination , buildHttpRequestConfig ( requestConfig ) , options ) ; } function buildDestinationHttpRequestConfig ( destination , headers ) { return { baseURL : destination . url , headers , params : destination . queryParameters , ... getAgentConfig ( destination ) } ; } function buildHeaders ( destination , customHeaders ? ) { return buildHeadersForDestination ( destination , customHeaders ) . catch ( error => { throw new ErrorWithCause ( 'Failed to build headers.' , error ) ; } ) ; } function resolveDestination ( destination ) { return useOrFetchDestination ( destination ) . catch ( error => { throw new ErrorWithCause ( 'Failed to load destination.' , error ) ; } ) ; } function merge < T extends HttpRequestConfig > ( destinationRequestConfig , customRequestConfig ) ; function merge < T extends HttpRequestConfig > ( destinationRequestConfig , customRequestConfig ) ; function merge < T extends HttpRequestConfig > ( destinationRequestConfig , customRequestConfig ) { return { ... destinationRequestConfig , ... customRequestConfig , headers : { ... destinationRequestConfig . headers , ... customRequestConfig . headers } } ; } function mergeRequestWithAxiosDefaults ( request ) { return { ... getAxiosConfigWithDefaults ( ) , ... request } ; } function executeWithAxios ( request ) { return axios . request ( mergeRequestWithAxiosDefaults ( request ) ) ; } returns internal export function getAxiosConfigWithDefaults ( ) { return { ... getAxiosConfigWithDefaultsWithoutMethod ( ) , method : 'get' } ; } internal export function getAxiosConfigWithDefaultsWithoutMethod ( ) { return { proxy : false , httpAgent : new http . Agent ( ) , httpsAgent : new https . Agent ( ) , paramsSerializer : ( params = { } ) => Object . entries ( params ) . map ( ( [ key , value ] ) => `${ key }=${ value }` ) . join ( '&' ) } ; } function getDefaultHttpRequestOptions ( ) { return { fetchCsrfToken : false } ; } function buildHttpRequestOptions ( httpRequestOptions ? ) { return httpRequestOptions ? { ... getDefaultHttpRequestOptions ( ) , ... httpRequestOptions } : getDefaultHttpRequestOptions ( ) ; } internal export function shouldHandleCsrfToken ( requestConfig , options ) { return ( ! ! options . fetchCsrfToken && requestConfig . method !== 'get' && requestConfig . method !== 'GET' ) ; } async function getCsrfHeaders ( destination , request ) { const csrfHeaders = pickIgnoreCase ( request . headers , 'x-csrf-token' ) ; return Object . keys ( csrfHeaders ) . length ? csrfHeaders : buildCsrfHeaders ( destination , { params : request . params , headers : request . headers , url : request . url , proxy : request . proxy , httpAgent : request . httpAgent , httpsAgent : request . httpsAgent } ) ; } async function addCsrfTokenToHeader ( destination , request , httpRequestOptions ? ) { const options = buildHttpRequestOptions ( httpRequestOptions ) ; const csrfHeaders = shouldHandleCsrfToken ( request , options ) ? await getCsrfHeaders ( destination , request ) : { } ; return { ... request . headers , ... csrfHeaders } ; }