From b1b848ca7d83edbec6438ab5d0bf6864ae9ec7fd Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Fri, 27 Mar 2026 23:24:02 +0530 Subject: [PATCH 01/13] Added size support to network tab --- .../src/screens/network/network_model.dart | 9 ++++++++ .../network_request_inspector_views.dart | 17 ++++++++++++++ .../src/screens/network/network_screen.dart | 23 +++++++++++++++++++ .../src/shared/http/http_request_data.dart | 14 +++++++++++ 4 files changed, 63 insertions(+) diff --git a/packages/devtools_app/lib/src/screens/network/network_model.dart b/packages/devtools_app/lib/src/screens/network/network_model.dart index 8a6697fbe65..9ccc3c5217a 100644 --- a/packages/devtools_app/lib/src/screens/network/network_model.dart +++ b/packages/devtools_app/lib/src/screens/network/network_model.dart @@ -29,6 +29,9 @@ abstract class NetworkRequest int? get port; + int? get requestBytes => null; + int? get responseBytes => null; + bool get didFail; /// True if the request hasn't completed yet. @@ -160,6 +163,12 @@ class Socket extends NetworkRequest { @override int get port => _socket.port; + @override + int get requestBytes => writeBytes; + + @override + int get responseBytes => readBytes; + // TODO(kenz): what determines a web socket request failure? @override bool get didFail => false; diff --git a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart index 831b3e52052..2c3a1f1e0d0 100644 --- a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart +++ b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart @@ -658,6 +658,14 @@ class NetworkRequestOverviewView extends StatelessWidget { ), const SizedBox(height: defaultSpacing), ], + const SizedBox(height: defaultSpacing), + _buildRow( + context: context, + title: 'Size', + child: _valueText(_formatBytes(data.responseBytes)), + ), + const SizedBox(height: defaultSpacing), + if (data.contentType != null) ...[ _buildRow( context: context, @@ -669,6 +677,15 @@ class NetworkRequestOverviewView extends StatelessWidget { ]; } + String _formatBytes(int? bytes) { + if (bytes == null) return '-'; + if (bytes < 1024) return '$bytes B'; + if (bytes < 1024 * 1024) { + return '${(bytes / 1024).toStringAsFixed(1)} KB'; + } + return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB'; + } + List _buildTimingOverview(BuildContext context) { return [ _buildRow( diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index 5171c5e6736..24187b0e4d8 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -371,6 +371,7 @@ class NetworkRequestsTable extends StatelessWidget { statusColumn, typeColumn, durationColumn, + const ResponseSizeColumn(), timestampColumn, actionsColumn, ]; @@ -405,6 +406,28 @@ class NetworkRequestsTable extends StatelessWidget { } } +String _formatBytes(int? bytes) { + if (bytes == null) return '-'; + if (bytes < 1024) return '$bytes B'; + if (bytes < 1024 * 1024) { + return '${(bytes / 1024).toStringAsFixed(1)} KB'; + } + return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB'; +} + +class ResponseSizeColumn extends ColumnData { + const ResponseSizeColumn() + : super('Size', alignment: ColumnAlignment.right, fixedWidthPx: 90); + + @override + int? getValue(NetworkRequest data) => data.responseBytes; + + @override + String getDisplayValue(NetworkRequest data) { + return _formatBytes(data.responseBytes); + } +} + class AddressColumn extends ColumnData implements ColumnRenderer { AddressColumn() diff --git a/packages/devtools_app/lib/src/shared/http/http_request_data.dart b/packages/devtools_app/lib/src/shared/http/http_request_data.dart index 8be9458d23f..9c432eb295d 100644 --- a/packages/devtools_app/lib/src/shared/http/http_request_data.dart +++ b/packages/devtools_app/lib/src/shared/http/http_request_data.dart @@ -212,6 +212,20 @@ class DartIOHttpRequestData extends NetworkRequest { return connectionInfo != null ? connectionInfo[_localPortKey] : null; } + @override + int? get responseBytes { + final headers = responseHeaders; + final contentLength = headers?['content-length']; + + if (contentLength is String) { + return int.tryParse(contentLength); + } + if (contentLength is List && contentLength.isNotEmpty) { + return int.tryParse(contentLength.first); + } + return null; + } + /// True if the HTTP request hasn't completed yet, determined by the lack of /// an end time in the response data. @override From aa06a0c63cf0ba2948c2c4ba9e9de35e17dad66b Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 00:09:09 +0530 Subject: [PATCH 02/13] Added release notes entry for network response size feature --- packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md index d5d4a6c8a09..dad97a9bbf2 100644 --- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md +++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md @@ -43,7 +43,8 @@ TODO: Remove this section if there are not any updates. ## Network profiler updates -TODO: Remove this section if there are not any updates. +- Added response size ("Size") column to the Network tab and displayed size in the request inspector overview. - + [#9744](https://github.com/flutter/devtools/pull/9744) ## Logging updates From 63e204148b9ec22b2d1269868af40efac45616c9 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 00:13:00 +0530 Subject: [PATCH 03/13] Resolve merge conflict in release notes --- packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md index dad97a9bbf2..46f7b9fce16 100644 --- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md +++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md @@ -43,9 +43,10 @@ TODO: Remove this section if there are not any updates. ## Network profiler updates -- Added response size ("Size") column to the Network tab and displayed size in the request inspector overview. - +- Added response size ("Res Size") column to the Network tab and displayed response size in the request inspector overview. - [#9744](https://github.com/flutter/devtools/pull/9744) +- Added a filter setting to hide HTTP-profiler socket data. [#9698](https://github.com/flutter/devtools/pull/9698) ## Logging updates TODO: Remove this section if there are not any updates. From 49aa68b38c78e6fac34afea3976a54a0dd1ce3c0 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 00:29:09 +0530 Subject: [PATCH 04/13] Added documentation for byte formatting --- .../src/screens/network/network_request_inspector_views.dart | 5 +++++ .../devtools_app/lib/src/screens/network/network_screen.dart | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart index 2c3a1f1e0d0..af2f0304bca 100644 --- a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart +++ b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart @@ -677,6 +677,11 @@ class NetworkRequestOverviewView extends StatelessWidget { ]; } + // Output Formats: + // - 512 → "512 B" + // - 2048 → "2.0 KB" + // - 1048576 → "1.0 MB" + // Values are rounded to one decimal place for KB and MB. String _formatBytes(int? bytes) { if (bytes == null) return '-'; if (bytes < 1024) return '$bytes B'; diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index 24187b0e4d8..dd5b92a7b59 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -406,6 +406,11 @@ class NetworkRequestsTable extends StatelessWidget { } } +// Output Formats: +// - 512 → "512 B" +// - 2048 → "2.0 KB" +// - 1048576 → "1.0 MB" +// Values are rounded to one decimal place for KB and MB. String _formatBytes(int? bytes) { if (bytes == null) return '-'; if (bytes < 1024) return '$bytes B'; From 4bb20f1b40adb88e1673f1cc59d34d89827b4a38 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 01:02:42 +0530 Subject: [PATCH 05/13] Fix lint: match parameter names with base class --- .../devtools_app/lib/src/screens/network/network_screen.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index dd5b92a7b59..ab79fb7a5c8 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -428,8 +428,8 @@ class ResponseSizeColumn extends ColumnData { int? getValue(NetworkRequest data) => data.responseBytes; @override - String getDisplayValue(NetworkRequest data) { - return _formatBytes(data.responseBytes); + String getDisplayValue(NetworkRequest dataObject) { + return _formatBytes(dataObject.responseBytes); } } From 1b4fc2547eeb3d841a3d506bedce0b2f5f1153c2 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 01:10:49 +0530 Subject: [PATCH 06/13] Fix lint: correct parameter name in AddressColumn --- .../devtools_app/lib/src/screens/network/network_screen.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index ab79fb7a5c8..33953cc2d05 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -443,8 +443,8 @@ class AddressColumn extends ColumnData ); @override - String getValue(NetworkRequest dataObject) { - return dataObject.uri; + String getValue(NetworkRequest data) { + return data.uri; } @override From ec2e7d962d3317b25c519f870cf105bcac6bd817 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 01:14:25 +0530 Subject: [PATCH 07/13] Fix type handling for content-length header in responseBytes --- .../lib/src/shared/http/http_request_data.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/shared/http/http_request_data.dart b/packages/devtools_app/lib/src/shared/http/http_request_data.dart index aafa3b89a02..b5e716b28b4 100644 --- a/packages/devtools_app/lib/src/shared/http/http_request_data.dart +++ b/packages/devtools_app/lib/src/shared/http/http_request_data.dart @@ -236,7 +236,14 @@ class DartIOHttpRequestData extends NetworkRequest { return int.tryParse(contentLength); } if (contentLength is List && contentLength.isNotEmpty) { - return int.tryParse(contentLength.first); + final first = contentLength.first; + + if (first is int) { + return first; + } + if (first is String) { + return int.tryParse(first); + } } return null; } From 3c17534d8bbbe130da3ad4c5bc58f3b362be8a11 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 01:24:11 +0530 Subject: [PATCH 08/13] Fix layout spacing to ensure consistent widget tree --- .../src/screens/network/network_request_inspector_views.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart index af2f0304bca..506ad844ca6 100644 --- a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart +++ b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart @@ -658,10 +658,10 @@ class NetworkRequestOverviewView extends StatelessWidget { ), const SizedBox(height: defaultSpacing), ], - const SizedBox(height: defaultSpacing), + _buildRow( context: context, - title: 'Size', + title: 'Response Size', child: _valueText(_formatBytes(data.responseBytes)), ), const SizedBox(height: defaultSpacing), From 4257c47e1546ec35707b8d3651bad86a759efff3 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sat, 28 Mar 2026 01:34:46 +0530 Subject: [PATCH 09/13] Fix variable placement for response size rendering --- .../src/screens/network/network_request_inspector_views.dart | 3 ++- .../devtools_app/lib/src/screens/network/network_screen.dart | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart index 506ad844ca6..19eb83daf9c 100644 --- a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart +++ b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart @@ -625,6 +625,7 @@ class NetworkRequestOverviewView extends StatelessWidget { } List _buildGeneralRows(BuildContext context) { + final bytes = data.responseBytes; return [ // TODO(kenz): show preview for requests (png, response body, proto) _buildRow( @@ -662,7 +663,7 @@ class NetworkRequestOverviewView extends StatelessWidget { _buildRow( context: context, title: 'Response Size', - child: _valueText(_formatBytes(data.responseBytes)), + child: _valueText(bytes != null ? _formatBytes(bytes) : '-'), ), const SizedBox(height: defaultSpacing), diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index 33953cc2d05..807ec98c669 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -429,7 +429,8 @@ class ResponseSizeColumn extends ColumnData { @override String getDisplayValue(NetworkRequest dataObject) { - return _formatBytes(dataObject.responseBytes); + final bytes = dataObject.responseBytes; + return bytes != null ? _formatBytes(bytes) : '-'; } } From 6fb03f97381547ade99c42d5b42f5a26d8b7e859 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Sun, 29 Mar 2026 10:58:04 +0530 Subject: [PATCH 10/13] Fix parameter name to match ColumnData override --- .../devtools_app/lib/src/screens/network/network_screen.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index 807ec98c669..070bf270941 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -425,7 +425,7 @@ class ResponseSizeColumn extends ColumnData { : super('Size', alignment: ColumnAlignment.right, fixedWidthPx: 90); @override - int? getValue(NetworkRequest data) => data.responseBytes; + int? getValue(NetworkRequest dataObject) => dataObject.responseBytes; @override String getDisplayValue(NetworkRequest dataObject) { From b4a124b81abe261aa9d9cc6adcff9a746c95306d Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Tue, 31 Mar 2026 08:23:08 +0530 Subject: [PATCH 11/13] Addressed Requested changes: update size units, refactor column definition, simplify code, and revert unnecessary changes --- .../network_request_inspector_views.dart | 15 +++++++------ .../src/screens/network/network_screen.dart | 22 ++++++++++--------- .../src/shared/http/http_request_data.dart | 3 +-- 3 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart index 19eb83daf9c..50752d3541f 100644 --- a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart +++ b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart @@ -680,16 +680,17 @@ class NetworkRequestOverviewView extends StatelessWidget { // Output Formats: // - 512 → "512 B" - // - 2048 → "2.0 KB" - // - 1048576 → "1.0 MB" - // Values are rounded to one decimal place for KB and MB. + // - 2000 → "2.0 kB" + // - 1000000 → "1.0 MB" + // Values are rounded to one decimal place for kB and MB. + // Uses decimal (base-10) units to match Chrome DevTools. String _formatBytes(int? bytes) { if (bytes == null) return '-'; - if (bytes < 1024) return '$bytes B'; - if (bytes < 1024 * 1024) { - return '${(bytes / 1024).toStringAsFixed(1)} KB'; + if (bytes < 1000) return '$bytes B'; + if (bytes < 1000 * 1000) { + return '${(bytes / 1000).toStringAsFixed(1)} kB'; } - return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB'; + return '${(bytes / (1000 * 1000)).toStringAsFixed(1)} MB'; } List _buildTimingOverview(BuildContext context) { diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index 070bf270941..9e81284d296 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -363,6 +363,7 @@ class NetworkRequestsTable extends StatelessWidget { static const statusColumn = StatusColumn(); static const typeColumn = TypeColumn(); static const durationColumn = DurationColumn(); + static const responseSizeColumn = ResponseSizeColumn(); static final timestampColumn = TimestampColumn(); static const actionsColumn = ActionsColumn(); static final columns = >[ @@ -371,7 +372,7 @@ class NetworkRequestsTable extends StatelessWidget { statusColumn, typeColumn, durationColumn, - const ResponseSizeColumn(), + responseSizeColumn, timestampColumn, actionsColumn, ]; @@ -408,16 +409,17 @@ class NetworkRequestsTable extends StatelessWidget { // Output Formats: // - 512 → "512 B" -// - 2048 → "2.0 KB" -// - 1048576 → "1.0 MB" -// Values are rounded to one decimal place for KB and MB. +// - 2000 → "2.0 kB" +// - 1000000 → "1.0 MB" +// Values are rounded to one decimal place for kB and MB. +// Uses decimal (base-10) units to match Chrome DevTools. String _formatBytes(int? bytes) { if (bytes == null) return '-'; - if (bytes < 1024) return '$bytes B'; - if (bytes < 1024 * 1024) { - return '${(bytes / 1024).toStringAsFixed(1)} KB'; + if (bytes < 1000) return '$bytes B'; + if (bytes < 1000 * 1000) { + return '${(bytes / 1000).toStringAsFixed(1)} kB'; } - return '${(bytes / (1024 * 1024)).toStringAsFixed(1)} MB'; + return '${(bytes / (1000 * 1000)).toStringAsFixed(1)} MB'; } class ResponseSizeColumn extends ColumnData { @@ -444,8 +446,8 @@ class AddressColumn extends ColumnData ); @override - String getValue(NetworkRequest data) { - return data.uri; + String getValue(NetworkRequest dataObject) { + return dataObject.uri; } @override diff --git a/packages/devtools_app/lib/src/shared/http/http_request_data.dart b/packages/devtools_app/lib/src/shared/http/http_request_data.dart index b5e716b28b4..77a4a6cd965 100644 --- a/packages/devtools_app/lib/src/shared/http/http_request_data.dart +++ b/packages/devtools_app/lib/src/shared/http/http_request_data.dart @@ -229,8 +229,7 @@ class DartIOHttpRequestData extends NetworkRequest { @override int? get responseBytes { - final headers = responseHeaders; - final contentLength = headers?['content-length']; + final contentLength = responseHeaders?['content-length']; if (contentLength is String) { return int.tryParse(contentLength); From 71e3db3223520649881406e38aae323ec59cf280 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Wed, 1 Apr 2026 00:50:06 +0530 Subject: [PATCH 12/13] Addressed Rquested Changes: refactor formatBytes into http_utils, update units and added tests for responseBytes & formatBytes --- .../network_request_inspector_views.dart | 18 +---- .../src/screens/network/network_screen.dart | 18 +---- .../src/screens/network/utils/http_utils.dart | 15 ++++ .../release_notes/NEXT_RELEASE_NOTES.md | 2 +- .../shared/http/http_request_data_test.dart | 70 +++++++++++++++++++ .../test/shared/http/http_utils_test.dart | 19 +++++ 6 files changed, 109 insertions(+), 33 deletions(-) create mode 100644 packages/devtools_app/test/shared/http/http_request_data_test.dart create mode 100644 packages/devtools_app/test/shared/http/http_utils_test.dart diff --git a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart index 50752d3541f..aad90c72bf3 100644 --- a/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart +++ b/packages/devtools_app/lib/src/screens/network/network_request_inspector_views.dart @@ -17,6 +17,7 @@ import '../../shared/ui/colors.dart'; import '../../shared/ui/common_widgets.dart'; import 'network_controller.dart'; import 'network_model.dart'; +import 'utils/http_utils.dart'; // Approximately double the indent of the expandable tile's title. const _rowIndentPadding = 30.0; @@ -663,7 +664,7 @@ class NetworkRequestOverviewView extends StatelessWidget { _buildRow( context: context, title: 'Response Size', - child: _valueText(bytes != null ? _formatBytes(bytes) : '-'), + child: _valueText(bytes != null ? formatBytes(bytes) : '-'), ), const SizedBox(height: defaultSpacing), @@ -678,21 +679,6 @@ class NetworkRequestOverviewView extends StatelessWidget { ]; } - // Output Formats: - // - 512 → "512 B" - // - 2000 → "2.0 kB" - // - 1000000 → "1.0 MB" - // Values are rounded to one decimal place for kB and MB. - // Uses decimal (base-10) units to match Chrome DevTools. - String _formatBytes(int? bytes) { - if (bytes == null) return '-'; - if (bytes < 1000) return '$bytes B'; - if (bytes < 1000 * 1000) { - return '${(bytes / 1000).toStringAsFixed(1)} kB'; - } - return '${(bytes / (1000 * 1000)).toStringAsFixed(1)} MB'; - } - List _buildTimingOverview(BuildContext context) { return [ _buildRow( diff --git a/packages/devtools_app/lib/src/screens/network/network_screen.dart b/packages/devtools_app/lib/src/screens/network/network_screen.dart index 9e81284d296..7e8315520b5 100644 --- a/packages/devtools_app/lib/src/screens/network/network_screen.dart +++ b/packages/devtools_app/lib/src/screens/network/network_screen.dart @@ -30,6 +30,7 @@ import '../../shared/ui/utils.dart'; import 'network_controller.dart'; import 'network_model.dart'; import 'network_request_inspector.dart'; +import 'utils/http_utils.dart'; class NetworkScreen extends Screen { NetworkScreen() : super.fromMetaData(ScreenMetaData.network); @@ -407,21 +408,6 @@ class NetworkRequestsTable extends StatelessWidget { } } -// Output Formats: -// - 512 → "512 B" -// - 2000 → "2.0 kB" -// - 1000000 → "1.0 MB" -// Values are rounded to one decimal place for kB and MB. -// Uses decimal (base-10) units to match Chrome DevTools. -String _formatBytes(int? bytes) { - if (bytes == null) return '-'; - if (bytes < 1000) return '$bytes B'; - if (bytes < 1000 * 1000) { - return '${(bytes / 1000).toStringAsFixed(1)} kB'; - } - return '${(bytes / (1000 * 1000)).toStringAsFixed(1)} MB'; -} - class ResponseSizeColumn extends ColumnData { const ResponseSizeColumn() : super('Size', alignment: ColumnAlignment.right, fixedWidthPx: 90); @@ -432,7 +418,7 @@ class ResponseSizeColumn extends ColumnData { @override String getDisplayValue(NetworkRequest dataObject) { final bytes = dataObject.responseBytes; - return bytes != null ? _formatBytes(bytes) : '-'; + return bytes != null ? formatBytes(bytes) : '-'; } } diff --git a/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart b/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart index 9efd5482a73..1ebe5d33e79 100644 --- a/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart +++ b/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart @@ -29,3 +29,18 @@ int calculateHeadersSize(Map? headers) { // Calculate the byte length of the headers string return utf8.encode(headersString).length; } + +// Output Formats: +// - 512 → "512 B" +// - 2000 → "2.0 kB" +// - 1000000 → "1.0 MB" +// Values are rounded to one decimal place for kB and MB. +// Uses decimal (base-10) units to match Chrome DevTools. +String formatBytes(int? bytes) { + if (bytes == null) return '-'; + if (bytes < 1000) return '$bytes B'; + if (bytes < 1000 * 1000) { + return '${(bytes / 1000).toStringAsFixed(1)} kB'; + } + return '${(bytes / (1000 * 1000)).toStringAsFixed(1)} MB'; +} diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md index 25a74c25d19..7f732713318 100644 --- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md +++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md @@ -39,7 +39,7 @@ TODO: Remove this section if there are not any updates. ## Network profiler updates -- Added response size ("Res Size") column to the Network tab and displayed response size in the request inspector overview. - +- Added response size column to the Network tab and displayed response size in the request inspector overview. - [#9744](https://github.com/flutter/devtools/pull/9744) - Added a filter setting to hide HTTP-profiler socket data. [#9698](https://github.com/flutter/devtools/pull/9698) diff --git a/packages/devtools_app/test/shared/http/http_request_data_test.dart b/packages/devtools_app/test/shared/http/http_request_data_test.dart new file mode 100644 index 00000000000..0cb15143ede --- /dev/null +++ b/packages/devtools_app/test/shared/http/http_request_data_test.dart @@ -0,0 +1,70 @@ +import 'package:devtools_app/src/shared/http/http_request_data.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('responseBytes', () { + Map baseJson(Map headers) { + return { + 'method': 'GET', + 'uri': 'https://example.com', + 'status': 200, + 'responseHeaders': headers, + }; + } + + // Verifies parsing when content-length is a string value. + test('parses content-length from string', () { + final request = DartIOHttpRequestData.fromJson( + baseJson({'content-length': '1234'}), + null, // requestPostData not used for this test + null, // responseContent not used for this test + ); + + expect(request.responseBytes, 1234); + }); + + // Verifies parsing when content-length is a list of strings. + test('parses content-length from list of strings', () { + final request = DartIOHttpRequestData.fromJson( + baseJson({'content-length': '5678'}), + null, // requestPostData not used for this test + null, // responseContent not used for this test + ); + + expect(request.responseBytes, 5678); + }); + + // Ensures integer values inside a list are handled correctly. + test('handles integer in list', () { + final request = DartIOHttpRequestData.fromJson( + baseJson({'content-length': '91011'}), + null, // requestPostData not used for this test + null, // responseContent not used for this test + ); + + expect(request.responseBytes, 91011); + }); + + // Returns null when header is missing. + test('returns null for missing header', () { + final request = DartIOHttpRequestData.fromJson( + baseJson({}), // No content-length header + null, // requestPostData not used for this test + null, // responseContent not used for this test + ); + + expect(request.responseBytes, null); + }); + + // Returns null when parsing fails. + test('returns null for invalid value', () { + final request = DartIOHttpRequestData.fromJson( + baseJson({'content-length': 'invalid'}), + null, // requestPostData not used for this test + null, // responseContent not used for this test + ); + + expect(request.responseBytes, null); + }); + }); +} diff --git a/packages/devtools_app/test/shared/http/http_utils_test.dart b/packages/devtools_app/test/shared/http/http_utils_test.dart new file mode 100644 index 00000000000..94853734b4d --- /dev/null +++ b/packages/devtools_app/test/shared/http/http_utils_test.dart @@ -0,0 +1,19 @@ +import 'package:devtools_app/src/screens/network/utils/http_utils.dart'; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + group('formatBytes', () { + // Verifies correct formatting across different unit ranges. + test('formats bytes correctly', () { + expect(formatBytes(512), '512 B'); // bytes + expect(formatBytes(2000), '2.0 kB'); // kilobytes (base-10) + expect(formatBytes(1000000), '1.0 MB'); // megabytes (base-10) + }); + + // Ensures handling of invalid or missing values. + test('handles null and negative values', () { + expect(formatBytes(null), '-'); + expect(formatBytes(-1), '-'); + }); + }); +} From bfb9fb47ae2c0753c08cf7d1458affcac6eff845 Mon Sep 17 00:00:00 2001 From: VictoWolf Date: Wed, 1 Apr 2026 00:56:03 +0530 Subject: [PATCH 13/13] fix : formatBytes test fail --- .../devtools_app/lib/src/screens/network/utils/http_utils.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart b/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart index 1ebe5d33e79..b4c30797df0 100644 --- a/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart +++ b/packages/devtools_app/lib/src/screens/network/utils/http_utils.dart @@ -37,7 +37,7 @@ int calculateHeadersSize(Map? headers) { // Values are rounded to one decimal place for kB and MB. // Uses decimal (base-10) units to match Chrome DevTools. String formatBytes(int? bytes) { - if (bytes == null) return '-'; + if (bytes == null || bytes < 0) return '-'; if (bytes < 1000) return '$bytes B'; if (bytes < 1000 * 1000) { return '${(bytes / 1000).toStringAsFixed(1)} kB';