diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a9399c0..c1a4ca81 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +# 2.0.0-alpha.19 +* `parseBody` checks for null content type, and throws a `400` if none was given. +* Add `ResponseContext.contentLength`. +* Update `streamFile` to set content length, and also to work on `HEAD` requests. + # 2.0.0-alpha.18 * Upgrade `http2` dependency. * Upgrade `uuid` dependency. diff --git a/lib/src/core/request_context.dart b/lib/src/core/request_context.dart index 0e081106..6ac8f4a8 100644 --- a/lib/src/core/request_context.dart +++ b/lib/src/core/request_context.dart @@ -185,6 +185,10 @@ abstract class RequestContext { /// Manually parses the request body, if it has not already been parsed. Future parseBody({Encoding encoding: utf8}) async { + if (contentType == null) { + throw FormatException('Missing "content-type" header.'); + } + if (!_hasParsedBody) { _hasParsedBody = true; diff --git a/lib/src/core/response_context.dart b/lib/src/core/response_context.dart index eccea030..50697dd5 100644 --- a/lib/src/core/response_context.dart +++ b/lib/src/core/response_context.dart @@ -76,7 +76,7 @@ abstract class ResponseContext /// This response's status code. int get statusCode => _statusCode; - void set statusCode(int value) { + set statusCode(int value) { if (!isOpen) throw closed(); else @@ -104,6 +104,23 @@ abstract class ResponseContext /// open indefinitely. FutureOr detach(); + /// Gets or sets the content length to send back to a client. + /// + /// Returns `null` if the header is invalidly formatted. + int get contentLength { + return int.tryParse(headers['content-length']); + } + + /// Gets or sets the content length to send back to a client. + /// + /// If [value] is `null`, then the header will be removed. + set contentLength(int value) { + if (value == null) + headers.remove('content-length'); + else + headers['content-length'] = value.toString(); + } + /// Gets or sets the content type to send back to a client. MediaType get contentType { try { @@ -114,7 +131,7 @@ abstract class ResponseContext } /// Gets or sets the content type to send back to a client. - void set contentType(MediaType value) { + set contentType(MediaType value) { headers['content-type'] = value.toString(); } @@ -289,13 +306,18 @@ abstract class ResponseContext } /// Streams a file to this response. - Future streamFile(File file) { + /// + /// `HEAD` responses will not actually write data. + Future streamFile(File file) async { if (!isOpen) throw closed(); var mimeType = app.mimeTypeResolver.lookup(file.path); + contentLength = await file.length(); contentType = mimeType == null ? new MediaType('application', 'octet-stream') : MediaType.parse(mimeType); - return file.openRead().pipe(this); + + if (correspondingRequest.method != 'HEAD') + return file.openRead().pipe(this); } /// Configure the response to write to an intermediate response buffer, rather than to the stream directly. diff --git a/pubspec.yaml b/pubspec.yaml index a3380ed4..5055412d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: angel_framework -version: 2.0.0-alpha.18 +version: 2.0.0-alpha.19 description: A high-powered HTTP server with dependency injection, routing and much more. author: Tobe O homepage: https://github.com/angel-dart/angel_framework