Skip to content

Commit 7236510

Browse files
authored
feat(node): Vendor cookie module (#9308)
1 parent 7abd153 commit 7236510

File tree

4 files changed

+148
-4
lines changed

4 files changed

+148
-4
lines changed

packages/node/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
"@sentry/core": "7.74.1",
2828
"@sentry/types": "7.74.1",
2929
"@sentry/utils": "7.74.1",
30-
"cookie": "^0.5.0",
3130
"https-proxy-agent": "^5.0.0"
3231
},
3332
"devDependencies": {

packages/node/src/cookie.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/**
2+
* This code was originally copied from the 'cookie` module at v0.5.0 and was simplified for our use case.
3+
* https://github.com/jshttp/cookie/blob/a0c84147aab6266bdb3996cf4062e93907c0b0fc/index.js
4+
* It had the following license:
5+
*
6+
* (The MIT License)
7+
*
8+
* Copyright (c) 2012-2014 Roman Shtylman <[email protected]>
9+
* Copyright (c) 2015 Douglas Christopher Wilson <[email protected]>
10+
*
11+
* Permission is hereby granted, free of charge, to any person obtaining
12+
* a copy of this software and associated documentation files (the
13+
* 'Software'), to deal in the Software without restriction, including
14+
* without limitation the rights to use, copy, modify, merge, publish,
15+
* distribute, sublicense, and/or sell copies of the Software, and to
16+
* permit persons to whom the Software is furnished to do so, subject to
17+
* the following conditions:
18+
*
19+
* The above copyright notice and this permission notice shall be
20+
* included in all copies or substantial portions of the Software.
21+
*
22+
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
23+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29+
*/
30+
31+
/**
32+
* Parses a cookie string
33+
*/
34+
export function parseCookie(str: string): Record<string, string> {
35+
const obj: Record<string, string> = {};
36+
let index = 0;
37+
38+
while (index < str.length) {
39+
const eqIdx = str.indexOf('=', index);
40+
41+
// no more cookie pairs
42+
if (eqIdx === -1) {
43+
break;
44+
}
45+
46+
let endIdx = str.indexOf(';', index);
47+
48+
if (endIdx === -1) {
49+
endIdx = str.length;
50+
} else if (endIdx < eqIdx) {
51+
// backtrack on prior semicolon
52+
index = str.lastIndexOf(';', eqIdx - 1) + 1;
53+
continue;
54+
}
55+
56+
const key = str.slice(index, eqIdx).trim();
57+
58+
// only assign once
59+
if (undefined === obj[key]) {
60+
let val = str.slice(eqIdx + 1, endIdx).trim();
61+
62+
// quoted values
63+
if (val.charCodeAt(0) === 0x22) {
64+
val = val.slice(1, -1);
65+
}
66+
67+
try {
68+
obj[key] = val.indexOf('%') !== -1 ? decodeURIComponent(val) : val;
69+
} catch (e) {
70+
obj[key] = val;
71+
}
72+
}
73+
74+
index = endIdx + 1;
75+
}
76+
77+
return obj;
78+
}

packages/node/src/requestdata.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import type {
66
TransactionSource,
77
} from '@sentry/types';
88
import { isPlainObject, isString, normalize, stripUrlQueryAndFragment } from '@sentry/utils';
9-
import * as cookie from 'cookie';
109
import * as url from 'url';
1110

11+
import { parseCookie } from './cookie';
12+
1213
const DEFAULT_INCLUDES = {
1314
ip: false,
1415
request: true,
@@ -202,11 +203,10 @@ export function extractRequestData(
202203
// cookies:
203204
// node, express, koa: req.headers.cookie
204205
// vercel, sails.js, express (w/ cookie middleware), nextjs: req.cookies
205-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
206206
requestData.cookies =
207207
// TODO (v8 / #5257): We're only sending the empty object for backwards compatibility, so the last bit can
208208
// come off in v8
209-
req.cookies || (headers.cookie && cookie.parse(headers.cookie)) || {};
209+
req.cookies || (headers.cookie && parseCookie(headers.cookie)) || {};
210210
break;
211211
}
212212
case 'query_string': {

packages/node/test/cookie.test.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* This code was originally copied from the 'cookie` module at v0.5.0 and was simplified for our use case.
3+
* https://github.com/jshttp/cookie/blob/a0c84147aab6266bdb3996cf4062e93907c0b0fc/test/parse.js
4+
* It had the following license:
5+
*
6+
* (The MIT License)
7+
*
8+
* Copyright (c) 2012-2014 Roman Shtylman <[email protected]>
9+
* Copyright (c) 2015 Douglas Christopher Wilson <[email protected]>
10+
*
11+
* Permission is hereby granted, free of charge, to any person obtaining
12+
* a copy of this software and associated documentation files (the
13+
* 'Software'), to deal in the Software without restriction, including
14+
* without limitation the rights to use, copy, modify, merge, publish,
15+
* distribute, sublicense, and/or sell copies of the Software, and to
16+
* permit persons to whom the Software is furnished to do so, subject to
17+
* the following conditions:
18+
*
19+
* The above copyright notice and this permission notice shall be
20+
* included in all copies or substantial portions of the Software.
21+
*
22+
* THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
23+
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24+
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25+
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
26+
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
27+
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
28+
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29+
*/
30+
31+
import { parseCookie } from '../src/cookie';
32+
33+
describe('parseCookie(str)', function () {
34+
it('should parse cookie string to object', function () {
35+
expect(parseCookie('foo=bar')).toEqual({ foo: 'bar' });
36+
expect(parseCookie('foo=123')).toEqual({ foo: '123' });
37+
});
38+
39+
it('should ignore OWS', function () {
40+
expect(parseCookie('FOO = bar; baz = raz')).toEqual({ FOO: 'bar', baz: 'raz' });
41+
});
42+
43+
it('should parse cookie with empty value', function () {
44+
expect(parseCookie('foo= ; bar=')).toEqual({ foo: '', bar: '' });
45+
});
46+
47+
it('should URL-decode values', function () {
48+
expect(parseCookie('foo="bar=123456789&name=Magic+Mouse"')).toEqual({ foo: 'bar=123456789&name=Magic+Mouse' });
49+
50+
expect(parseCookie('email=%20%22%2c%3b%2f')).toEqual({ email: ' ",;/' });
51+
});
52+
53+
it('should return original value on escape error', function () {
54+
expect(parseCookie('foo=%1;bar=bar')).toEqual({ foo: '%1', bar: 'bar' });
55+
});
56+
57+
it('should ignore cookies without value', function () {
58+
expect(parseCookie('foo=bar;fizz ; buzz')).toEqual({ foo: 'bar' });
59+
expect(parseCookie(' fizz; foo= bar')).toEqual({ foo: 'bar' });
60+
});
61+
62+
it('should ignore duplicate cookies', function () {
63+
expect(parseCookie('foo=%1;bar=bar;foo=boo')).toEqual({ foo: '%1', bar: 'bar' });
64+
expect(parseCookie('foo=false;bar=bar;foo=tre')).toEqual({ foo: 'false', bar: 'bar' });
65+
expect(parseCookie('foo=;bar=bar;foo=boo')).toEqual({ foo: '', bar: 'bar' });
66+
});
67+
});

0 commit comments

Comments
 (0)