Skip to content

Commit 9d00de6

Browse files
chore: absorb necessary 'dart:io' components to remove references (#2186)
1 parent fdc089a commit 9d00de6

File tree

7 files changed

+387
-9
lines changed

7 files changed

+387
-9
lines changed

.github/workflows/branch.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name: "Branch & PR"
22
on:
33
push:
4-
branches: ["!master"]
4+
branches: [ "!master" ]
55
pull_request:
66
workflow_dispatch:
77

@@ -23,8 +23,7 @@ jobs:
2323
- name: Install pana
2424
run: dart pub global activate pana
2525
- name: Check package score
26-
# we cannot reach the top score: we use logger that doesn't support wasm, so -10
27-
run: pana --exit-code-threshold 10 .
26+
run: pana --exit-code-threshold 0 .
2827

2928
analyse-code:
3029
name: "Analyse Code"
@@ -50,7 +49,7 @@ jobs:
5049
strategy:
5150
fail-fast: false
5251
matrix:
53-
sdk: ["3.27.0", ""]
52+
sdk: [ "3.27.0", "" ]
5453
steps:
5554
- name: Checkout Repository
5655
uses: actions/checkout@v6
@@ -73,7 +72,7 @@ jobs:
7372
strategy:
7473
fail-fast: false
7574
matrix:
76-
sdk: ["3.27.0", ""]
75+
sdk: [ "3.27.0", "" ]
7776
defaults:
7877
run:
7978
working-directory: ./example
@@ -107,7 +106,7 @@ jobs:
107106
strategy:
108107
fail-fast: false
109108
matrix:
110-
sdk: ["3.27.0", ""]
109+
sdk: [ "3.27.0", "" ]
111110
defaults:
112111
run:
113112
working-directory: ./example
@@ -142,7 +141,7 @@ jobs:
142141
strategy:
143142
fail-fast: false
144143
matrix:
145-
sdk: ["3.27.0", ""]
144+
sdk: [ "3.27.0", "" ]
146145
defaults:
147146
run:
148147
working-directory: ./example

lib/src/dart_io/http_date.dart

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
1+
// Frequently used character codes.
2+
import 'package:flutter_map/src/dart_io/http_exception.dart';
3+
// ignore_for_file: constant_identifier_names
4+
5+
class _CharCode {
6+
static const int NONE = -1;
7+
static const int SP = 0x20;
8+
static const int COMMA = 0x2C;
9+
static const int MINUS = 0x2D;
10+
static const int COLON = 0x3A;
11+
static const int LETTER_a = 0x61;
12+
static const int LETTER_z = 0x7A;
13+
}
14+
15+
/// Utility functions for working with dates with HTTP specific date
16+
/// formats.
17+
class HttpDate {
18+
/// Format a date according to
19+
/// [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
20+
/// e.g. `Thu, 1 Jan 1970 00:00:00 GMT`.
21+
static String format(DateTime date) {
22+
final StringBuffer sb = StringBuffer();
23+
_formatTo(date, sb);
24+
return sb.toString();
25+
}
26+
27+
static String _formatTo(DateTime date, StringSink sb) {
28+
final DateTime d = date.toUtc();
29+
sb
30+
..write(_weekdayAbbreviations[d.weekday - 1])
31+
..write(', ')
32+
..write(d.day <= 9 ? '0' : '')
33+
..write(d.day.toString())
34+
..write(' ')
35+
..write(_monthAbbreviations[d.month - 1])
36+
..write(' ')
37+
..write(d.year.toString())
38+
..write(d.hour <= 9 ? ' 0' : ' ')
39+
..write(d.hour.toString())
40+
..write(d.minute <= 9 ? ':0' : ':')
41+
..write(d.minute.toString())
42+
..write(d.second <= 9 ? ':0' : ':')
43+
..write(d.second.toString())
44+
..write(' GMT');
45+
return sb.toString();
46+
}
47+
48+
// From RFC-2616 section "3.3.1 Full Date",
49+
// http://tools.ietf.org/html/rfc2616#section-3.3.1
50+
//
51+
// HTTP-date = rfc1123-date | rfc850-date | asctime-date
52+
// rfc1123-date = wkday "," SP date1 SP time SP "GMT"
53+
// rfc850-date = weekday "," SP date2 SP time SP "GMT"
54+
// asctime-date = wkday SP date3 SP time SP 4DIGIT
55+
// date1 = 2DIGIT SP month SP 4DIGIT
56+
// ; day month year (e.g., 02 Jun 1982)
57+
// date2 = 2DIGIT "-" month "-" 2DIGIT
58+
// ; day-month-year (e.g., 02-Jun-82)
59+
// date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
60+
// ; month day (e.g., Jun 2)
61+
// time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
62+
// ; 00:00:00 - 23:59:59
63+
// wkday = "Mon" | "Tue" | "Wed"
64+
// | "Thu" | "Fri" | "Sat" | "Sun"
65+
// weekday = "Monday" | "Tuesday" | "Wednesday"
66+
// | "Thursday" | "Friday" | "Saturday" | "Sunday"
67+
// month = "Jan" | "Feb" | "Mar" | "Apr"
68+
// | "May" | "Jun" | "Jul" | "Aug"
69+
// | "Sep" | "Oct" | "Nov" | "Dec"
70+
71+
static const List<String> _weekdayAbbreviations = <String>[
72+
'Mon',
73+
'Tue',
74+
'Wed',
75+
'Thu',
76+
'Fri',
77+
'Sat',
78+
'Sun',
79+
];
80+
81+
static const List<String> _weekdays = <String>[
82+
'Monday',
83+
'Tuesday',
84+
'Wednesday',
85+
'Thursday',
86+
'Friday',
87+
'Saturday',
88+
'Sunday',
89+
];
90+
91+
static const List<String> _monthAbbreviations = <String>[
92+
'Jan',
93+
'Feb',
94+
'Mar',
95+
'Apr',
96+
'May',
97+
'Jun',
98+
'Jul',
99+
'Aug',
100+
'Sep',
101+
'Oct',
102+
'Nov',
103+
'Dec',
104+
];
105+
106+
/// Parse a date string in either of the formats
107+
/// [RFC-1123](http://tools.ietf.org/html/rfc1123 "RFC-1123"),
108+
/// [RFC-850](http://tools.ietf.org/html/rfc850 "RFC-850") or
109+
/// ANSI C's asctime() format. These formats are listed here.
110+
///
111+
/// * Thu, 1 Jan 1970 00:00:00 GMT
112+
/// * Thursday, 1-Jan-1970 00:00:00 GMT
113+
/// * Thu Jan 1 00:00:00 1970
114+
///
115+
/// For more information see [RFC-2616 section
116+
/// 3.1.1](http://tools.ietf.org/html/rfc2616#section-3.3.1
117+
/// "RFC-2616 section 3.1.1").
118+
static DateTime parse(String date) =>
119+
_parse(date, 0, date.length, _invalidHttpDate, isCookieDate: false);
120+
121+
static Never _invalidHttpDate(String source, int start, int end) =>
122+
throw HttpException('Invalid HTTP date ${source.substring(start, end)}');
123+
124+
/// Implements [parse] on a substring.
125+
///
126+
/// If [isCookieDate] is `true`, also accepts `Thu, 1-Jan-1970 00:00:00 GMT`,
127+
/// with `-`s between day-month-year.
128+
/// This format was accepted by the special Cookie-date parser,
129+
/// which now uses this function too.
130+
static DateTime _parse(
131+
String source,
132+
int start,
133+
int end,
134+
Never Function(String, int, int) onError, {
135+
required bool isCookieDate,
136+
}) {
137+
// Almost same format after the week-day, only differ by one character.
138+
const int formatRfc1123 = _CharCode.SP;
139+
const int formatRfc850 = _CharCode.MINUS;
140+
// Separate format.
141+
const int formatAsctime = 0;
142+
143+
int index = start;
144+
145+
Never throwError() {
146+
onError(source, start, end);
147+
}
148+
149+
bool maybeExpectChar(int charCode) {
150+
if (index < end && source.codeUnitAt(index) == charCode) {
151+
index++;
152+
return true;
153+
}
154+
return false;
155+
}
156+
157+
void expectChar(int charCode) {
158+
if (!maybeExpectChar(charCode)) throwError();
159+
}
160+
161+
// Detects one of three recognized formats.
162+
//
163+
// All three formats start with the week-day in different ways:
164+
// * `Mon `: [formatAsctime]
165+
// * `Mon,`: [formatRfc1123]
166+
// * `Monday,`: [formatRfc850]
167+
int expectWeekday() {
168+
for (var i = 0; i < _weekdayAbbreviations.length; i++) {
169+
final wkday =
170+
_weekdayAbbreviations[i]; // Three-letter day abbreviation.
171+
assert(wkday.length == 3, '3 letters expected');
172+
if (index + 3 <= end && _isTextNoCase(source, index, 3, wkday)) {
173+
final weekday = _weekdays[i]; // Unabbreviated day.
174+
// Check if following characters are the rest of the day name.
175+
if (index + weekday.length <= end &&
176+
_isTextNoCase(
177+
source,
178+
index + 3,
179+
weekday.length - 3,
180+
weekday,
181+
3,
182+
)) {
183+
index += weekday.length;
184+
expectChar(_CharCode.COMMA);
185+
return formatRfc850;
186+
}
187+
index += 3;
188+
if (index < end) {
189+
final nextChar = source.codeUnitAt(index);
190+
if (nextChar == _CharCode.COMMA) {
191+
index++;
192+
return formatRfc1123;
193+
}
194+
if (nextChar == _CharCode.SP) {
195+
index++;
196+
return formatAsctime;
197+
}
198+
}
199+
break;
200+
}
201+
}
202+
throwError();
203+
}
204+
205+
int expectMonth() {
206+
for (var i = 0; i < _monthAbbreviations.length; i++) {
207+
final String monthAbbreviation = _monthAbbreviations[i];
208+
assert(monthAbbreviation.length == 3, '3 letters expected');
209+
if (index + 3 <= end &&
210+
_isTextNoCase(source, index, 3, monthAbbreviation)) {
211+
index += 3;
212+
return i;
213+
}
214+
}
215+
throwError();
216+
}
217+
218+
int expectNum(int maxLength) {
219+
int value = 0;
220+
final int start = index;
221+
while (index < end) {
222+
final int digit = source.codeUnitAt(index) ^ 0x30;
223+
if (digit <= 9) {
224+
value = value * 10 + digit;
225+
index++;
226+
continue;
227+
}
228+
break;
229+
}
230+
final int length = index - start;
231+
if (length > 0 && length <= maxLength) {
232+
return value;
233+
}
234+
throwError();
235+
}
236+
237+
final int format = expectWeekday();
238+
int year;
239+
int month;
240+
int day;
241+
int hours;
242+
int minutes;
243+
int seconds;
244+
if (format == formatAsctime) {
245+
month = expectMonth();
246+
expectChar(_CharCode.SP);
247+
if (source.codeUnitAt(index) == _CharCode.SP) index++;
248+
day = expectNum(2);
249+
expectChar(_CharCode.SP);
250+
hours = expectNum(2);
251+
expectChar(_CharCode.COLON);
252+
minutes = expectNum(2);
253+
expectChar(_CharCode.COLON);
254+
seconds = expectNum(2);
255+
expectChar(_CharCode.SP);
256+
year = expectNum(4);
257+
} else {
258+
final dateSeparator = format;
259+
final alternateDateSeparator =
260+
isCookieDate ? _CharCode.MINUS : _CharCode.NONE;
261+
expectChar(_CharCode.SP);
262+
day = expectNum(2);
263+
if (!maybeExpectChar(dateSeparator)) expectChar(alternateDateSeparator);
264+
month = expectMonth();
265+
if (!maybeExpectChar(dateSeparator)) expectChar(alternateDateSeparator);
266+
year = expectNum(4);
267+
expectChar(_CharCode.SP);
268+
hours = expectNum(2);
269+
expectChar(_CharCode.COLON);
270+
minutes = expectNum(2);
271+
expectChar(_CharCode.COLON);
272+
seconds = expectNum(2);
273+
if (index + 4 <= end && _isTextNoCase(source, index, 4, ' GMT')) {
274+
index += 4;
275+
} else {
276+
throwError();
277+
}
278+
}
279+
if (index != end) throwError();
280+
if (isCookieDate && year < 100) {
281+
year += year >= 70 ? 1900 : 2000;
282+
}
283+
return DateTime.utc(year, month + 1, day, hours, minutes, seconds);
284+
}
285+
}
286+
287+
/// Checks if `source.substring(at, at + length)` is the same as [text].
288+
///
289+
/// If [offset] is non-zero, only checks against `text.substring(offset)`.
290+
/// Starts by checking that [text] has length [length] - [offset].
291+
///
292+
/// Ignores case of ASCII letters.
293+
///
294+
/// The [text] should match the casing of the expected input to make
295+
/// checking faster.
296+
bool _isTextNoCase(
297+
String source,
298+
int at,
299+
int length,
300+
String text, [
301+
int offset = 0,
302+
]) {
303+
if (text.length - offset != length) return false;
304+
for (var i = 0; i < length; i++) {
305+
int testChar = text.codeUnitAt(offset + i);
306+
final actualChar = source.codeUnitAt(at + i);
307+
final delta = testChar ^ actualChar;
308+
if (delta == 0) continue;
309+
if (delta == 0x20) {
310+
testChar |= 0x20; // To lower case if ASCII letter.
311+
if (testChar >= _CharCode.LETTER_a && testChar <= _CharCode.LETTER_z) {
312+
continue;
313+
}
314+
}
315+
return false;
316+
}
317+
return true;
318+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/// HTTP exception.
2+
class HttpException implements Exception {
3+
/// Message.
4+
final String message;
5+
6+
/// Uri.
7+
final Uri? uri;
8+
9+
/// Http Exception constructor.
10+
const HttpException(this.message, {this.uri});
11+
12+
@override
13+
String toString() {
14+
final b = StringBuffer()
15+
..write('HttpException: ')
16+
..write(message);
17+
final uri = this.uri;
18+
if (uri != null) {
19+
b.write(', uri = $uri');
20+
}
21+
return b.toString();
22+
}
23+
}

0 commit comments

Comments
 (0)