Skip to content

fix(httpclient): Do not send undefined headers #8009

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import * as Sentry from '@sentry/browser';
import { HttpClient } from '@sentry/integrations';

window.Sentry = Sentry;

Sentry.init({
dsn: 'https://[email protected]/1337',
integrations: [new HttpClient()],
tracesSampleRate: 1,
sendDefaultPii: false,
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
fetch('http://localhost:7654/foo', {
method: 'GET',
credentials: 'include',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Cache: 'no-cache',
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { expect } from '@playwright/test';
import type { Event } from '@sentry/types';

import { sentryTest } from '../../../../../utils/fixtures';
import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers';

sentryTest(
'should assign request and response context from a failed 500 fetch request without pii',
async ({ getLocalTestPath, page }) => {
const url = await getLocalTestPath({ testDir: __dirname });

await page.route('**/foo', route => {
return route.fulfill({
status: 500,
body: JSON.stringify({
error: {
message: 'Internal Server Error',
},
}),
headers: {
'Content-Type': 'text/html',
},
});
});

const eventData = await getFirstSentryEnvelopeRequest<Event>(page, url);

expect(eventData.exception?.values).toHaveLength(1);

// Not able to get the cookies from the request/response because of Playwright bug
// https://github.com/microsoft/playwright/issues/11035
expect(eventData).toMatchObject({
message: 'HTTP Client Error with status code: 500',
exception: {
values: [
{
type: 'Error',
value: 'HTTP Client Error with status code: 500',
mechanism: {
type: 'http.client',
handled: true,
},
},
],
},
request: {
url: 'http://localhost:7654/foo',
method: 'GET',
headers: {}, // extra properties are ignored in the match object
},
contexts: {
response: {}, // extra properties are ignored in the match object
},
});
expect(eventData.request?.headers).toEqual({
'User-Agent': expect.any(String),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

out of interest, how would this test previously fail? meaning, what used to happen before this PR?

Copy link
Contributor Author

@krystofwoldrich krystofwoldrich May 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Like this toMatchObject ignores extra attributes, but toEqual requires values to be exactly the same.
I've updated the test to use toStrictEqual to catch also undefined keys, but the test looked the same with toEqual because the undefined keys were normalized to string.

Running 1 test using 1 worker

  ✘  1 …tpclient/fetch/simpleNoPii/test.ts:7:11 › should assign request and response context from a failed 500 fetch request without pii (1.7s)


  1) suites/integrations/httpclient/fetch/simpleNoPii/test.ts:7:11 › should assign request and response context from a failed 500 fetch request without pii

    Error: expect(received).toEqual(expected) // deep equality

    - Expected  - 0
    + Received  + 3

      Object {
    +   "body_size": "[undefined]",
    +   "cookies": "[undefined]",
    +   "headers": "[undefined]",
        "status_code": 500,
      }

      56 |       'User-Agent': expect.any(String),
      57 |     });
    > 58 |     expect(eventData.contexts?.response).toEqual({
         |                                          ^
      59 |       status_code: 500,
      60 |     });
      61 |   },

        at /Users/krystofwoldrich/repos/sentry-javascript/packages/browser-integration-tests/suites/integrations/httpclient/fetch/simpleNoPii/test.ts:58:42

  1 failed
    suites/integrations/httpclient/fetch/simpleNoPii/test.ts:7:11 › should assign request and response context from a failed 500 fetch request without pii
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

});
expect(eventData.contexts?.response).toEqual({
status_code: 500,
});
},
);
9 changes: 5 additions & 4 deletions packages/integrations/src/httpclient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type {
import {
addExceptionMechanism,
addInstrumentationHandler,
dropUndefinedKeys,
GLOBAL_OBJ,
logger,
SENTRY_XHR_DATA_KEY,
Expand Down Expand Up @@ -397,19 +398,19 @@ export class HttpClient implements Integration {
},
],
},
request: {
request: dropUndefinedKeys({
url: data.url,
method: data.method,
headers: data.requestHeaders,
cookies: data.requestCookies,
},
}),
contexts: {
response: {
response: dropUndefinedKeys({
status_code: data.status,
headers: data.responseHeaders,
cookies: data.responseCookies,
body_size: this._getResponseSizeFromHeaders(data.responseHeaders),
},
}),
},
};

Expand Down