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 10 matching lines...) Expand all Loading... | |
21 | 21 |
22 _HttpHeaders(this.protocolVersion, | 22 _HttpHeaders(this.protocolVersion, |
23 {int defaultPortForScheme: HttpClient.DEFAULT_HTTP_PORT}) | 23 {int defaultPortForScheme: HttpClient.DEFAULT_HTTP_PORT}) |
24 : _headers = new HashMap<String, List<String>>(), | 24 : _headers = new HashMap<String, List<String>>(), |
25 _defaultPortForScheme = defaultPortForScheme { | 25 _defaultPortForScheme = defaultPortForScheme { |
26 if (protocolVersion == "1.0") { | 26 if (protocolVersion == "1.0") { |
27 _persistentConnection = false; | 27 _persistentConnection = false; |
28 } | 28 } |
29 } | 29 } |
30 | 30 |
31 List<String> operator[](String name) => _headers[name.toLowerCase()]; | 31 List<String> operator[](String name) => _headers[_toLowerCase(name)]; |
32 | 32 |
33 String value(String name) { | 33 String value(String name) { |
34 name = name.toLowerCase(); | 34 name = _toLowerCase(name); |
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(_toLowerCase(name), value); |
46 } | 46 } |
47 | 47 |
48 void _addAll(String name, value) { | 48 void _addAll(String name, value) { |
49 if (value is List) { | 49 if (value is List) { |
50 value.forEach((v) => _add(name, v)); | 50 value.forEach((v) => _add(name, v)); |
51 } else { | 51 } else { |
52 _add(name, value); | 52 _add(name, value); |
53 } | 53 } |
54 } | 54 } |
55 | 55 |
56 void set(String name, Object value) { | 56 void set(String name, Object value) { |
57 _checkMutable(); | 57 _checkMutable(); |
58 name = name.toLowerCase(); | 58 name = _toLowerCase(name); |
59 _headers.remove(name); | 59 _headers.remove(name); |
60 _addAll(name, value); | 60 _addAll(name, value); |
61 } | 61 } |
62 | 62 |
63 void remove(String name, Object value) { | 63 void remove(String name, Object value) { |
64 _checkMutable(); | 64 _checkMutable(); |
65 name = name.toLowerCase(); | 65 name = _toLowerCase(name); |
66 List<String> values = _headers[name]; | 66 List<String> values = _headers[name]; |
67 if (values != null) { | 67 if (values != null) { |
68 int index = values.indexOf(value); | 68 int index = values.indexOf(value); |
69 if (index != -1) { | 69 if (index != -1) { |
70 values.removeRange(index, index + 1); | 70 values.removeRange(index, index + 1); |
71 } | 71 } |
72 if (values.length == 0) _headers.remove(name); | 72 if (values.length == 0) _headers.remove(name); |
73 } | 73 } |
74 } | 74 } |
75 | 75 |
76 void removeAll(String name) { | 76 void removeAll(String name) { |
77 _checkMutable(); | 77 _checkMutable(); |
78 name = name.toLowerCase(); | 78 name = _toLowerCase(name); |
79 _headers.remove(name); | 79 _headers.remove(name); |
80 } | 80 } |
81 | 81 |
82 void forEach(void f(String name, List<String> values)) { | 82 void forEach(void f(String name, List<String> values)) { |
83 _headers.forEach(f); | 83 _headers.forEach(f); |
84 } | 84 } |
85 | 85 |
86 void noFolding(String name) { | 86 void noFolding(String name) { |
87 if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>(); | 87 if (_noFoldingHeaders == null) _noFoldingHeaders = new List<String>(); |
88 _noFoldingHeaders.add(name); | 88 _noFoldingHeaders.add(name); |
(...skipping 233 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
322 } | 322 } |
323 } | 323 } |
324 } | 324 } |
325 _set(HttpHeaders.HOST, value); | 325 _set(HttpHeaders.HOST, value); |
326 } else { | 326 } else { |
327 throw new HttpException("Unexpected type for header named $name"); | 327 throw new HttpException("Unexpected type for header named $name"); |
328 } | 328 } |
329 break; | 329 break; |
330 | 330 |
331 case HttpHeaders.CONNECTION: | 331 case HttpHeaders.CONNECTION: |
332 var lowerCaseValue = value.toLowerCase(); | 332 var lowerCaseValue = _toLowerCase(value); |
333 if (lowerCaseValue == 'close') { | 333 if (lowerCaseValue == 'close') { |
334 _persistentConnection = false; | 334 _persistentConnection = false; |
335 } else if (lowerCaseValue == 'keep-alive') { | 335 } else if (lowerCaseValue == 'keep-alive') { |
336 _persistentConnection = true; | 336 _persistentConnection = true; |
337 } | 337 } |
338 _addValue(name, value); | 338 _addValue(name, value); |
339 break; | 339 break; |
340 | 340 |
341 case HttpHeaders.CONTENT_TYPE: | 341 case HttpHeaders.CONTENT_TYPE: |
342 _set(HttpHeaders.CONTENT_TYPE, value); | 342 _set(HttpHeaders.CONTENT_TYPE, value); |
(...skipping 11 matching lines...) Expand all Loading... | |
354 _headers[name] = values; | 354 _headers[name] = values; |
355 } | 355 } |
356 if (value is DateTime) { | 356 if (value is DateTime) { |
357 values.add(HttpDate.format(value)); | 357 values.add(HttpDate.format(value)); |
358 } else { | 358 } else { |
359 values.add(value.toString()); | 359 values.add(value.toString()); |
360 } | 360 } |
361 } | 361 } |
362 | 362 |
363 void _set(String name, String value) { | 363 void _set(String name, String value) { |
364 assert(name == name.toLowerCase()); | 364 assert(name == _toLowerCase(name)); |
365 List<String> values = new List<String>(); | 365 List<String> values = new List<String>(); |
366 _headers[name] = values; | 366 _headers[name] = values; |
367 values.add(value); | 367 values.add(value); |
368 } | 368 } |
369 | 369 |
370 _checkMutable() { | 370 _checkMutable() { |
371 if (!_mutable) throw new HttpException("HTTP headers are not mutable"); | 371 if (!_mutable) throw new HttpException("HTTP headers are not mutable"); |
372 } | 372 } |
373 | 373 |
374 _updateHostHeader() { | 374 _updateHostHeader() { |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
511 continue; | 511 continue; |
512 } | 512 } |
513 } | 513 } |
514 } | 514 } |
515 List<String> values = _headers[HttpHeaders.COOKIE]; | 515 List<String> values = _headers[HttpHeaders.COOKIE]; |
516 if (values != null) { | 516 if (values != null) { |
517 values.forEach((headerValue) => parseCookieString(headerValue)); | 517 values.forEach((headerValue) => parseCookieString(headerValue)); |
518 } | 518 } |
519 return cookies; | 519 return cookies; |
520 } | 520 } |
521 | |
522 static String _toLowerCase(String str) { | |
523 int toLowerCase(int byte) { | |
524 final int aCode = "A".codeUnitAt(0); | |
kevmoo
2014/03/24 17:50:16
Is this only run the first time the method is call
Anders Johnsen
2014/03/24 19:02:59
When looking at the SSA of the VM, it's heavily in
kevmoo
2014/03/24 19:04:05
If they are only used in http_headers, just leave
Anders Johnsen
2014/03/24 19:05:04
Yeah, but so far there is two places it's used (pa
Søren Gjesse
2014/03/25 07:54:25
Yes, as you have noticed we have the _CharCodes co
| |
525 final int zCode = "Z".codeUnitAt(0); | |
526 final int delta = "a".codeUnitAt(0) - aCode; | |
527 return (aCode <= byte && byte <= zCode) ? byte + delta : byte; | |
528 } | |
529 | |
530 final length = str.length; | |
531 var result = new List(length); | |
532 for (int i = 0; i < length; i++) { | |
533 int codeUnit = str.codeUnitAt(i); | |
534 if (codeUnit > 127) { | |
535 throw new HttpException("HTTP header must be in ASCII encoding"); | |
536 } | |
537 result[i] = toLowerCase(codeUnit); | |
Søren Gjesse
2014/03/25 07:54:25
I don't see the need to a function call here (even
Anders Johnsen
2014/03/25 13:33:40
Pulled out and shared across all of IO.
| |
538 } | |
539 return new String.fromCharCodes(result); | |
540 } | |
521 } | 541 } |
522 | 542 |
523 | 543 |
524 class _HeaderValue implements HeaderValue { | 544 class _HeaderValue implements HeaderValue { |
525 String _value; | 545 String _value; |
526 _UnmodifiableMap<String, String> _parameters; | 546 _UnmodifiableMap<String, String> _parameters; |
527 | 547 |
528 _HeaderValue([String this._value = "", Map<String, String> parameters]) { | 548 _HeaderValue([String this._value = "", Map<String, String> parameters]) { |
529 if (parameters != null) { | 549 if (parameters != null) { |
530 _parameters = | 550 _parameters = |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
892 void clear() { | 912 void clear() { |
893 throw new UnsupportedError("Cannot modify an unmodifiable map"); | 913 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
894 } | 914 } |
895 void forEach(void f(K key, V value)) => _map.forEach(f); | 915 void forEach(void f(K key, V value)) => _map.forEach(f); |
896 Iterable<K> get keys => _map.keys; | 916 Iterable<K> get keys => _map.keys; |
897 Iterable<V> get values => _map.values; | 917 Iterable<V> get values => _map.values; |
898 int get length => _map.length; | 918 int get length => _map.length; |
899 bool get isEmpty => _map.isEmpty; | 919 bool get isEmpty => _map.isEmpty; |
900 bool get isNotEmpty => _map.isNotEmpty; | 920 bool get isNotEmpty => _map.isNotEmpty; |
901 } | 921 } |
OLD | NEW |