2
2
// Use of this source code is governed by a BSD-style license that can be
3
3
// found in the LICENSE file.
4
4
5
+ import '../network/network_model.dart' ;
5
6
import '../trace_event.dart' ;
6
7
import '../utils.dart' ;
7
8
import 'http.dart' ;
8
9
9
- /// Contains all state relevant to completed and in-progress HTTP requests.
10
- class HttpRequests {
11
- HttpRequests ({
12
- this .requests = const [],
13
- this .invalidRequests = const [],
14
- this .outstandingRequests = const {},
15
- }) : assert (requests != null ),
16
- assert (invalidRequests != null ),
17
- assert (outstandingRequests != null );
18
-
19
- /// A list of HTTP requests.
20
- ///
21
- /// Individual requests in this list can be either completed or in-progress.
22
- List <HttpRequestData > requests;
23
-
24
- /// A list of invalid HTTP requests received.
25
- ///
26
- /// These are requests that have completed but do not contain all the required
27
- /// information to display normally in the UI.
28
- List <HttpRequestData > invalidRequests;
29
-
30
- /// A mapping of timeline IDs to instances of HttpRequestData which are
31
- /// currently in-progress.
32
- Map <String , HttpRequestData > outstandingRequests;
33
-
34
- void clear () {
35
- requests.clear ();
36
- outstandingRequests.clear ();
37
- }
38
- }
39
-
40
10
/// Used to represent an instant event emitted during an HTTP request.
41
11
class HttpInstantEvent {
42
12
HttpInstantEvent ._(this ._event);
@@ -56,12 +26,12 @@ class HttpInstantEvent {
56
26
}
57
27
58
28
/// An abstraction of an HTTP request made through dart:io.
59
- class HttpRequestData {
29
+ class HttpRequestData extends NetworkRequest {
60
30
HttpRequestData ._(
61
- this ._timelineMicrosBase ,
31
+ int timelineMicrosBase ,
62
32
this ._startEvent,
63
33
this ._endEvent,
64
- );
34
+ ) : super (timelineMicrosBase) ;
65
35
66
36
/// Build an instance from timeline events.
67
37
///
@@ -99,26 +69,53 @@ class HttpRequestData {
99
69
return data;
100
70
}
101
71
102
- final int _timelineMicrosBase;
72
+ static const _connectionInfoKey = 'connectionInfo' ;
73
+ static const _contentTypeKey = 'content-type' ;
74
+ static const _cookieKey = 'cookie' ;
75
+ static const _errorKey = 'error' ;
76
+ static const _filterKey = 'filterKey' ;
77
+ static const _localPortKey = 'localPort' ;
78
+ static const _methodKey = 'method' ;
79
+ static const _requestHeadersKey = 'requestHeaders' ;
80
+ static const _responseHeadersKey = 'responseHeaders' ;
81
+ static const _statusCodeKey = 'statusCode' ;
82
+ // TODO(kenz): modify this to `setCookie` once
83
+ // https://github.com/dart-lang/sdk/issues/42822 is resolved
84
+ static const _setCookieKey = 'set-cookie' ;
85
+ static const _uriKey = 'uri' ;
86
+
103
87
final TraceEvent _startEvent;
104
88
TraceEvent _endEvent;
105
89
106
90
// Do not add to this list directly! Call `_addInstantEvents` which is
107
91
// responsible for calculating the time offsets of each event.
108
92
final List <HttpInstantEvent > _instantEvents = [];
109
93
110
- /// The duration of the HTTP request, in milliseconds.
94
+ @override
111
95
Duration get duration {
112
- if (_endEvent == null || _startEvent == null ) {
113
- return null ;
114
- }
96
+ if (inProgress || ! isValid) return null ;
115
97
// Timestamps are in microseconds
116
98
final range = TimeRange ()
117
99
..start = Duration (microseconds: _startEvent.timestampMicros)
118
100
..end = Duration (microseconds: _endEvent.timestampMicros);
119
101
return range.duration;
120
102
}
121
103
104
+ @override
105
+ String get contentType {
106
+ if (responseHeaders == null || responseHeaders[_contentTypeKey] == null ) {
107
+ return null ;
108
+ }
109
+ return responseHeaders[_contentTypeKey].toString ();
110
+ }
111
+
112
+ @override
113
+ String get type {
114
+ // TODO(kenz): pull in a package or implement functionality to pretty print
115
+ // the MIME type from the 'content-type' field in a response header.
116
+ return 'http' ;
117
+ }
118
+
122
119
/// Whether the request is safe to display in the UI.
123
120
///
124
121
/// It is possible to get invalid events if we receive an endEvent but no
@@ -135,14 +132,25 @@ class HttpRequestData {
135
132
136
133
/// A map of general information associated with an HTTP request.
137
134
Map <String , dynamic > get general {
135
+ if (_general != null ) return _general;
136
+ if (! isValid) return null ;
138
137
final copy = Map <String , dynamic >.from (_startEvent.args);
139
- if (_endEvent != null ) {
138
+ if (! inProgress ) {
140
139
copy.addAll (_endEvent.args);
141
140
}
142
- copy.remove ('requestHeaders' );
143
- copy.remove ('responseHeaders' );
144
- copy.remove ('filterKey' );
145
- return copy;
141
+ copy.remove (_requestHeadersKey);
142
+ copy.remove (_responseHeadersKey);
143
+ copy.remove (_filterKey);
144
+ return _general = copy;
145
+ }
146
+
147
+ Map <String , dynamic > _general;
148
+
149
+ @override
150
+ int get port {
151
+ if (general == null ) return null ;
152
+ final Map <String , dynamic > connectionInfo = general[_connectionInfoKey];
153
+ return connectionInfo != null ? connectionInfo[_localPortKey] : null ;
146
154
}
147
155
148
156
/// True if the HTTP request hasn't completed yet, determined by the lack of
@@ -152,15 +160,13 @@ class HttpRequestData {
152
160
/// All instant events logged to the timeline for this HTTP request.
153
161
List <HttpInstantEvent > get instantEvents => _instantEvents;
154
162
155
- /// The HTTP method associated with this request.
163
+ @override
156
164
String get method {
157
- assert (_startEvent.args.containsKey ('method' ));
158
- return _startEvent.args['method' ];
165
+ if (! isValid) return null ;
166
+ assert (_startEvent.args.containsKey (_methodKey));
167
+ return _startEvent.args[_methodKey];
159
168
}
160
169
161
- /// The name of the request (currently the URI).
162
- String get name => uri.toString ();
163
-
164
170
/// A list of all cookies contained within the request headers.
165
171
List <Cookie > get requestCookies {
166
172
// The request may still be in progress, in which case we don't display any
@@ -169,27 +175,34 @@ class HttpRequestData {
169
175
if (headers == null ) {
170
176
return [];
171
177
}
172
- return _parseCookies (headers['cookie' ] ?? []);
178
+ return _parseCookies (headers[_cookieKey ] ?? []);
173
179
}
174
180
175
181
/// The request headers for the HTTP request.
176
182
Map <String , dynamic > get requestHeaders {
177
183
// The request may still be in progress, in which case we don't display any
178
- // headers.
179
- if (_endEvent == null ) {
180
- return null ;
181
- }
182
- return _endEvent.args['requestHeaders' ];
184
+ // headers, or the request may be invalid, in which case we also don't
185
+ // display any headers.
186
+ if (inProgress || ! isValid) return null ;
187
+ return _endEvent.args[_requestHeadersKey];
183
188
}
184
189
185
190
/// The time the HTTP request was issued.
186
- DateTime get requestTime {
187
- assert (_startEvent != null );
191
+ @override
192
+ DateTime get startTimestamp {
193
+ if (! isValid) return null ;
188
194
return DateTime .fromMicrosecondsSinceEpoch (
189
- _getTimelineMicrosecondsSinceEpoch (_startEvent),
195
+ timelineMicrosecondsSinceEpoch (_startEvent.timestampMicros ),
190
196
);
191
197
}
192
198
199
+ @override
200
+ DateTime get endTimestamp {
201
+ if (inProgress || ! isValid) return null ;
202
+ return DateTime .fromMicrosecondsSinceEpoch (
203
+ timelineMicrosecondsSinceEpoch (_endEvent.timestampMicros));
204
+ }
205
+
193
206
/// A list of all cookies contained within the response headers.
194
207
List <Cookie > get responseCookies {
195
208
// The request may still be in progress, in which case we don't display any
@@ -199,43 +212,43 @@ class HttpRequestData {
199
212
return [];
200
213
}
201
214
return _parseCookies (
202
- headers['set-cookie' ] ?? [],
215
+ headers[_setCookieKey ] ?? [],
203
216
);
204
217
}
205
218
206
219
/// The response headers for the HTTP request.
207
220
Map <String , dynamic > get responseHeaders {
208
221
// The request may still be in progress, in which case we don't display any
209
- // headers.
210
- if (_endEvent == null ) {
211
- return null ;
212
- }
213
- return _endEvent.args['responseHeaders' ];
222
+ // headers, or the request may be invalid, in which case we also don't
223
+ // display any headers.
224
+ if (inProgress || ! isValid) return null ;
225
+ return _endEvent.args[_responseHeadersKey];
214
226
}
215
227
216
228
/// A string representing the status of the request.
217
229
///
218
230
/// If the request completed, this will be an HTTP status code. If an error
219
231
/// was encountered, this will return 'Error'.
232
+ @override
220
233
String get status {
234
+ if (inProgress || ! isValid) return null ;
221
235
String statusCode;
222
- if (_endEvent != null ) {
223
- final endArgs = _endEvent.args;
224
- if (endArgs.containsKey ('error' )) {
225
- // This case occurs when an exception has been thrown, so there's no
226
- // status code to associate with the request.
227
- statusCode = 'Error' ;
228
- } else {
229
- statusCode = endArgs['statusCode' ].toString ();
230
- }
236
+ final endArgs = _endEvent.args;
237
+ if (endArgs.containsKey (_errorKey)) {
238
+ // This case occurs when an exception has been thrown, so there's no
239
+ // status code to associate with the request.
240
+ statusCode = 'Error' ;
241
+ } else {
242
+ statusCode = endArgs[_statusCodeKey].toString ();
231
243
}
232
244
return statusCode;
233
245
}
234
246
235
- /// The address the HTTP request was issued to.
236
- Uri get uri {
237
- assert (_startEvent.args.containsKey ('uri' ));
238
- return Uri .parse (_startEvent.args['uri' ]);
247
+ @override
248
+ String get uri {
249
+ if (! isValid) return null ;
250
+ assert (_startEvent.args.containsKey (_uriKey));
251
+ return _startEvent.args[_uriKey];
239
252
}
240
253
241
254
/// Merges the information from another [HttpRequestData] into this instance.
@@ -276,10 +289,6 @@ class HttpRequestData {
276
289
}
277
290
}
278
291
279
- int _getTimelineMicrosecondsSinceEpoch (TraceEvent event) {
280
- return _timelineMicrosBase + event.timestampMicros;
281
- }
282
-
283
292
@override
284
- String toString () => '$method $name ' ;
293
+ String toString () => '$method $uri ' ;
285
294
}
0 commit comments