diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index aaad1c17..f012b5cd 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -4,6 +4,8 @@
+
+
@@ -18,7 +20,7 @@
-
+
@@ -29,14 +31,12 @@
-
-
+
+
-
-
-
-
-
+
+
+
@@ -45,10 +45,10 @@
-
-
+
+
-
+
@@ -56,56 +56,24 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
@@ -113,28 +81,65 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
+
+
@@ -175,6 +180,8 @@
_printDebug
use(
_injec
+ writeln
+ write(
_isClosed
@@ -198,16 +205,18 @@
-
-
+
+
+
+
@@ -244,6 +253,7 @@
+
@@ -326,7 +336,6 @@
-
@@ -355,12 +364,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -464,7 +487,8 @@
-
+
+
1481237183504
@@ -564,7 +588,14 @@
1497200046584
-
+
+ 1497200256280
+
+
+
+ 1497200256280
+
+
@@ -600,7 +631,7 @@
-
+
@@ -615,23 +646,23 @@
-
+
-
+
-
+
+
-
+
-
@@ -653,46 +684,18 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -850,20 +853,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -871,20 +860,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -892,13 +867,6 @@
-
-
-
-
-
-
-
@@ -934,24 +902,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -978,7 +931,7 @@
-
+
@@ -986,22 +939,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -1010,10 +947,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -1021,7 +1073,7 @@
-
+
@@ -1029,10 +1081,10 @@
-
-
+
+
-
+
diff --git a/README.md b/README.md
index 99210b04..5547bf0a 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,13 @@
# angel_framework
-[![pub 1.0.3+1](https://img.shields.io/badge/pub-1.0.3+1-brightgreen.svg)](https://pub.dartlang.org/packages/angel_framework)
+[![Pub](https://img.shields.io/pub/v/angel_framework.svg)](https://pub.dartlang.org/packages/angel_framework)
[![build status](https://travis-ci.org/angel-dart/framework.svg)](https://travis-ci.org/angel-dart/framework)
A high-powered HTTP server with support for dependency injection, sophisticated routing and more.
+This is the core of the [Angel](https://github.com/angel-dart/angel) framework.
+To build real-world applications, please see the [homepage](https://angel-dart.github.io).
+
```dart
import 'package:angel_framework/angel_framework.dart';
diff --git a/lib/src/http/metadata.dart b/lib/src/http/metadata.dart
index 194b0306..48676510 100644
--- a/lib/src/http/metadata.dart
+++ b/lib/src/http/metadata.dart
@@ -14,6 +14,8 @@ class Hooked {
const Hooked();
}
+const Hooked hooked = const Hooked();
+
/// Attaches hooks to a [HookedService].
class Hooks {
final List before;
diff --git a/lib/src/http/response_context.dart b/lib/src/http/response_context.dart
index 9c49ca43..de4e318c 100644
--- a/lib/src/http/response_context.dart
+++ b/lib/src/http/response_context.dart
@@ -11,7 +11,7 @@ import 'server.dart' show Angel;
import 'controller.dart';
final RegExp _contentType =
-new RegExp(r'([^/\n]+)\/\s*([^;\n]+)\s*(;\s*charset=([^$;\n]+))?');
+ new RegExp(r'([^/\n]+)\/\s*([^;\n]+)\s*(;\s*charset=([^$;\n]+))?');
final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
@@ -19,11 +19,10 @@ final RegExp _straySlashes = new RegExp(r'(^/+)|(/+$)');
typedef String ResponseSerializer(data);
/// A convenience wrapper around an outgoing HTTP request.
-class ResponseContext extends Extensible {
+class ResponseContext extends Extensible implements StringSink {
final _LockableBytesBuilder _buffer = new _LockableBytesBuilder();
final Map _headers = {HttpHeaders.SERVER: 'angel'};
- bool _isOpen = true,
- _isClosed = false;
+ bool _isOpen = true, _isClosed = false;
int _statusCode = 200;
/// The [Angel] instance that is sending a response.
@@ -124,7 +123,7 @@ class ResponseContext extends Extensible {
if (!_isOpen) throw _closed();
headers["Content-Disposition"] =
- 'attachment; filename="${filename ?? file.path}"';
+ 'attachment; filename="${filename ?? file.path}"';
headers[HttpHeaders.CONTENT_TYPE] = lookupMimeType(file.path);
headers[HttpHeaders.CONTENT_LENGTH] = file.lengthSync().toString();
buffer.add(await file.readAsBytes());
@@ -203,7 +202,7 @@ class ResponseContext extends Extensible {
headers
..[HttpHeaders.CONTENT_TYPE] = ContentType.HTML.toString()
..[HttpHeaders.LOCATION] =
- url is String ? url : app.navigate(url, absolute: absolute);
+ url is String ? url : app.navigate(url, absolute: absolute);
statusCode = code ?? 302;
write('''
@@ -261,7 +260,7 @@ class ResponseContext extends Extensible {
"Controller redirects must take the form of 'Controller@action'. You gave: $action");
Controller controller =
- app.controller(split[0].replaceAll(_straySlashes, ''));
+ app.controller(split[0].replaceAll(_straySlashes, ''));
if (controller == null)
throw new Exception("Could not find a controller named '${split[0]}'");
@@ -273,11 +272,7 @@ class ResponseContext extends Extensible {
"Controller '${split[0]}' does not contain any action named '${split[1]}'");
final head =
- controller
- .findExpose()
- .path
- .toString()
- .replaceAll(_straySlashes, '');
+ controller.findExpose().path.toString().replaceAll(_straySlashes, '');
final tail = matched.makeUri(params).replaceAll(_straySlashes, '');
redirect('$head/$tail'.replaceAll(_straySlashes, ''), code: code);
@@ -313,9 +308,9 @@ class ResponseContext extends Extensible {
/// You can optionally transform the file stream with a [codec].
Future streamFile(File file,
{int chunkSize,
- int sleepMs: 0,
- bool resumable: true,
- Codec, List> codec}) async {
+ int sleepMs: 0,
+ bool resumable: true,
+ Codec, List> codec}) async {
if (_isClosed) throw _closed();
headers[HttpHeaders.CONTENT_TYPE] = lookupMimeType(file.path);
@@ -339,6 +334,25 @@ class ResponseContext extends Extensible {
buffer.add(encoding.encode(value.toString()));
}
}
+
+ @override
+ void writeCharCode(int charCode) {
+ if (_isClosed)
+ throw _closed();
+ else
+ buffer.addByte(charCode);
+ }
+
+ @override
+ void writeln([Object obj = ""]) {
+ write(obj.toString());
+ write('\r\n');
+ }
+
+ @override
+ void writeAll(Iterable objects, [String separator = ""]) {
+ write(objects.join(separator));
+ }
}
abstract class _LockableBytesBuilder extends BytesBuilder {
diff --git a/lib/src/http/server.dart b/lib/src/http/server.dart
index 5e2b7f14..836a40c8 100644
--- a/lib/src/http/server.dart
+++ b/lib/src/http/server.dart
@@ -309,6 +309,8 @@ class Angel extends AngelBase {
contentType: res.headers[HttpHeaders.CONTENT_TYPE] ??
ContentType.JSON.mimeType);
return false;
+ } else if (result is Stream) {
+ return await executeHandler(await result.toList(), req, res);
} else
return res.isOpen;
}
@@ -336,6 +338,22 @@ class Angel extends AngelBase {
return parent != null ? parent.findProperty(key) : null;
}
+ _handleAngelHttpException(AngelHttpException e, StackTrace st,
+ RequestContext req, ResponseContext res) async {
+ res.statusCode = e.statusCode;
+ List accept = request.headers[HttpHeaders.ACCEPT] ?? ['*/*'];
+ if (accept.isEmpty ||
+ accept.contains('*/*') ||
+ accept.contains(ContentType.JSON.mimeType) ||
+ accept.contains("application/javascript")) {
+ res.serialize(e.toMap(),
+ contentType: res.headers[HttpHeaders.CONTENT_TYPE] ??
+ ContentType.JSON.mimeType);
+ } else {
+ await errorHandler(e, req, res);
+ }
+ }
+
/// Handles a single request.
Future handleRequest(HttpRequest request) async {
try {
@@ -377,42 +395,15 @@ class Angel extends AngelBase {
// _printDebug(
// 'Handler completed successfully, did not terminate response: $handler');
}
- } catch (e, st) {
- // _printDebug('Caught error in handler $handler: $e');
- // _printDebug(st);
-
- if (e is AngelHttpException) {
- // Special handling for AngelHttpExceptions :)
- try {
- res.statusCode = e.statusCode;
- List accept =
- request.headers[HttpHeaders.ACCEPT] ?? ['*/*'];
- if (accept.isEmpty ||
- accept.contains('*/*') ||
- accept.contains(ContentType.JSON.mimeType) ||
- accept.contains("application/javascript")) {
- res.serialize(e.toMap(),
- contentType: res.headers[HttpHeaders.CONTENT_TYPE] ??
- ContentType.JSON.mimeType);
- } else {
- await errorHandler(e, req, res);
- }
- // _finalizeResponse(request, res);
- } catch (e, st) {
- _fatalErrorStream.add(
- new AngelFatalError(request: request, error: e, stack: st));
- }
- } else {
- _fatalErrorStream.add(
- new AngelFatalError(request: request, error: e, stack: st));
- }
-
- break;
+ } on AngelHttpException catch (e, st) {
+ return await _handleAngelHttpException(e, st, req, res);
}
}
try {
await sendResponse(request, req, res);
+ } on AngelHttpException catch (e, st) {
+ return await _handleAngelHttpException(e, st, req, res);
} catch (e, st) {
_fatalErrorStream
.add(new AngelFatalError(request: request, error: e, stack: st));
diff --git a/pubspec.yaml b/pubspec.yaml
index 76c3009b..9e8946f2 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: angel_framework
-version: 1.0.3+1
+version: 1.0.4
description: A high-powered HTTP server with DI, routing and more.
author: Tobe O
homepage: https://github.com/angel-dart/angel_framework