OLD | NEW |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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.core; | 5 part of dart.core; |
6 | 6 |
7 /** | 7 /** |
8 * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986. | 8 * A parsed URI, as specified by RFC-3986, http://tools.ietf.org/html/rfc3986. |
9 */ | 9 */ |
10 class Uri { | 10 class Uri { |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 | 75 |
76 /** | 76 /** |
77 * Returns the fragment identifier component. | 77 * Returns the fragment identifier component. |
78 * | 78 * |
79 * Returns the empty string if there is no fragment identifier | 79 * Returns the empty string if there is no fragment identifier |
80 * component. | 80 * component. |
81 */ | 81 */ |
82 final String fragment; | 82 final String fragment; |
83 | 83 |
84 /** | 84 /** |
| 85 * Cache the computed return value of [pathSegements]. |
| 86 */ |
| 87 List<String> _pathSegments; |
| 88 |
| 89 /** |
| 90 * Cache the computed return value of [queryParameters]. |
| 91 */ |
| 92 Map<String, String> _queryParameters; |
| 93 |
| 94 /** |
85 * Creates a new URI object by parsing a URI string. | 95 * Creates a new URI object by parsing a URI string. |
86 */ | 96 */ |
87 static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri)); | 97 static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri)); |
88 | 98 |
89 Uri._fromMatch(Match m) : | 99 Uri._fromMatch(Match m) : |
90 this(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]), | 100 this(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]), |
91 userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]), | 101 userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]), |
92 host: _eitherOf( | 102 host: _eitherOf( |
93 m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]), | 103 m[_COMPONENT_HOST], m[_COMPONENT_HOST_IPV6]), |
94 port: _parseIntOrZero(m[_COMPONENT_PORT]), | 104 port: _parseIntOrZero(m[_COMPONENT_PORT]), |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
160 _port = 0; | 170 _port = 0; |
161 } else { | 171 } else { |
162 _port = port; | 172 _port = port; |
163 } | 173 } |
164 } | 174 } |
165 | 175 |
166 /* | 176 /* |
167 * Returns the URI path split into its segments. Each of the | 177 * Returns the URI path split into its segments. Each of the |
168 * segments in the returned list have been decoded. If the path is | 178 * segments in the returned list have been decoded. If the path is |
169 * empty the empty list will be returned. | 179 * empty the empty list will be returned. |
| 180 * |
| 181 * The returned list is immutable and will throw [StateError] on any |
| 182 * calls that would mutate it. |
170 */ | 183 */ |
171 List<String> get pathSegments { | 184 List<String> get pathSegments { |
172 if (path == "") return const<String>[]; | 185 if (_pathSegments == null) { |
173 return path.split("/").map(Uri.decodeComponent).toList(growable: false); | 186 _pathSegments = new UnmodifiableListView( |
| 187 path == "" ? const<String>[] |
| 188 : path.split("/") |
| 189 .map(Uri.decodeComponent) |
| 190 .toList(growable: false)); |
| 191 } |
| 192 return _pathSegments; |
174 } | 193 } |
175 | 194 |
176 /* | 195 /* |
177 * Returns the URI query split into a map according to the rules | 196 * Returns the URI query split into a map according to the rules |
178 * specified for FORM post in the HTML 4.01 specification. Each key | 197 * specified for FORM post in the HTML 4.01 specification. Each key |
179 * and value in the returned map have been decoded. If there is no | 198 * and value in the returned map have been decoded. If there is no |
180 * query the empty map will be returned. | 199 * query the empty map will be returned. |
| 200 * |
| 201 * The returned map is immutable and will throw [StateError] on any |
| 202 * calls that would mutate it. |
181 */ | 203 */ |
182 Map<String, String> get queryParameters { | 204 Map<String, String> get queryParameters { |
183 return query.split("&").fold({}, (map, element) { | 205 if (_queryParameters == null) { |
| 206 var map; |
| 207 map = query.split("&").fold({}, (map, element) { |
184 int index = element.indexOf("="); | 208 int index = element.indexOf("="); |
185 if (index == -1) { | 209 if (index == -1) { |
186 if (!element.isEmpty) map[element] = ""; | 210 if (!element.isEmpty) map[element] = ""; |
187 } else if (index != 0) { | 211 } else if (index != 0) { |
188 var key = element.substring(0, index); | 212 var key = element.substring(0, index); |
189 var value = element.substring(index + 1); | 213 var value = element.substring(index + 1); |
190 map[Uri.decodeQueryComponent(key)] = decodeQueryComponent(value); | 214 map[Uri.decodeQueryComponent(key)] = decodeQueryComponent(value); |
191 } | 215 } |
192 return map; | 216 return map; |
193 }); | 217 }); |
| 218 _queryParameters = new _UnmodifiableMap(map); |
| 219 } |
| 220 return _queryParameters; |
194 } | 221 } |
195 | 222 |
196 static String _makeScheme(String scheme) { | 223 static String _makeScheme(String scheme) { |
197 bool isSchemeLowerCharacter(int ch) { | 224 bool isSchemeLowerCharacter(int ch) { |
198 return ch < 128 && | 225 return ch < 128 && |
199 ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | 226 ((_schemeLowerTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); |
200 } | 227 } |
201 | 228 |
202 bool isSchemeCharacter(int ch) { | 229 bool isSchemeCharacter(int ch) { |
203 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); | 230 return ch < 128 && ((_schemeTable[ch >> 4] & (1 << (ch & 0x0f))) != 0); |
(...skipping 733 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
937 0xafff, // 0x30 - 0x3f 1111111111110101 | 964 0xafff, // 0x30 - 0x3f 1111111111110101 |
938 // @ABCDEFGHIJKLMNO | 965 // @ABCDEFGHIJKLMNO |
939 0xffff, // 0x40 - 0x4f 1111111111111111 | 966 0xffff, // 0x40 - 0x4f 1111111111111111 |
940 // PQRSTUVWXYZ _ | 967 // PQRSTUVWXYZ _ |
941 0x87ff, // 0x50 - 0x5f 1111111111100001 | 968 0x87ff, // 0x50 - 0x5f 1111111111100001 |
942 // abcdefghijklmno | 969 // abcdefghijklmno |
943 0xfffe, // 0x60 - 0x6f 0111111111111111 | 970 0xfffe, // 0x60 - 0x6f 0111111111111111 |
944 // pqrstuvwxyz ~ | 971 // pqrstuvwxyz ~ |
945 0x47ff]; // 0x70 - 0x7f 1111111111100010 | 972 0x47ff]; // 0x70 - 0x7f 1111111111100010 |
946 } | 973 } |
| 974 |
| 975 class _UnmodifiableMap<K, V> implements Map<K, V> { |
| 976 final Map _map; |
| 977 const _UnmodifiableMap(this._map); |
| 978 |
| 979 bool containsValue(V value) => _map.containsValue(value); |
| 980 bool containsKey(K key) => _map.containsKey(key); |
| 981 V operator [](K key) => _map[key]; |
| 982 void operator []=(K key, V value) { |
| 983 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
| 984 } |
| 985 V putIfAbsent(K key, V ifAbsent()) { |
| 986 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
| 987 } |
| 988 V remove(K key) { |
| 989 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
| 990 } |
| 991 void clear() { |
| 992 throw new UnsupportedError("Cannot modify an unmodifiable map"); |
| 993 } |
| 994 void forEach(void f(K key, V value)) => _map.forEach(f); |
| 995 Iterable<K> get keys => _map.keys; |
| 996 Iterable<V> get values => _map.values; |
| 997 int get length => _map.length; |
| 998 bool get isEmpty => _map.isEmpty; |
| 999 bool get isNotEmpty => _map.isNotEmpty; |
| 1000 } |
OLD | NEW |