Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(38)

Side by Side Diff: sdk/lib/uri/uri.dart

Issue 16019002: Merge the dart:uri library into dart:core and update the Uri class (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Final cleanup Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « sdk/lib/uri/helpers.dart ('k') | sdk/lib/uri/uri_sources.gypi » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library dart.uri;
6
7 import 'dart:math';
8 import 'dart:utf';
9
10 part 'encode_decode.dart';
11 part 'helpers.dart';
12
13 /**
14 * A parsed URI, inspired by Closure's [URI][] class. Implements [RFC-3986][].
15 * The domain component can either be a hostname, a IPv4 address or an IPv6
16 * address, contained in '[' and ']', following [RFC-2732][]. If the domain
17 * component contains a ':', the String returned from [toString] will have
18 * '[' and ']' around the domain part.
19 * [URI]: http://closure-library.googlecode.com/svn/docs/class_goog_Uri.html
20 * [RFC-3986]: http://tools.ietf.org/html/rfc3986#section-4.3)
21 * [RFC-2732]: http://www.ietf.org/rfc/rfc2732.txt
22 */
23 class Uri {
24 final String scheme;
25 final String userInfo;
26 final String domain;
27 final int port;
28 final String path;
29 final String query;
30 final String fragment;
31
32 static Uri parse(String uri) => new Uri._fromMatch(_splitRe.firstMatch(uri));
33
34 Uri._fromMatch(Match m) :
35 this.fromComponents(scheme: _emptyIfNull(m[_COMPONENT_SCHEME]),
36 userInfo: _emptyIfNull(m[_COMPONENT_USER_INFO]),
37 domain: _eitherOf(
38 m[_COMPONENT_DOMAIN], m[_COMPONENT_DOMAIN_IPV6]),
39 port: _parseIntOrZero(m[_COMPONENT_PORT]),
40 path: _emptyIfNull(m[_COMPONENT_PATH]),
41 query: _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
42 fragment: _emptyIfNull(m[_COMPONENT_FRAGMENT]));
43
44 const Uri.fromComponents({this.scheme: "",
45 this.userInfo: "",
46 this.domain: "",
47 this.port: 0,
48 this.path: "",
49 this.query: "",
50 this.fragment: ""});
51
52 Uri(String uri) : this._fromMatch(_splitRe.firstMatch(uri));
53
54 static String _emptyIfNull(String val) => val != null ? val : '';
55
56 static int _parseIntOrZero(String val) {
57 if (val != null && val != '') {
58 return int.parse(val);
59 } else {
60 return 0;
61 }
62 }
63
64 static String _eitherOf(String val1, String val2) {
65 if (val1 != null) return val1;
66 if (val2 != null) return val2;
67 return '';
68 }
69
70 // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
71 static final RegExp _splitRe = new RegExp(
72 '^'
73 '(?:'
74 '([^:/?#.]+)' // scheme - ignore special characters
75 // used by other URL parts such as :,
76 // ?, /, #, and .
77 ':)?'
78 '(?://'
79 '(?:([^/?#]*)@)?' // userInfo
80 '(?:'
81 r'([\w\d\-\u0100-\uffff.%]*)'
82 // domain - restrict to letters,
83 // digits, dashes, dots, percent
84 // escapes, and unicode characters.
85 '|'
86 // TODO(ajohnsen): Only allow a max number of parts?
87 r'\[([A-Fa-f0-9:.]*)\])'
88 // IPv6 domain - restrict to hex,
89 // dot and colon.
90 '(?::([0-9]+))?' // port
91 ')?'
92 r'([^?#[]+)?' // path
93 r'(?:\?([^#]*))?' // query
94 '(?:#(.*))?' // fragment
95 r'$');
96
97 static const _COMPONENT_SCHEME = 1;
98 static const _COMPONENT_USER_INFO = 2;
99 static const _COMPONENT_DOMAIN = 3;
100 static const _COMPONENT_DOMAIN_IPV6 = 4;
101 static const _COMPONENT_PORT = 5;
102 static const _COMPONENT_PATH = 6;
103 static const _COMPONENT_QUERY_DATA = 7;
104 static const _COMPONENT_FRAGMENT = 8;
105
106 /**
107 * Returns `true` if the URI is absolute.
108 */
109 bool get isAbsolute {
110 if ("" == scheme) return false;
111 if ("" != fragment) return false;
112 return true;
113
114 /* absolute-URI = scheme ":" hier-part [ "?" query ]
115 * hier-part = "//" authority path-abempty
116 * / path-absolute
117 * / path-rootless
118 * / path-empty
119 *
120 * path = path-abempty ; begins with "/" or is empty
121 * / path-absolute ; begins with "/" but not "//"
122 * / path-noscheme ; begins with a non-colon segment
123 * / path-rootless ; begins with a segment
124 * / path-empty ; zero characters
125 *
126 * path-abempty = *( "/" segment )
127 * path-absolute = "/" [ segment-nz *( "/" segment ) ]
128 * path-noscheme = segment-nz-nc *( "/" segment )
129 * path-rootless = segment-nz *( "/" segment )
130 * path-empty = 0<pchar>
131 * segment = *pchar
132 * segment-nz = 1*pchar
133 * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
134 * ; non-zero-length segment without any colon ":"
135 *
136 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
137 */
138 }
139
140 Uri resolve(String uri) {
141 return resolveUri(Uri.parse(uri));
142 }
143
144 Uri resolveUri(Uri reference) {
145 // From RFC 3986.
146 String targetScheme;
147 String targetUserInfo;
148 String targetDomain;
149 int targetPort;
150 String targetPath;
151 String targetQuery;
152 if (reference.scheme != "") {
153 targetScheme = reference.scheme;
154 targetUserInfo = reference.userInfo;
155 targetDomain = reference.domain;
156 targetPort = reference.port;
157 targetPath = removeDotSegments(reference.path);
158 targetQuery = reference.query;
159 } else {
160 if (reference.hasAuthority) {
161 targetUserInfo = reference.userInfo;
162 targetDomain = reference.domain;
163 targetPort = reference.port;
164 targetPath = removeDotSegments(reference.path);
165 targetQuery = reference.query;
166 } else {
167 if (reference.path == "") {
168 targetPath = this.path;
169 if (reference.query != "") {
170 targetQuery = reference.query;
171 } else {
172 targetQuery = this.query;
173 }
174 } else {
175 if (reference.path.startsWith("/")) {
176 targetPath = removeDotSegments(reference.path);
177 } else {
178 targetPath = removeDotSegments(merge(this.path, reference.path));
179 }
180 targetQuery = reference.query;
181 }
182 targetUserInfo = this.userInfo;
183 targetDomain = this.domain;
184 targetPort = this.port;
185 }
186 targetScheme = this.scheme;
187 }
188 return new Uri.fromComponents(scheme: targetScheme,
189 userInfo: targetUserInfo,
190 domain: targetDomain,
191 port: targetPort,
192 path: targetPath,
193 query: targetQuery,
194 fragment: reference.fragment);
195 }
196
197 bool get hasAuthority {
198 return (userInfo != "") || (domain != "") || (port != 0);
199 }
200
201 /**
202 * For http/https schemes returns URI's [origin][] - scheme://domain:port.
203 * For all other schemes throws ArgumentError.
204 * [origin]: http://www.w3.org/TR/2011/WD-html5-20110405/origin-0.html#origin
205 */
206 String get origin {
207 if (scheme == "") {
208 // TODO(aprelev@gmail.com): Use StateException instead
209 throw new ArgumentError("Cannot use origin without a scheme");
210 }
211 if (scheme != "http" && scheme != "https") {
212 // TODO(aprelev@gmail.com): Use StateException instead
213 throw new ArgumentError(
214 "origin is applicable to http/https schemes only. Not \'$scheme\'");
215 }
216 StringBuffer sb = new StringBuffer();
217 sb.write(scheme);
218 sb.write(":");
219 if (domain == null || domain == "") {
220 // TODO(aprelev@gmail.com): Use StateException instead
221 throw new ArgumentError("Cannot use origin without a domain");
222 }
223
224 sb.write("//");
225 sb.write(domain);
226 if (port != 0) {
227 sb.write(":");
228 sb.write(port);
229 }
230 return sb.toString();
231 }
232
233 String toString() {
234 StringBuffer sb = new StringBuffer();
235 _addIfNonEmpty(sb, scheme, scheme, ':');
236 if (hasAuthority || (scheme == "file")) {
237 sb.write("//");
238 _addIfNonEmpty(sb, userInfo, userInfo, "@");
239 sb.write(domain == null ? "null" :
240 domain.contains(':') ? '[$domain]' : domain);
241 if (port != 0) {
242 sb.write(":");
243 sb.write(port.toString());
244 }
245 }
246 sb.write(path == null ? "null" : path);
247 _addIfNonEmpty(sb, query, "?", query);
248 _addIfNonEmpty(sb, fragment, "#", fragment);
249 return sb.toString();
250 }
251
252 bool operator==(other) {
253 if (other is! Uri) return false;
254 Uri uri = other;
255 return scheme == uri.scheme &&
256 userInfo == uri.userInfo &&
257 domain == uri.domain &&
258 port == uri.port &&
259 path == uri.path &&
260 query == uri.query &&
261 fragment == uri.fragment;
262 }
263
264 int get hashCode {
265 int combine(part, current) {
266 // The sum is truncated to 30 bits to make sure it fits into a Smi.
267 return (current * 31 + part.hashCode) & 0x3FFFFFFF;
268 }
269 return combine(scheme, combine(userInfo, combine(domain, combine(port,
270 combine(path, combine(query, combine(fragment, 1)))))));
271 }
272
273 static void _addIfNonEmpty(StringBuffer sb, String test,
274 String first, String second) {
275 if ("" != test) {
276 sb.write(first == null ? "null" : first);
277 sb.write(second == null ? "null" : second);
278 }
279 }
280 }
OLDNEW
« no previous file with comments | « sdk/lib/uri/helpers.dart ('k') | sdk/lib/uri/uri_sources.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698