diff --git a/.idea/runConfigurations/json_dart.xml b/.idea/runConfigurations/json_dart.xml
new file mode 100644
index 00000000..0c6db2aa
--- /dev/null
+++ b/.idea/runConfigurations/json_dart.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/runConfigurations/templating_dart.xml b/.idea/runConfigurations/templating_dart.xml
deleted file mode 100644
index 618351c8..00000000
--- a/.idea/runConfigurations/templating_dart.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index c290ba05..a95b8d23 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,14 +2,13 @@
+
+
-
-
-
-
-
-
+
+
+
@@ -32,108 +31,30 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -254,7 +175,6 @@
-
@@ -266,7 +186,6 @@
-
@@ -278,9 +197,11 @@
-
-
+
+
+
+
@@ -318,11 +239,6 @@
-
-
-
-
-
@@ -341,23 +257,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -406,7 +305,7 @@
-
+
@@ -553,15 +452,18 @@
-
-
-
-
+
+
+
+
+
+
+
@@ -598,11 +500,13 @@
-
-
-
+
+
+
+
+
@@ -701,21 +605,7 @@
-
-
-
- 1531155020859
-
-
-
- 1531155020859
-
-
- 1531408133584
-
-
-
- 1531408133586
+
1531408765286
@@ -1046,7 +936,21 @@
1534812824990
-
+
+ 1534813505067
+
+
+
+ 1534813505067
+
+
+ 1534813932227
+
+
+
+ 1534813932227
+
+
@@ -1082,7 +986,7 @@
-
+
@@ -1145,8 +1049,6 @@
-
-
@@ -1170,7 +1072,9 @@
-
+
+
+
@@ -1178,21 +1082,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1250,16 +1139,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -1284,16 +1163,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -1343,13 +1212,6 @@
-
-
-
-
-
-
-
@@ -1364,16 +1226,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -1470,24 +1322,27 @@
-
+
-
-
+
+
+
+
+
-
+
-
-
+
+
-
-
+
+
@@ -1498,6 +1353,16 @@
+
+
+
+
+
+
+
+
+
+
@@ -1512,32 +1377,78 @@
-
+
-
-
-
-
-
+
+
-
-
+
+
-
+
-
-
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1545,8 +1456,8 @@
-
-
+
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e49c819f..df51c8da 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -51,4 +51,9 @@ type-safe manner.
not very elegant.
* Removed `Angel.createZoneForRequest`.
* Removed `Angel.defaultZoneCreator`.
-* Added all flags to the `Angel` constructor, ex. `Angel.eagerParseBodies`.
\ No newline at end of file
+* Added all flags to the `Angel` constructor, ex. `Angel.eagerParseBodies`.
+* Fix a bug where synchronous errors in `handleRequest` would not be caught.
+* `AngelHttp.useZone` now defaults to `false`.
+* `ResponseContext` now starts in streaming mode by default; the response buffer is opt-in,
+as in many cases it is unnecessary and slows down response time.
+* `ResponseContext.streaming` was replaced by `ResponseContext.isBuffered`.
\ No newline at end of file
diff --git a/example/json.dart b/example/json.dart
index 2d608c34..2b556da6 100644
--- a/example/json.dart
+++ b/example/json.dart
@@ -1,6 +1,8 @@
import 'dart:async';
import 'dart:convert';
+import 'dart:io';
import 'dart:isolate';
+
import 'package:angel_container/mirrors.dart';
import 'package:angel_framework/angel_framework.dart';
@@ -16,7 +18,7 @@ main() async {
}
});
- for (int i = 0; i < 50; i++) {
+ for (int i = 1; i < Platform.numberOfProcessors; i++) {
var isolate = await Isolate.spawn(serverMain, null);
isolates.add(isolate);
print('Spawned isolate #${i + 1}...');
@@ -24,6 +26,8 @@ main() async {
isolate.addOnExitListener(exit.sendPort);
}
+ serverMain(null);
+
print('Angel listening at http://localhost:3000');
await c.future;
}
@@ -40,9 +44,6 @@ serverMain(_) async {
});
});
- // Performance tuning
- app..serializer = json.encode;
-
app.errorHandler = (e, req, res) {
print(e.message ?? e.error ?? e);
print(e.stackTrace);
diff --git a/lib/src/core/response_context.dart b/lib/src/core/response_context.dart
index e1877cde..9689f724 100644
--- a/lib/src/core/response_context.dart
+++ b/lib/src/core/response_context.dart
@@ -20,7 +20,7 @@ final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
abstract class ResponseContext
implements StreamSink>, StringSink {
final Map properties = {};
- final BytesBuilder _buffer = new _LockableBytesBuilder();
+ BytesBuilder _buffer;
final Map _headers = {'server': 'angel'};
Completer _done;
@@ -54,7 +54,7 @@ abstract class ResponseContext
/// Headers that will be sent to the user.
Map get headers {
/// If the response is closed, then this getter will return an immutable `Map`.
- if (streaming)
+ if (!isBuffered)
return new Map.unmodifiable(_headers);
else
return _headers;
@@ -87,8 +87,8 @@ abstract class ResponseContext
/// Can we still write to this response?
bool get isOpen;
- /// Returns `true` if a [Stream] is being written directly.
- bool get streaming;
+ /// Returns `true` if response data is being written to a buffer, rather than to the underlying stream.
+ bool get isBuffered;
/// A set of UTF-8 encoded bytes that will be written to the response.
BytesBuilder get buffer => _buffer;
@@ -116,7 +116,7 @@ abstract class ResponseContext
headers['content-type'] = lookupMimeType(file.path);
headers['content-length'] = file.lengthSync().toString();
- if (streaming) {
+ if (!isBuffered) {
file.openRead().pipe(this);
} else {
buffer.add(file.readAsBytesSync());
@@ -128,7 +128,7 @@ abstract class ResponseContext
///
/// This method should be overwritten, setting [streaming] to `false`, **after** a `super` call.
Future close() {
- if (streaming) {
+ if (!isBuffered) {
_buffer?.clear();
} else if (_buffer is _LockableBytesBuilder) {
(_buffer as _LockableBytesBuilder)._lock();
@@ -340,13 +340,10 @@ abstract class ResponseContext
void write(value, {Encoding encoding}) {
encoding ??= utf8;
- if (!isOpen && !streaming)
+ if (!isOpen && isBuffered)
throw closed();
- else if (streaming) {
- if (value is List)
- add(value);
- else
- add(encoding.encode(value.toString()));
+ else if (!isBuffered) {
+ add(encoding.encode(value.toString()));
} else {
if (value is List)
buffer.add(value);
@@ -357,9 +354,9 @@ abstract class ResponseContext
@override
void writeCharCode(int charCode) {
- if (!isOpen && !streaming)
+ if (!isOpen && isBuffered)
throw closed();
- else if (streaming)
+ else if (!isBuffered)
add([charCode]);
else
buffer.addByte(charCode);
diff --git a/lib/src/http/angel_http.dart b/lib/src/http/angel_http.dart
index 69dd6eb4..e5afaf33 100644
--- a/lib/src/http/angel_http.dart
+++ b/lib/src/http/angel_http.dart
@@ -30,7 +30,7 @@ class AngelHttp {
Future Function(dynamic, int) _serverGenerator = HttpServer.bind;
StreamSubscription _sub;
- AngelHttp(this.app, {this.useZone: true});
+ AngelHttp(this.app, {this.useZone: false});
/// The function used to bind this instance to an HTTP server.
Future Function(dynamic, int) get serverGenerator =>
@@ -62,7 +62,7 @@ class AngelHttp {
/// the server.
factory AngelHttp.secure(
Angel app, String certificateChainPath, String serverKeyPath,
- { String password, bool useZone: true}) {
+ {String password, bool useZone: true}) {
var certificateChain =
Platform.script.resolve(certificateChainPath).toFilePath();
var serverKey = Platform.script.resolve(serverKeyPath).toFilePath();
@@ -162,7 +162,15 @@ class AngelHttp {
}
if (useZone == false) {
- return handle().catchError((e, StackTrace st) {
+ Future f;
+
+ try {
+ f = handle();
+ } catch (e, st) {
+ f = Future.error(e, st);
+ }
+
+ return f.catchError((e, StackTrace st) {
if (e is FormatException)
throw new AngelHttpException.badRequest(message: e.message)
..stackTrace = st;