Skip to content

Commit f17bc54

Browse files
authored
fix(tracing-internal): Prefer fetch init headers over fetch input headers (#10176)
When a `fetch` call is made with a `Request` object as the input/resource param (i.e. the first) and additionally provided headers in the fetch init options (the second param), browsers ignore the headers from the request object but only add the headers from the init options when making the request. Our `fetch` instrumentation had it the other way around, preferring headers from the request object over the headers in the options, as reported in #10172 . This patch fixes this behaviour by essentially turning around the logic we previously had.
1 parent 2171633 commit f17bc54

File tree

4 files changed

+49
-1
lines changed

4 files changed

+49
-1
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import * as Sentry from '@sentry/browser';
2+
import { Integrations } from '@sentry/tracing';
3+
4+
window.Sentry = Sentry;
5+
6+
Sentry.init({
7+
dsn: 'https://[email protected]/1337',
8+
integrations: [new Integrations.BrowserTracing({ tracingOrigins: ['http://example.com'] })],
9+
tracesSampleRate: 1,
10+
});
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const request = new Request('http://example.com/api/test/', {
2+
headers: { foo: '11' },
3+
});
4+
5+
fetch(request, {
6+
headers: { bar: '22' },
7+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { expect } from '@playwright/test';
2+
3+
import { sentryTest } from '../../../../utils/fixtures';
4+
import { shouldSkipTracingTest } from '../../../../utils/helpers';
5+
6+
sentryTest(
7+
'instrumentation should pass on headers from fetch options instead of init request, if set',
8+
async ({ getLocalTestPath, page }) => {
9+
if (shouldSkipTracingTest()) {
10+
sentryTest.skip();
11+
}
12+
13+
await page.route('**/api/test/', async route => {
14+
const req = route.request();
15+
const headers = await req.allHeaders();
16+
17+
// headers.bar was set in fetch options (and should be sent)
18+
expect(headers.bar).toBe('22');
19+
// headers.foo was set in init request object (and should be ignored)
20+
expect(headers.foo).toBeUndefined();
21+
22+
return route.fulfill({
23+
status: 200,
24+
body: 'ok',
25+
});
26+
});
27+
28+
await getLocalTestPath({ testDir: __dirname });
29+
},
30+
);

packages/tracing-internal/src/common/fetch.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ export function addTracingHeadersToFetchRequest(
149149
const sentryBaggageHeader = dynamicSamplingContextToSentryBaggageHeader(dynamicSamplingContext);
150150

151151
const headers =
152-
typeof Request !== 'undefined' && isInstanceOf(request, Request) ? (request as Request).headers : options.headers;
152+
options.headers ||
153+
(typeof Request !== 'undefined' && isInstanceOf(request, Request) ? (request as Request).headers : undefined);
153154

154155
if (!headers) {
155156
return { 'sentry-trace': sentryTraceHeader, baggage: sentryBaggageHeader };

0 commit comments

Comments
 (0)