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 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 class _HttpHeaders implements HttpHeaders { | 7 class _HttpHeaders implements HttpHeaders { |
8 final Map<String, List<String>> _headers; | 8 final Map<String, List<String>> _headers; |
9 final String protocolVersion; | 9 final String protocolVersion; |
10 | 10 |
(...skipping 24 matching lines...) Expand all Loading... |
35 List<String> values = _headers[name]; | 35 List<String> values = _headers[name]; |
36 if (values == null) return null; | 36 if (values == null) return null; |
37 if (values.length > 1) { | 37 if (values.length > 1) { |
38 throw new HttpException("More than one value for header $name"); | 38 throw new HttpException("More than one value for header $name"); |
39 } | 39 } |
40 return values[0]; | 40 return values[0]; |
41 } | 41 } |
42 | 42 |
43 void add(String name, value) { | 43 void add(String name, value) { |
44 _checkMutable(); | 44 _checkMutable(); |
45 _addAll(name.toLowerCase(), value); | 45 _addAll(_validateField(name), value); |
46 } | 46 } |
47 | 47 |
48 void _addAll(String name, value) { | 48 void _addAll(String name, value) { |
49 if (value is List) { | 49 assert(name == _validateField(name)); |
50 value.forEach((v) => _add(name, v)); | 50 if (value is Iterable) { |
| 51 for (var v in value) { |
| 52 _add(name, _validateValue(v)); |
| 53 } |
51 } else { | 54 } else { |
52 _add(name, value); | 55 _add(name, _validateValue(value)); |
53 } | 56 } |
54 } | 57 } |
55 | 58 |
56 void set(String name, Object value) { | 59 void set(String name, Object value) { |
57 _checkMutable(); | 60 _checkMutable(); |
58 name = name.toLowerCase(); | 61 name = _validateField(name); |
59 _headers.remove(name); | 62 _headers.remove(name); |
60 _addAll(name, value); | 63 _addAll(name, value); |
61 } | 64 } |
62 | 65 |
63 void remove(String name, Object value) { | 66 void remove(String name, Object value) { |
64 _checkMutable(); | 67 _checkMutable(); |
65 name = name.toLowerCase(); | 68 name = _validateField(name); |
| 69 value = _validateValue(value); |
66 List<String> values = _headers[name]; | 70 List<String> values = _headers[name]; |
67 if (values != null) { | 71 if (values != null) { |
68 int index = values.indexOf(value); | 72 int index = values.indexOf(value); |
69 if (index != -1) { | 73 if (index != -1) { |
70 values.removeRange(index, index + 1); | 74 values.removeRange(index, index + 1); |
71 } | 75 } |
72 if (values.length == 0) _headers.remove(name); | 76 if (values.length == 0) _headers.remove(name); |
73 } | 77 } |
74 } | 78 } |
75 | 79 |
76 void removeAll(String name) { | 80 void removeAll(String name) { |
77 _checkMutable(); | 81 _checkMutable(); |
78 name = name.toLowerCase(); | 82 name = _validateField(name); |
79 _headers.remove(name); | 83 _headers.remove(name); |
80 } | 84 } |
81 | 85 |
82 void forEach(void f(String name, List<String> values)) { | 86 void forEach(void f(String name, List<String> values)) { |
83 _headers.forEach(f); | 87 _headers.forEach(f); |
84 } | 88 } |
85 | 89 |
86 void noFolding(String name) { | 90 void noFolding(String name) { |
87 if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>(); | 91 if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>(); |
88 _noFoldingHeaders.add(name); | 92 _noFoldingHeaders.add(name); |
(...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
243 } | 247 } |
244 } | 248 } |
245 | 249 |
246 void set contentType(ContentType contentType) { | 250 void set contentType(ContentType contentType) { |
247 _checkMutable(); | 251 _checkMutable(); |
248 _set(HttpHeaders.CONTENT_TYPE, contentType.toString()); | 252 _set(HttpHeaders.CONTENT_TYPE, contentType.toString()); |
249 } | 253 } |
250 | 254 |
251 // [name] must be a lower-case version of the name. | 255 // [name] must be a lower-case version of the name. |
252 void _add(String name, value) { | 256 void _add(String name, value) { |
253 assert(name == name.toLowerCase()); | 257 assert(name == _validateField(name)); |
254 // Use the length as index on what method to call. This is notable | 258 // Use the length as index on what method to call. This is notable |
255 // faster than computing hash and looking up in a hash-map. | 259 // faster than computing hash and looking up in a hash-map. |
256 switch (name.length) { | 260 switch (name.length) { |
257 case 4: | 261 case 4: |
258 if (HttpHeaders.DATE == name) { | 262 if (HttpHeaders.DATE == name) { |
259 _addDate(name, value); | 263 _addDate(name, value); |
260 return; | 264 return; |
261 } | 265 } |
262 if (HttpHeaders.HOST == name) { | 266 if (HttpHeaders.HOST == name) { |
263 _addHost(name, value); | 267 _addHost(name, value); |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 } | 396 } |
393 | 397 |
394 void _addValue(String name, Object value) { | 398 void _addValue(String name, Object value) { |
395 List<String> values = _headers[name]; | 399 List<String> values = _headers[name]; |
396 if (values == null) { | 400 if (values == null) { |
397 values = new List<String>(); | 401 values = new List<String>(); |
398 _headers[name] = values; | 402 _headers[name] = values; |
399 } | 403 } |
400 if (value is DateTime) { | 404 if (value is DateTime) { |
401 values.add(HttpDate.format(value)); | 405 values.add(HttpDate.format(value)); |
| 406 } else if (value is String) { |
| 407 values.add(value); |
402 } else { | 408 } else { |
403 values.add(value.toString()); | 409 values.add(_validateValue(value.toString())); |
404 } | 410 } |
405 } | 411 } |
406 | 412 |
407 void _set(String name, String value) { | 413 void _set(String name, String value) { |
408 assert(name == name.toLowerCase()); | 414 assert(name == _validateField(name)); |
409 List<String> values = new List<String>(); | 415 List<String> values = new List<String>(); |
410 _headers[name] = values; | 416 _headers[name] = values; |
411 values.add(value); | 417 values.add(value); |
412 } | 418 } |
413 | 419 |
414 _checkMutable() { | 420 _checkMutable() { |
415 if (!_mutable) throw new HttpException("HTTP headers are not mutable"); | 421 if (!_mutable) throw new HttpException("HTTP headers are not mutable"); |
416 } | 422 } |
417 | 423 |
418 _updateHostHeader() { | 424 _updateHostHeader() { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
555 continue; | 561 continue; |
556 } | 562 } |
557 } | 563 } |
558 } | 564 } |
559 List<String> values = _headers[HttpHeaders.COOKIE]; | 565 List<String> values = _headers[HttpHeaders.COOKIE]; |
560 if (values != null) { | 566 if (values != null) { |
561 values.forEach((headerValue) => parseCookieString(headerValue)); | 567 values.forEach((headerValue) => parseCookieString(headerValue)); |
562 } | 568 } |
563 return cookies; | 569 return cookies; |
564 } | 570 } |
| 571 |
| 572 static String _validateField(String field) { |
| 573 for (var i = 0; i < field.length; i++) { |
| 574 if (!_HttpParser._isTokenChar(field.codeUnitAt(i))) { |
| 575 throw new FormatException( |
| 576 "Invalid HTTP header field name: ${JSON.encode(field)}"); |
| 577 } |
| 578 } |
| 579 return field.toLowerCase(); |
| 580 } |
| 581 |
| 582 static _validateValue(value) { |
| 583 if (value is! String) return value; |
| 584 for (var i = 0; i < value.length; i++) { |
| 585 if (!_HttpParser._isValueChar(value.codeUnitAt(i))) { |
| 586 throw new FormatException( |
| 587 "Invalid HTTP header field value: ${JSON.encode(value)}"); |
| 588 } |
| 589 } |
| 590 return value; |
| 591 } |
565 } | 592 } |
566 | 593 |
567 | 594 |
568 class _HeaderValue implements HeaderValue { | 595 class _HeaderValue implements HeaderValue { |
569 String _value; | 596 String _value; |
570 Map<String, String> _parameters; | 597 Map<String, String> _parameters; |
571 Map<String, String> _unmodifiableParameters; | 598 Map<String, String> _unmodifiableParameters; |
572 | 599 |
573 _HeaderValue([String this._value = "", Map<String, String> parameters]) { | 600 _HeaderValue([String this._value = "", Map<String, String> parameters]) { |
574 if (parameters != null) { | 601 if (parameters != null) { |
(...skipping 333 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
908 (codeUnit >= 0x23 && codeUnit <= 0x2B) || | 935 (codeUnit >= 0x23 && codeUnit <= 0x2B) || |
909 (codeUnit >= 0x2D && codeUnit <= 0x3A) || | 936 (codeUnit >= 0x2D && codeUnit <= 0x3A) || |
910 (codeUnit >= 0x3C && codeUnit <= 0x5B) || | 937 (codeUnit >= 0x3C && codeUnit <= 0x5B) || |
911 (codeUnit >= 0x5D && codeUnit <= 0x7E))) { | 938 (codeUnit >= 0x5D && codeUnit <= 0x7E))) { |
912 throw new FormatException( | 939 throw new FormatException( |
913 "Invalid character in cookie value, code unit: '$codeUnit'"); | 940 "Invalid character in cookie value, code unit: '$codeUnit'"); |
914 } | 941 } |
915 } | 942 } |
916 } | 943 } |
917 } | 944 } |
OLD | NEW |