@@ -103,8 +103,10 @@ export function instrumentFetchRequest(
103103
104104/**
105105 * Adds sentry-trace and baggage headers to the various forms of fetch headers.
106+ * exported only for testing purposes
106107 */
107- function _addTracingHeadersToFetchRequest (
108+ // eslint-disable-next-line complexity -- yup it's this complicated :(
109+ export function _addTracingHeadersToFetchRequest (
108110 request : string | Request ,
109111 fetchOptionsObj : {
110112 headers ?:
@@ -124,78 +126,74 @@ function _addTracingHeadersToFetchRequest(
124126 return undefined ;
125127 }
126128
127- const headers = fetchOptionsObj . headers || ( isRequest ( request ) ? request . headers : undefined ) ;
129+ const originalHeaders = fetchOptionsObj . headers || ( isRequest ( request ) ? request . headers : undefined ) ;
128130
129- if ( ! headers ) {
131+ if ( ! originalHeaders ) {
130132 return { ...traceHeaders } ;
131- } else if ( isHeaders ( headers ) ) {
132- const newHeaders = new Headers ( headers ) ;
133- newHeaders . set ( 'sentry-trace' , sentryTrace ) ;
133+ } else if ( isHeaders ( originalHeaders ) ) {
134+ const newHeaders = new Headers ( originalHeaders ) ;
135+
136+ // We don't want to override manually added sentry headers
137+ if ( ! newHeaders . get ( 'sentry-trace' ) ) {
138+ newHeaders . set ( 'sentry-trace' , sentryTrace ) ;
139+ }
134140
135141 if ( baggage ) {
136142 const prevBaggageHeader = newHeaders . get ( 'baggage' ) ;
137- if ( prevBaggageHeader ) {
138- const prevHeaderStrippedFromSentryBaggage = stripBaggageHeaderOfSentryBaggageValues ( prevBaggageHeader ) ;
139- newHeaders . set (
140- 'baggage' ,
141- // If there are non-sentry entries (i.e. if the stripped string is non-empty/truthy) combine the stripped header and sentry baggage header
142- // otherwise just set the sentry baggage header
143- prevHeaderStrippedFromSentryBaggage ? `${ prevHeaderStrippedFromSentryBaggage } ,${ baggage } ` : baggage ,
144- ) ;
145- } else {
143+
144+ // 3 cases:
145+ // 1. No previous baggage header -> add baggage
146+ // 2. Previous baggage header has no sentry baggage values -> add our baggage
147+ // 3. Previous baggage header has sentry baggage values -> do nothing (might have been added manually by users)
148+ if ( ! prevBaggageHeader ) {
146149 newHeaders . set ( 'baggage' , baggage ) ;
150+ } else if ( ! baggageHeaderHasSentryBaggageValues ( prevBaggageHeader ) ) {
151+ newHeaders . set ( 'baggage' , `${ prevBaggageHeader } ,${ baggage } ` ) ;
147152 }
148153 }
149154
150155 return newHeaders ;
151- } else if ( Array . isArray ( headers ) ) {
152- const newHeaders = [
153- ...headers
154- // Remove any existing sentry-trace headers
155- . filter ( header => {
156- return ! ( Array . isArray ( header ) && header [ 0 ] === 'sentry-trace' ) ;
157- } )
158- // Get rid of previous sentry baggage values in baggage header
159- . map ( header => {
160- if ( Array . isArray ( header ) && header [ 0 ] === 'baggage' && typeof header [ 1 ] === 'string' ) {
161- const [ headerName , headerValue , ...rest ] = header ;
162- return [ headerName , stripBaggageHeaderOfSentryBaggageValues ( headerValue ) , ...rest ] ;
163- } else {
164- return header ;
165- }
166- } ) ,
167- // Attach the new sentry-trace header
168- [ 'sentry-trace' , sentryTrace ] ,
169- ] ;
156+ } else if ( Array . isArray ( originalHeaders ) ) {
157+ const newHeaders = [ ...originalHeaders ] ;
170158
171- if ( baggage ) {
159+ if ( ! originalHeaders . find ( header => header [ 0 ] === 'sentry-trace' ) ) {
160+ newHeaders . push ( [ 'sentry-trace' , sentryTrace ] ) ;
161+ }
162+
163+ const prevBaggageHeaderWithSentryValues = originalHeaders . find (
164+ header => header [ 0 ] === 'baggage' && baggageHeaderHasSentryBaggageValues ( header [ 1 ] ) ,
165+ ) ;
166+
167+ if ( baggage && ! prevBaggageHeaderWithSentryValues ) {
172168 // If there are multiple entries with the same key, the browser will merge the values into a single request header.
173169 // Its therefore safe to simply push a "baggage" entry, even though there might already be another baggage header.
174170 newHeaders . push ( [ 'baggage' , baggage ] ) ;
175171 }
176172
177173 return newHeaders as PolymorphicRequestHeaders ;
178174 } else {
179- const existingBaggageHeader = 'baggage' in headers ? headers . baggage : undefined ;
180- let newBaggageHeaders : string [ ] = [ ] ;
181-
182- if ( Array . isArray ( existingBaggageHeader ) ) {
183- newBaggageHeaders = existingBaggageHeader
184- . map ( headerItem =>
185- typeof headerItem === 'string' ? stripBaggageHeaderOfSentryBaggageValues ( headerItem ) : headerItem ,
186- )
187- . filter ( headerItem => headerItem === '' ) ;
188- } else if ( existingBaggageHeader ) {
189- newBaggageHeaders . push ( stripBaggageHeaderOfSentryBaggageValues ( existingBaggageHeader ) ) ;
190- }
191-
192- if ( baggage ) {
175+ const existingSentryTraceHeader = 'sentry-trace' in originalHeaders ? originalHeaders [ 'sentry-trace' ] : undefined ;
176+
177+ const existingBaggageHeader = 'baggage' in originalHeaders ? originalHeaders . baggage : undefined ;
178+ const newBaggageHeaders : string [ ] = existingBaggageHeader
179+ ? Array . isArray ( existingBaggageHeader )
180+ ? [ ...existingBaggageHeader ]
181+ : [ existingBaggageHeader ]
182+ : [ ] ;
183+
184+ const prevBaggageHeaderWithSentryValues =
185+ existingBaggageHeader &&
186+ ( Array . isArray ( existingBaggageHeader )
187+ ? existingBaggageHeader . find ( headerItem => baggageHeaderHasSentryBaggageValues ( headerItem ) )
188+ : baggageHeaderHasSentryBaggageValues ( existingBaggageHeader ) ) ;
189+
190+ if ( baggage && ! prevBaggageHeaderWithSentryValues ) {
193191 newBaggageHeaders . push ( baggage ) ;
194192 }
195193
196194 return {
197- ...( headers as Exclude < typeof headers , Headers > ) ,
198- 'sentry-trace' : sentryTrace ,
195+ ...( originalHeaders as Exclude < typeof originalHeaders , Headers > ) ,
196+ 'sentry-trace' : ( existingSentryTraceHeader as string | undefined ) ?? sentryTrace ,
199197 baggage : newBaggageHeaders . length > 0 ? newBaggageHeaders . join ( ',' ) : undefined ,
200198 } ;
201199 }
@@ -219,14 +217,10 @@ function endSpan(span: Span, handlerData: HandlerDataFetch): void {
219217 span . end ( ) ;
220218}
221219
222- function stripBaggageHeaderOfSentryBaggageValues ( baggageHeader : string ) : string {
223- return (
224- baggageHeader
225- . split ( ',' )
226- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
227- . filter ( baggageEntry => ! baggageEntry . split ( '=' ) [ 0 ] ! . startsWith ( SENTRY_BAGGAGE_KEY_PREFIX ) )
228- . join ( ',' )
229- ) ;
220+ function baggageHeaderHasSentryBaggageValues ( baggageHeader : string ) : boolean {
221+ return baggageHeader
222+ . split ( ',' )
223+ . some ( baggageEntry => baggageEntry . split ( '=' ) [ 0 ] ?. startsWith ( SENTRY_BAGGAGE_KEY_PREFIX ) ) ;
230224}
231225
232226function isHeaders ( headers : unknown ) : headers is Headers {
0 commit comments