OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 import 'dart:math'; | 6 import 'dart:math'; |
7 | 7 |
8 import "package:test/test.dart"; | 8 import "package:test/test.dart"; |
9 import "package:mime/mime.dart"; | 9 import "package:mime/mime.dart"; |
10 | 10 |
11 void _writeInChunks(List<int> data, | 11 void _writeInChunks( |
12 int chunkSize, | 12 List<int> data, int chunkSize, StreamController<List<int>> controller) { |
13 StreamController<List<int>> controller) { | |
14 if (chunkSize == -1) chunkSize = data.length; | 13 if (chunkSize == -1) chunkSize = data.length; |
15 | 14 |
16 int written = 0; | 15 int written = 0; |
17 for (int pos = 0; pos < data.length; pos += chunkSize) { | 16 for (int pos = 0; pos < data.length; pos += chunkSize) { |
18 int remaining = data.length - pos; | 17 int remaining = data.length - pos; |
19 int writeLength = min(chunkSize, remaining); | 18 int writeLength = min(chunkSize, remaining); |
20 controller.add(data.sublist(pos, pos + writeLength)); | 19 controller.add(data.sublist(pos, pos + writeLength)); |
21 written += writeLength; | 20 written += writeLength; |
22 } | 21 } |
23 controller.close(); | 22 controller.close(); |
24 } | 23 } |
25 | 24 |
| 25 enum TestMode { IMMEDIATE_LISTEN, DELAY_LISTEN, PAUSE_RESUME } |
26 | 26 |
27 enum TestMode { | 27 void _runParseTest(String message, String boundary, TestMode mode, |
28 IMMEDIATE_LISTEN, | 28 [List<Map> expectedHeaders, List expectedParts, bool expectError = false]) { |
29 DELAY_LISTEN, | |
30 PAUSE_RESUME | |
31 } | |
32 | |
33 void _runParseTest(String message, | |
34 String boundary, | |
35 TestMode mode, | |
36 [List<Map> expectedHeaders, | |
37 List expectedParts, | |
38 bool expectError = false]) { | |
39 Future testWrite(List<int> data, [int chunkSize = -1]) { | 29 Future testWrite(List<int> data, [int chunkSize = -1]) { |
40 StreamController controller = new StreamController(sync: true); | 30 StreamController controller = new StreamController(sync: true); |
41 | 31 |
42 var stream = controller.stream.transform( | 32 var stream = |
43 new MimeMultipartTransformer(boundary)); | 33 controller.stream.transform(new MimeMultipartTransformer(boundary)); |
44 int i = 0; | 34 int i = 0; |
45 var completer = new Completer(); | 35 var completer = new Completer(); |
46 var futures = []; | 36 var futures = []; |
47 stream.listen((multipart) { | 37 stream.listen((multipart) { |
48 int part = i++; | 38 int part = i++; |
49 if (expectedHeaders != null) { | 39 if (expectedHeaders != null) { |
50 expect(multipart.headers, equals(expectedHeaders[part])); | 40 expect(multipart.headers, equals(expectedHeaders[part])); |
51 } | 41 } |
52 switch (mode) { | 42 switch (mode) { |
53 case TestMode.IMMEDIATE_LISTEN: | 43 case TestMode.IMMEDIATE_LISTEN: |
54 futures.add(multipart.fold([], (buffer, data) => buffer..addAll(data)) | 44 futures.add(multipart.fold([], (buffer, data) => buffer..addAll(data)) |
55 .then((data) { | 45 .then((data) { |
56 if (expectedParts[part] != null) { | 46 if (expectedParts[part] != null) { |
57 expect(data, equals(expectedParts[part].codeUnits)); | 47 expect(data, equals(expectedParts[part].codeUnits)); |
58 } | 48 } |
59 })); | 49 })); |
60 break; | 50 break; |
61 | 51 |
62 case TestMode.DELAY_LISTEN: | 52 case TestMode.DELAY_LISTEN: |
63 futures.add(new Future(() { | 53 futures.add(new Future(() { |
64 return multipart.fold([], (buffer, data) => buffer..addAll(data)) | 54 return multipart.fold([], (buffer, data) => buffer..addAll(data)) |
65 .then((data) { | 55 .then((data) { |
66 if (expectedParts[part] != null) { | 56 if (expectedParts[part] != null) { |
67 expect(data, equals(expectedParts[part].codeUnits)); | 57 expect(data, equals(expectedParts[part].codeUnits)); |
68 } | 58 } |
69 }); | 59 }); |
70 })); | 60 })); |
71 break; | 61 break; |
72 | 62 |
73 case TestMode.PAUSE_RESUME: | 63 case TestMode.PAUSE_RESUME: |
74 var completer = new Completer(); | 64 var completer = new Completer(); |
75 futures.add(completer.future); | 65 futures.add(completer.future); |
76 var buffer = []; | 66 var buffer = []; |
77 var subscription; | 67 var subscription; |
78 subscription = multipart.listen( | 68 subscription = multipart.listen((data) { |
79 (data) { | 69 buffer.addAll(data); |
80 buffer.addAll(data); | 70 subscription.pause(); |
81 subscription.pause(); | 71 new Future(() => subscription.resume()); |
82 new Future(() => subscription.resume()); | 72 }, onDone: () { |
83 }, | 73 if (expectedParts[part] != null) { |
84 onDone: () { | 74 expect(buffer, equals(expectedParts[part].codeUnits)); |
85 if (expectedParts[part] != null) { | 75 } |
86 expect(buffer, equals(expectedParts[part].codeUnits)); | 76 completer.complete(); |
87 } | 77 }); |
88 completer.complete(); | |
89 }); | |
90 break; | 78 break; |
91 } | 79 } |
92 }, onError: (error) { | 80 }, onError: (error) { |
93 if (!expectError) throw error; | 81 if (!expectError) throw error; |
94 }, onDone: () { | 82 }, onDone: () { |
95 if (expectedParts != null) { | 83 if (expectedParts != null) { |
96 expect(i, equals(expectedParts.length)); | 84 expect(i, equals(expectedParts.length)); |
97 } | 85 } |
98 Future.wait(futures).then(completer.complete); | 86 Future.wait(futures).then(completer.complete); |
99 }); | 87 }); |
100 | 88 |
101 _writeInChunks(data, chunkSize, controller); | 89 _writeInChunks(data, chunkSize, controller); |
102 | 90 |
103 return completer.future; | 91 return completer.future; |
104 } | 92 } |
105 | 93 |
106 Future testFirstPartOnly(List<int> data, [int chunkSize = -1]) { | 94 Future testFirstPartOnly(List<int> data, [int chunkSize = -1]) { |
107 var completer = new Completer(); | 95 var completer = new Completer(); |
108 var controller = new StreamController(sync: true); | 96 var controller = new StreamController(sync: true); |
109 | 97 |
110 var stream = controller.stream.transform( | 98 var stream = |
111 new MimeMultipartTransformer(boundary)); | 99 controller.stream.transform(new MimeMultipartTransformer(boundary)); |
112 | 100 |
113 var subscription; | 101 var subscription; |
114 subscription = stream.first.then((multipart) { | 102 subscription = stream.first.then((multipart) { |
115 if (expectedHeaders != null) { | 103 if (expectedHeaders != null) { |
116 expect(multipart.headers, equals(expectedHeaders[0])); | 104 expect(multipart.headers, equals(expectedHeaders[0])); |
117 } | 105 } |
118 return (multipart.fold([], (b, d) => b..addAll(d)).then((data) { | 106 return (multipart.fold([], (b, d) => b..addAll(d)).then((data) { |
119 if (expectedParts != null && expectedParts[0] != null) { | 107 if (expectedParts != null && expectedParts[0] != null) { |
120 expect(data, equals(expectedParts[0].codeUnits)); | 108 expect(data, equals(expectedParts[0].codeUnits)); |
121 } | 109 } |
122 })); | 110 })); |
123 }).then((_) { | 111 }).then((_) { |
124 completer.complete(); | 112 completer.complete(); |
125 }); | 113 }); |
126 | 114 |
127 _writeInChunks(data, chunkSize, controller); | 115 _writeInChunks(data, chunkSize, controller); |
128 | 116 |
129 return completer.future; | 117 return completer.future; |
130 } | 118 } |
131 | 119 |
132 Future testCompletePartAfterCancel(List<int> data, | 120 Future testCompletePartAfterCancel(List<int> data, int parts, |
133 int parts, | 121 [int chunkSize = -1]) { |
134 [int chunkSize = -1]) { | |
135 var completer = new Completer(); | 122 var completer = new Completer(); |
136 var controller = new StreamController(sync: true); | 123 var controller = new StreamController(sync: true); |
137 var stream = controller.stream.transform( | 124 var stream = |
138 new MimeMultipartTransformer(boundary)); | 125 controller.stream.transform(new MimeMultipartTransformer(boundary)); |
139 var subscription; | 126 var subscription; |
140 int i = 0; | 127 int i = 0; |
141 var futures = []; | 128 var futures = []; |
142 subscription = stream.listen((multipart) { | 129 subscription = stream.listen((multipart) { |
143 int partIndex = i; | 130 int partIndex = i; |
144 | 131 |
145 if (partIndex >= parts) { | 132 if (partIndex >= parts) { |
146 throw 'Expected no more parts, but got one.'; | 133 throw 'Expected no more parts, but got one.'; |
147 } | 134 } |
148 | 135 |
(...skipping 15 matching lines...) Expand all Loading... |
164 | 151 |
165 _writeInChunks(data, chunkSize, controller); | 152 _writeInChunks(data, chunkSize, controller); |
166 | 153 |
167 return completer.future; | 154 return completer.future; |
168 } | 155 } |
169 | 156 |
170 // Test parsing the data three times delivering the data in | 157 // Test parsing the data three times delivering the data in |
171 // different chunks. | 158 // different chunks. |
172 List<int> data = message.codeUnits; | 159 List<int> data = message.codeUnits; |
173 test('test', () { | 160 test('test', () { |
174 expect(Future.wait([ | 161 expect( |
175 testWrite(data), | 162 Future.wait([ |
176 testWrite(data, 10), | 163 testWrite(data), |
177 testWrite(data, 2), | 164 testWrite(data, 10), |
178 testWrite(data, 1), | 165 testWrite(data, 2), |
179 ]), completes); | 166 testWrite(data, 1), |
| 167 ]), |
| 168 completes); |
180 }); | 169 }); |
181 | 170 |
182 if (expectedParts.length > 0) { | 171 if (expectedParts.length > 0) { |
183 test('test-first-part-only', () { | 172 test('test-first-part-only', () { |
184 expect(Future.wait([ | 173 expect( |
185 testFirstPartOnly(data), | 174 Future.wait([ |
186 testFirstPartOnly(data, 10), | 175 testFirstPartOnly(data), |
187 testFirstPartOnly(data, 2), | 176 testFirstPartOnly(data, 10), |
188 testFirstPartOnly(data, 1), | 177 testFirstPartOnly(data, 2), |
189 ]), completes); | 178 testFirstPartOnly(data, 1), |
| 179 ]), |
| 180 completes); |
190 }); | 181 }); |
191 | 182 |
192 test('test-n-parts-only', () { | 183 test('test-n-parts-only', () { |
193 int numPartsExpected = expectedParts.length - 1; | 184 int numPartsExpected = expectedParts.length - 1; |
194 if (numPartsExpected == 0) numPartsExpected = 1; | 185 if (numPartsExpected == 0) numPartsExpected = 1; |
195 | 186 |
196 expect(Future.wait([ | 187 expect( |
197 testCompletePartAfterCancel(data, numPartsExpected), | 188 Future.wait([ |
198 testCompletePartAfterCancel(data, numPartsExpected, 10), | 189 testCompletePartAfterCancel(data, numPartsExpected), |
199 testCompletePartAfterCancel(data, numPartsExpected, 2), | 190 testCompletePartAfterCancel(data, numPartsExpected, 10), |
200 testCompletePartAfterCancel(data, numPartsExpected, 1), | 191 testCompletePartAfterCancel(data, numPartsExpected, 2), |
201 ]), completes); | 192 testCompletePartAfterCancel(data, numPartsExpected, 1), |
| 193 ]), |
| 194 completes); |
202 }); | 195 }); |
203 } | 196 } |
204 } | 197 } |
205 | 198 |
206 void _testParse(String message, | 199 void _testParse(String message, String boundary, |
207 String boundary, | 200 [List<Map> expectedHeaders, List expectedParts, bool expectError = false]) { |
208 [List<Map> expectedHeaders, | 201 _runParseTest(message, boundary, TestMode.IMMEDIATE_LISTEN, expectedHeaders, |
209 List expectedParts, | 202 expectedParts, expectError); |
210 bool expectError = false]) { | 203 _runParseTest(message, boundary, TestMode.DELAY_LISTEN, expectedHeaders, |
211 _runParseTest( | 204 expectedParts, expectError); |
212 message, boundary, TestMode.IMMEDIATE_LISTEN, | 205 _runParseTest(message, boundary, TestMode.PAUSE_RESUME, expectedHeaders, |
213 expectedHeaders, expectedParts, expectError); | 206 expectedParts, expectError); |
214 _runParseTest( | |
215 message, boundary, TestMode.DELAY_LISTEN, | |
216 expectedHeaders, expectedParts, expectError); | |
217 _runParseTest( | |
218 message, boundary, TestMode.PAUSE_RESUME, | |
219 expectedHeaders, expectedParts, expectError); | |
220 } | 207 } |
221 | 208 |
222 void _testParseValid() { | 209 void _testParseValid() { |
223 // Empty message from Chrome form post. | 210 // Empty message from Chrome form post. |
224 var message = '------WebKitFormBoundaryU3FBruSkJKG0Yor1--\r\n'; | 211 var message = '------WebKitFormBoundaryU3FBruSkJKG0Yor1--\r\n'; |
225 _testParse(message, "----WebKitFormBoundaryU3FBruSkJKG0Yor1", [], []); | 212 _testParse(message, "----WebKitFormBoundaryU3FBruSkJKG0Yor1", [], []); |
226 | 213 |
227 // Sample from Wikipedia. | 214 // Sample from Wikipedia. |
228 message = """ | 215 message = """ |
229 This is a message with multiple parts in MIME format.\r | 216 This is a message with multiple parts in MIME format.\r |
230 --frontier\r | 217 --frontier\r |
231 Content-Type: text/plain\r | 218 Content-Type: text/plain\r |
232 \r | 219 \r |
233 This is the body of the message.\r | 220 This is the body of the message.\r |
234 --frontier\r | 221 --frontier\r |
235 Content-Type: application/octet-stream\r | 222 Content-Type: application/octet-stream\r |
236 Content-Transfer-Encoding: base64\r | 223 Content-Transfer-Encoding: base64\r |
237 \r | 224 \r |
238 PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg | 225 PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg |
239 Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg=\r | 226 Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg=\r |
240 --frontier--\r\n"""; | 227 --frontier--\r\n"""; |
241 var headers1 = <String, String>{"content-type": "text/plain"}; | 228 var headers1 = <String, String>{"content-type": "text/plain"}; |
242 var headers2 = <String, String>{"content-type": "application/octet-stream", | 229 var headers2 = <String, String>{ |
243 "content-transfer-encoding": "base64"}; | 230 "content-type": "application/octet-stream", |
| 231 "content-transfer-encoding": "base64" |
| 232 }; |
244 var body1 = "This is the body of the message."; | 233 var body1 = "This is the body of the message."; |
245 var body2 = """ | 234 var body2 = """ |
246 PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg | 235 PGh0bWw+CiAgPGhlYWQ+CiAgPC9oZWFkPgogIDxib2R5PgogICAgPHA+VGhpcyBpcyB0aGUg |
247 Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg="""; | 236 Ym9keSBvZiB0aGUgbWVzc2FnZS48L3A+CiAgPC9ib2R5Pgo8L2h0bWw+Cg="""; |
248 _testParse(message, "frontier", [headers1, headers2], [body1, body2]); | 237 _testParse(message, "frontier", [headers1, headers2], [body1, body2]); |
249 | 238 |
250 // Sample from HTML 4.01 Specification. | 239 // Sample from HTML 4.01 Specification. |
251 message = """ | 240 message = """ |
252 \r\n--AaB03x\r | 241 \r\n--AaB03x\r |
253 Content-Disposition: form-data; name=\"submit-name\"\r | 242 Content-Disposition: form-data; name=\"submit-name\"\r |
254 \r | 243 \r |
255 Larry\r | 244 Larry\r |
256 --AaB03x\r | 245 --AaB03x\r |
257 Content-Disposition: form-data; name=\"files\"; filename=\"file1.txt\"\r | 246 Content-Disposition: form-data; name=\"files\"; filename=\"file1.txt\"\r |
258 Content-Type: text/plain\r | 247 Content-Type: text/plain\r |
259 \r | 248 \r |
260 ... contents of file1.txt ...\r | 249 ... contents of file1.txt ...\r |
261 --AaB03x--\r\n"""; | 250 --AaB03x--\r\n"""; |
262 headers1 = <String, String>{ | 251 headers1 = <String, String>{ |
263 "content-disposition": "form-data; name=\"submit-name\""}; | 252 "content-disposition": "form-data; name=\"submit-name\"" |
| 253 }; |
264 headers2 = <String, String>{ | 254 headers2 = <String, String>{ |
265 "content-type": "text/plain", | 255 "content-type": "text/plain", |
266 "content-disposition": "form-data; name=\"files\"; filename=\"file1.txt\"" | 256 "content-disposition": "form-data; name=\"files\"; filename=\"file1.txt\"" |
267 }; | 257 }; |
268 body1 = "Larry"; | 258 body1 = "Larry"; |
269 body2 = "... contents of file1.txt ..."; | 259 body2 = "... contents of file1.txt ..."; |
270 _testParse(message, "AaB03x", [headers1, headers2], [body1, body2]); | 260 _testParse(message, "AaB03x", [headers1, headers2], [body1, body2]); |
271 | 261 |
272 // Longer form from submitting the following from Chrome. | 262 // Longer form from submitting the following from Chrome. |
273 // | 263 // |
274 // <html> | 264 // <html> |
275 // <body> | 265 // <body> |
276 // <FORM action="http://127.0.0.1:1234/" | 266 // <FORM action="http://127.0.0.1:1234/" |
(...skipping 22 matching lines...) Expand all Loading... |
299 ------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r | 289 ------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r |
300 Content-Disposition: form-data; name=\"checkbox_input\"\r | 290 Content-Disposition: form-data; name=\"checkbox_input\"\r |
301 \r | 291 \r |
302 on\r | 292 on\r |
303 ------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r | 293 ------WebKitFormBoundaryQ3cgYAmGRF8yOeYB\r |
304 Content-Disposition: form-data; name=\"radio_input\"\r | 294 Content-Disposition: form-data; name=\"radio_input\"\r |
305 \r | 295 \r |
306 on\r | 296 on\r |
307 ------WebKitFormBoundaryQ3cgYAmGRF8yOeYB--\r\n"""; | 297 ------WebKitFormBoundaryQ3cgYAmGRF8yOeYB--\r\n"""; |
308 headers1 = <String, String>{ | 298 headers1 = <String, String>{ |
309 "content-disposition": "form-data; name=\"text_input\""}; | 299 "content-disposition": "form-data; name=\"text_input\"" |
| 300 }; |
310 headers2 = <String, String>{ | 301 headers2 = <String, String>{ |
311 "content-disposition": "form-data; name=\"password_input\""}; | 302 "content-disposition": "form-data; name=\"password_input\"" |
| 303 }; |
312 var headers3 = <String, String>{ | 304 var headers3 = <String, String>{ |
313 "content-disposition": "form-data; name=\"checkbox_input\""}; | 305 "content-disposition": "form-data; name=\"checkbox_input\"" |
| 306 }; |
314 var headers4 = <String, String>{ | 307 var headers4 = <String, String>{ |
315 "content-disposition": "form-data; name=\"radio_input\""}; | 308 "content-disposition": "form-data; name=\"radio_input\"" |
| 309 }; |
316 body1 = "text"; | 310 body1 = "text"; |
317 body2 = "password"; | 311 body2 = "password"; |
318 var body3 = "on"; | 312 var body3 = "on"; |
319 var body4 = "on"; | 313 var body4 = "on"; |
320 _testParse(message, | 314 _testParse(message, "----WebKitFormBoundaryQ3cgYAmGRF8yOeYB", |
321 "----WebKitFormBoundaryQ3cgYAmGRF8yOeYB", | 315 [headers1, headers2, headers3, headers4], [body1, body2, body3, body4]); |
322 [headers1, headers2, headers3, headers4], | |
323 [body1, body2, body3, body4]); | |
324 | 316 |
325 // Same form from Firefox. | 317 // Same form from Firefox. |
326 message = """ | 318 message = """ |
327 \r\n-----------------------------52284550912143824192005403738\r | 319 \r\n-----------------------------52284550912143824192005403738\r |
328 Content-Disposition: form-data; name=\"text_input\"\r | 320 Content-Disposition: form-data; name=\"text_input\"\r |
329 \r | 321 \r |
330 text\r | 322 text\r |
331 -----------------------------52284550912143824192005403738\r | 323 -----------------------------52284550912143824192005403738\r |
332 Content-Disposition: form-data; name=\"password_input\"\r | 324 Content-Disposition: form-data; name=\"password_input\"\r |
333 \r | 325 \r |
334 password\r | 326 password\r |
335 -----------------------------52284550912143824192005403738\r | 327 -----------------------------52284550912143824192005403738\r |
336 Content-Disposition: form-data; name=\"checkbox_input\"\r | 328 Content-Disposition: form-data; name=\"checkbox_input\"\r |
337 \r | 329 \r |
338 on\r | 330 on\r |
339 -----------------------------52284550912143824192005403738\r | 331 -----------------------------52284550912143824192005403738\r |
340 Content-Disposition: form-data; name=\"radio_input\"\r | 332 Content-Disposition: form-data; name=\"radio_input\"\r |
341 \r | 333 \r |
342 on\r | 334 on\r |
343 -----------------------------52284550912143824192005403738--\r\n"""; | 335 -----------------------------52284550912143824192005403738--\r\n"""; |
344 _testParse(message, | 336 _testParse( |
345 "---------------------------52284550912143824192005403738", | 337 message, |
346 [headers1, headers2, headers3, headers4], | 338 "---------------------------52284550912143824192005403738", |
347 [body1, body2, body3, body4]); | 339 [headers1, headers2, headers3, headers4], |
| 340 [body1, body2, body3, body4]); |
348 | 341 |
349 // And Internet Explorer | 342 // And Internet Explorer |
350 message = """ | 343 message = """ |
351 \r\n-----------------------------7dc8f38c60326\r | 344 \r\n-----------------------------7dc8f38c60326\r |
352 Content-Disposition: form-data; name=\"text_input\"\r | 345 Content-Disposition: form-data; name=\"text_input\"\r |
353 \r | 346 \r |
354 text\r | 347 text\r |
355 -----------------------------7dc8f38c60326\r | 348 -----------------------------7dc8f38c60326\r |
356 Content-Disposition: form-data; name=\"password_input\"\r | 349 Content-Disposition: form-data; name=\"password_input\"\r |
357 \r | 350 \r |
358 password\r | 351 password\r |
359 -----------------------------7dc8f38c60326\r | 352 -----------------------------7dc8f38c60326\r |
360 Content-Disposition: form-data; name=\"checkbox_input\"\r | 353 Content-Disposition: form-data; name=\"checkbox_input\"\r |
361 \r | 354 \r |
362 on\r | 355 on\r |
363 -----------------------------7dc8f38c60326\r | 356 -----------------------------7dc8f38c60326\r |
364 Content-Disposition: form-data; name=\"radio_input\"\r | 357 Content-Disposition: form-data; name=\"radio_input\"\r |
365 \r | 358 \r |
366 on\r | 359 on\r |
367 -----------------------------7dc8f38c60326--\r\n"""; | 360 -----------------------------7dc8f38c60326--\r\n"""; |
368 _testParse(message, | 361 _testParse(message, "---------------------------7dc8f38c60326", |
369 "---------------------------7dc8f38c60326", | 362 [headers1, headers2, headers3, headers4], [body1, body2, body3, body4]); |
370 [headers1, headers2, headers3, headers4], | |
371 [body1, body2, body3, body4]); | |
372 | 363 |
373 // Test boundary prefix inside prefix and content. | 364 // Test boundary prefix inside prefix and content. |
374 message = """ | 365 message = """ |
375 -\r | 366 -\r |
376 --\r | 367 --\r |
377 --b\r | 368 --b\r |
378 --bo\r | 369 --bo\r |
379 --bou\r | 370 --bou\r |
380 --boun\r | 371 --boun\r |
381 --bound\r | 372 --bound\r |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
456 \r | 447 \r |
457 Body2\r | 448 Body2\r |
458 --xxx\r\n"""; | 449 --xxx\r\n"""; |
459 _testParse(message, "xxx", null, [null, null], true); | 450 _testParse(message, "xxx", null, [null, null], true); |
460 } | 451 } |
461 | 452 |
462 void main() { | 453 void main() { |
463 _testParseValid(); | 454 _testParseValid(); |
464 _testParseInvalid(); | 455 _testParseInvalid(); |
465 } | 456 } |
OLD | NEW |