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