OLD | NEW |
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2016, 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 #include "vm/uri.h" | 5 #include "vm/uri.h" |
6 | 6 |
7 #include "vm/zone.h" | 7 #include "vm/zone.h" |
8 | 8 |
9 namespace dart { | 9 namespace dart { |
10 | 10 |
11 static bool IsUnreservedChar(intptr_t value) { | 11 static bool IsUnreservedChar(intptr_t value) { |
12 return ((value >= 'a' && value <= 'z') || | 12 return ((value >= 'a' && value <= 'z') || (value >= 'A' && value <= 'Z') || |
13 (value >= 'A' && value <= 'Z') || | 13 (value >= '0' && value <= '9') || value == '-' || value == '.' || |
14 (value >= '0' && value <= '9') || | 14 value == '_' || value == '~'); |
15 value == '-' || | |
16 value == '.' || | |
17 value == '_' || | |
18 value == '~'); | |
19 } | 15 } |
20 | 16 |
21 | 17 |
22 static bool IsDelimiter(intptr_t value) { | 18 static bool IsDelimiter(intptr_t value) { |
23 switch (value) { | 19 switch (value) { |
24 case ':': case '/': case '?': case '#': | 20 case ':': |
25 case '[': case ']': case '@': case '!': | 21 case '/': |
26 case '$': case '&': case '\'': case '(': | 22 case '?': |
27 case ')': case '*': case '+': case ',': | 23 case '#': |
28 case ';': case '=': | 24 case '[': |
| 25 case ']': |
| 26 case '@': |
| 27 case '!': |
| 28 case '$': |
| 29 case '&': |
| 30 case '\'': |
| 31 case '(': |
| 32 case ')': |
| 33 case '*': |
| 34 case '+': |
| 35 case ',': |
| 36 case ';': |
| 37 case '=': |
29 return true; | 38 return true; |
30 default: | 39 default: |
31 return false; | 40 return false; |
32 } | 41 } |
33 } | 42 } |
34 | 43 |
35 | 44 |
36 static bool IsHexDigit(char value) { | 45 static bool IsHexDigit(char value) { |
37 return ((value >= '0' && value <= '9') || | 46 return ((value >= '0' && value <= '9') || (value >= 'A' && value <= 'F') || |
38 (value >= 'A' && value <= 'F') || | |
39 (value >= 'a' && value <= 'f')); | 47 (value >= 'a' && value <= 'f')); |
40 } | 48 } |
41 | 49 |
42 | 50 |
43 static int HexValue(char digit) { | 51 static int HexValue(char digit) { |
44 if ((digit >= '0' && digit <= '9')) { | 52 if ((digit >= '0' && digit <= '9')) { |
45 return digit - '0'; | 53 return digit - '0'; |
46 } | 54 } |
47 if ((digit >= 'A' && digit <= 'F')) { | 55 if ((digit >= 'A' && digit <= 'F')) { |
48 return digit - 'A' + 10; | 56 return digit - 'A' + 10; |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
217 } else { | 225 } else { |
218 parsed_uri->fragment = NULL; | 226 parsed_uri->fragment = NULL; |
219 } | 227 } |
220 | 228 |
221 // The first '?' or '#' separates the hierarchical part from the | 229 // The first '?' or '#' separates the hierarchical part from the |
222 // optional query. | 230 // optional query. |
223 const char* question_pos = rest + strcspn(rest, "?#"); | 231 const char* question_pos = rest + strcspn(rest, "?#"); |
224 if (*question_pos == '?') { | 232 if (*question_pos == '?') { |
225 // There is a query part. | 233 // There is a query part. |
226 const char* query_start = question_pos + 1; | 234 const char* query_start = question_pos + 1; |
227 parsed_uri->query = | 235 parsed_uri->query = NormalizeEscapes(query_start, (hash_pos - query_start)); |
228 NormalizeEscapes(query_start, (hash_pos - query_start)); | |
229 } else { | 236 } else { |
230 parsed_uri->query = NULL; | 237 parsed_uri->query = NULL; |
231 } | 238 } |
232 | 239 |
233 const char* path_start = rest; | 240 const char* path_start = rest; |
234 if (rest[0] == '/' && rest[1] == '/') { | 241 if (rest[0] == '/' && rest[1] == '/') { |
235 // There is an authority part. | 242 // There is an authority part. |
236 const char* authority_start = rest + 2; // 2 for '//'. | 243 const char* authority_start = rest + 2; // 2 for '//'. |
237 | 244 |
238 intptr_t authority_len = | 245 intptr_t authority_len = ParseAuthority(authority_start, parsed_uri); |
239 ParseAuthority(authority_start, parsed_uri); | |
240 if (authority_len < 0) { | 246 if (authority_len < 0) { |
241 ClearParsedUri(parsed_uri); | 247 ClearParsedUri(parsed_uri); |
242 return false; | 248 return false; |
243 } | 249 } |
244 path_start = authority_start + authority_len; | 250 path_start = authority_start + authority_len; |
245 } else { | 251 } else { |
246 parsed_uri->userinfo = NULL; | 252 parsed_uri->userinfo = NULL; |
247 parsed_uri->host = NULL; | 253 parsed_uri->host = NULL; |
248 parsed_uri->port = NULL; | 254 parsed_uri->port = NULL; |
249 } | 255 } |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
360 if (last_slash == NULL) { | 366 if (last_slash == NULL) { |
361 // There is no slash in the base_path. Return the ref_path unchanged. | 367 // There is no slash in the base_path. Return the ref_path unchanged. |
362 return ref_path; | 368 return ref_path; |
363 } | 369 } |
364 | 370 |
365 // We found a '/' in the base_path. Cut off everything after it and | 371 // We found a '/' in the base_path. Cut off everything after it and |
366 // add the ref_path. | 372 // add the ref_path. |
367 intptr_t truncated_base_len = last_slash - base_path; | 373 intptr_t truncated_base_len = last_slash - base_path; |
368 intptr_t ref_path_len = strlen(ref_path); | 374 intptr_t ref_path_len = strlen(ref_path); |
369 intptr_t len = truncated_base_len + ref_path_len + 1; // +1 for '/' | 375 intptr_t len = truncated_base_len + ref_path_len + 1; // +1 for '/' |
370 char* buffer = zone->Alloc<char>(len + 1); // +1 for '\0' | 376 char* buffer = zone->Alloc<char>(len + 1); // +1 for '\0' |
371 | 377 |
372 // Copy truncated base. | 378 // Copy truncated base. |
373 strncpy(buffer, base_path, truncated_base_len); | 379 strncpy(buffer, base_path, truncated_base_len); |
374 | 380 |
375 // Add a slash. | 381 // Add a slash. |
376 buffer[truncated_base_len] = '/'; | 382 buffer[truncated_base_len] = '/'; |
377 | 383 |
378 // Copy the ref_path. | 384 // Copy the ref_path. |
379 strncpy((buffer + truncated_base_len + 1), ref_path, ref_path_len); | 385 strncpy((buffer + truncated_base_len + 1), ref_path, ref_path_len); |
380 | 386 |
(...skipping 11 matching lines...) Expand all Loading... |
392 const char* fragment = uri.fragment == NULL ? "" : uri.fragment; | 398 const char* fragment = uri.fragment == NULL ? "" : uri.fragment; |
393 const char* fragment_separator = uri.fragment == NULL ? "" : "#"; | 399 const char* fragment_separator = uri.fragment == NULL ? "" : "#"; |
394 const char* query = uri.query == NULL ? "" : uri.query; | 400 const char* query = uri.query == NULL ? "" : uri.query; |
395 const char* query_separator = uri.query == NULL ? "" : "?"; | 401 const char* query_separator = uri.query == NULL ? "" : "?"; |
396 | 402 |
397 // If there is no scheme for this uri, just build a relative uri of | 403 // If there is no scheme for this uri, just build a relative uri of |
398 // the form: "path[?query][#fragment]". This occurs when we resolve | 404 // the form: "path[?query][#fragment]". This occurs when we resolve |
399 // relative urls inside a "dart:" library. | 405 // relative urls inside a "dart:" library. |
400 if (uri.scheme == NULL) { | 406 if (uri.scheme == NULL) { |
401 ASSERT(uri.userinfo == NULL && uri.host == NULL && uri.port == NULL); | 407 ASSERT(uri.userinfo == NULL && uri.host == NULL && uri.port == NULL); |
402 return zone->PrintToString("%s%s%s%s%s", | 408 return zone->PrintToString("%s%s%s%s%s", uri.path, query_separator, query, |
403 uri.path, query_separator, query, | |
404 fragment_separator, fragment); | 409 fragment_separator, fragment); |
405 } | 410 } |
406 | 411 |
407 // Uri with no authority: "scheme:path[?query][#fragment]" | 412 // Uri with no authority: "scheme:path[?query][#fragment]" |
408 if (uri.host == NULL) { | 413 if (uri.host == NULL) { |
409 ASSERT(uri.userinfo == NULL && uri.port == NULL); | 414 ASSERT(uri.userinfo == NULL && uri.port == NULL); |
410 return zone->PrintToString("%s:%s%s%s%s%s", | 415 return zone->PrintToString("%s:%s%s%s%s%s", uri.scheme, uri.path, |
411 uri.scheme, uri.path, query_separator, query, | 416 query_separator, query, fragment_separator, |
412 fragment_separator, fragment); | 417 fragment); |
413 } | 418 } |
414 | 419 |
415 const char* user = uri.userinfo == NULL ? "" : uri.userinfo; | 420 const char* user = uri.userinfo == NULL ? "" : uri.userinfo; |
416 const char* user_separator = uri.userinfo == NULL ? "" : "@"; | 421 const char* user_separator = uri.userinfo == NULL ? "" : "@"; |
417 const char* port = uri.port == NULL ? "" : uri.port; | 422 const char* port = uri.port == NULL ? "" : uri.port; |
418 const char* port_separator = uri.port == NULL ? "" : ":"; | 423 const char* port_separator = uri.port == NULL ? "" : ":"; |
419 | 424 |
420 // If the path doesn't start with a '/', add one. We need it to | 425 // If the path doesn't start with a '/', add one. We need it to |
421 // separate the path from the authority. | 426 // separate the path from the authority. |
422 const char* path_separator = ((uri.path[0] == '\0' || uri.path[0] == '/') | 427 const char* path_separator = |
423 ? "" : "/"); | 428 ((uri.path[0] == '\0' || uri.path[0] == '/') ? "" : "/"); |
424 | 429 |
425 // Uri with authority: | 430 // Uri with authority: |
426 // "scheme://[userinfo@]host[:port][/]path[?query][#fragment]" | 431 // "scheme://[userinfo@]host[:port][/]path[?query][#fragment]" |
427 return zone->PrintToString( | 432 return zone->PrintToString( |
428 "%s://%s%s%s%s%s%s%s%s%s%s%s", // There is *nothing* wrong with this. | 433 "%s://%s%s%s%s%s%s%s%s%s%s%s", // There is *nothing* wrong with this. |
429 uri.scheme, user, user_separator, uri.host, port_separator, port, | 434 uri.scheme, user, user_separator, uri.host, port_separator, port, |
430 path_separator, uri.path, query_separator, query, | 435 path_separator, uri.path, query_separator, query, fragment_separator, |
431 fragment_separator, fragment); | 436 fragment); |
432 } | 437 } |
433 | 438 |
434 | 439 |
435 // See RFC 3986 Section 5: Reference Resolution | 440 // See RFC 3986 Section 5: Reference Resolution |
436 bool ResolveUri(const char* ref_uri, | 441 bool ResolveUri(const char* ref_uri, |
437 const char* base_uri, | 442 const char* base_uri, |
438 const char** target_uri) { | 443 const char** target_uri) { |
439 // Parse the reference uri. | 444 // Parse the reference uri. |
440 ParsedUri ref; | 445 ParsedUri ref; |
441 if (!ParseUri(ref_uri, &ref)) { | 446 if (!ParseUri(ref_uri, &ref)) { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
532 target.port = base.port; | 537 target.port = base.port; |
533 target.path = RemoveDotSegments(MergePaths(base.path, ref.path)); | 538 target.path = RemoveDotSegments(MergePaths(base.path, ref.path)); |
534 target.query = ref.query; | 539 target.query = ref.query; |
535 target.fragment = ref.fragment; | 540 target.fragment = ref.fragment; |
536 *target_uri = BuildUri(target); | 541 *target_uri = BuildUri(target); |
537 return true; | 542 return true; |
538 } | 543 } |
539 } | 544 } |
540 | 545 |
541 } // namespace dart | 546 } // namespace dart |
OLD | NEW |