OLD | NEW |
| (Empty) |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 import "package:expect/expect.dart"; | |
6 import "dart:convert"; | |
7 import "dart:typed_data"; | |
8 | |
9 main() { | |
10 testMediaType(); | |
11 | |
12 testRoundTrip(""); | |
13 testRoundTrip("a"); | |
14 testRoundTrip("ab"); | |
15 testRoundTrip("abc"); | |
16 testRoundTrip("abcd"); | |
17 testRoundTrip("Content with special%25 characters: # ? = % # ? = %"); | |
18 testRoundTrip("blåbærgrød", UTF8); | |
19 testRoundTrip("blåbærgrød", LATIN1); | |
20 | |
21 testUriEquals("data:,abc?d"); | |
22 testUriEquals("DATA:,ABC?D"); | |
23 testUriEquals("data:,a%20bc?d"); | |
24 testUriEquals("DATA:,A%20BC?D"); | |
25 testUriEquals("data:,abc?d%23e"); // # must and will be is escaped. | |
26 | |
27 // Test that UriData.uri normalizes path and query. | |
28 | |
29 testUtf8Encoding("\u1000\uffff"); | |
30 testBytes(); | |
31 testInvalidCharacters(); | |
32 testNormalization(); | |
33 testErrors(); | |
34 } | |
35 | |
36 void testMediaType() { | |
37 for (var mimeType in ["", "text/plain", "text/javascript"]) { | |
38 for (var charset in ["", ";charset=US-ASCII", ";charset=UTF-8"]) { | |
39 for (var base64 in ["", ";base64"]) { | |
40 bool isBase64 = base64.isNotEmpty; | |
41 var text = "data:$mimeType$charset$base64,"; | |
42 var uri = UriData.parse(text); | |
43 | |
44 String expectedCharset = | |
45 charset.isEmpty ? "US-ASCII" : charset.substring(9); | |
46 String expectedMimeType = mimeType.isEmpty ? "text/plain" : mimeType; | |
47 | |
48 Expect.equals(text, "$uri"); | |
49 Expect.equals(expectedMimeType, uri.mimeType); | |
50 Expect.equals(expectedCharset, uri.charset); | |
51 Expect.equals(isBase64, uri.isBase64); | |
52 } | |
53 } | |
54 } | |
55 } | |
56 | |
57 void testRoundTrip(String content, [Encoding encoding]) { | |
58 UriData dataUri = new UriData.fromString(content, encoding: encoding); | |
59 Expect.isFalse(dataUri.isBase64); | |
60 Uri uri = dataUri.uri; | |
61 expectUriEquals(new Uri.dataFromString(content, encoding: encoding), uri); | |
62 | |
63 if (encoding != null) { | |
64 UriData dataUriParams = | |
65 new UriData.fromString(content, parameters: {"charset": encoding.name}); | |
66 Expect.equals("$dataUri", "$dataUriParams"); | |
67 } | |
68 | |
69 Expect.equals(encoding ?? ASCII, Encoding.getByName(dataUri.charset)); | |
70 Expect.equals(content, dataUri.contentAsString(encoding: encoding)); | |
71 Expect.equals(content, dataUri.contentAsString()); | |
72 Expect.equals(content, (encoding ?? ASCII).decode(dataUri.contentAsBytes())); | |
73 | |
74 uri = dataUri.uri; | |
75 Expect.equals(uri.toString(), dataUri.toString()); | |
76 Expect.equals(dataUri.toString(), new UriData.fromUri(uri).toString()); | |
77 | |
78 dataUri = new UriData.fromBytes(content.codeUnits); | |
79 Expect.listEquals(content.codeUnits, dataUri.contentAsBytes()); | |
80 Expect.equals(content, dataUri.contentAsString(encoding: LATIN1)); | |
81 | |
82 uri = dataUri.uri; | |
83 Expect.equals(uri.toString(), dataUri.toString()); | |
84 Expect.equals(dataUri.toString(), new UriData.fromUri(uri).toString()); | |
85 // Check that the URI is properly normalized. | |
86 expectUriEquals(uri, Uri.parse("$uri")); | |
87 } | |
88 | |
89 void testUtf8Encoding(String content) { | |
90 UriData uri = new UriData.fromString(content, encoding: UTF8); | |
91 Expect.equals(content, uri.contentAsString(encoding: UTF8)); | |
92 Expect.listEquals(UTF8.encode(content), uri.contentAsBytes()); | |
93 } | |
94 | |
95 void testInvalidCharacters() { | |
96 // SPACE, CTL and tspecial, plus '%' and '#' (URI gen-delim) | |
97 // This contains all ASCII character that are not valid in attribute/value | |
98 // parts. | |
99 var invalid = | |
100 '\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x7f' | |
101 ' ()<>@,;:"/[]?=%#\x80\u{1000}\u{10000}'; | |
102 var invalidNoSlash = invalid.replaceAll('/', ''); | |
103 var dataUri = new UriData.fromString(invalid, | |
104 encoding: UTF8, | |
105 mimeType: "$invalidNoSlash/$invalidNoSlash", | |
106 parameters: {invalid: invalid}); | |
107 | |
108 Expect.equals(invalid, dataUri.contentAsString()); | |
109 Expect.equals("$invalidNoSlash/$invalidNoSlash", dataUri.mimeType); | |
110 Expect.equals(invalid, dataUri.parameters[invalid]); | |
111 | |
112 var uri = dataUri.uri; | |
113 Expect.equals("$uri", "$dataUri"); | |
114 expectUriEquals(uri, Uri.parse("$uri")); // Check that it's canonicalized. | |
115 Expect.equals("$dataUri", new UriData.fromUri(uri).toString()); | |
116 } | |
117 | |
118 void testBytes() { | |
119 void testList(List<int> list) { | |
120 var dataUri = new UriData.fromBytes(list); | |
121 Expect.equals("application/octet-stream", dataUri.mimeType); | |
122 Expect.isTrue(dataUri.isBase64); | |
123 Expect.listEquals(list, dataUri.contentAsBytes()); | |
124 | |
125 dataUri = new UriData.fromBytes(list, percentEncoded: true); | |
126 Expect.equals("application/octet-stream", dataUri.mimeType); | |
127 Expect.isFalse(dataUri.isBase64); | |
128 Expect.listEquals(list, dataUri.contentAsBytes()); | |
129 | |
130 var string = new String.fromCharCodes(list); | |
131 | |
132 dataUri = new UriData.fromString(string, encoding: LATIN1); | |
133 Expect.equals("text/plain", dataUri.mimeType); | |
134 Expect.isFalse(dataUri.isBase64); | |
135 Expect.listEquals(list, dataUri.contentAsBytes()); | |
136 | |
137 dataUri = new UriData.fromString(string, encoding: LATIN1, base64: true); | |
138 Expect.equals("text/plain", dataUri.mimeType); | |
139 Expect.isTrue(dataUri.isBase64); | |
140 Expect.listEquals(list, dataUri.contentAsBytes()); | |
141 } | |
142 | |
143 void testLists(List<int> list) { | |
144 testList(list); | |
145 for (int i = 0; i < 27; i++) { | |
146 testList(list.sublist(i, i + i)); // All lengths from 0 to 27. | |
147 } | |
148 } | |
149 | |
150 var bytes = new Uint8List(512); | |
151 for (int i = 0; i < bytes.length; i++) { | |
152 bytes[i] = i; | |
153 } | |
154 testLists(bytes); | |
155 testLists(new List.from(bytes)); | |
156 testLists(new List.unmodifiable(bytes)); | |
157 } | |
158 | |
159 void testNormalization() { | |
160 // Base-64 normalization. | |
161 | |
162 // Normalized URI-alphabet characters. | |
163 Expect.equals( | |
164 "data:;base64,AA/+", UriData.parse("data:;base64,AA_-").toString()); | |
165 // Normalized escapes. | |
166 Expect.equals( | |
167 "data:;base64,AB==", UriData.parse("data:;base64,A%42=%3D").toString()); | |
168 Expect.equals("data:;base64,/+/+", | |
169 UriData.parse("data:;base64,%5F%2D%2F%2B").toString()); | |
170 // Normalized padded data. | |
171 Expect.equals( | |
172 "data:;base64,AA==", UriData.parse("data:;base64,AA%3D%3D").toString()); | |
173 Expect.equals( | |
174 "data:;base64,AAA=", UriData.parse("data:;base64,AAA%3D").toString()); | |
175 // Normalized unpadded data. | |
176 Expect.equals( | |
177 "data:;base64,AA==", UriData.parse("data:;base64,AA").toString()); | |
178 Expect.equals( | |
179 "data:;base64,AAA=", UriData.parse("data:;base64,AAA").toString()); | |
180 | |
181 // "URI normalization" of non-base64 content. | |
182 var uri = UriData.parse("data:,\x20\xa0"); | |
183 Expect.equals("data:,%20%C2%A0", uri.toString()); | |
184 uri = UriData.parse("data:,x://x@y:[z]:42/p/./?q=x&y=z#?#\u1234\u{12345}"); | |
185 Expect.equals( | |
186 "data:,x://x@y:%5Bz%5D:42/p/./?q=x&y=z%23?%23%E1%88%B4%F0%92%8D%85", | |
187 uri.toString()); | |
188 } | |
189 | |
190 bool badArgument(e) => e is ArgumentError; | |
191 bool badFormat(e) => e is FormatException; | |
192 | |
193 void testErrors() { | |
194 // Invalid constructor parameters. | |
195 Expect.throws(() { | |
196 new UriData.fromBytes([], mimeType: "noslash"); | |
197 }, badArgument); | |
198 Expect.throws(() { | |
199 new UriData.fromBytes([257]); | |
200 }, badArgument); | |
201 Expect.throws(() { | |
202 new UriData.fromBytes([-1]); | |
203 }, badArgument); | |
204 Expect.throws(() { | |
205 new UriData.fromBytes([0x10000000]); | |
206 }, badArgument); | |
207 Expect.throws(() { | |
208 new UriData.fromString("", mimeType: "noslash"); | |
209 }, badArgument); | |
210 | |
211 Expect.throws(() { | |
212 new Uri.dataFromBytes([], mimeType: "noslash"); | |
213 }, badArgument); | |
214 Expect.throws(() { | |
215 new Uri.dataFromBytes([257]); | |
216 }, badArgument); | |
217 Expect.throws(() { | |
218 new Uri.dataFromBytes([-1]); | |
219 }, badArgument); | |
220 Expect.throws(() { | |
221 new Uri.dataFromBytes([0x10000000]); | |
222 }, badArgument); | |
223 Expect.throws(() { | |
224 new Uri.dataFromString("", mimeType: "noslash"); | |
225 }, badArgument); | |
226 | |
227 // Empty parameters allowed, not an error. | |
228 var uri = new UriData.fromString("", mimeType: "", parameters: {}); | |
229 Expect.equals("data:,", "$uri"); | |
230 // Empty parameter key or value is an error. | |
231 Expect.throws( | |
232 () => new UriData.fromString("", parameters: {"": "X"}), badArgument); | |
233 Expect.throws( | |
234 () => new UriData.fromString("", parameters: {"X": ""}), badArgument); | |
235 | |
236 // Not recognizing charset is an error. | |
237 uri = UriData.parse("data:;charset=arglebargle,X"); | |
238 Expect.throws(() { | |
239 uri.contentAsString(); | |
240 }); | |
241 // Doesn't throw if we specify the encoding. | |
242 Expect.equals("X", uri.contentAsString(encoding: ASCII)); | |
243 | |
244 // Parse format. | |
245 Expect.throws(() { | |
246 UriData.parse("notdata:,"); | |
247 }, badFormat); | |
248 Expect.throws(() { | |
249 UriData.parse("text/plain,noscheme"); | |
250 }, badFormat); | |
251 Expect.throws(() { | |
252 UriData.parse("data:noseparator"); | |
253 }, badFormat); | |
254 Expect.throws(() { | |
255 UriData.parse("data:noslash,text"); | |
256 }, badFormat); | |
257 Expect.throws(() { | |
258 UriData.parse("data:type/sub;noequals,text"); | |
259 }, badFormat); | |
260 Expect.throws(() { | |
261 UriData.parse("data:type/sub;knocomma="); | |
262 }, badFormat); | |
263 Expect.throws(() { | |
264 UriData.parse("data:type/sub;k=v;nocomma"); | |
265 }, badFormat); | |
266 Expect.throws(() { | |
267 UriData.parse("data:type/sub;k=nocomma"); | |
268 }, badFormat); | |
269 Expect.throws(() { | |
270 UriData.parse("data:type/sub;k=v;base64"); | |
271 }, badFormat); | |
272 | |
273 void formatError(String input) { | |
274 Expect.throws(() => UriData.parse("data:;base64,$input"), badFormat, input); | |
275 } | |
276 | |
277 // Invalid base64 format (detected when parsed). | |
278 for (var a = 0; a <= 4; a++) { | |
279 for (var p = 0; p <= 4; p++) { | |
280 // Base-64 encoding must have length divisible by four and no more | |
281 // than two padding characters at the end. | |
282 if (p < 3 && (a + p) % 4 == 0) continue; | |
283 if (p == 0 && a > 1) continue; | |
284 formatError("A" * a + "=" * p); | |
285 formatError("A" * a + "%3D" * p); | |
286 } | |
287 } | |
288 // Invalid base64 encoding: padding not at end. | |
289 formatError("AA=A"); | |
290 formatError("A=AA"); | |
291 formatError("=AAA"); | |
292 formatError("A==A"); | |
293 formatError("==AA"); | |
294 formatError("===A"); | |
295 formatError("AAA%3D="); | |
296 formatError("A%3D=="); | |
297 | |
298 // Invalid unpadded data. | |
299 formatError("A"); | |
300 formatError("AAAAA"); | |
301 | |
302 // Invalid characters. | |
303 formatError("AAA*"); | |
304 formatError("AAA\x00"); | |
305 formatError("AAA\\"); | |
306 formatError("AAA,"); | |
307 | |
308 // Invalid escapes. | |
309 formatError("AAA%25"); | |
310 formatError("AAA%7F"); | |
311 formatError("AAA%7F"); | |
312 } | |
313 | |
314 /// Checks that two [Uri]s are exactly the same. | |
315 expectUriEquals(Uri expect, Uri actual) { | |
316 Expect.equals(expect.scheme, actual.scheme, "scheme"); | |
317 Expect.equals(expect.hasAuthority, actual.hasAuthority, "hasAuthority"); | |
318 Expect.equals(expect.userInfo, actual.userInfo, "userInfo"); | |
319 Expect.equals(expect.host, actual.host, "host"); | |
320 Expect.equals(expect.hasPort, actual.hasPort, "hasPort"); | |
321 Expect.equals(expect.port, actual.port, "port"); | |
322 Expect.equals(expect.port, actual.port, "port"); | |
323 Expect.equals(expect.hasQuery, actual.hasQuery, "hasQuery"); | |
324 Expect.equals(expect.query, actual.query, "query"); | |
325 Expect.equals(expect.hasFragment, actual.hasFragment, "hasFragment"); | |
326 Expect.equals(expect.fragment, actual.fragment, "fragment"); | |
327 } | |
328 | |
329 void testUriEquals(String uriText) { | |
330 var data = UriData.parse(uriText); | |
331 var uri = Uri.parse(uriText); | |
332 Expect.equals(data.uri, uri); | |
333 Expect.equals(data.toString(), uri.data.toString()); | |
334 Expect.equals(data.toString(), uri.toString()); | |
335 } | |
OLD | NEW |