1
1
import { createTransport } from '@sentry/core' ;
2
2
import { EventEnvelope , EventItem } from '@sentry/types' ;
3
- import { createEnvelope , serializeEnvelope } from '@sentry/utils' ;
3
+ import { addItemToEnvelope , createAttachmentEnvelopeItem , createEnvelope , serializeEnvelope } from '@sentry/utils' ;
4
4
import * as http from 'http' ;
5
5
import { TextEncoder } from 'util' ;
6
+ import { createGunzip } from 'zlib' ;
6
7
7
8
import { makeNodeTransport } from '../../src/transports' ;
8
9
@@ -34,17 +35,21 @@ let testServer: http.Server | undefined;
34
35
35
36
function setupTestServer (
36
37
options : TestServerOptions ,
37
- requestInspector ?: ( req : http . IncomingMessage , body : string ) => void ,
38
+ requestInspector ?: ( req : http . IncomingMessage , body : string , raw : Uint8Array ) => void ,
38
39
) {
39
40
testServer = http . createServer ( ( req , res ) => {
40
- let body = '' ;
41
+ const chunks : Buffer [ ] = [ ] ;
41
42
42
- req . on ( 'data' , data => {
43
- body += data ;
43
+ const stream = req . headers [ 'content-encoding' ] === 'gzip' ? req . pipe ( createGunzip ( { } ) ) : req ;
44
+
45
+ stream . on ( 'error' , ( ) => { } ) ;
46
+
47
+ stream . on ( 'data' , data => {
48
+ chunks . push ( data ) ;
44
49
} ) ;
45
50
46
- req . on ( 'end' , ( ) => {
47
- requestInspector ?.( req , body ) ;
51
+ stream . on ( 'end' , ( ) => {
52
+ requestInspector ?.( req , chunks . join ( ) , Buffer . concat ( chunks ) ) ;
48
53
} ) ;
49
54
50
55
res . writeHead ( options . statusCode , options . responseHeaders ) ;
@@ -69,6 +74,16 @@ const EVENT_ENVELOPE = createEnvelope<EventEnvelope>({ event_id: 'aa3ff046696b4b
69
74
70
75
const SERIALIZED_EVENT_ENVELOPE = serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ;
71
76
77
+ const ATTACHMENT_ITEM = createAttachmentEnvelopeItem (
78
+ { filename : 'empty-file.bin' , data : new Uint8Array ( 50_000 ) } ,
79
+ new TextEncoder ( ) ,
80
+ ) ;
81
+ const EVENT_ATTACHMENT_ENVELOPE = addItemToEnvelope ( EVENT_ENVELOPE , ATTACHMENT_ITEM ) ;
82
+ const SERIALIZED_EVENT_ATTACHMENT_ENVELOPE = serializeEnvelope (
83
+ EVENT_ATTACHMENT_ENVELOPE ,
84
+ new TextEncoder ( ) ,
85
+ ) as Uint8Array ;
86
+
72
87
const defaultOptions = {
73
88
url : TEST_SERVER_URL ,
74
89
recordDroppedEvent : ( ) => undefined ,
@@ -155,6 +170,40 @@ describe('makeNewHttpTransport()', () => {
155
170
} ) ;
156
171
} ) ;
157
172
173
+ describe ( 'compression' , ( ) => {
174
+ it ( 'small envelopes should not be compressed' , async ( ) => {
175
+ await setupTestServer (
176
+ {
177
+ statusCode : SUCCESS ,
178
+ responseHeaders : { } ,
179
+ } ,
180
+ ( req , body ) => {
181
+ expect ( req . headers [ 'content-encoding' ] ) . toBeUndefined ( ) ;
182
+ expect ( body ) . toBe ( SERIALIZED_EVENT_ENVELOPE ) ;
183
+ } ,
184
+ ) ;
185
+
186
+ const transport = makeNodeTransport ( defaultOptions ) ;
187
+ await transport . send ( EVENT_ENVELOPE ) ;
188
+ } ) ;
189
+
190
+ it ( 'large envelopes should be compressed' , async ( ) => {
191
+ await setupTestServer (
192
+ {
193
+ statusCode : SUCCESS ,
194
+ responseHeaders : { } ,
195
+ } ,
196
+ ( req , _ , raw ) => {
197
+ expect ( req . headers [ 'content-encoding' ] ) . toEqual ( 'gzip' ) ;
198
+ expect ( raw . buffer ) . toStrictEqual ( SERIALIZED_EVENT_ATTACHMENT_ENVELOPE . buffer ) ;
199
+ } ,
200
+ ) ;
201
+
202
+ const transport = makeNodeTransport ( defaultOptions ) ;
203
+ await transport . send ( EVENT_ATTACHMENT_ENVELOPE ) ;
204
+ } ) ;
205
+ } ) ;
206
+
158
207
describe ( 'proxy' , ( ) => {
159
208
it ( 'can be configured through option' , ( ) => {
160
209
makeNodeTransport ( {
@@ -236,104 +285,106 @@ describe('makeNewHttpTransport()', () => {
236
285
} ) ;
237
286
} ) ;
238
287
239
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (rate limit)' , async ( ) => {
240
- await setupTestServer ( {
241
- statusCode : RATE_LIMIT ,
242
- responseHeaders : { } ,
243
- } ) ;
244
-
245
- makeNodeTransport ( defaultOptions ) ;
246
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
247
-
248
- const executorResult = registeredRequestExecutor ( {
249
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
250
- category : 'error' ,
251
- } ) ;
252
-
253
- await expect ( executorResult ) . resolves . toEqual (
254
- expect . objectContaining ( {
288
+ describe ( 'should register TransportRequestExecutor that returns the correct object from server response' , ( ) => {
289
+ it ( 'rate limit' , async ( ) => {
290
+ await setupTestServer ( {
255
291
statusCode : RATE_LIMIT ,
256
- } ) ,
257
- ) ;
258
- } ) ;
292
+ responseHeaders : { } ,
293
+ } ) ;
259
294
260
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (OK)' , async ( ) => {
261
- await setupTestServer ( {
262
- statusCode : SUCCESS ,
263
- } ) ;
295
+ makeNodeTransport ( defaultOptions ) ;
296
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
264
297
265
- makeNodeTransport ( defaultOptions ) ;
266
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
298
+ const executorResult = registeredRequestExecutor ( {
299
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
300
+ category : 'error' ,
301
+ } ) ;
267
302
268
- const executorResult = registeredRequestExecutor ( {
269
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
270
- category : 'error' ,
303
+ await expect ( executorResult ) . resolves . toEqual (
304
+ expect . objectContaining ( {
305
+ statusCode : RATE_LIMIT ,
306
+ } ) ,
307
+ ) ;
271
308
} ) ;
272
309
273
- await expect ( executorResult ) . resolves . toEqual (
274
- expect . objectContaining ( {
310
+ it ( 'OK' , async ( ) => {
311
+ await setupTestServer ( {
275
312
statusCode : SUCCESS ,
276
- headers : {
277
- 'retry-after' : null ,
278
- 'x-sentry-rate-limits' : null ,
279
- } ,
280
- } ) ,
281
- ) ;
282
- } ) ;
313
+ } ) ;
283
314
284
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (OK with rate-limit headers)' , async ( ) => {
285
- await setupTestServer ( {
286
- statusCode : SUCCESS ,
287
- responseHeaders : {
288
- 'Retry-After' : '2700' ,
289
- 'X-Sentry-Rate-Limits' : '60::organization, 2700::organization' ,
290
- } ,
291
- } ) ;
315
+ makeNodeTransport ( defaultOptions ) ;
316
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
292
317
293
- makeNodeTransport ( defaultOptions ) ;
294
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
318
+ const executorResult = registeredRequestExecutor ( {
319
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
320
+ category : 'error' ,
321
+ } ) ;
295
322
296
- const executorResult = registeredRequestExecutor ( {
297
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
298
- category : 'error' ,
323
+ await expect ( executorResult ) . resolves . toEqual (
324
+ expect . objectContaining ( {
325
+ statusCode : SUCCESS ,
326
+ headers : {
327
+ 'retry-after' : null ,
328
+ 'x-sentry-rate-limits' : null ,
329
+ } ,
330
+ } ) ,
331
+ ) ;
299
332
} ) ;
300
333
301
- await expect ( executorResult ) . resolves . toEqual (
302
- expect . objectContaining ( {
334
+ it ( 'OK with rate-limit headers' , async ( ) => {
335
+ await setupTestServer ( {
303
336
statusCode : SUCCESS ,
304
- headers : {
305
- 'retry-after ' : '2700' ,
306
- 'x-sentry-rate-limits ' : '60::organization, 2700::organization' ,
337
+ responseHeaders : {
338
+ 'Retry-After ' : '2700' ,
339
+ 'X-Sentry-Rate-Limits ' : '60::organization, 2700::organization' ,
307
340
} ,
308
- } ) ,
309
- ) ;
310
- } ) ;
341
+ } ) ;
311
342
312
- it ( 'should register TransportRequestExecutor that returns the correct object from server response (NOK with rate-limit headers)' , async ( ) => {
313
- await setupTestServer ( {
314
- statusCode : RATE_LIMIT ,
315
- responseHeaders : {
316
- 'Retry-After' : '2700' ,
317
- 'X-Sentry-Rate-Limits' : '60::organization, 2700::organization' ,
318
- } ,
319
- } ) ;
343
+ makeNodeTransport ( defaultOptions ) ;
344
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
320
345
321
- makeNodeTransport ( defaultOptions ) ;
322
- const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
346
+ const executorResult = registeredRequestExecutor ( {
347
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
348
+ category : 'error' ,
349
+ } ) ;
323
350
324
- const executorResult = registeredRequestExecutor ( {
325
- body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
326
- category : 'error' ,
351
+ await expect ( executorResult ) . resolves . toEqual (
352
+ expect . objectContaining ( {
353
+ statusCode : SUCCESS ,
354
+ headers : {
355
+ 'retry-after' : '2700' ,
356
+ 'x-sentry-rate-limits' : '60::organization, 2700::organization' ,
357
+ } ,
358
+ } ) ,
359
+ ) ;
327
360
} ) ;
328
361
329
- await expect ( executorResult ) . resolves . toEqual (
330
- expect . objectContaining ( {
362
+ it ( 'NOK with rate-limit headers' , async ( ) => {
363
+ await setupTestServer ( {
331
364
statusCode : RATE_LIMIT ,
332
- headers : {
333
- 'retry-after ' : '2700' ,
334
- 'x-sentry-rate-limits ' : '60::organization, 2700::organization' ,
365
+ responseHeaders : {
366
+ 'Retry-After ' : '2700' ,
367
+ 'X-Sentry-Rate-Limits ' : '60::organization, 2700::organization' ,
335
368
} ,
336
- } ) ,
337
- ) ;
369
+ } ) ;
370
+
371
+ makeNodeTransport ( defaultOptions ) ;
372
+ const registeredRequestExecutor = ( createTransport as jest . Mock ) . mock . calls [ 0 ] [ 1 ] ;
373
+
374
+ const executorResult = registeredRequestExecutor ( {
375
+ body : serializeEnvelope ( EVENT_ENVELOPE , new TextEncoder ( ) ) ,
376
+ category : 'error' ,
377
+ } ) ;
378
+
379
+ await expect ( executorResult ) . resolves . toEqual (
380
+ expect . objectContaining ( {
381
+ statusCode : RATE_LIMIT ,
382
+ headers : {
383
+ 'retry-after' : '2700' ,
384
+ 'x-sentry-rate-limits' : '60::organization, 2700::organization' ,
385
+ } ,
386
+ } ) ,
387
+ ) ;
388
+ } ) ;
338
389
} ) ;
339
390
} ) ;
0 commit comments