1
+ /* eslint-disable complexity */
1
2
import { getClient } from './currentScopes' ;
2
3
import { SEMANTIC_ATTRIBUTE_SENTRY_OP , SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from './semanticAttributes' ;
3
4
import { SPAN_STATUS_ERROR , setHttpStatus , startInactiveSpan } from './tracing' ;
4
5
import { SentryNonRecordingSpan } from './tracing/sentryNonRecordingSpan' ;
5
6
import type { FetchBreadcrumbHint , HandlerDataFetch , Span , SpanOrigin } from './types-hoist' ;
6
7
import { SENTRY_BAGGAGE_KEY_PREFIX } from './utils-hoist/baggage' ;
7
8
import { isInstanceOf } from './utils-hoist/is' ;
8
- import { parseUrl , stripUrlQueryAndFragment } from './utils-hoist/url' ;
9
+ import { parseStringToURL , stripUrlQueryAndFragment } from './utils-hoist/url' ;
9
10
import { hasSpansEnabled } from './utils/hasSpansEnabled' ;
10
11
import { getActiveSpan } from './utils/spanUtils' ;
11
12
import { getTraceData } from './utils/traceData' ;
@@ -53,8 +54,20 @@ export function instrumentFetchRequest(
53
54
return undefined ;
54
55
}
55
56
56
- const fullUrl = getFullURL ( url ) ;
57
- const parsedUrl = fullUrl ? parseUrl ( fullUrl ) : parseUrl ( url ) ;
57
+ // Curious about `thismessage:/`? See: https://www.rfc-editor.org/rfc/rfc2557.html
58
+ // > When the methods above do not yield an absolute URI, a base URL
59
+ // > of "thismessage:/" MUST be employed. This base URL has been
60
+ // > defined for the sole purpose of resolving relative references
61
+ // > within a multipart/related structure when no other base URI is
62
+ // > specified.
63
+ //
64
+ // We need to provide a base URL to `parseStringToURL` because the fetch API gives us a
65
+ // relative URL sometimes.
66
+ //
67
+ // This is the only case where we need to provide a base URL to `parseStringToURL`
68
+ // because the relative URL is not valid on its own.
69
+ const parsedUrl = url . startsWith ( '/' ) ? parseStringToURL ( url , 'thismessage:/' ) : parseStringToURL ( url ) ;
70
+ const fullUrl = url . startsWith ( '/' ) ? undefined : parsedUrl ?. href ;
58
71
59
72
const hasParent = ! ! getActiveSpan ( ) ;
60
73
@@ -66,12 +79,13 @@ export function instrumentFetchRequest(
66
79
url,
67
80
type : 'fetch' ,
68
81
'http.method' : method ,
69
- 'http.url' : fullUrl ,
70
- 'server.address' : parsedUrl ?. host ,
82
+ 'http.url' : parsedUrl ?. href ,
71
83
[ SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN ] : spanOrigin ,
72
84
[ SEMANTIC_ATTRIBUTE_SENTRY_OP ] : 'http.client' ,
73
- ...( parsedUrl ?. search && { 'http.query' : parsedUrl ?. search } ) ,
74
- ...( parsedUrl ?. hash && { 'http.fragment' : parsedUrl ?. hash } ) ,
85
+ ...( fullUrl && { 'http.url' : fullUrl } ) ,
86
+ ...( fullUrl && parsedUrl ?. host && { 'server.address' : parsedUrl . host } ) ,
87
+ ...( parsedUrl ?. search && { 'http.query' : parsedUrl . search } ) ,
88
+ ...( parsedUrl ?. hash && { 'http.fragment' : parsedUrl . hash } ) ,
75
89
} ,
76
90
} )
77
91
: new SentryNonRecordingSpan ( ) ;
@@ -215,15 +229,6 @@ function _addTracingHeadersToFetchRequest(
215
229
}
216
230
}
217
231
218
- function getFullURL ( url : string ) : string | undefined {
219
- try {
220
- const parsed = new URL ( url ) ;
221
- return parsed . href ;
222
- } catch {
223
- return undefined ;
224
- }
225
- }
226
-
227
232
function endSpan ( span : Span , handlerData : HandlerDataFetch ) : void {
228
233
if ( handlerData . response ) {
229
234
setHttpStatus ( span , handlerData . response . status ) ;
0 commit comments