@@ -2,8 +2,6 @@ import 'dart:convert';
22import 'dart:io' ;
33import 'dart:typed_data' ;
44
5- import 'package:crypto/crypto.dart' ;
6-
75import '../extensions/object_extensions.dart' ;
86
97/// Shared JSON encoder to avoid repeated allocations.
@@ -14,11 +12,14 @@ class WrappedResponse {
1412 /// The wrapped data.
1513 Object ? _data;
1614
15+ List <int >? _encodedBytes;
16+
1717 /// Get the wrapped data.
1818 Object ? get data => _data;
1919
2020 set data (Object ? value) {
2121 _data = value;
22+ _encodedBytes = null ;
2223 isEncoded = false ;
2324 }
2425
@@ -30,39 +31,54 @@ class WrappedResponse {
3031
3132 /// Convert the data to bytes.
3233 List <int > toBytes () {
34+ final encodedBytes = _encodedBytes;
35+ if (encodedBytes != null ) {
36+ return encodedBytes;
37+ }
3338 if (data == null ) {
34- return Uint8List (0 );
39+ return _encodedBytes = Uint8List (0 );
3540 }
3641 if (isEncoded && data is List <int >) {
37- return data as List <int >;
42+ return _encodedBytes = data as List <int >;
3843 }
3944 if (data is Uint8List ) {
40- return data as Uint8List ;
45+ return _encodedBytes = data as Uint8List ;
4146 }
4247 // Primitive types
4348 if (data is String || data is num || data is bool ) {
44- return data? .toBytes () ?? Uint8List (0 );
49+ return _encodedBytes = data? .toBytes () ?? Uint8List (0 );
4550 }
4651 // File
4752 if (data is File ) {
48- return (data as File ).readAsBytesSync ();
53+ return _encodedBytes = (data as File ).readAsBytesSync ();
4954 }
5055 // If data was JSON-serializable but wasn't encoded earlier, fall back to encoding here.
5156 if (data! .canBeJson ()) {
52- return sharedJsonUtf8Encoder.convert (data);
57+ return _encodedBytes = sharedJsonUtf8Encoder.convert (data);
5358 }
5459 // Fallback: string representation
55- return utf8.encode (data.toString ()) as Uint8List ? ?? Uint8List ( 0 );
60+ return _encodedBytes = utf8.encode (data.toString ());
5661 }
5762
5863 /// Get the ETag for the response data.
5964 String get eTag {
6065 final bytes = toBytes ();
6166 if (bytes.isEmpty) {
62- return '"0-2jmj7l5rSw0yVb/vlWAYkK/YBwk"' ; // ETag for empty response
67+ return 'W/"0-0"' ;
68+ }
69+ final hash = _fastHash (bytes);
70+ return 'W/"${bytes .length .toRadixString (16 )}-${hash .toRadixString (16 )}"' ;
71+ }
72+
73+ int _fastHash (List <int > bytes) {
74+ const int offsetBasis = 0x811c9dc5 ;
75+ const int fnvPrime = 0x01000193 ;
76+
77+ var hash = offsetBasis;
78+ for (final byte in bytes) {
79+ hash ^ = byte;
80+ hash = (hash * fnvPrime) & 0xffffffff ;
6381 }
64- // Simple ETag generation using a hash of the bytes
65- final hash = base64Encode (sha1.convert (bytes).bytes).substring (0 , 27 );
66- return '"${bytes .length }-$hash "' ;
82+ return hash;
6783 }
6884}
0 commit comments