| Index: pkg/shelf/lib/src/util.dart
|
| diff --git a/pkg/shelf/lib/src/util.dart b/pkg/shelf/lib/src/util.dart
|
| index 09b8cb4dd878f00e99ea087b864a90ec2f64aa8b..bf8e370804ddd81dbbdbe3f453ca760ad2372e26 100644
|
| --- a/pkg/shelf/lib/src/util.dart
|
| +++ b/pkg/shelf/lib/src/util.dart
|
| @@ -7,8 +7,7 @@ library shelf.util;
|
| import 'dart:async';
|
|
|
| import 'package:stack_trace/stack_trace.dart';
|
| -
|
| -import 'string_scanner.dart';
|
| +import 'package:string_scanner/string_scanner.dart';
|
|
|
| /// Like [Future.sync], but wraps the Future in [Chain.track] as well.
|
| Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
|
| @@ -56,88 +55,90 @@ String formatHttpDate(DateTime date) {
|
| /// 2616](http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3). It will
|
| /// throw a [FormatException] if [date] is invalid.
|
| DateTime parseHttpDate(String date) {
|
| - var errorMessage = 'Invalid HTTP date "$date".';
|
| - var scanner = new StringScanner(date);
|
| -
|
| - if (scanner.scan(_longWeekdayRegExp)) {
|
| - // RFC 850 starts with a long weekday.
|
| - scanner.expect(", ", errorMessage);
|
| - var day = _parseInt(scanner, errorMessage, 2);
|
| - scanner.expect("-", errorMessage);
|
| - var month = _parseMonth(scanner, errorMessage);
|
| - scanner.expect("-", errorMessage);
|
| - var year = 1900 + _parseInt(scanner, errorMessage, 2);
|
| - scanner.expect(" ", errorMessage);
|
| - var time = _parseTime(scanner, errorMessage);
|
| - scanner.expect(" GMT", errorMessage);
|
| - if (!scanner.isDone) throw new FormatException(errorMessage);
|
| -
|
| - return _makeDateTime(year, month, day, time, errorMessage);
|
| - }
|
| -
|
| - // RFC 1123 and asctime both start with a short weekday.
|
| - scanner.expect(_shortWeekdayRegExp, errorMessage);
|
| - if (scanner.scan(", ")) {
|
| - // RFC 1123 follows the weekday with a comma.
|
| - var day = _parseInt(scanner, errorMessage, 2);
|
| - scanner.expect(" ", errorMessage);
|
| - var month = _parseMonth(scanner, errorMessage);
|
| - scanner.expect(" ", errorMessage);
|
| - var year = _parseInt(scanner, errorMessage, 4);
|
| - scanner.expect(" ", errorMessage);
|
| - var time = _parseTime(scanner, errorMessage);
|
| - scanner.expect(" GMT", errorMessage);
|
| - if (!scanner.isDone) throw new FormatException(errorMessage);
|
| -
|
| - return _makeDateTime(year, month, day, time, errorMessage);
|
| + try {
|
| + var scanner = new StringScanner(date);
|
| +
|
| + if (scanner.scan(_longWeekdayRegExp)) {
|
| + // RFC 850 starts with a long weekday.
|
| + scanner.expect(", ");
|
| + var day = _parseInt(scanner, 2);
|
| + scanner.expect("-");
|
| + var month = _parseMonth(scanner);
|
| + scanner.expect("-");
|
| + var year = 1900 + _parseInt(scanner, 2);
|
| + scanner.expect(" ");
|
| + var time = _parseTime(scanner);
|
| + scanner.expect(" GMT");
|
| + scanner.expectDone();
|
| +
|
| + return _makeDateTime(year, month, day, time);
|
| + }
|
| +
|
| + // RFC 1123 and asctime both start with a short weekday.
|
| + scanner.expect(_shortWeekdayRegExp);
|
| + if (scanner.scan(", ")) {
|
| + // RFC 1123 follows the weekday with a comma.
|
| + var day = _parseInt(scanner, 2);
|
| + scanner.expect(" ");
|
| + var month = _parseMonth(scanner);
|
| + scanner.expect(" ");
|
| + var year = _parseInt(scanner, 4);
|
| + scanner.expect(" ");
|
| + var time = _parseTime(scanner);
|
| + scanner.expect(" GMT");
|
| + scanner.expectDone();
|
| +
|
| + return _makeDateTime(year, month, day, time);
|
| + }
|
| +
|
| + // asctime follows the weekday with a space.
|
| + scanner.expect(" ");
|
| + var month = _parseMonth(scanner);
|
| + scanner.expect(" ");
|
| + var day = scanner.scan(" ") ?
|
| + _parseInt(scanner, 1) :
|
| + _parseInt(scanner, 2);
|
| + scanner.expect(" ");
|
| + var time = _parseTime(scanner);
|
| + scanner.expect(" ");
|
| + var year = _parseInt(scanner, 4);
|
| + scanner.expectDone();
|
| +
|
| + return _makeDateTime(year, month, day, time);
|
| + } on FormatException catch (error) {
|
| + throw new FormatException('Invalid HTTP date "$date": ${error.message}');
|
| }
|
| -
|
| - // asctime follows the weekday with a space.
|
| - scanner.expect(" ", errorMessage);
|
| - var month = _parseMonth(scanner, errorMessage);
|
| - scanner.expect(" ", errorMessage);
|
| - var day = scanner.scan(" ") ?
|
| - _parseInt(scanner, errorMessage, 1) :
|
| - _parseInt(scanner, errorMessage, 2);
|
| - scanner.expect(" ", errorMessage);
|
| - var time = _parseTime(scanner, errorMessage);
|
| - scanner.expect(" ", errorMessage);
|
| - var year = _parseInt(scanner, errorMessage, 4);
|
| - if (!scanner.isDone) throw new FormatException(errorMessage);
|
| -
|
| - return _makeDateTime(year, month, day, time, errorMessage);
|
| }
|
|
|
| /// Parses a short-form month name to a form accepted by [DateTime].
|
| -int _parseMonth(StringScanner scanner, String errorMessage) {
|
| - scanner.expect(_monthRegExp, errorMessage);
|
| +int _parseMonth(StringScanner scanner) {
|
| + scanner.expect(_monthRegExp);
|
| // DateTime uses 1-indexed months.
|
| return _MONTHS.indexOf(scanner.lastMatch[0]) + 1;
|
| }
|
|
|
| /// Parses an int an enforces that it has exactly [digits] digits.
|
| -int _parseInt(StringScanner scanner, String errorMessage, int digits) {
|
| - scanner.expect(_digitRegExp, errorMessage);
|
| +int _parseInt(StringScanner scanner, int digits) {
|
| + scanner.expect(_digitRegExp);
|
| if (scanner.lastMatch[0].length != digits) {
|
| - throw new FormatException(errorMessage);
|
| + scanner.error("expected a $digits-digit number.");
|
| } else {
|
| return int.parse(scanner.lastMatch[0]);
|
| }
|
| }
|
|
|
| /// Parses an timestamp of the form "HH:MM:SS" on a 24-hour clock.
|
| -DateTime _parseTime(StringScanner scanner, String errorMessage) {
|
| - var hours = _parseInt(scanner, errorMessage, 2);
|
| - scanner.expect(':', errorMessage);
|
| +DateTime _parseTime(StringScanner scanner) {
|
| + var hours = _parseInt(scanner, 2);
|
| + if (hours >= 24) scanner.error("hours may not be greater than 24.");
|
| + scanner.expect(':');
|
|
|
| - var minutes = _parseInt(scanner, errorMessage, 2);
|
| - scanner.expect(':', errorMessage);
|
| + var minutes = _parseInt(scanner, 2);
|
| + if (minutes >= 60) scanner.error("minutes may not be greater than 60.");
|
| + scanner.expect(':');
|
|
|
| - var seconds = _parseInt(scanner, errorMessage, 2);
|
| -
|
| - if (hours >= 24 || minutes >= 60 || seconds >= 60) {
|
| - throw new FormatException(errorMessage);
|
| - }
|
| + var seconds = _parseInt(scanner, 2);
|
| + if (seconds >= 60) scanner.error("seconds may not be greater than 60.");
|
|
|
| return new DateTime(1, 1, 1, hours, minutes, seconds);
|
| }
|
| @@ -145,14 +146,14 @@ DateTime _parseTime(StringScanner scanner, String errorMessage) {
|
| /// Returns a UTC [DateTime] from the given components.
|
| ///
|
| /// Validates that [day] is a valid day for [month]. If it's not, throws a
|
| -/// [FormatException] with [errorMessage].
|
| -DateTime _makeDateTime(int year, int month, int day, DateTime time,
|
| - String errorMessage) {
|
| - if (day < 1) throw new FormatException(errorMessage);
|
| +/// [FormatException].
|
| +DateTime _makeDateTime(int year, int month, int day, DateTime time) {
|
| var dateTime = new DateTime.utc(
|
| year, month, day, time.hour, time.minute, time.second);
|
|
|
| // If [day] was too large, it will cause [month] to overflow.
|
| - if (dateTime.month != month) throw new FormatException(errorMessage);
|
| + if (dateTime.month != month) {
|
| + throw new FormatException("invalid day '$day' for month '$month'.");
|
| + }
|
| return dateTime;
|
| }
|
|
|