| 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 |