Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ [RUMF-1469] introduce a new proxy initialization parameter #1947

Merged
merged 8 commits into from
Feb 8, 2023
7 changes: 6 additions & 1 deletion packages/core/src/domain/configuration/configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ export interface InitConfiguration {
trackLongTasks?: boolean | undefined

// transport options
proxy?: string | undefined
/**
* @deprecated use `proxy` instead
*/
proxyUrl?: string | undefined
site?: string | undefined

Expand Down Expand Up @@ -164,14 +168,15 @@ function mustUseSecureCookie(initConfiguration: InitConfiguration) {
}

export function serializeConfiguration(configuration: InitConfiguration): Partial<RawTelemetryConfiguration> {
const proxy = configuration.proxy ?? configuration.proxyUrl
return {
session_sample_rate: configuration.sessionSampleRate ?? configuration.sampleRate,
telemetry_sample_rate: configuration.telemetrySampleRate,
telemetry_configuration_sample_rate: configuration.telemetryConfigurationSampleRate,
use_before_send: !!configuration.beforeSend,
use_cross_site_session_cookie: configuration.useCrossSiteSessionCookie,
use_secure_session_cookie: configuration.useSecureSessionCookie,
use_proxy: configuration.proxyUrl !== undefined ? !!configuration.proxyUrl : undefined,
use_proxy: proxy !== undefined ? !!proxy : undefined,
silent_multiple_init: configuration.silentMultipleInit,
track_session_across_subdomains: configuration.trackSessionAcrossSubdomains,
track_resources: configuration.trackResources,
Expand Down
52 changes: 51 additions & 1 deletion packages/core/src/domain/configuration/endpointBuilder.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { BuildEnvWindow } from '../../../test/specHelper'
import { startsWith } from '../../tools/utils'
import type { InitConfiguration } from './configuration'
import { createEndpointBuilder } from './endpointBuilder'

Expand Down Expand Up @@ -36,7 +37,47 @@ describe('endpointBuilder', () => {
})
})

describe('proxyUrl', () => {
describe('proxy configuration', () => {
it('should replace the intake endpoint by the proxy and set the intake path and parameters in the attribute ddforward', () => {
expect(
createEndpointBuilder({ ...initConfiguration, proxy: 'https://proxy.io/path' }, 'rum', []).build('xhr')
).toMatch(
`https://proxy.io/path\\?ddforward=${encodeURIComponent(
`/api/v2/rum?ddsource=(.*)&ddtags=(.*)&dd-api-key=${clientToken}` +
'&dd-evp-origin-version=(.*)&dd-evp-origin=browser&dd-request-id=(.*)&batch_time=(.*)'
)}`
)
})

it('normalizes the proxy url', () => {
bcaudan marked this conversation as resolved.
Show resolved Hide resolved
expect(
startsWith(
createEndpointBuilder({ ...initConfiguration, proxy: '/path' }, 'rum', []).build('xhr'),
`${location.origin}/path?ddforward`
)
).toBeTrue()
})

it('uses `proxy` over `proxyUrl`', () => {
expect(
createEndpointBuilder(
{ ...initConfiguration, proxy: 'https://proxy.io/path', proxyUrl: 'https://legacy-proxy.io/path' },
'rum',
[]
).build('xhr')
).toMatch(/^https:\/\/proxy.io\/path\?/)

expect(
createEndpointBuilder(
{ ...initConfiguration, proxy: false as any, proxyUrl: 'https://legacy-proxy.io/path' },
'rum',
[]
).build('xhr')
).toMatch(/^https:\/\/rum.browser-intake-datadoghq.com\//)
})
})

describe('deprecated proxyUrl configuration', () => {
it('should replace the full intake endpoint by the proxyUrl and set it in the attribute ddforward', () => {
expect(
createEndpointBuilder({ ...initConfiguration, proxyUrl: 'https://proxy.io/path' }, 'rum', []).build('xhr')
Expand All @@ -47,6 +88,15 @@ describe('endpointBuilder', () => {
)}`
)
})

it('normalizes the proxy url', () => {
expect(
startsWith(
createEndpointBuilder({ ...initConfiguration, proxyUrl: '/path' }, 'rum', []).build('xhr'),
`${location.origin}/path?ddforward`
)
).toBeTrue()
})
})

describe('tags', () => {
Expand Down
32 changes: 23 additions & 9 deletions packages/core/src/domain/configuration/endpointBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ export function createEndpointBuilder(
) {
const { clientToken } = initConfiguration

const host = buildEndpointHost(initConfiguration, endpointType)
const baseUrl = `https://${host}/api/v2/${INTAKE_TRACKS[endpointType]}`
const proxyUrl = initConfiguration.proxyUrl && normalizeUrl(initConfiguration.proxyUrl)
const baseUrl = buildEndpointBaseUrl(initConfiguration, endpointType)
const proxyUrl = buildProxyUrl(initConfiguration)
bcaudan marked this conversation as resolved.
Show resolved Hide resolved

return {
build(api: 'xhr' | 'fetch' | 'beacon', retry?: RetryInfo) {
Expand Down Expand Up @@ -67,14 +66,29 @@ export function createEndpointBuilder(
}
}

function buildEndpointHost(initConfiguration: InitConfiguration, endpointType: EndpointType) {
const { site = INTAKE_SITE_US1, internalAnalyticsSubdomain } = initConfiguration
function buildProxyUrl({ proxy, proxyUrl }: InitConfiguration) {
const rawProxyUrl = proxy ?? proxyUrl
return rawProxyUrl && normalizeUrl(rawProxyUrl)
}

function buildEndpointBaseUrl(
{ site = INTAKE_SITE_US1, internalAnalyticsSubdomain, proxy }: InitConfiguration,
endpointType: EndpointType
) {
const path = `/api/v2/${INTAKE_TRACKS[endpointType]}`

if (proxy) {
return path
}

let host: string
if (internalAnalyticsSubdomain && site === INTAKE_SITE_US1) {
return `${internalAnalyticsSubdomain}.${INTAKE_SITE_US1}`
host = `${internalAnalyticsSubdomain}.${INTAKE_SITE_US1}`
} else {
const domainParts = site.split('.')
const extension = domainParts.pop()
host = `${ENDPOINTS[endpointType]}.browser-intake-${domainParts.join('-')}.${extension!}`
}

const domainParts = site.split('.')
const extension = domainParts.pop()
return `${ENDPOINTS[endpointType]}.browser-intake-${domainParts.join('-')}.${extension!}`
return `https://${host}${path}`
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,30 @@ describe('transportConfiguration', () => {
configuration.isIntakeUrl('https://session-replay.browser-intake-foo-datadoghq.com/api/v2/replay?xxx')
).toBe(true)
})
;['proxy' as const, 'proxyUrl' as const].forEach((proxyConfigurationName) => {
describe(`${proxyConfigurationName} configuration`, () => {
it('should detect proxy intake request', () => {
let configuration = computeTransportConfiguration({
clientToken,
[proxyConfigurationName]: 'https://www.proxy.com',
})
expect(configuration.isIntakeUrl('https://www.proxy.com/?ddforward=xxx')).toBe(true)

configuration = computeTransportConfiguration({
clientToken,
[proxyConfigurationName]: 'https://www.proxy.com/custom/path',
})
expect(configuration.isIntakeUrl('https://www.proxy.com/custom/path?ddforward=xxx')).toBe(true)
})

it('should detect proxy intake request', () => {
let configuration = computeTransportConfiguration({ clientToken, proxyUrl: 'https://www.proxy.com' })
expect(configuration.isIntakeUrl('https://www.proxy.com/?ddforward=xxx')).toBe(true)

configuration = computeTransportConfiguration({ clientToken, proxyUrl: 'https://www.proxy.com/custom/path' })
expect(configuration.isIntakeUrl('https://www.proxy.com/custom/path?ddforward=xxx')).toBe(true)
})

it('should not detect request done on the same host as the proxy', () => {
const configuration = computeTransportConfiguration({ clientToken, proxyUrl: 'https://www.proxy.com' })
expect(configuration.isIntakeUrl('https://www.proxy.com/foo')).toBe(false)
it('should not detect request done on the same host as the proxy', () => {
const configuration = computeTransportConfiguration({
clientToken,
[proxyConfigurationName]: 'https://www.proxy.com',
})
expect(configuration.isIntakeUrl('https://www.proxy.com/foo')).toBe(false)
})
})
})
;[
{ site: 'datadoghq.eu', intakeDomain: 'browser-intake-datadoghq.eu' },
Expand Down