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; |
} |