Skip to content

Commit 159a446

Browse files
luiscib3ralestiago
andauthored
feat(dart_frog): allow disabling Response buffer output (#1261)
Co-authored-by: Alejandro Santiago <[email protected]>
1 parent 49c9562 commit 159a446

File tree

3 files changed

+71
-1
lines changed

3 files changed

+71
-1
lines changed

packages/dart_frog/lib/src/_internal.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import 'dart:io';
66
import 'package:dart_frog/dart_frog.dart';
77
import 'package:dart_frog/src/body_parsers/body_parsers.dart';
88
import 'package:http_methods/http_methods.dart' show isHttpMethod;
9+
import 'package:meta/meta.dart';
910
import 'package:shelf/shelf.dart' as shelf;
1011
import 'package:shelf/shelf_io.dart' as shelf_io;
1112

packages/dart_frog/lib/src/response.dart

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,32 @@ class Response {
1818
encoding: encoding,
1919
),
2020
);
21+
Response._(this._response);
2122

2223
/// Create a [Response] with a stream of bytes.
24+
///
25+
/// If [bufferOutput] is `true` (the default), streamed responses will be
26+
/// buffered to improve performance. If `false`, all chunks will be pushed
27+
/// over the wire as they're received. Note that, disabling buffering of the
28+
/// output can result in very poor performance, when writing many small
29+
/// chunks.
30+
///
31+
/// See also:
32+
///
33+
/// * [HttpResponse.bufferOutput](https://api.flutter.dev/flutter/dart-io/HttpResponse/bufferOutput.html)
2334
Response.stream({
2435
int statusCode = 200,
2536
Stream<List<int>>? body,
2637
Map<String, Object>? headers,
38+
bool bufferOutput = true,
2739
}) : this._(
2840
shelf.Response(
2941
statusCode,
3042
body: body,
3143
headers: headers,
44+
context: !bufferOutput
45+
? {Response.shelfBufferOutputContextKey: bufferOutput}
46+
: null,
3247
),
3348
);
3449

@@ -80,7 +95,15 @@ class Response {
8095
encoding: encoding,
8196
);
8297

83-
Response._(this._response);
98+
/// A [shelf.Response.context] key used to determine if if the
99+
/// [HttpResponse.bufferOutput] should be enabled or disabled.
100+
///
101+
/// See also:
102+
///
103+
/// * [shelf_io library](https://pub.dev/documentation/shelf/latest/shelf_io/shelf_io-library.html)
104+
/// * [HttpResponse.bufferOutput](https://api.flutter.dev/flutter/dart-io/HttpResponse/bufferOutput.html)
105+
@visibleForTesting
106+
static const shelfBufferOutputContextKey = 'shelf.io.buffer_output';
84107

85108
shelf.Response _response;
86109

@@ -91,6 +114,12 @@ class Response {
91114
/// The returned map is unmodifiable.
92115
Map<String, String> get headers => _response.headers;
93116

117+
/// Extra context that can be used by for middleware and handlers.
118+
///
119+
/// The value is immutable.
120+
@visibleForTesting
121+
Map<String, Object> get context => _response.context;
122+
94123
/// Returns a [Stream] representing the body.
95124
Stream<List<int>> bytes() => _response.read();
96125

packages/dart_frog/test/src/response_test.dart

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,46 @@ void main() {
107107
final response = Response.stream(body: stream);
108108
expect(response.bytes(), emits(equals(bytes)));
109109
});
110+
111+
group('bufferOutput', () {
112+
test('is omitted by default', () {
113+
final response = Response.stream(
114+
body: const Stream.empty(),
115+
// ignore: avoid_redundant_argument_values
116+
bufferOutput: true,
117+
);
118+
119+
expect(
120+
response.context,
121+
isNot(contains(Response.shelfBufferOutputContextKey)),
122+
reason:
123+
'''The context should not have the '${Response.shelfBufferOutputContextKey}' key.''',
124+
);
125+
});
126+
127+
test('can be disabled', () {
128+
final response = Response.stream(
129+
body: const Stream.empty(),
130+
bufferOutput: false,
131+
);
132+
133+
expect(
134+
response.context,
135+
contains(Response.shelfBufferOutputContextKey),
136+
reason:
137+
'''The context should have the '${Response.shelfBufferOutputContextKey}' key.''',
138+
);
139+
140+
final bufferOutput =
141+
response.context[Response.shelfBufferOutputContextKey];
142+
expect(
143+
bufferOutput,
144+
isFalse,
145+
reason:
146+
'''The '${Response.shelfBufferOutputContextKey}' should be 'false' when disabled.''',
147+
);
148+
});
149+
});
110150
});
111151

112152
group('formData', () {

0 commit comments

Comments
 (0)