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