mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 16:55:08 +00:00
[VM/Service] Update dart:io service extension spec
The main purpose of these changes is to make sure that the types in package:http_profile are compatible with the interfaces in the spec. See runtime/vm/service/service_extension.md and pkg/vm_service/CHANGELOG.md for the full list of changes. TEST=pkg/vm_service/test/get_http_profile_test.dart, DevTools tests CoreLibraryReviewExempt: Only touches sdk/lib/io/network_profiling.dart to update the version returned by the getVersion dart:io service extension. Change-Id: I1b9d0b7d43defbc857a2a8fde003012effd1ee15 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/341120 Reviewed-by: Ben Konyi <bkonyi@google.com>
This commit is contained in:
parent
e8b20f66b2
commit
60833d9cd9
|
@ -1,4 +1,4 @@
|
|||
## 13.1.0-dev
|
||||
## 14.0.0
|
||||
- Add the following error codes to `RPCErrorKind`:
|
||||
- `kVmMustBePaused`
|
||||
- `kCannotAddBreakpoint`
|
||||
|
@ -8,6 +8,32 @@
|
|||
- `kIsolateCannotReload`
|
||||
- `kIsolateNoReloadChangesApplied`
|
||||
- `kInvalidTimelineRequest`
|
||||
- Update to version `4.0` of the Dart IO service protocol extensions by making
|
||||
the following changes:
|
||||
- Change the type of the `updatedSince` parameter of `getHttpProfile` from
|
||||
`int?` to `DateTime?`.
|
||||
- Change the type of the `timestamp` property of `HttpProfile` from `int` to
|
||||
`DateTime`.
|
||||
- Add `events` property to `HttpProfileRequestRef` and `HttpProfileRequest`.
|
||||
- Change the type of the `startTime` property of `HttpProfileRequestRef` and
|
||||
`HttpProfileRequest` from `int` to `DateTime`.
|
||||
- Change the type of the `endTime` property of `HttpProfileRequestRef` and
|
||||
`HttpProfileRequest` from `int?` to `DateTime?`.
|
||||
- Remove the `events` and `method` properties from `HttpProfileRequestData`.
|
||||
- Make the `contentLength`, `cookies`, `followRedirects`, `headers`,
|
||||
`maxRedirects`, `method`, and `persistentConnection` properties of
|
||||
`HttpProfileRequestData` nullable.
|
||||
- Change the type of the `startTime` property of `HttpProfileResponseData`
|
||||
from `int` to `DateTime?`.
|
||||
- Change the type of the `endTime` property of `HttpProfileResponseData`
|
||||
from `int?` to `DateTime?`.
|
||||
- Make the `cookies`, `headers`, `compressionState`, `reasonPhrase`,
|
||||
`isRedirect`, `persistentConnection`, `contentLength`, `statusCode`, and
|
||||
`startTime` properties of `HttpProfileResponseData` nullable.
|
||||
- Add `isDirect` and `port` properties to `HttpProfileProxyData`.
|
||||
- Add `arguments` property to `HttpProfileRequestEvent`.
|
||||
- Change the type of the `timestamp` property of `HttpProfileRequestEvent`
|
||||
from `int` to `DateTime`.
|
||||
|
||||
## 13.0.0
|
||||
- Add Dart IO extension methods:
|
||||
|
@ -98,7 +124,7 @@ instance and connect it to a web socket URI.
|
|||
- Change `HttpProfileRequestRef.id` type from `int` to `String`.
|
||||
- Change `SocketStatistic.id` type from `int` to `String`.
|
||||
- Change `ext.dart.io.getHttpProfileRequest` `id` parameter type from `int` to `String`.
|
||||
- Change `ext.dart.io.socketProfilingEnabled` parameter from 'enable' to 'enabled'.
|
||||
- Change `ext.dart.io.httpEnableTimelineLogging` parameter from 'enable' to 'enabled'.
|
||||
|
||||
## 10.1.2
|
||||
- Fix bug where code would try to call `.toJson()` on `String`s.
|
||||
|
|
|
@ -111,11 +111,12 @@ extension DartIOExtension on VmService {
|
|||
/// the specified time will be reported.
|
||||
Future<HttpProfile> getHttpProfile(
|
||||
String isolateId, {
|
||||
int? updatedSince,
|
||||
DateTime? updatedSince,
|
||||
}) async {
|
||||
assert(await isHttpProfilingAvailable(isolateId));
|
||||
return _callHelper('ext.dart.io.getHttpProfile', isolateId, args: {
|
||||
if (updatedSince != null) 'updatedSince': updatedSince,
|
||||
if (updatedSince != null)
|
||||
'updatedSince': updatedSince.microsecondsSinceEpoch,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -320,10 +321,11 @@ class HttpProfile extends Response {
|
|||
json == null ? null : HttpProfile._fromJson(json);
|
||||
|
||||
HttpProfile._fromJson(Map<String, dynamic> json)
|
||||
: timestamp = json['timestamp'],
|
||||
requests = (json['requests'] as List)
|
||||
: timestamp = DateTime.fromMicrosecondsSinceEpoch(json['timestamp']!),
|
||||
requests = json['requests']!
|
||||
.cast<Map<String, dynamic>>()
|
||||
.map((e) => HttpProfileRequest._fromJson(e))
|
||||
.cast<HttpProfileRequest>()
|
||||
.toList();
|
||||
|
||||
HttpProfile({required this.requests, required this.timestamp});
|
||||
|
@ -334,8 +336,8 @@ class HttpProfile extends Response {
|
|||
@override
|
||||
String toString() => '[HttpProfile]';
|
||||
|
||||
/// The time at which this HTTP profile was built, in microseconds.
|
||||
final int timestamp;
|
||||
/// The time at which this HTTP profile was built.
|
||||
final DateTime timestamp;
|
||||
|
||||
/// The set of recorded HTTP requests.
|
||||
final List<HttpProfileRequest> requests;
|
||||
|
@ -347,12 +349,19 @@ class HttpProfileRequestRef {
|
|||
json == null ? null : HttpProfileRequestRef._fromJson(json);
|
||||
|
||||
HttpProfileRequestRef._fromJson(Map<String, dynamic> json)
|
||||
: isolateId = json['isolateId'],
|
||||
id = json['id'],
|
||||
method = json['method'],
|
||||
uri = Uri.parse(json['uri']),
|
||||
startTime = json['startTime'],
|
||||
endTime = json['endTime'],
|
||||
: isolateId = json['isolateId']!,
|
||||
id = json['id']!,
|
||||
method = json['method']!,
|
||||
uri = Uri.parse(json['uri']!),
|
||||
events = json['events']!
|
||||
.cast<Map<String, dynamic>>()
|
||||
.map((e) => HttpProfileRequestEvent._fromJson(e))
|
||||
.cast<HttpProfileRequestEvent>()
|
||||
.toList(),
|
||||
startTime = DateTime.fromMicrosecondsSinceEpoch(json['startTime']!),
|
||||
endTime = json['endTime'] == null
|
||||
? null
|
||||
: DateTime.fromMicrosecondsSinceEpoch(json['endTime']),
|
||||
request = HttpProfileRequestData.parse(json['request']),
|
||||
response = HttpProfileResponseData.parse(json['response']);
|
||||
|
||||
|
@ -361,6 +370,7 @@ class HttpProfileRequestRef {
|
|||
required this.id,
|
||||
required this.method,
|
||||
required this.uri,
|
||||
required this.events,
|
||||
required this.startTime,
|
||||
this.endTime,
|
||||
this.request,
|
||||
|
@ -372,22 +382,26 @@ class HttpProfileRequestRef {
|
|||
|
||||
/// The ID associated with this request.
|
||||
///
|
||||
/// This ID corresponds to the ID of the timeline event for this request.
|
||||
/// If the ID does not start with the prefix 'from_package/', then there
|
||||
/// will be a corresponding timeline event with the same ID.
|
||||
final String id;
|
||||
|
||||
/// The HTTP request method associated with this request.
|
||||
final String method;
|
||||
|
||||
/// The URI for this HTTP request.
|
||||
/// The URI to which this HTTP request was sent.
|
||||
final Uri uri;
|
||||
|
||||
/// The time at which this request was initiated, in microseconds.
|
||||
final int startTime;
|
||||
/// Events related to this HTTP request.
|
||||
final List<HttpProfileRequestEvent> events;
|
||||
|
||||
/// The time at which this request was completed, in microseconds.
|
||||
/// The time at which this request was initiated.
|
||||
final DateTime startTime;
|
||||
|
||||
/// The time at which this request was completed.
|
||||
///
|
||||
/// Will be `null` if the request is still in progress.
|
||||
final int? endTime;
|
||||
final DateTime? endTime;
|
||||
|
||||
/// Returns `true` if the initial HTTP request has completed.
|
||||
bool get isRequestComplete => endTime != null;
|
||||
|
@ -395,12 +409,12 @@ class HttpProfileRequestRef {
|
|||
/// Returns `true` if the entirety of the response has been received.
|
||||
bool get isResponseComplete => response?.isComplete ?? false;
|
||||
|
||||
/// Information sent as part of the initial HTTP request.
|
||||
/// Details about the request.
|
||||
///
|
||||
/// Can be `null` if the request has not yet been completed.
|
||||
final HttpProfileRequestData? request;
|
||||
|
||||
/// Information received in response to the initial HTTP request.
|
||||
/// Details about the response.
|
||||
///
|
||||
/// Can be `null` if the request has not yet been responded to.
|
||||
final HttpProfileResponseData? response;
|
||||
|
@ -424,12 +438,13 @@ class HttpProfileRequest extends HttpProfileRequestRef {
|
|||
required super.isolateId,
|
||||
required super.method,
|
||||
required super.uri,
|
||||
required super.events,
|
||||
required super.startTime,
|
||||
required this.requestBody,
|
||||
required this.responseBody,
|
||||
super.endTime,
|
||||
super.request,
|
||||
super.response,
|
||||
this.requestBody,
|
||||
this.responseBody,
|
||||
});
|
||||
|
||||
/// The body sent as part of this request.
|
||||
|
@ -448,54 +463,45 @@ class HttpProfileRequestData {
|
|||
json == null ? null : HttpProfileRequestData._fromJson(json);
|
||||
|
||||
HttpProfileRequestData._fromJson(Map<String, dynamic> json)
|
||||
: _headers = json['headers'],
|
||||
: _headers = UnmodifiableMapView(json['headers'] ?? {}),
|
||||
_connectionInfo = UnmodifiableMapView(json['connectionInfo'] ?? {}),
|
||||
_contentLength = json['contentLength'],
|
||||
_cookies = UnmodifiableListView(json['cookies']?.cast<String>() ?? []),
|
||||
_followRedirects = json['followRedirects'] ?? false,
|
||||
_maxRedirects = json['maxRedirects'] ?? 0,
|
||||
_method = json['method'],
|
||||
_persistentConnection = json['persistentConnection'] ?? false,
|
||||
proxyDetails = HttpProfileProxyData.parse(json['proxyDetails']),
|
||||
error = json['error'],
|
||||
events = UnmodifiableListView((json['events'] as List)
|
||||
.cast<Map<String, dynamic>>()
|
||||
.map((e) => HttpProfileRequestEvent._fromJson(e))
|
||||
.toList());
|
||||
_proxyDetails = HttpProfileProxyData.parse(json['proxyDetails']),
|
||||
error = json['error'];
|
||||
|
||||
HttpProfileRequestData.buildSuccessfulRequest({
|
||||
required Map<String, dynamic> headers,
|
||||
required Map<String, dynamic>? connectionInfo,
|
||||
required int contentLength,
|
||||
Map<String, dynamic>? headers,
|
||||
Map<String, dynamic>? connectionInfo,
|
||||
int? contentLength,
|
||||
required List<String> cookies,
|
||||
required bool followRedirects,
|
||||
required int maxRedirects,
|
||||
required String method,
|
||||
required bool persistentConnection,
|
||||
required this.events,
|
||||
this.proxyDetails,
|
||||
bool? followRedirects,
|
||||
int? maxRedirects,
|
||||
bool? persistentConnection,
|
||||
HttpProfileProxyData? proxyDetails,
|
||||
}) : _headers = headers,
|
||||
_connectionInfo = connectionInfo,
|
||||
_contentLength = contentLength,
|
||||
_cookies = cookies,
|
||||
_followRedirects = followRedirects,
|
||||
_maxRedirects = maxRedirects,
|
||||
_method = method,
|
||||
_persistentConnection = persistentConnection,
|
||||
_proxyDetails = proxyDetails,
|
||||
error = null;
|
||||
|
||||
HttpProfileRequestData.buildErrorRequest({
|
||||
required this.error,
|
||||
required this.events,
|
||||
}) : _connectionInfo = null,
|
||||
_contentLength = null,
|
||||
_cookies = [],
|
||||
_cookies = null,
|
||||
_followRedirects = null,
|
||||
_headers = null,
|
||||
_maxRedirects = null,
|
||||
_method = null,
|
||||
_persistentConnection = null,
|
||||
proxyDetails = null;
|
||||
_proxyDetails = null;
|
||||
|
||||
/// Returns `true` if an error has occurred while issuing the request.
|
||||
///
|
||||
|
@ -504,72 +510,61 @@ class HttpProfileRequestData {
|
|||
bool get hasError => error != null;
|
||||
|
||||
/// Information about the client connection.
|
||||
Map<String, dynamic>? get connectionInfo {
|
||||
return _connectionInfo == null
|
||||
? null
|
||||
: UnmodifiableMapView(_connectionInfo);
|
||||
}
|
||||
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
Map<String, dynamic>? get connectionInfo => _returnIfNoError(_connectionInfo);
|
||||
final Map<String, dynamic>? _connectionInfo;
|
||||
|
||||
/// The content length of the request, in bytes.
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] is `hasError` is `true`.
|
||||
int get contentLength => _returnIfNoError(_contentLength);
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
int? get contentLength => _returnIfNoError(_contentLength);
|
||||
final int? _contentLength;
|
||||
|
||||
/// Cookies presented to the server (in the 'cookie' header).
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] is `hasError` is `true`.
|
||||
List<String> get cookies => _returnIfNoError(_cookies);
|
||||
final List<String> _cookies;
|
||||
|
||||
/// Events that has occurred while issuing this HTTP request.
|
||||
final List<HttpProfileRequestEvent> events;
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
List<String>? get cookies => _returnIfNoError(_cookies);
|
||||
final List<String>? _cookies;
|
||||
|
||||
/// The error associated with the failed request.
|
||||
final String? error;
|
||||
|
||||
/// Whether redirects are followed automatically.
|
||||
/// Whether automatic redirect following was enabled for the request.
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] is `hasError` is `true`.
|
||||
bool get followRedirects => _returnIfNoError(_followRedirects);
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
bool? get followRedirects => _returnIfNoError(_followRedirects);
|
||||
final bool? _followRedirects;
|
||||
|
||||
/// Returns the client request headers.
|
||||
/// The client request headers.
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] is `hasError` is `true`.
|
||||
Map<String, dynamic> get headers => UnmodifiableMapView(
|
||||
_returnIfNoError(_headers),
|
||||
);
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
Map<String, dynamic>? get headers => _returnIfNoError(_headers);
|
||||
final Map<String, dynamic>? _headers;
|
||||
|
||||
/// The maximum number of redirects to follow when `followRedirects` is true.
|
||||
/// The maximum number of redirects allowed during the request.
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] is `hasError` is `true`.
|
||||
int get maxRedirects => _returnIfNoError(_maxRedirects);
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
int? get maxRedirects => _returnIfNoError(_maxRedirects);
|
||||
final int? _maxRedirects;
|
||||
|
||||
/// The method of the request.
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] is `hasError` is `true`.
|
||||
String get method => _returnIfNoError(_method);
|
||||
final String? _method;
|
||||
|
||||
/// The requested persistent connection state.
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] is `hasError` is `true`.
|
||||
bool get persistentConnection => _returnIfNoError(_persistentConnection);
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
bool? get persistentConnection => _returnIfNoError(_persistentConnection);
|
||||
final bool? _persistentConnection;
|
||||
|
||||
/// Proxy authentication details for this request.
|
||||
final HttpProfileProxyData? proxyDetails;
|
||||
///
|
||||
/// Throws [HttpProfileRequestError] if `hasError` is `true`.
|
||||
HttpProfileProxyData? get proxyDetails => _returnIfNoError(_proxyDetails);
|
||||
final HttpProfileProxyData? _proxyDetails;
|
||||
|
||||
T _returnIfNoError<T>(T? field) {
|
||||
T? _returnIfNoError<T>(T? field) {
|
||||
if (hasError) {
|
||||
throw HttpProfileRequestError(error!);
|
||||
}
|
||||
return field!;
|
||||
return field;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -587,40 +582,45 @@ class HttpProfileRequestError implements Error {
|
|||
String toString() => 'HttpProfileRequestError: $error.';
|
||||
}
|
||||
|
||||
/// Proxy authentication details associated with an [HttpProfileRequest].
|
||||
/// Describes proxy authentication details associated with an
|
||||
/// [HttpProfileRequest].
|
||||
class HttpProfileProxyData {
|
||||
static HttpProfileProxyData? parse(Map<String, dynamic>? json) =>
|
||||
json == null ? null : HttpProfileProxyData._fromJson(json);
|
||||
|
||||
HttpProfileProxyData._fromJson(Map<String, dynamic> json)
|
||||
: host = json['timestamp'],
|
||||
port = json['event'],
|
||||
username = json['arguments'];
|
||||
: host = json['host'],
|
||||
username = json['username'],
|
||||
isDirect = json['isDirect'],
|
||||
port = json['port'];
|
||||
|
||||
HttpProfileProxyData({
|
||||
this.host,
|
||||
this.username,
|
||||
this.isDirect,
|
||||
this.port,
|
||||
});
|
||||
|
||||
/// The URI of the proxy server.
|
||||
final String? host;
|
||||
|
||||
/// The port the proxy server is listening on.
|
||||
final int? port;
|
||||
|
||||
/// The username used to authenticate with the proxy server.
|
||||
final String? username;
|
||||
|
||||
final bool? isDirect;
|
||||
|
||||
/// The port the proxy server is listening on.
|
||||
final int? port;
|
||||
}
|
||||
|
||||
/// Describes an event that has occurred while issuing a HTTP request.
|
||||
/// Describes an event related to an HTTP request.
|
||||
class HttpProfileRequestEvent {
|
||||
static HttpProfileRequestEvent? parse(Map<String, dynamic>? json) =>
|
||||
json == null ? null : HttpProfileRequestEvent._fromJson(json);
|
||||
|
||||
HttpProfileRequestEvent._fromJson(Map<String, dynamic> json)
|
||||
: timestamp = json['timestamp'],
|
||||
event = json['event'],
|
||||
: timestamp = DateTime.fromMicrosecondsSinceEpoch(json['timestamp']!),
|
||||
event = json['event']!,
|
||||
arguments = json['arguments'];
|
||||
|
||||
HttpProfileRequestEvent({
|
||||
|
@ -629,9 +629,13 @@ class HttpProfileRequestEvent {
|
|||
this.arguments,
|
||||
});
|
||||
|
||||
final Map<String, dynamic>? arguments;
|
||||
/// The title of the recorded event.
|
||||
final String event;
|
||||
final int timestamp;
|
||||
|
||||
/// The time at which the event occurred.
|
||||
final DateTime timestamp;
|
||||
|
||||
final Map<String, dynamic>? arguments;
|
||||
}
|
||||
|
||||
/// Information received in response to an initial HTTP request.
|
||||
|
@ -640,13 +644,17 @@ class HttpProfileResponseData {
|
|||
json == null ? null : HttpProfileResponseData._fromJson(json);
|
||||
|
||||
HttpProfileResponseData._fromJson(Map<String, dynamic> json)
|
||||
: startTime = json['startTime']!,
|
||||
endTime = json['endTime'],
|
||||
headers = json['headers']!,
|
||||
connectionInfo = json['connectionInfo']!,
|
||||
contentLength = json['contentLength']!,
|
||||
compressionState = json['compressionState']!,
|
||||
cookies = UnmodifiableListView(json['cookies']!.cast<String>()),
|
||||
: startTime = json['startTime'] == null
|
||||
? null
|
||||
: DateTime.fromMicrosecondsSinceEpoch(json['startTime']),
|
||||
endTime = json['endTime'] == null
|
||||
? null
|
||||
: DateTime.fromMicrosecondsSinceEpoch(json['endTime']),
|
||||
headers = json['headers'],
|
||||
connectionInfo = json['connectionInfo'],
|
||||
contentLength = json['contentLength'],
|
||||
compressionState = json['compressionState'],
|
||||
cookies = UnmodifiableListView(json['cookies']?.cast<String>() ?? []),
|
||||
error = json['error'],
|
||||
isRedirect = json['isRedirect'],
|
||||
persistentConnection = json['persistentConnection'],
|
||||
|
@ -656,38 +664,38 @@ class HttpProfileResponseData {
|
|||
statusCode = json['statusCode'];
|
||||
|
||||
HttpProfileResponseData({
|
||||
required this.startTime,
|
||||
this.startTime,
|
||||
this.endTime,
|
||||
required this.headers,
|
||||
required this.compressionState,
|
||||
required this.connectionInfo,
|
||||
required this.contentLength,
|
||||
required this.cookies,
|
||||
required this.isRedirect,
|
||||
required this.persistentConnection,
|
||||
required this.reasonPhrase,
|
||||
this.headers,
|
||||
this.compressionState,
|
||||
this.connectionInfo,
|
||||
this.contentLength,
|
||||
this.cookies,
|
||||
this.isRedirect,
|
||||
this.persistentConnection,
|
||||
this.reasonPhrase,
|
||||
required this.redirects,
|
||||
required this.statusCode,
|
||||
this.statusCode,
|
||||
this.error,
|
||||
});
|
||||
|
||||
bool get isComplete => endTime != null;
|
||||
bool get hasError => error != null;
|
||||
|
||||
/// Returns the series of redirects this connection has been through.
|
||||
/// The series of redirects this connection has been through.
|
||||
///
|
||||
/// The list will be empty if no redirects were followed. redirects will be
|
||||
/// The list will be empty if no redirects were followed. Redirects will be
|
||||
/// updated both in the case of an automatic and a manual redirect.
|
||||
final List<Map<String, dynamic>> redirects;
|
||||
|
||||
/// Cookies set by the server (from the 'set-cookie' header).
|
||||
final List<String> cookies;
|
||||
final List<String>? cookies;
|
||||
|
||||
/// Information about the client connection.
|
||||
final Map<String, dynamic>? connectionInfo;
|
||||
|
||||
/// Returns the client response headers.
|
||||
final Map<String, dynamic> headers;
|
||||
/// The client response headers.
|
||||
final Map<String, dynamic>? headers;
|
||||
|
||||
/// The compression state of the response.
|
||||
///
|
||||
|
@ -696,32 +704,32 @@ class HttpProfileResponseData {
|
|||
/// uncompressed bytes when they listed to this response's byte stream.
|
||||
///
|
||||
/// See [HttpClientResponseCompressionState](https://api.dart.dev/stable/dart-io/HttpClientResponseCompressionState-class.html) for possible values.
|
||||
final String compressionState;
|
||||
final String? compressionState;
|
||||
|
||||
/// Returns the reason phrase associated with the status code.
|
||||
final String reasonPhrase;
|
||||
/// The reason phrase associated with the status code.
|
||||
final String? reasonPhrase;
|
||||
|
||||
/// Returns whether the status code is one of the normal redirect codes.
|
||||
final bool isRedirect;
|
||||
/// Whether the status code is one of the normal redirect codes.
|
||||
final bool? isRedirect;
|
||||
|
||||
/// The persistent connection state returned by the server.
|
||||
final bool persistentConnection;
|
||||
final bool? persistentConnection;
|
||||
|
||||
/// Returns the content length of the response body.
|
||||
/// The content length of the response body, in bytes.
|
||||
///
|
||||
/// Returns -1 if the size of the response body is not known in advance.
|
||||
final int contentLength;
|
||||
final int? contentLength;
|
||||
|
||||
/// Returns the status code.
|
||||
final int statusCode;
|
||||
/// The status code.
|
||||
final int? statusCode;
|
||||
|
||||
/// The time at which the initial response was received, in microseconds.
|
||||
final int startTime;
|
||||
/// The time at which the initial response was received.
|
||||
final DateTime? startTime;
|
||||
|
||||
/// The time at which the response was completed, in microseconds.
|
||||
/// The time at which the response was completed.
|
||||
///
|
||||
/// Will be `null` if response data is still being received.
|
||||
final int? endTime;
|
||||
final DateTime? endTime;
|
||||
|
||||
/// The error associated with the failed response.
|
||||
final String? error;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: vm_service
|
||||
version: 13.0.0
|
||||
version: 14.0.0
|
||||
description: >-
|
||||
A library to communicate with a service implementing the Dart VM
|
||||
service protocol.
|
||||
|
|
|
@ -71,6 +71,10 @@ Uri randomlyAddRequestParams(Uri uri) {
|
|||
Future<HttpServer> startServer() async {
|
||||
final server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
|
||||
server.listen((request) async {
|
||||
// Randomly delay starting the response.
|
||||
await Future.delayed(
|
||||
Duration(milliseconds: rng.nextInt(maxResponseDelayMs) + 1),
|
||||
);
|
||||
final response = request.response;
|
||||
response.write(request.method);
|
||||
randomlyAddCookie(response);
|
||||
|
@ -78,9 +82,9 @@ Future<HttpServer> startServer() async {
|
|||
// Redirect calls close() on the response.
|
||||
return;
|
||||
}
|
||||
// Randomly delay response.
|
||||
// Randomly delay finishing the response.
|
||||
await Future.delayed(
|
||||
Duration(milliseconds: rng.nextInt(maxResponseDelayMs)),
|
||||
Duration(milliseconds: rng.nextInt(maxResponseDelayMs) + 1),
|
||||
);
|
||||
await response.close();
|
||||
});
|
||||
|
@ -206,7 +210,7 @@ Future<void> hasValidHttpRequests(HttpProfile profile, String method) async {
|
|||
expect(requestData.error!.isNotEmpty, true);
|
||||
|
||||
// Some data is available even if a request errored out.
|
||||
expect(requestData.events.length, greaterThanOrEqualTo(0));
|
||||
expect(r.events.length, greaterThanOrEqualTo(0));
|
||||
expect(fullRequest.requestBody!.length, greaterThanOrEqualTo(0));
|
||||
|
||||
// Accessing the following properties should cause an exception for
|
||||
|
@ -216,7 +220,6 @@ Future<void> hasValidHttpRequests(HttpProfile profile, String method) async {
|
|||
expectThrows(() => requestData.followRedirects);
|
||||
expectThrows(() => requestData.headers);
|
||||
expectThrows(() => requestData.maxRedirects);
|
||||
expectThrows(() => requestData.method);
|
||||
expectThrows(() => requestData.persistentConnection);
|
||||
} else {
|
||||
// Invoke all non-nullable getters to ensure each is present in the JSON
|
||||
|
@ -255,8 +258,8 @@ Future<void> hasValidHttpRequests(HttpProfile profile, String method) async {
|
|||
final responseData = r.response!;
|
||||
expect(responseData.statusCode, greaterThanOrEqualTo(100));
|
||||
expect(responseData.endTime, isNotNull);
|
||||
expect(responseData.startTime > r.endTime!, true);
|
||||
expect(responseData.endTime! >= responseData.startTime, true);
|
||||
expect(responseData.startTime!.isAfter(r.endTime!), true);
|
||||
expect(responseData.startTime!.isBefore(responseData.endTime!), true);
|
||||
expect(utf8.decode(fullRequest.responseBody!), method);
|
||||
responseData.headers;
|
||||
responseData.compressionState;
|
||||
|
@ -301,8 +304,8 @@ void hasDefaultRequestHeaders(HttpProfile profile) {
|
|||
// requests.
|
||||
if (!request.isRequestComplete) continue;
|
||||
if (!request.request!.hasError) {
|
||||
expect(request.request?.headers['host'], isNotNull);
|
||||
expect(request.request?.headers['user-agent'], isNotNull);
|
||||
expect(request.request?.headers?['host'], isNotNull);
|
||||
expect(request.request?.headers?['user-agent'], isNotNull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -315,7 +318,7 @@ void hasCustomRequestHeaders(HttpProfile profile) {
|
|||
// requests.
|
||||
if (!request.isRequestComplete) continue;
|
||||
if (!request.request!.hasError) {
|
||||
expect(request.request?.headers['cookie-eater'], isNotNull);
|
||||
expect(request.request?.headers?['cookie-eater'], isNotNull);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Dart VM Service Protocol Extension 1.6
|
||||
# Dart VM Service Protocol Extension 4.0
|
||||
|
||||
This protocol describes service extensions that are made available through
|
||||
the Dart core libraries, but are not part of the core
|
||||
|
@ -10,7 +10,7 @@ invoked by prepending the service extension name (e.g.,
|
|||
|
||||
## dart:io Extensions
|
||||
|
||||
This section describes _version 1.6_ of the dart:io service protocol extensions.
|
||||
This section describes _version 4.0_ of the dart:io service protocol extensions.
|
||||
|
||||
### getVersion
|
||||
|
||||
|
@ -130,8 +130,9 @@ The returned `HttpProfile` will only include requests issued after
|
|||
`httpTimelineLogging` has been enabled or after the last
|
||||
`clearHttpProfile` invocation.
|
||||
|
||||
If `updatedSince` is provided, only requests started or updated since
|
||||
the specified time will be reported.
|
||||
If `updatedSince` is provided, only requests started or updated since the
|
||||
specified time will be reported. The specified time must be represented in
|
||||
microseconds since the "Unix epoch".
|
||||
|
||||
See [HttpProfile](#httpprofile).
|
||||
|
||||
|
@ -172,7 +173,7 @@ class @OpenFile extends Response {
|
|||
}
|
||||
```
|
||||
|
||||
_@File_ is a reference to a _File_.
|
||||
_@OpenFile_ is a reference to an _OpenFile_.
|
||||
|
||||
```
|
||||
class OpenFile extends Response {
|
||||
|
@ -230,7 +231,8 @@ See [httpEnableTimelineLogging](#httpenabletimelinelogging).
|
|||
|
||||
```
|
||||
class HttpProfile extends Response {
|
||||
// The time at which this HTTP profile was built, in microseconds.
|
||||
// The time at which this HTTP profile was built, represented as microseconds
|
||||
// since the "Unix epoch".
|
||||
int timestamp;
|
||||
|
||||
// The set of recorded HTTP requests.
|
||||
|
@ -248,8 +250,9 @@ See [getHttpProfile](#gethttpprofile).
|
|||
class @HttpProfileRequest extends Response {
|
||||
// The ID associated with this request.
|
||||
//
|
||||
// This ID corresponds to the ID of the timeline event for this request.
|
||||
int id;
|
||||
// If the ID does not start with the prefix "from_package/", then there
|
||||
// will be a corresponding timeline event with the same ID.
|
||||
string id;
|
||||
|
||||
// The ID of the isolate this request was issued from.
|
||||
string isolateId;
|
||||
|
@ -257,21 +260,28 @@ class @HttpProfileRequest extends Response {
|
|||
// The HTTP request method associated with this request.
|
||||
string method;
|
||||
|
||||
// The URI for this HTTP request.
|
||||
// The URI to which this HTTP request was sent.
|
||||
string uri;
|
||||
|
||||
// The time at which this request was initiated, in microseconds.
|
||||
final int startTime;
|
||||
// Events related to this HTTP request.
|
||||
//
|
||||
// Events which occurred before encountering an error will be reported.
|
||||
HttpProfileRequestEvent[] events;
|
||||
|
||||
// The time at which this request was completed, in microseconds.
|
||||
// The time at which this request was initiated, represented as microseconds
|
||||
// since the "Unix epoch".
|
||||
int startTime;
|
||||
|
||||
// The time at which this request was completed, represented as microseconds
|
||||
// since the "Unix epoch".
|
||||
int endTime [optional];
|
||||
|
||||
// Information sent as part of the initial HTTP request.
|
||||
// Details about the request.
|
||||
//
|
||||
// Will not be provided if the initial request has not yet completed.
|
||||
HttpProfileRequestData request [optional];
|
||||
|
||||
// Information received in response to the initial HTTP request.
|
||||
// Details about the response.
|
||||
//
|
||||
// Will not be provided if the request has not yet been responded to.
|
||||
HttpProfileResponseData response [optional];
|
||||
|
@ -300,36 +310,26 @@ See [HttpProfile](#httpprofile).
|
|||
```
|
||||
class HttpProfileRequestData {
|
||||
// Information about the client connection.
|
||||
//
|
||||
// This property can be null, regardless of error state.
|
||||
map<string, dynamic> connectionInfo [optional];
|
||||
|
||||
// The content length of the request, in bytes.
|
||||
int contentLength [optional];
|
||||
|
||||
// Cookies presented to the server (in the 'cookie' header).
|
||||
string[] cookies;
|
||||
|
||||
// Events that has occurred while issuing this HTTP request.
|
||||
//
|
||||
// Events which occurred before encountering an error will be reported.
|
||||
HttpProfileRequestEvent[] events;
|
||||
string[] cookies [optional];
|
||||
|
||||
// The error associated with the failed request.
|
||||
string error [optional];
|
||||
|
||||
// Whether to redirects are followed automatically.
|
||||
// Whether automatic redirect following was enabled for the request.
|
||||
bool followRedirects [optional];
|
||||
|
||||
// Returns the client request headers.
|
||||
// The client request headers.
|
||||
map<string, dynamic> headers [optional];
|
||||
|
||||
// The maximum number of redirects to follow when `followRedirects` is true.
|
||||
// The maximum number of redirects allowed during the request.
|
||||
int maxRedirects [optional];
|
||||
|
||||
// The method of the request.
|
||||
string method [optional];
|
||||
|
||||
// The requested persistent connection state.
|
||||
bool persistentConnection [optional];
|
||||
|
||||
|
@ -339,8 +339,7 @@ class HttpProfileRequestData {
|
|||
```
|
||||
|
||||
Information sent as part of the initial HTTP request. If `error` is present,
|
||||
other properties will be null. If `error` is not present, all other properties
|
||||
will be provided unless otherwise specified.
|
||||
the other properties will be null.
|
||||
|
||||
See [HttpProfileRequest](#httpprofilerequest).
|
||||
|
||||
|
@ -348,49 +347,51 @@ See [HttpProfileRequest](#httpprofilerequest).
|
|||
|
||||
```
|
||||
class HttpProfileResponseData {
|
||||
// Returns the series of redirects this connection has been through.
|
||||
// The series of redirects this connection has been through.
|
||||
//
|
||||
// The list will be empty if no redirects were followed. redirects will be
|
||||
// The list will be empty if no redirects were followed. Redirects will be
|
||||
// updated both in the case of an automatic and a manual redirect.
|
||||
map<string, dynamic>[] redirects;
|
||||
|
||||
// Cookies set by the server (from the 'set-cookie' header).
|
||||
string[] cookies;
|
||||
string[] cookies [optional];
|
||||
|
||||
// Information about the client connection.
|
||||
map<string, dynamic> connectionInfo [optional];
|
||||
|
||||
// Returns the client response headers.
|
||||
map<string, dynamic> headers;
|
||||
// The client response headers.
|
||||
map<string, dynamic> headers [optional];
|
||||
|
||||
// The compression state of the response.
|
||||
//
|
||||
// This specifies whether the response bytes were compressed when they were
|
||||
// received across the wire and whether callers will receive compressed or
|
||||
// uncompressed bytes when they listed to this response's byte stream.
|
||||
string compressionState;
|
||||
string compressionState [optional];
|
||||
|
||||
// Returns the reason phrase associated with the status code.
|
||||
string reasonPhrase;
|
||||
// The reason phrase associated with the status code.
|
||||
string reasonPhrase [optional];
|
||||
|
||||
// Returns whether the status code is one of the normal redirect codes.
|
||||
bool isRedirect;
|
||||
// Whether the status code is one of the normal redirect codes.
|
||||
bool isRedirect [optional];
|
||||
|
||||
// The persistent connection state returned by the server.
|
||||
bool persistentConnection;
|
||||
bool persistentConnection [optional];
|
||||
|
||||
// Returns the content length of the response body.
|
||||
// The content length of the response body, in bytes.
|
||||
//
|
||||
// Returns -1 if the size of the response body is not known in advance.
|
||||
int contentLength;
|
||||
int contentLength [optional];
|
||||
|
||||
// Returns the status code.
|
||||
int statusCode;
|
||||
// The status code.
|
||||
int statusCode [optional];
|
||||
|
||||
// The time at which the initial response was received, in microseconds.
|
||||
int startTime;
|
||||
// The time at which the initial response was received, represented as
|
||||
// microseconds since the "Unix epoch".
|
||||
int startTime [optional];
|
||||
|
||||
// The time at which the response was completed, in microseconds.
|
||||
// The time at which the response was completed, represented as
|
||||
// microseconds since the "Unix epoch".
|
||||
int endTime [optional];
|
||||
|
||||
// The error associated with the failed request.
|
||||
|
@ -408,12 +409,12 @@ See [HttpProfileRequest](#httpprofilerequest).
|
|||
class HttpProfileProxyData {
|
||||
string host [optional];
|
||||
string username [optional];
|
||||
bool isDirect;
|
||||
bool isDirect [optional];
|
||||
int port [optional];
|
||||
}
|
||||
```
|
||||
|
||||
Proxy authentication details associated with a HTTP request.
|
||||
Proxy authentication details associated with an HTTP request.
|
||||
|
||||
See [HttpProfileRequestData](#httpprofilerequestdata).
|
||||
|
||||
|
@ -424,7 +425,8 @@ class HttpProfileRequestEvent {
|
|||
// The title of the recorded event.
|
||||
string event;
|
||||
|
||||
// The time at which the event occurred, in microseconds.
|
||||
// The time at which the event occurred, represented as microseconds since
|
||||
// the "Unix epoch".
|
||||
int timestamp;
|
||||
|
||||
// Any arguments recorded for the event.
|
||||
|
@ -432,7 +434,7 @@ class HttpProfileRequestEvent {
|
|||
}
|
||||
```
|
||||
|
||||
Describes an event that has occurred while issuing a HTTP request.
|
||||
Describes an event related to an HTTP request.
|
||||
|
||||
See [HttpProfileRequestData](#httpprofilerequestdata).
|
||||
|
||||
|
@ -590,3 +592,31 @@ version | comments
|
|||
1.5 | Added `socketProfilingEnabled` RPC and `SocketProfilingStateChanged` event, deprecated `startSocketProfiling` and `pauseSocketProfiling`.
|
||||
1.6 | Added `isSocketProfilingAvailable`, `isHttpTimelineLoggingAvailable`, `isHttpProfilingAvailable`, removed deprecated RPCs `startSocketProfiling`,
|
||||
`pauseSocketProfiling`, `getHttpEnableTimelineLogging`, and `setHttpEnableTimelineLogging`.
|
||||
2.0 | Changed the type of the `id` property of `@HttpProfileRequestRef` and
|
||||
`HttpProfileRequestRef` from `int` to `String`. Changed the type of
|
||||
`SocketStatistic.id` from `int` to `String`. Changed the type of the `id`
|
||||
parameter of `getHttpProfileRequest` from `int` to `String`. Changed the name of
|
||||
the `enable` parameter of `httpEnableTimelineLogging` to `enabled`.
|
||||
3.0 | Added `isSocketProfilingAvailable`, `isHttpTimelineLoggingAvailable`,
|
||||
and `isHttpProfilingAvailable` methods. Removed deprecated
|
||||
`startSocketProfiling`, `pauseSocketProfiling`, `getHttpEnableTimelineLogging`,
|
||||
and `setHttpEnableTimelineLogging` methods.
|
||||
4.0 | Made the `updatedSince` parameter of `getHttpProfile` require the time to
|
||||
be represented in microseconds since the "Unix epoch" instead of as a timestamp
|
||||
on the monotonic clock used by the timeline. Made the `timestamp` property of
|
||||
`HttpProfile` represent time in microseconds since the "Unix epoch" instead of
|
||||
as a timestamp on the monotonic clock used by the timeline. Added `events`
|
||||
property to `@HttpProfileRequest` and `HttpProfileRequest`. Made the `startTime`
|
||||
and `endTime` properties of `@HttpProfileRequest` and `HttpProfileRequest`
|
||||
represent time in microseconds since the "Unix epoch" instead of as timestamps
|
||||
on the monotonic clock used by the timeline. Removed the `events` and `method`
|
||||
properties from `HttpProfileRequestData`. Made the `cookies` property of
|
||||
`HttpProfileRequestData` optional. Made the `startTime` and `endTime` properties
|
||||
of `HttpProfileResponseData` represent time in microseconds since the "Unix
|
||||
epoch" instead of as timestamps on the monotonic clock used by the timeline.
|
||||
Made the `cookies`, `headers`, `compressionState`, `reasonPhrase`, `isRedirect`,
|
||||
`persistentConnection`, `contentLength`, `statusCode`, and `startTime`
|
||||
properties of `HttpProfileResponseData` optional. Made the `isDirect` property
|
||||
of `HttpProfileProxyData` optional. Made the `timestamp` property of
|
||||
`HttpProfileRequestEvent` represent time in microseconds since the "Unix epoch"
|
||||
instead of as a timestamp on the monotonic clock used by the timeline.
|
||||
|
|
|
@ -27,7 +27,7 @@ abstract final class HttpProfiler {
|
|||
static String toJson(int? updatedSince) {
|
||||
return json.encode({
|
||||
'type': _kType,
|
||||
'timestamp': Timeline.now,
|
||||
'timestamp': DateTime.now().microsecondsSinceEpoch,
|
||||
'requests': [
|
||||
for (final request in _profile.values.where(
|
||||
(e) {
|
||||
|
@ -42,7 +42,7 @@ abstract final class HttpProfiler {
|
|||
|
||||
class _HttpProfileEvent {
|
||||
_HttpProfileEvent(this.name, this.arguments);
|
||||
final int timestamp = Timeline.now;
|
||||
final int timestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
final String name;
|
||||
final Map? arguments;
|
||||
|
||||
|
@ -66,7 +66,7 @@ class _HttpProfileData {
|
|||
// to the timeline.
|
||||
id = _timeline.pass().toString();
|
||||
requestInProgress = true;
|
||||
requestStartTimestamp = Timeline.now;
|
||||
requestStartTimestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
_timeline.start('HTTP CLIENT $method', arguments: {
|
||||
'method': method.toUpperCase(),
|
||||
'uri': uri.toString(),
|
||||
|
@ -119,7 +119,7 @@ class _HttpProfileData {
|
|||
}) {
|
||||
// TODO(bkonyi): include encoding?
|
||||
requestInProgress = false;
|
||||
requestEndTimestamp = Timeline.now;
|
||||
requestEndTimestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
requestDetails = <String, dynamic>{
|
||||
// TODO(bkonyi): consider exposing certificate information?
|
||||
// 'certificate': response.certificate,
|
||||
|
@ -176,7 +176,7 @@ class _HttpProfileData {
|
|||
filterKey: 'HTTP/client',
|
||||
);
|
||||
|
||||
responseStartTimestamp = Timeline.now;
|
||||
responseStartTimestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
_responseTimeline.start(
|
||||
'HTTP CLIENT response of $method',
|
||||
arguments: {
|
||||
|
@ -189,7 +189,7 @@ class _HttpProfileData {
|
|||
|
||||
void finishRequestWithError(String error) {
|
||||
requestInProgress = false;
|
||||
requestEndTimestamp = Timeline.now;
|
||||
requestEndTimestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
requestError = error;
|
||||
_timeline.finish(arguments: {
|
||||
'error': error,
|
||||
|
@ -199,7 +199,7 @@ class _HttpProfileData {
|
|||
|
||||
void finishResponse() {
|
||||
responseInProgress = false;
|
||||
responseEndTimestamp = Timeline.now;
|
||||
responseEndTimestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
requestEvent('Content Download');
|
||||
_responseTimeline.finish();
|
||||
_updated();
|
||||
|
@ -210,7 +210,7 @@ class _HttpProfileData {
|
|||
// the response stream is listened to with `cancelOnError: false`.
|
||||
if (!responseInProgress!) return;
|
||||
responseInProgress = false;
|
||||
responseEndTimestamp = Timeline.now;
|
||||
responseEndTimestamp = DateTime.now().microsecondsSinceEpoch;
|
||||
responseError = error;
|
||||
_responseTimeline.finish(arguments: {
|
||||
'error': error,
|
||||
|
@ -230,13 +230,13 @@ class _HttpProfileData {
|
|||
'isolateId': isolateId,
|
||||
'method': method,
|
||||
'uri': uri.toString(),
|
||||
'events': <Map<String, dynamic>>[
|
||||
for (final event in requestEvents) event.toJson(),
|
||||
],
|
||||
'startTime': requestStartTimestamp,
|
||||
if (!requestInProgress) 'endTime': requestEndTimestamp,
|
||||
if (!requestInProgress)
|
||||
'request': {
|
||||
'events': <Map<String, dynamic>>[
|
||||
for (final event in requestEvents) event.toJson(),
|
||||
],
|
||||
if (proxyDetails != null) 'proxyDetails': proxyDetails!,
|
||||
if (requestDetails != null) ...requestDetails!,
|
||||
if (requestError != null) 'error': requestError,
|
||||
|
@ -255,7 +255,7 @@ class _HttpProfileData {
|
|||
};
|
||||
}
|
||||
|
||||
void _updated() => _lastUpdateTime = Timeline.now;
|
||||
void _updated() => _lastUpdateTime = DateTime.now().microsecondsSinceEpoch;
|
||||
|
||||
static final String isolateId = Service.getIsolateID(Isolate.current)!;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
part of dart.io;
|
||||
|
||||
// TODO(bkonyi): refactor into io_resource_info.dart
|
||||
const int _versionMajor = 3;
|
||||
const int _versionMajor = 4;
|
||||
const int _versionMinor = 0;
|
||||
|
||||
const String _tcpSocket = 'tcp';
|
||||
|
|
Loading…
Reference in a new issue