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

Side by Side Diff: dart/utils/uri/uri.dart

Issue 9295043: Create a URI class in utils/ (based on client/util/). (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 8 years, 10 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 | « dart/client/util/utilslib.dart ('k') | no next file » | 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('uri');
6
7 /**
8 * A parsed URI, inspired by:
9 * http://closure-library.googlecode.com/svn/docs/class_goog_Uri.html
10 */
11 class Uri {
12 final String scheme;
13 final String userInfo;
14 final String domain;
15 final int port;
16 final String path;
17 final String query;
18 final String fragment;
19
20 /**
21 * Determines whether a URI is absolute.
22 *
23 * See: http://tools.ietf.org/html/rfc3986#section-4.3
24 */
25 bool isAbsolute() {
26 if ("" == scheme) return false;
27 if ("" != fragment) return false;
28 return true;
29
30 /* absolute-URI = scheme ":" hier-part [ "?" query ]
31 * hier-part = "//" authority path-abempty
32 * / path-absolute
33 * / path-rootless
34 * / path-empty
35 *
36 * path = path-abempty ; begins with "/" or is empty
37 * / path-absolute ; begins with "/" but not "//"
38 * / path-noscheme ; begins with a non-colon segment
39 * / path-rootless ; begins with a segment
40 * / path-empty ; zero characters
41 *
42 * path-abempty = *( "/" segment )
43 * path-absolute = "/" [ segment-nz *( "/" segment ) ]
44 * path-noscheme = segment-nz-nc *( "/" segment )
45 * path-rootless = segment-nz *( "/" segment )
46 * path-empty = 0<pchar>
47 * segment = *pchar
48 * segment-nz = 1*pchar
49 * segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
50 * ; non-zero-length segment without any colon ":"
51 *
52 * pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
53 */
54 }
55
56 Uri resolve(String uri) {
57 return resolveUri(new Uri.fromString(uri));
58 }
59
60 Uri resolveUri(Uri reference) {
61 // From RFC 3986.
62 String targetScheme;
63 String targetUserInfo;
64 String targetDomain;
65 int targetPort;
66 String targetPath;
67 String targetQuery;
68 if (reference.scheme != "") {
69 targetScheme = reference.scheme;
70 targetUserInfo = reference.userInfo;
71 targetDomain = reference.domain;
72 targetPort = reference.port;
73 targetPath = removeDotSegments(reference.path);
74 targetQuery = reference.query;
75 } else {
76 if (reference.hasAuthority()) {
77 targetUserInfo = reference.userInfo;
78 targetDomain = reference.domain;
79 targetPort = reference.port;
80 targetPath = removeDotSegments(reference.path);
81 targetQuery = reference.query;
82 } else {
83 if (reference.path == "") {
84 targetPath = this.path;
85 if (reference.query != "") {
86 targetQuery = reference.query;
87 } else {
88 targetQuery = this.query;
89 }
90 } else {
91 if (reference.path.startsWith("/")) {
92 targetPath = removeDotSegments(reference.path);
93 } else {
94 targetPath = removeDotSegments(merge(this.path, reference.path));
95 }
96 targetQuery = reference.query;
97 }
98 targetUserInfo = this.userInfo;
99 targetDomain = this.domain;
100 targetPort = this.port;
101 }
102 targetScheme = this.scheme;
103 }
104 return new Uri(targetScheme, targetUserInfo, targetDomain, targetPort,
105 targetPath, targetQuery, reference.fragment);
106 }
107
108 bool hasAuthority() {
109 return (userInfo != "") || (domain != "") || (port != 0);
110 }
111
112 String toString() {
113 StringBuffer sb = new StringBuffer();
114 _addIfNonEmpty(sb, scheme, scheme, ':');
115 if (hasAuthority() || (scheme == "file")) {
116 sb.add("//");
117 _addIfNonEmpty(sb, userInfo, userInfo, "@");
118 sb.add(domain);
119 if (port != 0) {
120 sb.add(":");
121 sb.add(port.toString());
122 }
123 }
124 sb.add(path);
125 _addIfNonEmpty(sb, query, "?", query);
126 _addIfNonEmpty(sb, fragment, "#", fragment);
127 return sb.toString();
128 }
129
130 static void _addIfNonEmpty(StringBuffer sb, String test,
131 String first, String second) {
132 if ("" != test) {
133 sb.add(first);
134 sb.add(second);
135 }
136 }
137
138 Uri.fromString(String uri) : this._fromMatch(_splitRe.firstMatch(uri));
139
140 Uri._fromMatch(Match m) : this(_emptyIfNull(m[_COMPONENT_SCHEME]),
141 _emptyIfNull(m[_COMPONENT_USER_INFO]),
142 _emptyIfNull(m[_COMPONENT_DOMAIN]),
143 _parseIntOrZero(m[_COMPONENT_PORT]),
144 _emptyIfNull(m[_COMPONENT_PATH]),
145 _emptyIfNull(m[_COMPONENT_QUERY_DATA]),
146 _emptyIfNull(m[_COMPONENT_FRAGMENT]));
147
148 const Uri([String this.scheme = "", String this.userInfo ="",
149 String this.domain = "", int this.port = 0,
150 String this.path = "", String this.query = "",
151 String this.fragment = ""]);
152
153 static String _emptyIfNull(String val) => val != null ? val : '';
154
155 static int _parseIntOrZero(String val) {
156 if (val !== null && val != '') {
157 return Math.parseInt(val);
158 } else {
159 return 0;
160 }
161 }
162
163 // NOTE: This code was ported from: closure-library/closure/goog/uri/utils.js
164 static RegExp _splitReLazy;
165
166 static RegExp get _splitRe() {
167 if (_splitReLazy == null) {
168 _splitReLazy = new RegExp(
169 '^' +
170 '(?:' +
171 '([^:/?#.]+)' + // scheme - ignore special characters
172 // used by other URL parts such as :,
173 // ?, /, #, and .
174 ':)?' +
175 '(?://' +
176 '(?:([^/?#]*)@)?' + // userInfo
177 '([\\w\\d\\-\\u0100-\\uffff.%]*)' +
178 // domain - restrict to letters,
179 // digits, dashes, dots, percent
180 // escapes, and unicode characters.
181 '(?::([0-9]+))?' + // port
182 ')?' +
183 '([^?#]+)?' + // path
184 '(?:\\?([^#]*))?' + // query
185 '(?:#(.*))?' + // fragment
186 '\$');
187 }
188 return _splitReLazy;
189 }
190
191 static final _COMPONENT_SCHEME = 1;
192 static final _COMPONENT_USER_INFO = 2;
193 static final _COMPONENT_DOMAIN = 3;
194 static final _COMPONENT_PORT = 4;
195 static final _COMPONENT_PATH = 5;
196 static final _COMPONENT_QUERY_DATA = 6;
197 static final _COMPONENT_FRAGMENT = 7;
198 }
199
200 testUri(String uri, bool isAbsolute) {
201 Expect.equals(isAbsolute, new Uri.fromString(uri).isAbsolute());
202 Expect.stringEquals(uri, new Uri.fromString(uri).toString());
203 }
204
205 main() {
ahe 2012/01/29 14:38:00 I'll move this method and testUri to a test case b
206 testUri("http:", true);
207 testUri("file://", true);
208 testUri("file", false);
209 testUri("http://user@example.com:80/fisk?query=89&hest=silas", true);
210 testUri("http://user@example.com:80/fisk?query=89&hest=silas#fragment",
211 false);
212 Expect.stringEquals("http://user@example.com:80/a/b/c?query#fragment",
213 const Uri("http", "user", "example.com", 80, "/a/b/c",
214 "query", "fragment").toString());
215 Expect.stringEquals("null://null@null/a/b/c/?null#null",
216 const Uri(null, null, null, 0, "/a/b/c/",
217 null, null).toString());
218 Expect.stringEquals("file://", new Uri.fromString("file:").toString());
219 Expect.stringEquals("/a/g", removeDotSegments("/a/b/c/./../../g"));
220 Expect.stringEquals("mid/6", removeDotSegments("mid/content=5/../6"));
221 Expect.stringEquals("a/b/e", removeDotSegments("a/b/c/d/../../e"));
222 Expect.stringEquals("a/b/e", removeDotSegments("../a/b/c/d/../../e"));
223 Expect.stringEquals("a/b/e", removeDotSegments("./a/b/c/d/../../e"));
224 Expect.stringEquals("a/b/e", removeDotSegments("../a/b/./c/d/../../e"));
225 Expect.stringEquals("a/b/e", removeDotSegments("./a/b/./c/d/../../e"));
226 Expect.stringEquals("a/b/e/", removeDotSegments("./a/b/./c/d/../../e/."));
227 Expect.stringEquals("a/b/e/", removeDotSegments("./a/b/./c/d/../../e/./."));
228 Expect.stringEquals("a/b/e/", removeDotSegments("./a/b/./c/d/../../e/././."));
229
230 // From RFC 3986.
231 Uri base = new Uri.fromString("http://a/b/c/d;p?q");
232 Expect.stringEquals("g:h", base.resolve("g:h").toString());
233 Expect.stringEquals("http://a/b/c/g", base.resolve("g").toString());
234 Expect.stringEquals("http://a/b/c/g", base.resolve("./g").toString());
235 Expect.stringEquals("http://a/b/c/g/", base.resolve("g/").toString());
236 Expect.stringEquals("http://a/g", base.resolve("/g").toString());
237 Expect.stringEquals("http://g", base.resolve("//g").toString());
238 Expect.stringEquals("http://a/b/c/d;p?y", base.resolve("?y").toString());
239 Expect.stringEquals("http://a/b/c/g?y", base.resolve("g?y").toString());
240 Expect.stringEquals("http://a/b/c/d;p?q#s", base.resolve("#s").toString());
241 Expect.stringEquals("http://a/b/c/g#s", base.resolve("g#s").toString());
242 Expect.stringEquals("http://a/b/c/g?y#s", base.resolve("g?y#s").toString());
243 Expect.stringEquals("http://a/b/c/;x", base.resolve(";x").toString());
244 Expect.stringEquals("http://a/b/c/g;x", base.resolve("g;x").toString());
245 Expect.stringEquals("http://a/b/c/g;x?y#s",
246 base.resolve("g;x?y#s").toString());
247 Expect.stringEquals("http://a/b/c/d;p?q", base.resolve("").toString());
248 Expect.stringEquals("http://a/b/c/", base.resolve(".").toString());
249 Expect.stringEquals("http://a/b/c/", base.resolve("./").toString());
250 Expect.stringEquals("http://a/b/", base.resolve("..").toString());
251 Expect.stringEquals("http://a/b/", base.resolve("../").toString());
252 Expect.stringEquals("http://a/b/g", base.resolve("../g").toString());
253 Expect.stringEquals("http://a/", base.resolve("../..").toString());
254 Expect.stringEquals("http://a/", base.resolve("../../").toString());
255 Expect.stringEquals("http://a/g", base.resolve("../../g").toString());
256 Expect.stringEquals("http://a/g", base.resolve("../../../g").toString());
257 Expect.stringEquals("http://a/g", base.resolve("../../../../g").toString());
258 Expect.stringEquals("http://a/g", base.resolve("/./g").toString());
259 Expect.stringEquals("http://a/g", base.resolve("/../g").toString());
260 Expect.stringEquals("http://a/b/c/g.", base.resolve("g.").toString());
261 Expect.stringEquals("http://a/b/c/.g", base.resolve(".g").toString());
262 Expect.stringEquals("http://a/b/c/g..", base.resolve("g..").toString());
263 Expect.stringEquals("http://a/b/c/..g", base.resolve("..g").toString());
264 Expect.stringEquals("http://a/b/g", base.resolve("./../g").toString());
265 Expect.stringEquals("http://a/b/c/g/", base.resolve("./g/.").toString());
266 Expect.stringEquals("http://a/b/c/g/h", base.resolve("g/./h").toString());
267 Expect.stringEquals("http://a/b/c/h", base.resolve("g/../h").toString());
268 Expect.stringEquals("http://a/b/c/g;x=1/y",
269 base.resolve("g;x=1/./y").toString());
270 Expect.stringEquals("http://a/b/c/y", base.resolve("g;x=1/../y").toString());
271 Expect.stringEquals("http://a/b/c/g?y/./x",
272 base.resolve("g?y/./x").toString());
273 Expect.stringEquals("http://a/b/c/g?y/../x",
274 base.resolve("g?y/../x").toString());
275 Expect.stringEquals("http://a/b/c/g#s/./x",
276 base.resolve("g#s/./x").toString());
277 Expect.stringEquals("http://a/b/c/g#s/../x",
278 base.resolve("g#s/../x").toString());
Bill Hesse 2012/01/31 10:37:57 Should you also test parameters in the path elemen
ahe 2012/01/31 11:43:00 That's being tested on lines: 243-246 269-270 Bu
279 Expect.stringEquals("http:g", base.resolve("http:g").toString());
280 }
281
282 String merge(String base, String reference) {
283 if (base == "") return "/$reference";
284 return base.substring(0, base.lastIndexOf("/") + 1) + "$reference";
285 }
286
287 String removeDotSegments(String path) {
288 List<String> output = [];
289 bool appendSlash = false;
290 for (String segment in path.split("/")) {
291 appendSlash = false;
292 if (segment == "..") {
293 if (!output.isEmpty() &&
294 ((output.length != 1) || (output[0] != ""))) output.removeLast();
295 appendSlash = true;
296 } else if ("." == segment) {
297 appendSlash = true;
298 } else {
299 output.add(segment);
300 }
301 }
302 if (appendSlash) output.add("");
303 return Strings.join(output, "/");
304 }
OLDNEW
« no previous file with comments | « dart/client/util/utilslib.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698