1
1
import { captureEvent , getCurrentHub } from '@sentry/core' ;
2
2
import { Event as SentryEvent , Integration } from '@sentry/types' ;
3
- import { addExceptionMechanism , fill , GLOBAL_OBJ , logger } from '@sentry/utils' ;
3
+ import { addExceptionMechanism , fill , GLOBAL_OBJ , logger , supportsNativeFetch } from '@sentry/utils' ;
4
4
5
5
import { eventFromUnknownInput } from '../eventbuilder' ;
6
6
7
7
export type HttpStatusCodeRange = [ number , number ] | number ;
8
8
export type HttpRequestTarget = string | RegExp ;
9
-
10
9
interface HttpClientOptions {
10
+ /**
11
+ * Controls whether failed requests should be captured.
12
+ *
13
+ * Default: false
14
+ */
11
15
captureFailedRequests ?: boolean ;
16
+
17
+ /**
18
+ * HTTP status codes that should be considered failed.
19
+ * This array can contain tuples of `[begin, end]` (both inclusive),
20
+ * single status codes, or a combinations of both
21
+ *
22
+ * Example: [[500, 505], 507]
23
+ * Default: [[500, 599]]
24
+ */
12
25
failedRequestStatusCodes ?: HttpStatusCodeRange [ ] ;
26
+
27
+ /**
28
+ * Targets to track for failed requests.
29
+ * This array can contain strings or regular expressions.
30
+ *
31
+ * Example: ['http://localhost', /api\/.*\/]
32
+ * Default: [/.*\/]
33
+ */
13
34
failedRequestTargets ?: HttpRequestTarget [ ] ;
14
35
}
15
36
@@ -65,7 +86,6 @@ export class HttpClient implements Integration {
65
86
private _fetchResponseHandler ( requestInfo : RequestInfo , response : Response , requestInit ?: RequestInit ) : void {
66
87
if ( this . _shouldCaptureResponse ( response . status , response . url ) ) {
67
88
const request = new Request ( requestInfo , requestInit ) ;
68
- const url = new URL ( request . url ) ;
69
89
70
90
let requestHeaders , responseHeaders , requestCookies , responseCookies ;
71
91
@@ -96,7 +116,7 @@ export class HttpClient implements Integration {
96
116
}
97
117
98
118
const event = this . _createEvent ( {
99
- url : url ,
119
+ url : request . url ,
100
120
method : request . method ,
101
121
status : response . status ,
102
122
requestHeaders,
@@ -105,12 +125,7 @@ export class HttpClient implements Integration {
105
125
responseCookies,
106
126
} ) ;
107
127
108
- captureEvent ( event , {
109
- data : {
110
- OK_HTTP_REQUEST : request ,
111
- OK_HTTP_RESPONSE : response ,
112
- } ,
113
- } ) ;
128
+ captureEvent ( event ) ;
114
129
}
115
130
}
116
131
@@ -123,8 +138,6 @@ export class HttpClient implements Integration {
123
138
*/
124
139
private _xhrResponseHandler ( xhr : XMLHttpRequest , method : string , headers : Record < string , string > ) : void {
125
140
if ( this . _shouldCaptureResponse ( xhr . status , xhr . responseURL ) ) {
126
- const url = new URL ( xhr . responseURL ) ;
127
-
128
141
let requestHeaders , responseCookies , responseHeaders ;
129
142
130
143
if ( getCurrentHub ( ) . shouldSendDefaultPii ( ) ) {
@@ -148,7 +161,7 @@ export class HttpClient implements Integration {
148
161
}
149
162
150
163
const event = this . _createEvent ( {
151
- url : url ,
164
+ url : xhr . responseURL ,
152
165
method : method ,
153
166
status : xhr . status ,
154
167
requestHeaders,
@@ -274,34 +287,30 @@ export class HttpClient implements Integration {
274
287
*
275
288
*/
276
289
private _wrapFetch ( ) : void {
277
- if ( ! ( 'fetch' in GLOBAL_OBJ ) ) {
290
+ if ( ! supportsNativeFetch ( ) ) {
278
291
return ;
279
292
}
280
293
281
294
// eslint-disable-next-line @typescript-eslint/no-this-alias
282
295
const self = this ;
283
296
284
- fill (
285
- GLOBAL_OBJ ,
286
- 'fetch' ,
287
- function ( originalFetch : ( requestInfo : RequestInfo , requestInit ?: RequestInit ) => Promise < Response > ) {
288
- return function ( this : Window , requestInfo : RequestInfo , requestInit ?: RequestInit ) : Promise < Response > {
289
- const responsePromise : Promise < Response > = originalFetch . apply ( this , [ requestInfo , requestInit ] ) ;
290
-
291
- responsePromise
292
- . then ( ( response : Response ) => {
293
- self . _fetchResponseHandler ( requestInfo , response , requestInit ) ;
294
- return response ;
295
- } )
296
- . catch ( ( error : Error ) => {
297
- // TODO:
298
- throw error ;
299
- } ) ;
300
-
301
- return responsePromise ;
302
- } ;
303
- } ,
304
- ) ;
297
+ fill ( GLOBAL_OBJ , 'fetch' , function ( originalFetch : ( ...args : unknown [ ] ) => Promise < Response > ) {
298
+ return function ( this : Window , ...args : unknown [ ] ) : Promise < Response > {
299
+ const [ requestInfo , requestInit ] = args as [ RequestInfo , RequestInit | undefined ] ;
300
+ const responsePromise : Promise < Response > = originalFetch . apply ( this , args ) ;
301
+
302
+ responsePromise
303
+ . then ( ( response : Response ) => {
304
+ self . _fetchResponseHandler ( requestInfo , response , requestInit ) ;
305
+ return response ;
306
+ } )
307
+ . catch ( ( error : Error ) => {
308
+ throw error ;
309
+ } ) ;
310
+
311
+ return responsePromise ;
312
+ } ;
313
+ } ) ;
305
314
}
306
315
307
316
/**
@@ -315,11 +324,11 @@ export class HttpClient implements Integration {
315
324
// eslint-disable-next-line @typescript-eslint/no-this-alias
316
325
const self = this ;
317
326
318
- fill ( XMLHttpRequest . prototype , 'open' , function ( originalOpen : ( method : string ) => void ) : ( ) => void {
319
- return function ( this : XMLHttpRequest , ...openArgs : any [ ] ) : void {
327
+ fill ( XMLHttpRequest . prototype , 'open' , function ( originalOpen : ( ... openArgs : unknown [ ] ) => void ) : ( ) => void {
328
+ return function ( this : XMLHttpRequest , ...openArgs : unknown [ ] ) : void {
320
329
// eslint-disable-next-line @typescript-eslint/no-this-alias
321
330
const xhr = this ;
322
- const method = openArgs [ 0 ] ;
331
+ const method = openArgs [ 0 ] as string ;
323
332
const headers : Record < string , string > = { } ;
324
333
325
334
// Intercepting `setRequestHeader` to access the request headers of XHR instance.
@@ -329,25 +338,27 @@ export class HttpClient implements Integration {
329
338
xhr ,
330
339
'setRequestHeader' ,
331
340
// eslint-disable-next-line @typescript-eslint/ban-types
332
- function ( originalSetRequestHeader : ( header : string , value : string ) => void ) : Function {
333
- return function ( header : string , value : string ) : void {
341
+ function ( originalSetRequestHeader : ( ...setRequestHeaderArgs : unknown [ ] ) => void ) : Function {
342
+ return function ( ...setRequestHeaderArgs : unknown [ ] ) : void {
343
+ const [ header , value ] = setRequestHeaderArgs as [ string , string ] ;
344
+
334
345
headers [ header ] = value ;
335
346
336
- return originalSetRequestHeader . apply ( xhr , [ header , value ] ) ;
347
+ return originalSetRequestHeader . apply ( xhr , setRequestHeaderArgs ) ;
337
348
} ;
338
349
} ,
339
350
) ;
340
351
341
352
// eslint-disable-next-line @typescript-eslint/ban-types
342
- fill ( xhr , 'onloadend' , function ( original ?: ( progressEvent : ProgressEvent ) => void ) : Function {
343
- return function ( progressEvent : ProgressEvent ) : void {
353
+ fill ( xhr , 'onloadend' , function ( original ?: ( ... onloadendArgs : unknown [ ] ) => void ) : Function {
354
+ return function ( ... onloadendArgs : unknown [ ] ) : void {
344
355
try {
345
356
self . _xhrResponseHandler ( xhr , method , headers ) ;
346
357
} catch ( e ) {
347
358
__DEBUG_BUILD__ && logger . warn ( 'Error while extracting response event form XHR response' , e ) ;
348
359
}
349
360
350
- return original ?. apply ( xhr , progressEvent ) ;
361
+ return original ?. apply ( xhr , onloadendArgs ) ;
351
362
} ;
352
363
} ) ;
353
364
@@ -383,7 +394,7 @@ export class HttpClient implements Integration {
383
394
* @returns event
384
395
*/
385
396
private _createEvent ( data : {
386
- url : URL ;
397
+ url : string ;
387
398
method : string ;
388
399
status : number ;
389
400
responseHeaders ?: Record < string , string > ;
@@ -394,10 +405,7 @@ export class HttpClient implements Integration {
394
405
const event = eventFromUnknownInput ( ( ) => [ ] , `HTTP Client Error with status code: ${ data . status } ` ) ;
395
406
396
407
event . request = {
397
- url : data . url . href ,
398
- query_string : data . url . search ,
399
- // TODO: should we add `data: request.body` too?
400
- // https://develop.sentry.dev/sdk/event-payloads/request/
408
+ url : data . url ,
401
409
method : data . method ,
402
410
headers : data . requestHeaders ,
403
411
cookies : data . requestCookies ,
0 commit comments