@@ -2,11 +2,9 @@ import 'dart:async';
2
2
import 'dart:convert' ;
3
3
4
4
import 'package:http/http.dart' ;
5
+ import '../utils/transport_utils.dart' ;
6
+ import 'http_transport_request_handler.dart' ;
5
7
6
- import '../client_reports/client_report_recorder.dart' ;
7
- import '../client_reports/discard_reason.dart' ;
8
- import 'data_category.dart' ;
9
- import 'noop_encode.dart' if (dart.library.io) 'encode.dart' ;
10
8
import '../noop_client.dart' ;
11
9
import '../protocol.dart' ;
12
10
import '../sentry_options.dart' ;
@@ -18,15 +16,9 @@ import 'rate_limiter.dart';
18
16
class HttpTransport implements Transport {
19
17
final SentryOptions _options;
20
18
21
- final Dsn _dsn;
22
-
23
19
final RateLimiter _rateLimiter;
24
20
25
- final ClientReportRecorder _recorder;
26
-
27
- late _CredentialBuilder _credentialBuilder;
28
-
29
- final Map <String , String > _headers;
21
+ final HttpTransportRequestHandler _requestHandler;
30
22
31
23
factory HttpTransport (SentryOptions options, RateLimiter rateLimiter) {
32
24
if (options.httpClient is NoOpClient ) {
@@ -37,17 +29,8 @@ class HttpTransport implements Transport {
37
29
}
38
30
39
31
HttpTransport ._(this ._options, this ._rateLimiter)
40
- : _dsn = Dsn .parse (_options.dsn! ),
41
- _recorder = _options.recorder,
42
- _headers = _buildHeaders (
43
- _options.platformChecker.isWeb,
44
- _options.sentryClientName,
45
- ) {
46
- _credentialBuilder = _CredentialBuilder (
47
- _dsn,
48
- _options.sentryClientName,
49
- );
50
- }
32
+ : _requestHandler = HttpTransportRequestHandler (
33
+ _options, Dsn .parse (_options.dsn! ).postUri);
51
34
52
35
@override
53
36
Future <SentryId ?> send (SentryEnvelope envelope) async {
@@ -57,63 +40,31 @@ class HttpTransport implements Transport {
57
40
}
58
41
filteredEnvelope.header.sentAt = _options.clock ();
59
42
60
- final streamedRequest = await _createStreamedRequest (filteredEnvelope);
43
+ final streamedRequest =
44
+ await _requestHandler.createRequest (filteredEnvelope);
45
+
61
46
final response = await _options.httpClient
62
47
.send (streamedRequest)
63
48
.then (Response .fromStream);
64
49
65
50
_updateRetryAfterLimits (response);
66
51
67
- if (response.statusCode != 200 ) {
68
- // body guard to not log the error as it has performance impact to allocate
69
- // the body String.
70
- if (_options.debug) {
71
- _options.logger (
72
- SentryLevel .error,
73
- 'API returned an error, statusCode = ${response .statusCode }, '
74
- 'body = ${response .body }' ,
75
- );
76
- }
77
-
78
- if (response.statusCode >= 400 && response.statusCode != 429 ) {
79
- _recorder.recordLostEvent (
80
- DiscardReason .networkError, DataCategory .error);
81
- }
82
-
83
- return SentryId .empty ();
84
- } else {
85
- _options.logger (
86
- SentryLevel .debug,
87
- 'Envelope ${envelope .header .eventId ?? "--" } was sent successfully.' ,
88
- );
89
- }
52
+ TransportUtils .logResponse (_options, envelope, response, target: 'Sentry' );
90
53
91
- final eventId = json.decode (response.body)['id' ];
92
- if (eventId == null ) {
93
- return null ;
54
+ if (response.statusCode == 200 ) {
55
+ return _parseEventId (response);
94
56
}
95
- return SentryId .fromId (eventId );
57
+ return SentryId .empty ( );
96
58
}
97
59
98
- Future <StreamedRequest > _createStreamedRequest (
99
- SentryEnvelope envelope) async {
100
- final streamedRequest = StreamedRequest ('POST' , _dsn.postUri);
101
-
102
- if (_options.compressPayload) {
103
- final compressionSink = compressInSink (streamedRequest.sink, _headers);
104
- envelope
105
- .envelopeStream (_options)
106
- .listen (compressionSink.add)
107
- .onDone (compressionSink.close);
108
- } else {
109
- envelope
110
- .envelopeStream (_options)
111
- .listen (streamedRequest.sink.add)
112
- .onDone (streamedRequest.sink.close);
60
+ SentryId ? _parseEventId (Response response) {
61
+ try {
62
+ final eventId = json.decode (response.body)['id' ];
63
+ return eventId != null ? SentryId .fromId (eventId) : null ;
64
+ } catch (e) {
65
+ _options.logger (SentryLevel .error, 'Error parsing response: $e ' );
66
+ return null ;
113
67
}
114
- streamedRequest.headers.addAll (_credentialBuilder.configure (_headers));
115
-
116
- return streamedRequest;
117
68
}
118
69
119
70
void _updateRetryAfterLimits (Response response) {
@@ -131,51 +82,3 @@ class HttpTransport implements Transport {
131
82
sentryRateLimitHeader, retryAfterHeader, response.statusCode);
132
83
}
133
84
}
134
-
135
- class _CredentialBuilder {
136
- final String _authHeader;
137
-
138
- _CredentialBuilder ._(String authHeader) : _authHeader = authHeader;
139
-
140
- factory _CredentialBuilder (Dsn dsn, String sdkIdentifier) {
141
- final authHeader = _buildAuthHeader (
142
- publicKey: dsn.publicKey,
143
- secretKey: dsn.secretKey,
144
- sdkIdentifier: sdkIdentifier,
145
- );
146
-
147
- return _CredentialBuilder ._(authHeader);
148
- }
149
-
150
- static String _buildAuthHeader ({
151
- required String publicKey,
152
- String ? secretKey,
153
- required String sdkIdentifier,
154
- }) {
155
- var header = 'Sentry sentry_version=7, sentry_client=$sdkIdentifier , '
156
- 'sentry_key=$publicKey ' ;
157
-
158
- if (secretKey != null ) {
159
- header += ', sentry_secret=$secretKey ' ;
160
- }
161
-
162
- return header;
163
- }
164
-
165
- Map <String , String > configure (Map <String , String > headers) {
166
- return headers
167
- ..addAll (
168
- < String , String > {'X-Sentry-Auth' : _authHeader},
169
- );
170
- }
171
- }
172
-
173
- Map <String , String > _buildHeaders (bool isWeb, String sdkIdentifier) {
174
- final headers = {'Content-Type' : 'application/x-sentry-envelope' };
175
- // NOTE(lejard_h) overriding user agent on VM and Flutter not sure why
176
- // for web it use browser user agent
177
- if (! isWeb) {
178
- headers['User-Agent' ] = sdkIdentifier;
179
- }
180
- return headers;
181
- }
0 commit comments