Skip to content

Commit

Permalink
feat(dynamite_runtime): add new internal ByteStream extension based o…
Browse files Browse the repository at this point in the history
…n http.ByteStream

respects the content-type header when decoding

Signed-off-by: Nikolas Rimikis <leptopoda@users.noreply.github.com>
  • Loading branch information
Leptopoda committed Mar 3, 2024
1 parent 318855f commit f9c58c9
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:xml/xml_events.dart';
/// A stream of bytes.
///
/// Usually a `Stream<Uint8List>`.
@Deprecated('use ByteStream from package:http')
typedef BytesStream = Stream<List<int>>;

/// Converter for UTF-8 encoded bytes to JSON.
Expand All @@ -21,6 +22,7 @@ final xmlBytesConverter =
utf8.decoder.fuse(XmlEventDecoder()).fuse(const XmlNormalizeEvents()).fuse(const XmlNodeDecoder());

/// Extension on byte streams that enable efficient transformations.
@Deprecated('use HttpBytesStreamExtension to convert a ByteStream')
extension BytesStreamExtension on BytesStream {
/// Collects all bytes from this stream into one Uint8List.
///
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import 'dart:convert';
import 'dart:typed_data';

import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'package:meta/meta.dart';
import 'package:xml/xml.dart';
import 'package:xml/xml_events.dart';

/// Converter for `String` to `XML`.
@visibleForTesting
final xmlConverter = XmlEventDecoder().fuse(const XmlNormalizeEvents()).fuse(const XmlNodeDecoder());

/// Extension on byte streams that enable efficient transformations.
@internal
extension HttpBytesStreamExtension on http.ByteStream {
/// Collects the data of this stream in a [Uint8List].
///
/// The collector will assume that the bytes in this stream will not change.
/// See [BytesBuilder] for further information.
///
/// This method is more efficient than using [toBytes].
Future<Uint8List> get bytes async {
final buffer = BytesBuilder(copy: false);

await forEach(buffer.add);

return buffer.toBytes();
}

/// Collect the data of this stream in a json object, decoded according to
/// [encoding], which defaults to [utf8].
Future<Object?> bytesToJson([Encoding encoding = utf8]) =>
encoding.decoder.fuse(const JsonDecoder()).bind(this).first;

/// Collect the data of this stream in [XmlElement], decoded according to
/// [encoding], which defaults to [utf8].
Future<Object?> bytesToXml([Encoding encoding = utf8]) async {
final element = await encoding.decoder
.fuse(xmlConverter)
.bind(this)
.expand((events) => events)
.firstWhere((element) => element is XmlElement);

return element as XmlElement;
}
}

/// Returns the encoding to use for a response with the given headers.
///
/// Defaults to [latin1] if the headers don't specify a charset or if that
/// charset is unknown.
///
/// Copied from `package:http`.
@internal
Encoding encodingForHeaders(Map<String, String> headers) =>
_encodingForCharset(_contentTypeForHeaders(headers).parameters['charset']);

/// Returns the [Encoding] that corresponds to [charset].
///
/// Returns [fallback] if [charset] is null or if no [Encoding] was found that
/// corresponds to [charset].
///
/// Copied from `package:http`.
Encoding _encodingForCharset(String? charset, [Encoding fallback = latin1]) {
if (charset == null) {
return fallback;
}
return Encoding.getByName(charset) ?? fallback;
}

/// Returns the [MediaType] object for the given headers's content-type.
///
/// Defaults to `application/octet-stream`.
///
/// Copied from `package:http`.
MediaType _contentTypeForHeaders(Map<String, String> headers) {
final contentType = headers['content-type'];
if (contentType != null) {
return MediaType.parse(contentType);
}
return MediaType('application', 'octet-stream');
}
1 change: 1 addition & 0 deletions packages/dynamite/dynamite_runtime/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies:
collection: ^1.0.0
cookie_jar: ^4.0.7
http: ^1.2.0
http_parser: ^4.0.0
meta: ^1.0.0
xml: ^6.0.0

Expand Down
2 changes: 2 additions & 0 deletions packages/nextcloud/lib/nextcloud.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: deprecated_member_use

export 'package:dynamite_runtime/http_client.dart'
show BytesStreamExtension, DynamiteApiException, DynamiteRawResponse, DynamiteResponse, DynamiteStatusCodeException;
export 'package:dynamite_runtime/models.dart';
Expand Down

0 comments on commit f9c58c9

Please sign in to comment.