Changeset 212508 in webkit
- Timestamp:
- Feb 16, 2017, 5:10:35 PM (8 years ago)
- Location:
- trunk
- Files:
-
- 3 deleted
- 24 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r212485 r212508 1 2017-02-16 Alex Christensen <achristensen@webkit.org> 2 3 Remove old URL parser 4 https://bugs.webkit.org/show_bug.cgi?id=168483 5 6 Reviewed by Tim Horton. 7 8 * platform/URL.cpp: 9 (WebCore::isSchemeFirstChar): 10 (WebCore::isSchemeChar): 11 (WebCore::URL::URL): 12 (WebCore::URL::setProtocol): 13 (WebCore::URL::setHost): 14 (WebCore::URL::removePort): 15 (WebCore::URL::setPort): 16 (WebCore::URL::setHostAndPort): 17 (WebCore::URL::setUser): 18 (WebCore::URL::setPass): 19 (WebCore::URL::setFragmentIdentifier): 20 (WebCore::URL::setQuery): 21 (WebCore::URL::setPath): 22 (WebCore::URL::serialize): 23 (WebCore::isUserInfoChar): Deleted. 24 (WebCore::isHostnameChar): Deleted. 25 (WebCore::isIPv6Char): Deleted. 26 (WebCore::isPathSegmentEndChar): Deleted. 27 (WebCore::appendASCII): Deleted. 28 (WebCore::findFirstOf): Deleted. 29 (WebCore::checkEncodedString): Deleted. 30 (WebCore::URL::init): Deleted. 31 (WebCore::appendEscapingBadChars): Deleted. 32 (WebCore::escapeAndAppendNonHierarchicalPart): Deleted. 33 (WebCore::copyPathRemovingDots): Deleted. 34 (WebCore::hasSlashDotOrDotDot): Deleted. 35 (WebCore::URL::parse): Deleted. 36 (WebCore::cannotBeABaseURL): Deleted. 37 (WebCore::isDefaultPortForScheme): Deleted. 38 (WebCore::hostPortIsEmptyButCredentialsArePresent): Deleted. 39 (WebCore::isNonFileHierarchicalScheme): Deleted. 40 (WebCore::isCanonicalHostnameLowercaseForScheme): Deleted. 41 (WebCore::findHostnamesInMailToURL): Deleted. 42 (WebCore::findHostnameInHierarchicalURL): Deleted. 43 (WebCore::encodeHostnames): Deleted. 44 (WebCore::encodeRelativeString): Deleted. 45 (WebCore::substituteBackslashes): Deleted. 46 * platform/URLParser.cpp: 47 (WebCore::URLParser::URLParser): 48 (WebCore::URLParser::setEnabled): Deleted. 49 (WebCore::URLParser::enabled): Deleted. 50 * platform/URLParser.h: 51 * platform/cf/URLCF.cpp: 52 (WebCore::URL::URL): 53 * platform/mac/URLMac.mm: 54 (WebCore::URL::URL): 55 1 56 2017-02-16 Anders Carlsson <andersca@apple.com> 2 57 -
trunk/Source/WebCore/platform/URL.cpp
r211636 r212508 55 55 56 56 static const unsigned invalidPortNumber = 0xFFFF; 57 58 static const char wsScheme[] = {'w', 's'};59 static const char ftpScheme[] = {'f', 't', 'p'};60 static const char ftpPort[] = {'2', '1'};61 static const char wssScheme[] = {'w', 's', 's'};62 static const char fileScheme[] = {'f', 'i', 'l', 'e'};63 static const char httpScheme[] = {'h', 't', 't', 'p'};64 static const char httpPort[] = {'8', '0'};65 static const char httpsScheme[] = {'h', 't', 't', 'p', 's'};66 static const char httpsPort[] = {'4', '4', '3'};67 static const char gopherScheme[] = {'g', 'o', 'p', 'h', 'e', 'r'};68 static const char gopherPort[] = {'7', '0'};69 57 70 58 enum URLCharacterClasses { … … 329 317 }; 330 318 331 static unsigned copyPathRemovingDots(char* dst, const char* src, unsigned srcStart, unsigned srcEnd);332 static bool encodeRelativeString(const String& rel, const TextEncoding&, CharBuffer& ouput);333 static String substituteBackslashes(const String&);334 335 static inline bool isSchemeFirstChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeFirstChar; }336 319 static inline bool isSchemeFirstChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeFirstChar); } 337 static inline bool isSchemeChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeChar; }338 320 static inline bool isSchemeChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeChar); } 339 static inline bool isUserInfoChar(unsigned char c) { return characterClassTable[c] & UserInfoChar; }340 static inline bool isHostnameChar(unsigned char c) { return characterClassTable[c] & HostnameChar; }341 static inline bool isIPv6Char(unsigned char c) { return characterClassTable[c] & IPv6Char; }342 static inline bool isPathSegmentEndChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & PathSegmentEndChar; }343 static inline bool isPathSegmentEndChar(UChar c) { return c <= 0xff && (characterClassTable[c] & PathSegmentEndChar); }344 321 static inline bool isBadChar(unsigned char c) { return characterClassTable[c] & BadChar; } 345 322 static inline bool isTabNewline(UChar c) { return c <= 0xff && (characterClassTable[c] & TabNewline); } … … 363 340 dest[i] = static_cast<char>(src[i]); 364 341 } 365 }366 367 static void appendASCII(const String& base, const char* rel, size_t len, CharBuffer& buffer)368 {369 buffer.resize(base.length() + len + 1);370 copyASCII(base, buffer.data());371 memcpy(buffer.data() + base.length(), rel, len);372 buffer[buffer.size() - 1] = '\0';373 }374 375 // FIXME: Move to WTFString.h eventually.376 // Returns the index of the first index in string |s| of any of the characters377 // in |toFind|. |toFind| should be a null-terminated string, all characters up378 // to the null will be searched. Returns int if not found.379 const unsigned notFoundUnsigned = std::numeric_limits<unsigned>::max();380 static unsigned findFirstOf(StringView string, unsigned startPosition, const char* target)381 {382 unsigned length = string.length();383 for (unsigned i = startPosition; i < length; ++i) {384 for (unsigned j = 0; target[j]; ++j) {385 if (string[i] == target[j])386 return i;387 }388 }389 return notFoundUnsigned;390 }391 392 static inline void checkEncodedString(const String& url)393 {394 ASSERT_UNUSED(url, url.containsOnlyASCII());395 ASSERT_UNUSED(url, url.isEmpty() || isSchemeFirstChar(url[0]));396 342 } 397 343 … … 420 366 URL::URL(ParsedURLStringTag, const String& url) 421 367 { 422 if (URLParser::enabled()) { 423 URLParser parser(url); 424 *this = parser.result(); 425 } else 426 parse(url); 368 URLParser parser(url); 369 *this = parser.result(); 370 427 371 #if OS(WINDOWS) 428 429 372 // FIXME(148598): Work around Windows local file handling bug in CFNetwork 373 ASSERT(isLocalFile() || url == m_string); 430 374 #else 431 375 ASSERT(url == m_string); 432 376 #endif 433 377 } … … 435 379 URL::URL(const URL& base, const String& relative) 436 380 { 437 if (URLParser::enabled()) { 438 URLParser parser(relative, base); 439 *this = parser.result(); 440 } else 441 init(base, relative, UTF8Encoding()); 381 URLParser parser(relative, base); 382 *this = parser.result(); 442 383 } 443 384 … … 448 389 // has its contents added to a URL as query params and it makes sense 449 390 // to be consistent. 450 if (URLParser::enabled()) { 451 URLParser parser(relative, base, encoding.encodingForFormSubmission()); 452 *this = parser.result(); 453 } else { 454 init(base, relative, encoding.encodingForFormSubmission()); 455 } 391 URLParser parser(relative, base, encoding.encodingForFormSubmission()); 392 *this = parser.result(); 456 393 } 457 394 … … 462 399 // so this comparison should only catch control characters. 463 400 return c <= ' '; 464 }465 466 void URL::init(const URL& base, const String& relative, const TextEncoding& encoding)467 {468 if (URLParser::enabled())469 ASSERT_NOT_REACHED();470 471 // Allow resolutions with a null or empty base URL, but not with any other invalid one.472 // FIXME: Is this a good rule?473 if (!base.m_isValid && !base.isEmpty()) {474 m_string = relative;475 invalidate();476 return;477 }478 479 // Get rid of leading and trailing whitespace and control characters.480 String rel = relative.stripWhiteSpace(shouldTrimFromURL);481 482 // Get rid of any tabs and newlines.483 rel = rel.removeCharacters(isTabNewline);484 485 // For compatibility with Win IE, treat backslashes as if they were slashes,486 // as long as we're not dealing with javascript: or data: URLs.487 if (rel.contains('\\') && !(protocolIsJavaScript(rel) || protocolIs(rel, "data")))488 rel = substituteBackslashes(rel);489 490 bool allASCII = rel.containsOnlyASCII();491 CharBuffer strBuffer;492 char* str;493 size_t len;494 if (allASCII) {495 len = rel.length();496 strBuffer.resize(len + 1);497 copyASCII(rel, strBuffer.data());498 strBuffer[len] = 0;499 str = strBuffer.data();500 } else {501 if (!encodeRelativeString(rel, encoding, strBuffer)) {502 m_string = blankURL();503 invalidate();504 return;505 }506 507 str = strBuffer.data();508 len = strlen(str);509 }510 511 // According to the RFC, the reference should be interpreted as an512 // absolute URI if possible, using the "leftmost, longest"513 // algorithm. If the URI reference is absolute it will have a514 // scheme, meaning that it will have a colon before the first515 // non-scheme element.516 bool absolute = false;517 char* p = str;518 if (isSchemeFirstChar(*p)) {519 ++p;520 while (isSchemeChar(*p)) {521 ++p;522 }523 if (*p == ':') {524 if (p[1] != '/' && equalIgnoringASCIICase(base.protocol(), StringView(reinterpret_cast<LChar*>(str), p - str)) && base.isHierarchical())525 str = p + 1;526 else527 absolute = true;528 }529 }530 531 CharBuffer parseBuffer;532 533 if (absolute) {534 parse(str, &relative);535 } else {536 // If the base is empty or opaque (e.g. data: or javascript:), then the URL is invalid537 // unless the relative URL is a single fragment.538 if (!base.isHierarchical()) {539 if (str[0] == '#') {540 appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer);541 parse(parseBuffer.data(), &relative);542 } else {543 m_string = relative;544 invalidate();545 }546 return;547 }548 549 switch (str[0]) {550 case '\0':551 // The reference is empty, so this is a reference to the same document with any fragment identifier removed.552 *this = base;553 removeFragmentIdentifier();554 break;555 case '#': {556 // must be fragment-only reference557 appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer);558 parse(parseBuffer.data(), &relative);559 break;560 }561 case '?': {562 // query-only reference, special case needed for non-URL results563 appendASCII(base.m_string.left(base.m_pathEnd), str, len, parseBuffer);564 parse(parseBuffer.data(), &relative);565 break;566 }567 case '/':568 // must be net-path or absolute-path reference569 if (str[1] == '/') {570 // net-path571 appendASCII(base.m_string.left(base.m_schemeEnd + 1), str, len, parseBuffer);572 parse(parseBuffer.data(), &relative);573 } else {574 // abs-path575 appendASCII(base.m_string.left(base.m_portEnd), str, len, parseBuffer);576 parse(parseBuffer.data(), &relative);577 }578 break;579 default:580 {581 // must be relative-path reference582 583 // Base part plus relative part plus one possible slash added in between plus terminating \0 byte.584 const size_t bufferSize = base.m_pathEnd + 1 + len + 1;585 parseBuffer.resize(bufferSize);586 587 char* bufferPos = parseBuffer.data();588 char* bufferStart = bufferPos;589 590 // first copy everything before the path from the base591 CharBuffer baseStringBuffer(base.m_string.length());592 copyASCII(base.m_string, baseStringBuffer.data());593 const char* baseString = baseStringBuffer.data();594 const char* baseStringStart = baseString;595 const char* pathStart = baseStringStart + base.m_portEnd;596 while (baseStringStart < pathStart)597 *bufferPos++ = *baseStringStart++;598 char* bufferPathStart = bufferPos;599 600 // now copy the base path601 const char* baseStringEnd = baseString + base.m_pathEnd;602 603 // go back to the last slash604 while (baseStringEnd > baseStringStart && baseStringEnd[-1] != '/')605 baseStringEnd--;606 607 if (baseStringEnd == baseStringStart) {608 // no path in base, add a path separator if necessary609 if (base.m_schemeEnd + 1 != base.m_pathEnd && *str && *str != '?' && *str != '#')610 *bufferPos++ = '/';611 } else {612 bufferPos += copyPathRemovingDots(bufferPos, baseStringStart, 0, baseStringEnd - baseStringStart);613 }614 615 const char* relStringStart = str;616 const char* relStringPos = relStringStart;617 618 while (*relStringPos && *relStringPos != '?' && *relStringPos != '#') {619 if (relStringPos[0] == '.' && bufferPos[-1] == '/') {620 if (isPathSegmentEndChar(relStringPos[1])) {621 // skip over "." segment622 relStringPos += 1;623 if (relStringPos[0] == '/')624 relStringPos++;625 continue;626 } else if (relStringPos[1] == '.' && isPathSegmentEndChar(relStringPos[2])) {627 // skip over ".." segment and rewind the last segment628 // the RFC leaves it up to the app to decide what to do with excess629 // ".." segments - we choose to drop them since some web content630 // relies on this.631 relStringPos += 2;632 if (relStringPos[0] == '/')633 relStringPos++;634 if (bufferPos > bufferPathStart + 1)635 bufferPos--;636 while (bufferPos > bufferPathStart + 1 && bufferPos[-1] != '/')637 bufferPos--;638 continue;639 }640 }641 642 *bufferPos = *relStringPos;643 relStringPos++;644 bufferPos++;645 }646 647 // all done with the path work, now copy any remainder648 // of the relative reference; this will also add a null terminator649 const size_t currentOffset = bufferPos - bufferStart;650 auto remainingBufferSize = bufferSize - currentOffset;651 ASSERT(currentOffset + strlen(relStringPos) + 1 <= bufferSize);652 strncpy(bufferPos, relStringPos, remainingBufferSize);653 bufferPos[remainingBufferSize - 1] = '\0';654 655 parse(parseBuffer.data(), &relative);656 break;657 }658 }659 }660 401 } 661 402 … … 900 641 901 642 if (!m_isValid) { 902 if (URLParser::enabled()) { 903 URLParser parser(makeString(newProtocol, ":", m_string)); 904 *this = parser.result(); 905 } else 906 parse(newProtocol + ':' + m_string); 643 URLParser parser(makeString(newProtocol, ":", m_string)); 644 *this = parser.result(); 907 645 return true; 908 646 } 909 647 910 if (URLParser::enabled()) { 911 URLParser parser(makeString(newProtocol, m_string.substring(m_schemeEnd))); 912 *this = parser.result(); 913 } else 914 parse(newProtocol + m_string.substring(m_schemeEnd)); 915 648 URLParser parser(makeString(newProtocol, m_string.substring(m_schemeEnd))); 649 *this = parser.result(); 916 650 return true; 917 651 } … … 979 713 builder.append(StringView(encodedHostName.data(), encodedHostName.size())); 980 714 builder.append(m_string.substring(m_hostEnd)); 981 982 if (URLParser::enabled()) { 983 URLParser parser(builder.toString()); 984 *this = parser.result(); 985 } else 986 parse(builder.toString()); 715 716 URLParser parser(builder.toString()); 717 *this = parser.result(); 987 718 } 988 719 … … 991 722 if (m_hostEnd == m_portEnd) 992 723 return; 993 if (URLParser::enabled()) { 994 URLParser parser(m_string.left(m_hostEnd) + m_string.substring(m_portEnd)); 995 *this = parser.result(); 996 } else 997 parse(m_string.left(m_hostEnd) + m_string.substring(m_portEnd)); 724 URLParser parser(m_string.left(m_hostEnd) + m_string.substring(m_portEnd)); 725 *this = parser.result(); 998 726 } 999 727 … … 1006 734 unsigned portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1); 1007 735 1008 if (URLParser::enabled()) { 1009 URLParser parser(makeString(m_string.left(portStart), (colonNeeded ? ":" : ""), String::number(i), m_string.substring(m_portEnd))); 1010 *this = parser.result(); 1011 } else 1012 parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd)); 736 URLParser parser(makeString(m_string.left(portStart), (colonNeeded ? ":" : ""), String::number(i), m_string.substring(m_portEnd))); 737 *this = parser.result(); 1013 738 } 1014 739 … … 1051 776 builder.append(m_string.substring(m_portEnd)); 1052 777 1053 if (URLParser::enabled()) { 1054 URLParser parser(builder.toString()); 1055 *this = parser.result(); 1056 } else 1057 parse(builder.toString()); 778 URLParser parser(builder.toString()); 779 *this = parser.result(); 1058 780 } 1059 781 … … 1074 796 if (end == m_hostEnd || (end == m_passwordEnd && m_string[end] != '@')) 1075 797 u.append('@'); 1076 if (URLParser::enabled()) { 1077 URLParser parser(makeString(m_string.left(m_userStart), u, m_string.substring(end))); 1078 *this = parser.result(); 1079 } else 1080 parse(m_string.left(m_userStart) + u + m_string.substring(end)); 798 URLParser parser(makeString(m_string.left(m_userStart), u, m_string.substring(end))); 799 *this = parser.result(); 1081 800 } else { 1082 801 // Remove '@' if we now have neither user nor password. … … 1085 804 // We don't want to parse in the extremely common case where we are not going to make a change. 1086 805 if (m_userStart != end) { 1087 if (URLParser::enabled()) { 1088 URLParser parser(makeString(m_string.left(m_userStart), m_string.substring(end))); 1089 *this = parser.result(); 1090 } else 1091 parse(m_string.left(m_userStart) + m_string.substring(end)); 806 URLParser parser(makeString(m_string.left(m_userStart), m_string.substring(end))); 807 *this = parser.result(); 1092 808 } 1093 809 } … … 1107 823 if (end != m_hostEnd && m_string[end] == '@') 1108 824 end += 1; 1109 if (URLParser::enabled()) { 1110 URLParser parser(makeString(m_string.left(m_userEnd), p, m_string.substring(end))); 1111 *this = parser.result(); 1112 } else 1113 parse(m_string.left(m_userEnd) + p + m_string.substring(end)); 825 URLParser parser(makeString(m_string.left(m_userEnd), p, m_string.substring(end))); 826 *this = parser.result(); 1114 827 } else { 1115 828 // Remove '@' if we now have neither user nor password. … … 1118 831 // We don't want to parse in the extremely common case where we are not going to make a change. 1119 832 if (m_userEnd != end) { 1120 if (URLParser::enabled()) { 1121 URLParser parser(makeString(m_string.left(m_userEnd), m_string.substring(end))); 1122 *this = parser.result(); 1123 } else 1124 parse(m_string.left(m_userEnd) + m_string.substring(end)); 833 URLParser parser(makeString(m_string.left(m_userEnd), m_string.substring(end))); 834 *this = parser.result(); 1125 835 } 1126 836 } … … 1134 844 // FIXME: Optimize the case where the identifier already happens to be equal to what was passed? 1135 845 // FIXME: Is it correct to do this without encoding and escaping non-ASCII characters? 1136 if (URLParser::enabled()) 1137 *this = URLParser { makeString(StringView { m_string }.substring(0, m_queryEnd), '#', identifier) }.result(); 1138 else 1139 parse(m_string.left(m_queryEnd) + "#" + identifier); 846 *this = URLParser { makeString(StringView { m_string }.substring(0, m_queryEnd), '#', identifier) }.result(); 1140 847 } 1141 848 … … 1162 869 // https://webkit.org/b/161176 1163 870 if ((query.isEmpty() || query[0] != '?') && !query.isNull()) { 1164 if (URLParser::enabled()) { 1165 URLParser parser(makeString(m_string.left(m_pathEnd), "?", query, m_string.substring(m_queryEnd))); 1166 *this = parser.result(); 1167 } else 1168 parse(m_string.left(m_pathEnd) + "?" + query + m_string.substring(m_queryEnd)); 871 URLParser parser(makeString(m_string.left(m_pathEnd), "?", query, m_string.substring(m_queryEnd))); 872 *this = parser.result(); 1169 873 } else { 1170 if (URLParser::enabled()) { 1171 URLParser parser(makeString(m_string.left(m_pathEnd), query, m_string.substring(m_queryEnd))); 1172 *this = parser.result(); 1173 } else 1174 parse(m_string.left(m_pathEnd) + query + m_string.substring(m_queryEnd)); 874 URLParser parser(makeString(m_string.left(m_pathEnd), query, m_string.substring(m_queryEnd))); 875 *this = parser.result(); 1175 876 } 1176 877 … … 1188 889 path = "/" + path; 1189 890 1190 if (URLParser::enabled()) { 1191 URLParser parser(makeString(m_string.left(m_portEnd), encodeWithURLEscapeSequences(path), m_string.substring(m_pathEnd))); 1192 *this = parser.result(); 1193 } else 1194 parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(path) + m_string.substring(m_pathEnd)); 891 URLParser parser(makeString(m_string.left(m_portEnd), encodeWithURLEscapeSequences(path), m_string.substring(m_pathEnd))); 892 *this = parser.result(); 1195 893 } 1196 894 … … 1212 910 } 1213 911 1214 static void appendEscapingBadChars(char*& buffer, const char* strStart, size_t length)1215 {1216 char* p = buffer;1217 1218 const char* str = strStart;1219 const char* strEnd = strStart + length;1220 while (str < strEnd) {1221 unsigned char c = *str++;1222 if (isBadChar(c)) {1223 if (c == '%' || c == '?')1224 *p++ = c;1225 else if (c != 0x09 && c != 0x0a && c != 0x0d)1226 appendEscapedChar(p, c);1227 } else1228 *p++ = c;1229 }1230 1231 buffer = p;1232 }1233 1234 static void escapeAndAppendNonHierarchicalPart(char*& buffer, const char* strStart, size_t length)1235 {1236 char* p = buffer;1237 1238 const char* str = strStart;1239 const char* strEnd = strStart + length;1240 while (str < strEnd) {1241 unsigned char c = *str++;1242 // Strip CR, LF and Tab from fragments, per:1243 // https://bugs.webkit.org/show_bug.cgi?id=87701244 if (c == 0x09 || c == 0x0a || c == 0x0d)1245 continue;1246 1247 // Chrome and IE allow non-ascii characters in fragments, however doing1248 // so would hit an ASSERT in checkEncodedString, so for now we don't.1249 if (c < 0x20 || c >= 127) {1250 appendEscapedChar(p, c);1251 continue;1252 }1253 *p++ = c;1254 }1255 1256 buffer = p;1257 }1258 1259 // copy a path, accounting for "." and ".." segments1260 static unsigned copyPathRemovingDots(char* dst, const char* src, unsigned srcStart, unsigned srcEnd)1261 {1262 char* bufferPathStart = dst;1263 1264 // empty path is a special case, and need not have a leading slash1265 if (srcStart != srcEnd) {1266 const char* baseStringStart = src + srcStart;1267 const char* baseStringEnd = src + srcEnd;1268 const char* baseStringPos = baseStringStart;1269 1270 // this code is unprepared for paths that do not begin with a1271 // slash and we should always have one in the source string1272 ASSERT(baseStringPos[0] == '/');1273 1274 // copy the leading slash into the destination1275 *dst = *baseStringPos;1276 baseStringPos++;1277 dst++;1278 1279 while (baseStringPos < baseStringEnd) {1280 if (baseStringPos[0] == '.' && dst[-1] == '/') {1281 if (baseStringPos[1] == '/' || baseStringPos + 1 == baseStringEnd) {1282 // skip over "." segment1283 baseStringPos += 2;1284 continue;1285 } else if (baseStringPos[1] == '.' && (baseStringPos[2] == '/' ||1286 baseStringPos + 2 == baseStringEnd)) {1287 // skip over ".." segment and rewind the last segment1288 // the RFC leaves it up to the app to decide what to do with excess1289 // ".." segments - we choose to drop them since some web content1290 // relies on this.1291 baseStringPos += 3;1292 if (dst > bufferPathStart + 1)1293 dst--;1294 while (dst > bufferPathStart && dst[-1] != '/')1295 dst--;1296 continue;1297 }1298 }1299 1300 *dst = *baseStringPos;1301 baseStringPos++;1302 dst++;1303 }1304 }1305 *dst = '\0';1306 return dst - bufferPathStart;1307 }1308 1309 static inline bool hasSlashDotOrDotDot(const char* str)1310 {1311 const unsigned char* p = reinterpret_cast<const unsigned char*>(str);1312 if (!*p)1313 return false;1314 unsigned char pc = *p;1315 while (unsigned char c = *++p) {1316 if (c == '.' && (pc == '/' || pc == '.'))1317 return true;1318 pc = c;1319 }1320 return false;1321 }1322 1323 void URL::parse(const String& string)1324 {1325 if (URLParser::enabled())1326 ASSERT_NOT_REACHED();1327 checkEncodedString(string);1328 1329 CharBuffer buffer(string.length() + 1);1330 copyASCII(string, buffer.data());1331 buffer[string.length()] = '\0';1332 parse(buffer.data(), &string);1333 }1334 1335 static inline bool cannotBeABaseURL(const URL& url)1336 {1337 // FIXME: Support https://url.spec.whatwg.org/#url-cannot-be-a-base-url-flag properly1338 // According spec, this should be computed at parsing time.1339 // For the moment, we just check whether the scheme is special or not.1340 if (url.protocolIs("ftp") || url.protocolIs("file") || url.protocolIs("gopher") || url.protocolIs("http") || url.protocolIs("https") || url.protocolIs("ws") || url.protocolIs("wss"))1341 return false;1342 return true;1343 }1344 1345 // Implementation of https://url.spec.whatwg.org/#url-serializing1346 912 String URL::serialize(bool omitFragment) const 1347 913 { 1348 if (URLParser::enabled()) { 1349 if (omitFragment) 1350 return m_string.left(m_queryEnd); 1351 return m_string; 1352 } 1353 1354 if (isNull()) 1355 return String(); 1356 1357 StringBuilder urlBuilder; 1358 urlBuilder.append(m_string, 0, m_schemeEnd); 1359 urlBuilder.appendLiteral(":"); 1360 unsigned start = hostStart(); 1361 if (start < m_hostEnd) { 1362 urlBuilder.appendLiteral("//"); 1363 if (hasUsername()) { 1364 urlBuilder.append(m_string, m_userStart, m_userEnd - m_userStart); 1365 unsigned passwordStart = m_userEnd + 1; 1366 if (hasPassword()) { 1367 urlBuilder.appendLiteral(":"); 1368 urlBuilder.append(m_string, passwordStart, m_passwordEnd - passwordStart); 1369 } 1370 urlBuilder.appendLiteral("@"); 1371 } 1372 // FIXME: Serialize host according https://url.spec.whatwg.org/#concept-host-serializer for IPv4 and IPv6 addresses. 1373 urlBuilder.append(m_string, start, m_hostEnd - start); 1374 if (port()) { 1375 urlBuilder.appendLiteral(":"); 1376 urlBuilder.appendNumber(port().value()); 1377 } 1378 } else if (protocolIs("file")) 1379 urlBuilder.appendLiteral("//"); 1380 if (WebCore::cannotBeABaseURL(*this)) 1381 urlBuilder.append(m_string, m_portEnd, m_pathEnd - m_portEnd); 1382 else { 1383 urlBuilder.appendLiteral("/"); 1384 if (m_pathEnd > m_portEnd) { 1385 unsigned pathStart = m_portEnd + 1; 1386 urlBuilder.append(m_string, pathStart, m_pathEnd - pathStart); 1387 } 1388 } 1389 if (hasQuery()) { 1390 urlBuilder.appendLiteral("?"); 1391 urlBuilder.append(m_string, m_pathEnd + 1, m_queryEnd - (m_pathEnd + 1)); 1392 } 1393 if (!omitFragment && hasFragment()) { 1394 urlBuilder.appendLiteral("#"); 1395 urlBuilder.append(m_string, m_queryEnd + 1, m_fragmentEnd - (m_queryEnd + 1)); 1396 } 1397 return urlBuilder.toString(); 914 if (omitFragment) 915 return m_string.left(m_queryEnd); 916 return m_string; 1398 917 } 1399 918 … … 1432 951 { 1433 952 return lengthA == lengthB && equal(stringA, stringB); 1434 }1435 1436 // List of default schemes is taken from google-url:1437 // http://code.google.com/p/google-url/source/browse/trunk/src/url_canon_stdurl.cc#1201438 static inline bool isDefaultPortForScheme(const char* port, size_t portLength, const char* scheme, size_t schemeLength)1439 {1440 // This switch is theoretically a performance optimization. It came over when1441 // the code was moved from google-url, but may be removed later.1442 switch (schemeLength) {1443 case 2:1444 return equal(scheme, wsScheme) && equal(port, portLength, httpPort);1445 case 3:1446 if (equal(scheme, ftpScheme))1447 return equal(port, portLength, ftpPort);1448 if (equal(scheme, wssScheme))1449 return equal(port, portLength, httpsPort);1450 break;1451 case 4:1452 return equal(scheme, httpScheme) && equal(port, portLength, httpPort);1453 case 5:1454 return equal(scheme, httpsScheme) && equal(port, portLength, httpsPort);1455 case 6:1456 return equal(scheme, gopherScheme) && equal(port, portLength, gopherPort);1457 }1458 return false;1459 }1460 1461 static inline bool hostPortIsEmptyButCredentialsArePresent(unsigned hostStart, unsigned portEnd, char userinfoEndChar)1462 {1463 return userinfoEndChar == '@' && hostStart == portEnd;1464 }1465 1466 static bool isNonFileHierarchicalScheme(const char* scheme, size_t schemeLength)1467 {1468 switch (schemeLength) {1469 case 2:1470 return equal(scheme, wsScheme);1471 case 3:1472 return equal(scheme, ftpScheme) || equal(scheme, wssScheme);1473 case 4:1474 return equal(scheme, httpScheme);1475 case 5:1476 return equal(scheme, httpsScheme);1477 case 6:1478 return equal(scheme, gopherScheme);1479 }1480 return false;1481 }1482 1483 static bool isCanonicalHostnameLowercaseForScheme(const char* scheme, size_t schemeLength)1484 {1485 switch (schemeLength) {1486 case 2:1487 return equal(scheme, wsScheme);1488 case 3:1489 return equal(scheme, ftpScheme) || equal(scheme, wssScheme);1490 case 4:1491 return equal(scheme, httpScheme) || equal(scheme, fileScheme);1492 case 5:1493 return equal(scheme, httpsScheme);1494 case 6:1495 return equal(scheme, gopherScheme);1496 }1497 return false;1498 }1499 1500 void URL::parse(const char* url, const String* originalString)1501 {1502 if (URLParser::enabled())1503 ASSERT_NOT_REACHED();1504 if (!url || url[0] == '\0') {1505 // valid URL must be non-empty1506 m_string = originalString ? *originalString : url;1507 invalidate();1508 return;1509 }1510 1511 if (!isSchemeFirstChar(url[0])) {1512 // scheme must start with an alphabetic character1513 m_string = originalString ? *originalString : url;1514 invalidate();1515 return;1516 }1517 1518 unsigned schemeEnd = 0;1519 while (isSchemeChar(url[schemeEnd]))1520 schemeEnd++;1521 1522 if (url[schemeEnd] != ':') {1523 m_string = originalString ? *originalString : url;1524 invalidate();1525 return;1526 }1527 1528 unsigned userStart = schemeEnd + 1;1529 unsigned userEnd;1530 unsigned passwordStart;1531 unsigned passwordEnd;1532 unsigned hostStart;1533 unsigned hostEnd;1534 unsigned portStart;1535 unsigned portEnd;1536 1537 bool hierarchical = url[schemeEnd + 1] == '/';1538 bool hasSecondSlash = hierarchical && url[schemeEnd + 2] == '/';1539 1540 bool isFile = schemeEnd == 41541 && isASCIIAlphaCaselessEqual(url[0], 'f')1542 && isASCIIAlphaCaselessEqual(url[1], 'i')1543 && isASCIIAlphaCaselessEqual(url[2], 'l')1544 && isASCIIAlphaCaselessEqual(url[3], 'e');1545 1546 m_protocolIsInHTTPFamily = isASCIIAlphaCaselessEqual(url[0], 'h')1547 && isASCIIAlphaCaselessEqual(url[1], 't')1548 && isASCIIAlphaCaselessEqual(url[2], 't')1549 && isASCIIAlphaCaselessEqual(url[3], 'p')1550 && (url[4] == ':' || (isASCIIAlphaCaselessEqual(url[4], 's') && url[5] == ':'));1551 1552 if ((hierarchical && hasSecondSlash) || isNonFileHierarchicalScheme(url, schemeEnd)) {1553 // The part after the scheme is either a net_path or an abs_path whose first path segment is empty.1554 // Attempt to find an authority.1555 // FIXME: Authority characters may be scanned twice, and it would be nice to be faster.1556 1557 if (hierarchical) {1558 userStart++;1559 if (hasSecondSlash) {1560 userStart++;1561 if (isNonFileHierarchicalScheme(url, schemeEnd)) {1562 while (url[userStart] == '/')1563 userStart++;1564 }1565 }1566 }1567 1568 userEnd = userStart;1569 1570 unsigned colonPos = 0;1571 while (isUserInfoChar(url[userEnd])) {1572 if (url[userEnd] == ':' && colonPos == 0)1573 colonPos = userEnd;1574 userEnd++;1575 }1576 1577 if (url[userEnd] == '@') {1578 // actual end of the userinfo, start on the host1579 if (colonPos != 0) {1580 passwordEnd = userEnd;1581 userEnd = colonPos;1582 passwordStart = colonPos + 1;1583 } else1584 passwordStart = passwordEnd = userEnd;1585 1586 hostStart = passwordEnd + 1;1587 } else if (url[userEnd] == '[' || isPathSegmentEndChar(url[userEnd])) {1588 // hit the end of the authority, must have been no user1589 // or looks like an IPv6 hostname1590 // either way, try to parse it as a hostname1591 userEnd = userStart;1592 passwordStart = passwordEnd = userEnd;1593 hostStart = userStart;1594 } else {1595 // invalid character1596 m_string = originalString ? *originalString : url;1597 invalidate();1598 return;1599 }1600 1601 hostEnd = hostStart;1602 1603 // IPV6 IP address1604 if (url[hostEnd] == '[') {1605 hostEnd++;1606 while (isIPv6Char(url[hostEnd]))1607 hostEnd++;1608 if (url[hostEnd] == ']')1609 hostEnd++;1610 else {1611 // invalid character1612 m_string = originalString ? *originalString : url;1613 invalidate();1614 return;1615 }1616 } else {1617 while (isHostnameChar(url[hostEnd]))1618 hostEnd++;1619 }1620 1621 if (url[hostEnd] == ':') {1622 portStart = portEnd = hostEnd + 1;1623 1624 // possible start of port1625 portEnd = portStart;1626 while (isASCIIDigit(url[portEnd]))1627 portEnd++;1628 } else1629 portStart = portEnd = hostEnd;1630 1631 if (!isPathSegmentEndChar(url[portEnd])) {1632 // invalid character1633 m_string = originalString ? *originalString : url;1634 invalidate();1635 return;1636 }1637 1638 if (hostPortIsEmptyButCredentialsArePresent(hostStart, portEnd, url[passwordEnd])) {1639 m_string = originalString ? *originalString : url;1640 invalidate();1641 return;1642 }1643 1644 if (userStart == portEnd && !m_protocolIsInHTTPFamily && !isFile) {1645 // No authority found, which means that this is not a net_path, but rather an abs_path whose first two1646 // path segments are empty. For file, http and https only, an empty authority is allowed.1647 userStart -= 2;1648 userEnd = userStart;1649 passwordStart = userEnd;1650 passwordEnd = passwordStart;1651 hostStart = passwordEnd;1652 hostEnd = hostStart;1653 portStart = hostEnd;1654 portEnd = hostEnd;1655 }1656 } else {1657 // the part after the scheme must be an opaque_part or an abs_path1658 userEnd = userStart;1659 passwordStart = passwordEnd = userEnd;1660 hostStart = hostEnd = passwordEnd;1661 portStart = portEnd = hostEnd;1662 }1663 1664 unsigned pathStart = portEnd;1665 unsigned pathEnd = pathStart;1666 while (url[pathEnd] && url[pathEnd] != '?' && url[pathEnd] != '#')1667 pathEnd++;1668 1669 unsigned queryStart = pathEnd;1670 unsigned queryEnd = queryStart;1671 if (url[queryStart] == '?') {1672 while (url[queryEnd] && url[queryEnd] != '#')1673 queryEnd++;1674 }1675 1676 unsigned fragmentStart = queryEnd;1677 unsigned fragmentEnd = fragmentStart;1678 if (url[fragmentStart] == '#') {1679 fragmentStart++;1680 fragmentEnd = fragmentStart;1681 while (url[fragmentEnd])1682 fragmentEnd++;1683 }1684 1685 // assemble it all, remembering the real ranges1686 Checked<unsigned, RecordOverflow> bufferLength = fragmentEnd;1687 bufferLength *= 3;1688 1689 // The magic number 10 comes from the worst-case addition of characters for password start,1690 // user info, and colon for port number, colon after scheme, plus inserting missing slashes1691 // after protocol, slash for empty path, and possible end-of-query '#' character. This1692 // yields a max of nine additional characters, plus a null.1693 bufferLength += 10;1694 1695 if (bufferLength.hasOverflowed()) {1696 m_string = originalString ? *originalString : url;1697 invalidate();1698 return;1699 }1700 1701 Vector<char, 4096> buffer(bufferLength.unsafeGet());1702 1703 char* p = buffer.data();1704 const char* strPtr = url;1705 1706 // copy in the scheme1707 const char* schemeEndPtr = url + schemeEnd;1708 #if PLATFORM(IOS)1709 if (shouldCanonicalizeScheme || m_protocolIsInHTTPFamily) {1710 while (strPtr < schemeEndPtr)1711 *p++ = toASCIILower(*strPtr++);1712 } else {1713 while (strPtr < schemeEndPtr)1714 *p++ = *strPtr++;1715 }1716 #else1717 while (strPtr < schemeEndPtr)1718 *p++ = toASCIILower(*strPtr++);1719 #endif1720 m_schemeEnd = p - buffer.data();1721 1722 bool hostIsLocalHost = portEnd - userStart == 91723 && isASCIIAlphaCaselessEqual(url[userStart], 'l')1724 && isASCIIAlphaCaselessEqual(url[userStart+1], 'o')1725 && isASCIIAlphaCaselessEqual(url[userStart+2], 'c')1726 && isASCIIAlphaCaselessEqual(url[userStart+3], 'a')1727 && isASCIIAlphaCaselessEqual(url[userStart+4], 'l')1728 && isASCIIAlphaCaselessEqual(url[userStart+5], 'h')1729 && isASCIIAlphaCaselessEqual(url[userStart+6], 'o')1730 && isASCIIAlphaCaselessEqual(url[userStart+7], 's')1731 && isASCIIAlphaCaselessEqual(url[userStart+8], 't');1732 1733 // File URLs need a host part unless it is just file:// or file://localhost1734 bool degenerateFilePath = pathStart == pathEnd && (hostStart == hostEnd || hostIsLocalHost);1735 1736 // We drop empty credentials, but keep a colon in an empty host/port pair.1737 // Removing hostname completely would change the structure of the URL on re-parsing.1738 bool haveNonHostAuthorityPart = userStart != userEnd || passwordStart != passwordEnd || hostEnd != portEnd;1739 1740 // add ":" after scheme1741 *p++ = ':';1742 1743 // if we have at least one authority part or a file URL - add "//" and authority1744 if (isFile ? !degenerateFilePath : (haveNonHostAuthorityPart || hostStart != hostEnd)) {1745 *p++ = '/';1746 *p++ = '/';1747 1748 m_userStart = p - buffer.data();1749 1750 // copy in the user1751 strPtr = url + userStart;1752 const char* userEndPtr = url + userEnd;1753 while (strPtr < userEndPtr) {1754 char c = *strPtr++;1755 ASSERT(isUserInfoChar(c));1756 *p++ = c;1757 }1758 m_userEnd = p - buffer.data();1759 1760 // copy in the password1761 if (passwordEnd != passwordStart) {1762 *p++ = ':';1763 strPtr = url + passwordStart;1764 const char* passwordEndPtr = url + passwordEnd;1765 while (strPtr < passwordEndPtr) {1766 char c = *strPtr++;1767 ASSERT(isUserInfoChar(c));1768 *p++ = c;1769 }1770 }1771 m_passwordEnd = p - buffer.data();1772 1773 // If we had any user info, add "@"1774 if (static_cast<unsigned>(p - buffer.data()) != m_userStart)1775 *p++ = '@';1776 1777 // copy in the host, except in the case of a file URL with authority="localhost"1778 if (!(isFile && hostIsLocalHost && !haveNonHostAuthorityPart)) {1779 strPtr = url + hostStart;1780 const char* hostEndPtr = url + hostEnd;1781 if (isCanonicalHostnameLowercaseForScheme(buffer.data(), m_schemeEnd)) {1782 while (strPtr < hostEndPtr) {1783 char c = toASCIILower(*strPtr++);1784 ASSERT(isHostnameChar(c) || c == '[' || c == ']' || c == ':');1785 *p++ = c;1786 }1787 } else {1788 while (strPtr < hostEndPtr) {1789 char c = *strPtr++;1790 ASSERT(isHostnameChar(c) || c == '[' || c == ']' || c == ':');1791 *p++ = c;1792 }1793 }1794 }1795 m_hostEnd = p - buffer.data();1796 1797 // Copy in the port if the URL has one (and it's not default). Also, copy it if there was no hostname, so that there is still something in authority component.1798 if (hostEnd != portStart) {1799 const char* portStr = url + portStart;1800 size_t portLength = portEnd - portStart;1801 if ((portLength && !isDefaultPortForScheme(portStr, portLength, buffer.data(), m_schemeEnd))1802 || (hostStart == hostEnd && hostEnd != portStart)) {1803 *p++ = ':';1804 const char* portEndPtr = url + portEnd;1805 while (portStr < portEndPtr)1806 *p++ = *portStr++;1807 }1808 }1809 m_portEnd = p - buffer.data();1810 } else {1811 if (isFile) {1812 ASSERT(degenerateFilePath);1813 *p++ = '/';1814 *p++ = '/';1815 }1816 m_userStart = m_userEnd = m_passwordEnd = m_hostEnd = m_portEnd = p - buffer.data();1817 }1818 1819 // For canonicalization, ensure we have a '/' for no path.1820 // Do this only for URL with protocol file, http or https.1821 if ((m_protocolIsInHTTPFamily || isFile) && pathEnd == pathStart)1822 *p++ = '/';1823 1824 // add path, escaping bad characters1825 if (!hierarchical)1826 escapeAndAppendNonHierarchicalPart(p, url + pathStart, pathEnd - pathStart);1827 else if (!hasSlashDotOrDotDot(url))1828 appendEscapingBadChars(p, url + pathStart, pathEnd - pathStart);1829 else {1830 CharBuffer pathBuffer(pathEnd - pathStart + 1);1831 unsigned length = copyPathRemovingDots(pathBuffer.data(), url, pathStart, pathEnd);1832 appendEscapingBadChars(p, pathBuffer.data(), length);1833 }1834 1835 m_pathEnd = p - buffer.data();1836 1837 // Find the position after the last slash in the path, or1838 // the position before the path if there are no slashes in it.1839 unsigned i;1840 for (i = m_pathEnd; i > m_portEnd; --i) {1841 if (buffer[i - 1] == '/')1842 break;1843 }1844 m_pathAfterLastSlash = i;1845 1846 // add query, escaping bad characters1847 appendEscapingBadChars(p, url + queryStart, queryEnd - queryStart);1848 m_queryEnd = p - buffer.data();1849 1850 // add fragment, escaping bad characters1851 if (fragmentEnd != queryEnd) {1852 *p++ = '#';1853 escapeAndAppendNonHierarchicalPart(p, url + fragmentStart, fragmentEnd - fragmentStart);1854 }1855 m_fragmentEnd = p - buffer.data();1856 1857 ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));1858 ASSERT(buffer.size() > 0);1859 1860 // If we didn't end up actually changing the original string and1861 // it was already in a String, reuse it to avoid extra allocation.1862 if (originalString && equal(originalString->impl(), buffer.data(), m_fragmentEnd))1863 m_string = *originalString;1864 else1865 m_string = String(buffer.data(), m_fragmentEnd);1866 1867 m_isValid = true;1868 953 } 1869 954 … … 1968 1053 1969 1054 return String(buffer.data(), p - buffer.data()); 1970 }1971 1972 static bool protocolIs(StringView stringURL, const char* protocol)1973 {1974 assertProtocolIsGood(StringView(reinterpret_cast<const LChar*>(protocol), strlen(protocol)));1975 unsigned length = stringURL.length();1976 for (unsigned i = 0; i < length; ++i) {1977 if (!protocol[i])1978 return stringURL[i] == ':';1979 if (!isASCIIAlphaCaselessEqual(stringURL[i], protocol[i]))1980 return false;1981 }1982 return false;1983 }1984 1985 static void findHostnamesInMailToURL(StringView string, Vector<std::pair<unsigned, unsigned>>& nameRanges)1986 {1987 // In a mailto: URL, host names come after a '@' character and end with a '>' or ',' or '?' or end of string character.1988 // Skip quoted strings so that characters in them don't confuse us.1989 // When we find a '?' character, we are past the part of the URL that contains host names.1990 1991 nameRanges.clear();1992 1993 unsigned p = 0;1994 while (1) {1995 // Find start of host name or of quoted string.1996 unsigned hostnameOrStringStart = findFirstOf(string, p, "\"@?");1997 if (hostnameOrStringStart == notFoundUnsigned)1998 return;1999 UChar c = string[hostnameOrStringStart];2000 p = hostnameOrStringStart + 1;2001 2002 if (c == '?')2003 return;2004 2005 if (c == '@') {2006 // Find end of host name.2007 unsigned hostnameStart = p;2008 unsigned hostnameEnd = findFirstOf(string, p, ">,?");2009 bool done;2010 if (hostnameEnd == notFoundUnsigned) {2011 hostnameEnd = string.length();2012 done = true;2013 } else {2014 p = hostnameEnd;2015 done = false;2016 }2017 2018 nameRanges.append(std::make_pair(hostnameStart, hostnameEnd));2019 2020 if (done)2021 return;2022 } else {2023 // Skip quoted string.2024 ASSERT(c == '"');2025 while (1) {2026 unsigned escapedCharacterOrStringEnd = findFirstOf(string, p, "\"\\");2027 if (escapedCharacterOrStringEnd == notFoundUnsigned)2028 return;2029 2030 c = string[escapedCharacterOrStringEnd];2031 p = escapedCharacterOrStringEnd + 1;2032 2033 // If we are the end of the string, then break from the string loop back to the host name loop.2034 if (c == '"')2035 break;2036 2037 // Skip escaped character.2038 ASSERT(c == '\\');2039 if (p == string.length())2040 return;2041 2042 ++p;2043 }2044 }2045 }2046 }2047 2048 static bool findHostnameInHierarchicalURL(StringView string, unsigned& startOffset, unsigned& endOffset)2049 {2050 // Find the host name in a hierarchical URL.2051 // It comes after a "://" sequence, with scheme characters preceding, and2052 // this should be the first colon in the string.2053 // It ends with the end of the string or a ":" or a path segment ending character.2054 // If there is a "@" character, the host part is just the part after the "@".2055 unsigned separator = findFirstOf(string, 0, ":");2056 if (separator == notFoundUnsigned || separator + 2 >= string.length() || string[separator + 1] != '/' || string[separator + 2] != '/')2057 return false;2058 2059 // Check that all characters before the :// are valid scheme characters.2060 if (!isSchemeFirstChar(string[0]))2061 return false;2062 for (unsigned i = 1; i < separator; ++i) {2063 if (!isSchemeChar(string[i]))2064 return false;2065 }2066 2067 // Start after the separator.2068 unsigned authorityStart = separator + 3;2069 2070 // Find terminating character.2071 unsigned hostnameEnd = string.length();2072 for (unsigned i = authorityStart; i < hostnameEnd; ++i) {2073 UChar c = string[i];2074 if (c == ':' || (isPathSegmentEndChar(c) && c != 0)) {2075 hostnameEnd = i;2076 break;2077 }2078 }2079 2080 // Find "@" for the start of the host name.2081 unsigned userInfoTerminator = findFirstOf(string, authorityStart, "@");2082 unsigned hostnameStart;2083 if (userInfoTerminator == notFoundUnsigned || userInfoTerminator > hostnameEnd)2084 hostnameStart = authorityStart;2085 else2086 hostnameStart = userInfoTerminator + 1;2087 2088 startOffset = hostnameStart;2089 endOffset = hostnameEnd;2090 return true;2091 }2092 2093 // Converts all hostnames found in the given input to punycode, preserving the2094 // rest of the URL unchanged. The output will NOT be null-terminated.2095 // Return value of false means error in encoding.2096 static bool encodeHostnames(StringView string, UCharBuffer& buffer)2097 {2098 buffer.clear();2099 2100 if (protocolIs(string, "mailto")) {2101 Vector<std::pair<unsigned, unsigned>> hostnameRanges;2102 findHostnamesInMailToURL(string, hostnameRanges);2103 unsigned n = hostnameRanges.size();2104 unsigned p = 0;2105 for (unsigned i = 0; i < n; ++i) {2106 const std::pair<unsigned, unsigned>& r = hostnameRanges[i];2107 append(buffer, string.substring(p, r.first - p));2108 if (!appendEncodedHostname(buffer, string.substring(r.first, r.second - r.first)))2109 return false;2110 p = r.second;2111 }2112 // This will copy either everything after the last hostname, or the2113 // whole thing if there is no hostname.2114 append(buffer, string.substring(p));2115 } else {2116 unsigned hostStart, hostEnd;2117 if (findHostnameInHierarchicalURL(string, hostStart, hostEnd)) {2118 append(buffer, string.substring(0, hostStart)); // Before hostname.2119 if (!appendEncodedHostname(buffer, string.substring(hostStart, hostEnd - hostStart)))2120 return false;2121 append(buffer, string.substring(hostEnd)); // After hostname.2122 } else {2123 // No hostname to encode, return the input.2124 append(buffer, string);2125 }2126 }2127 2128 return true;2129 }2130 2131 // Return value of false means error in encoding.2132 static bool encodeRelativeString(const String& rel, const TextEncoding& encoding, CharBuffer& output)2133 {2134 UCharBuffer s;2135 if (!encodeHostnames(rel, s))2136 return false;2137 2138 TextEncoding pathEncoding(UTF8Encoding()); // Path is always encoded as UTF-8; other parts may depend on the scheme.2139 2140 unsigned pathEnd = notFoundUnsigned;2141 if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data") && !protocolIsJavaScript(rel)) {2142 // Find the first instance of either # or ?, keep pathEnd at -1 otherwise.2143 pathEnd = findFirstOf(StringView(s.data(), s.size()), 0, "#?");2144 }2145 2146 if (pathEnd == notFoundUnsigned) {2147 CString decoded = pathEncoding.encode(StringView(s.data(), s.size()), URLEncodedEntitiesForUnencodables);2148 output.resize(decoded.length());2149 memcpy(output.data(), decoded.data(), decoded.length());2150 } else {2151 CString pathDecoded = pathEncoding.encode(StringView(s.data(), pathEnd), URLEncodedEntitiesForUnencodables);2152 // Unencodable characters in URLs are represented by converting2153 // them to XML entities and escaping non-alphanumeric characters.2154 CString otherDecoded = encoding.encode(StringView(s.data() + pathEnd, s.size() - pathEnd), URLEncodedEntitiesForUnencodables);2155 2156 output.resize(pathDecoded.length() + otherDecoded.length());2157 memcpy(output.data(), pathDecoded.data(), pathDecoded.length());2158 memcpy(output.data() + pathDecoded.length(), otherDecoded.data(), otherDecoded.length());2159 }2160 output.append('\0'); // null-terminate the output.2161 2162 return true;2163 }2164 2165 static String substituteBackslashes(const String& string)2166 {2167 size_t questionPos = string.find('?');2168 size_t hashPos = string.find('#');2169 unsigned pathEnd;2170 2171 if (hashPos != notFound && (questionPos == notFound || questionPos > hashPos))2172 pathEnd = hashPos;2173 else if (questionPos != notFound)2174 pathEnd = questionPos;2175 else2176 pathEnd = string.length();2177 2178 return string.left(pathEnd).replace('\\','/') + string.substring(pathEnd);2179 1055 } 2180 1056 -
trunk/Source/WebCore/platform/URLParser.cpp
r212470 r212508 1118 1118 } 1119 1119 #endif 1120 1121 #if COMPARE_URLPARSERS1122 ASSERT(URLParser::enabled());1123 URLParser::setEnabled(false);1124 URL parsedWithOldParser = URL(base, input, encoding);1125 if (parsedWithOldParser != m_url)1126 WTFLogAlways("URLParser Differs: Input <%s> Base <%s> Encoding <%s>", input.utf8().data(), base.string().utf8().data(), encoding.name());1127 else1128 WTFLogAlways("URLParser Same: Input <%s> Base <%s> Encoding <%s>", input.utf8().data(), base.string().utf8().data(), encoding.name());1129 URLParser::setEnabled(true);1130 #endif1131 1120 } 1132 1121 … … 2871 2860 } 2872 2861 2873 static bool urlParserEnabled = true;2874 2875 void URLParser::setEnabled(bool enabled)2876 {2877 urlParserEnabled = enabled;2878 }2879 2880 bool URLParser::enabled()2881 {2882 return urlParserEnabled;2883 }2884 2885 2862 } // namespace WebCore -
trunk/Source/WebCore/platform/URLParser.h
r212279 r212508 44 44 WEBCORE_EXPORT static bool allValuesEqual(const URL&, const URL&); 45 45 WEBCORE_EXPORT static bool internalValuesConsistent(const URL&); 46 47 WEBCORE_EXPORT static bool enabled();48 WEBCORE_EXPORT static void setEnabled(bool);49 46 50 47 typedef Vector<WTF::KeyValuePair<String, String>> URLEncodedForm; -
trunk/Source/WebCore/platform/cf/URLCF.cpp
r206329 r212508 48 48 CString urlBytes; 49 49 getURLBytes(url, urlBytes); 50 if (URLParser::enabled()) { 51 URLParser parser(urlBytes.data()); 52 *this = parser.result(); 53 } else 54 parse(urlBytes.data()); 50 URLParser parser(urlBytes.data()); 51 *this = parser.result(); 55 52 } 56 53 -
trunk/Source/WebCore/platform/mac/URLMac.mm
r206329 r212508 44 44 CString urlBytes; 45 45 getURLBytes(reinterpret_cast<CFURLRef>(url), urlBytes); 46 if (URLParser::enabled()) { 47 URLParser parser(urlBytes.data()); 48 *this = parser.result(); 49 } else 50 parse(urlBytes.data()); 46 URLParser parser(urlBytes.data()); 47 *this = parser.result(); 51 48 } 52 49 -
trunk/Source/WebCore/platform/soup/URLSoup.cpp
r207293 r212508 44 44 45 45 GUniquePtr<gchar> urlString(soup_uri_to_string(soupURI, FALSE)); 46 if (URLParser::enabled()) { 47 URLParser parser(String::fromUTF8(urlString.get())); 48 *this = parser.result(); 49 } else 50 parse(String::fromUTF8(urlString.get())); 46 URLParser parser(String::fromUTF8(urlString.get())); 47 *this = parser.result(); 51 48 52 49 if (!isValid()) -
trunk/Source/WebKit2/ChangeLog
r212507 r212508 1 2017-02-16 Alex Christensen <achristensen@webkit.org> 2 3 Remove old URL parser 4 https://bugs.webkit.org/show_bug.cgi?id=168483 5 6 Reviewed by Tim Horton. 7 8 * NetworkProcess/NetworkProcess.cpp: 9 (WebKit::NetworkProcess::initializeNetworkProcess): 10 * NetworkProcess/NetworkProcessCreationParameters.cpp: 11 (WebKit::NetworkProcessCreationParameters::encode): 12 (WebKit::NetworkProcessCreationParameters::decode): 13 * NetworkProcess/NetworkProcessCreationParameters.h: 14 * PlatformEfl.cmake: 15 * PlatformGTK.cmake: 16 * PlatformMac.cmake: 17 * Shared/Cocoa/WebKit2InitializeCocoa.mm: Removed. 18 * Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h: 19 (WebKit::XPCServiceInitializer): 20 * Shared/WebKit2Initialize.cpp: 21 (WebKit::InitializeWebKit2): 22 * Shared/WebKit2Initialize.h: 23 (): Deleted. 24 * Shared/WebProcessCreationParameters.cpp: 25 (WebKit::WebProcessCreationParameters::encode): 26 (WebKit::WebProcessCreationParameters::decode): 27 * Shared/WebProcessCreationParameters.h: 28 * Shared/efl/WebKit2InitializeEFL.cpp: Removed. 29 * Shared/gtk/WebKit2InitializeGTK.cpp: Removed. 30 * UIProcess/WebProcessPool.cpp: 31 (WebKit::WebProcessPool::ensureNetworkProcess): 32 (WebKit::WebProcessPool::createNewWebProcess): 33 * WebKit2.xcodeproj/project.pbxproj: 34 * WebProcess/WebProcess.cpp: 35 (WebKit::WebProcess::initializeWebProcess): 36 1 37 2017-02-16 Wenson Hsieh <wenson_hsieh@apple.com> 2 38 -
trunk/Source/WebKit2/NetworkProcess/NetworkProcess.cpp
r212041 r212508 202 202 void NetworkProcess::initializeNetworkProcess(NetworkProcessCreationParameters&& parameters) 203 203 { 204 URLParser::setEnabled(parameters.urlParserEnabled);205 206 204 platformInitializeNetworkProcess(parameters); 207 205 -
trunk/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.cpp
r212451 r212508 68 68 encoder << shouldSuppressMemoryPressureHandler; 69 69 encoder << shouldUseTestingNetworkSession; 70 encoder << urlParserEnabled;71 70 encoder << loadThrottleLatency; 72 71 encoder << urlSchemesRegisteredForCustomProtocols; … … 148 147 if (!decoder.decode(result.shouldUseTestingNetworkSession)) 149 148 return false; 150 if (!decoder.decode(result.urlParserEnabled))151 return false;152 149 if (!decoder.decode(result.loadThrottleLatency)) 153 150 return false; -
trunk/Source/WebKit2/NetworkProcess/NetworkProcessCreationParameters.h
r212451 r212508 74 74 bool shouldSuppressMemoryPressureHandler { false }; 75 75 bool shouldUseTestingNetworkSession; 76 bool urlParserEnabled { false };77 76 std::chrono::milliseconds loadThrottleLatency { 0ms }; 78 77 -
trunk/Source/WebKit2/PlatformEfl.cmake
r212183 r212508 51 51 Shared/efl/ProcessExecutablePathEfl.cpp 52 52 Shared/efl/WebEventFactory.cpp 53 Shared/efl/WebKit2InitializeEFL.cpp54 53 55 54 Shared/linux/WebMemorySamplerLinux.cpp -
trunk/Source/WebKit2/PlatformGTK.cmake
r212183 r212508 75 75 Shared/gtk/WebContextMenuItemGtk.cpp 76 76 Shared/gtk/WebEventFactory.cpp 77 Shared/gtk/WebKit2InitializeGTK.cpp78 77 Shared/gtk/WebSelectionData.cpp 79 78 … … 1117 1116 Shared/gtk/ProcessExecutablePathGtk.cpp 1118 1117 Shared/gtk/WebEventFactory.cpp 1119 Shared/gtk/WebKit2InitializeGTK.cpp1120 1118 1121 1119 Shared/soup/WebCoreArgumentCodersSoup.cpp -
trunk/Source/WebKit2/PlatformMac.cmake
r212183 r212508 103 103 Shared/Cocoa/DataDetectionResult.mm 104 104 Shared/Cocoa/LoadParametersCocoa.mm 105 Shared/Cocoa/WebKit2InitializeCocoa.mm106 105 Shared/Cocoa/WKNSArray.mm 107 106 Shared/Cocoa/WKNSData.mm -
trunk/Source/WebKit2/Shared/EntryPointUtilities/mac/XPCService/XPCServiceEntryPoint.h
r211482 r212508 76 76 xpc_transaction_begin(); 77 77 78 InitializeWebKit2( ChildProcess);78 InitializeWebKit2(); 79 79 80 80 if (!delegate.checkEntitlements()) -
trunk/Source/WebKit2/Shared/WebKit2Initialize.cpp
r211666 r212508 42 42 namespace WebKit { 43 43 44 void InitializeWebKit2( ProcessType processType)44 void InitializeWebKit2() 45 45 { 46 46 #if PLATFORM(COCOA) 47 47 InitWebCoreSystemInterface(); 48 48 #endif 49 platformInitializeWebKit2(processType);50 49 #if PLATFORM(IOS) 51 50 InitWebCoreThreadSystemInterface(); -
trunk/Source/WebKit2/Shared/WebKit2Initialize.h
r205266 r212508 28 28 namespace WebKit { 29 29 30 enum ProcessType { 31 ChildProcess, 32 UIProcess, 33 }; 34 35 void InitializeWebKit2(ProcessType = UIProcess); 36 void platformInitializeWebKit2(ProcessType); 30 void InitializeWebKit2(); 37 31 38 32 }; -
trunk/Source/WebKit2/Shared/WebProcessCreationParameters.cpp
r212404 r212508 85 85 encoder << shouldUseFontSmoothing; 86 86 encoder << resourceLoadStatisticsEnabled; 87 encoder << urlParserEnabled;88 87 encoder << fontWhitelist; 89 88 encoder << iconDatabaseEnabled; … … 220 219 if (!decoder.decode(parameters.resourceLoadStatisticsEnabled)) 221 220 return false; 222 if (!decoder.decode(parameters.urlParserEnabled))223 return false;224 221 if (!decoder.decode(parameters.fontWhitelist)) 225 222 return false; -
trunk/Source/WebKit2/Shared/WebProcessCreationParameters.h
r212404 r212508 114 114 bool shouldUseFontSmoothing { true }; 115 115 bool resourceLoadStatisticsEnabled { false }; 116 bool urlParserEnabled { false };117 116 bool iconDatabaseEnabled { false }; 118 117 bool fullKeyboardAccessEnabled { false }; -
trunk/Source/WebKit2/UIProcess/WebProcessPool.cpp
r212443 r212508 382 382 parameters.shouldUseTestingNetworkSession = m_shouldUseTestingNetworkSession; 383 383 384 parameters.urlParserEnabled = URLParser::enabled();385 386 384 // Add any platform specific parameters 387 385 platformInitializeNetworkProcess(parameters); … … 550 548 WebProcessCreationParameters parameters; 551 549 552 parameters.urlParserEnabled = URLParser::enabled();553 554 550 parameters.injectedBundlePath = m_resolvedPaths.injectedBundlePath; 555 551 if (!parameters.injectedBundlePath.isEmpty()) -
trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj
r212254 r212508 1131 1131 5C298DA01C3DF02100470AFE /* PendingDownload.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C298D9E1C3DEF2900470AFE /* PendingDownload.h */; }; 1132 1132 5C7706741D1138380012700F /* WebSocketProvider.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C7706731D111D8B0012700F /* WebSocketProvider.cpp */; }; 1133 5C79439B1D762D62003102D4 /* WebKit2InitializeCocoa.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5C79439A1D762CDF003102D4 /* WebKit2InitializeCocoa.mm */; };1134 1133 5C85C7881C3F23CE0061A4FA /* PendingDownload.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C85C7861C3F23C50061A4FA /* PendingDownload.cpp */; }; 1135 1134 5C9E56821DF7F1AB00C9EE33 /* WKWebsitePolicies.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5C9E56801DF7F05500C9EE33 /* WKWebsitePolicies.cpp */; }; … … 3314 3313 5C298D9E1C3DEF2900470AFE /* PendingDownload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PendingDownload.h; path = NetworkProcess/Downloads/PendingDownload.h; sourceTree = "<group>"; }; 3315 3314 5C7706731D111D8B0012700F /* WebSocketProvider.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = WebSocketProvider.cpp; path = Network/WebSocketProvider.cpp; sourceTree = "<group>"; }; 3316 5C79439A1D762CDF003102D4 /* WebKit2InitializeCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebKit2InitializeCocoa.mm; sourceTree = "<group>"; };3317 3315 5C7C88DC1D0F41A0009D2F6D /* WebSocketProvider.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = WebSocketProvider.h; path = Network/WebSocketProvider.h; sourceTree = "<group>"; }; 3318 3316 5C85C7861C3F23C50061A4FA /* PendingDownload.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PendingDownload.cpp; path = NetworkProcess/Downloads/PendingDownload.cpp; sourceTree = "<group>"; }; … … 5537 5535 2D1087621D2C641B00B85F82 /* LoadParametersCocoa.mm */, 5538 5536 1AB1F78E1D1B34A6007C9BD1 /* WebCoreArgumentCodersCocoa.mm */, 5539 5C79439A1D762CDF003102D4 /* WebKit2InitializeCocoa.mm */,5540 5537 37C4C0921814B3AF003688B9 /* WKNSArray.h */, 5541 5538 37C4C0911814B3AF003688B9 /* WKNSArray.mm */, … … 9909 9906 1A6280F31919982A006AD9F9 /* WebKit.m in Sources */, 9910 9907 BC9BA5041697C45300E44616 /* WebKit2Initialize.cpp in Sources */, 9911 5C79439B1D762D62003102D4 /* WebKit2InitializeCocoa.mm in Sources */,9912 9908 51FB08FF1639DE1A00EC324A /* WebLoaderStrategy.cpp in Sources */, 9913 9909 CD003A5219D49B5D005ABCE0 /* WebMediaKeyStorageManager.cpp in Sources */, … … 9997 9993 510AFFB916542048001BA05E /* WebResourceLoader.cpp in Sources */, 9998 9994 51F060E11654318500F3281B /* WebResourceLoaderMessageReceiver.cpp in Sources */, 9999 9995 6BE969A21E43B8A4008B7483 /* WebResourceLoadStatisticsManager.cpp in Sources */, 10000 9996 51F060E11654318500F3281C /* WebRTCSocketMessageReceiver.cpp in Sources */, 10001 9997 51F060E11654318500F3282C /* WebRTCResolverMessageReceiver.cpp in Sources */, … … 10188 10184 37608822150414F700FC82C7 /* WKRenderObject.cpp in Sources */, 10189 10185 3336763A130C99DC006C9DE2 /* WKResourceCacheManager.cpp in Sources */, 10190 10186 6BE9699E1E43B41D008B7483 /* WKResourceLoadStatisticsManager.cpp in Sources */, 10191 10187 1A7E377818E4A4FE003D0FFF /* WKScriptMessage.mm in Sources */, 10192 10188 0FCB4E5518BBE044000FCFC9 /* WKScrollView.mm in Sources */, -
trunk/Source/WebKit2/WebProcess/WebProcess.cpp
r212424 r212508 240 240 241 241 void WebProcess::initializeWebProcess(WebProcessCreationParameters&& parameters) 242 { 243 URLParser::setEnabled(parameters.urlParserEnabled); 244 242 { 245 243 ASSERT(m_pageMap.isEmpty()); 246 244 -
trunk/Tools/ChangeLog
r212507 r212508 1 2017-02-16 Alex Christensen <achristensen@webkit.org> 2 3 Remove old URL parser 4 https://bugs.webkit.org/show_bug.cgi?id=168483 5 6 Reviewed by Tim Horton. 7 8 * TestWebKitAPI/Tests/WebCore/URLParser.cpp: 9 (TestWebKitAPI::checkURL): 10 (TestWebKitAPI::checkRelativeURL): 11 (TestWebKitAPI::checkURLDifferences): 12 (TestWebKitAPI::checkRelativeURLDifferences): 13 1 14 2017-02-16 Wenson Hsieh <wenson_hsieh@apple.com> 2 15 -
trunk/Tools/TestWebKitAPI/Tests/WebCore/URLParser.cpp
r212470 r212508 89 89 static void checkURL(const String& urlString, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes) 90 90 { 91 bool wasEnabled = URLParser::enabled();92 URLParser::setEnabled(true);93 91 auto url = URL(URL(), urlString); 94 URLParser::setEnabled(false);95 auto oldURL = URL(URL(), urlString);96 URLParser::setEnabled(wasEnabled);97 92 98 93 EXPECT_TRUE(eq(parts.protocol, url.protocol().toString())); … … 105 100 EXPECT_TRUE(eq(parts.fragment, url.fragmentIdentifier())); 106 101 EXPECT_TRUE(eq(parts.string, url.string())); 107 108 EXPECT_TRUE(eq(parts.protocol, oldURL.protocol().toString())); 109 EXPECT_TRUE(eq(parts.user, oldURL.user())); 110 EXPECT_TRUE(eq(parts.password, oldURL.pass())); 111 EXPECT_TRUE(eq(parts.host, oldURL.host())); 112 EXPECT_EQ(parts.port, oldURL.port().value_or(0)); 113 EXPECT_TRUE(eq(parts.path, oldURL.path())); 114 EXPECT_TRUE(eq(parts.query, oldURL.query())); 115 EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier())); 116 EXPECT_TRUE(eq(parts.string, oldURL.string())); 117 118 EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL)); 102 119 103 EXPECT_TRUE(URLParser::internalValuesConsistent(url)); 120 EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));121 104 122 105 if (testTabs == TestTabs::No) … … 133 116 static void checkRelativeURL(const String& urlString, const String& baseURLString, const ExpectedParts& parts, TestTabs testTabs = TestTabs::Yes) 134 117 { 135 bool wasEnabled = URLParser::enabled();136 URLParser::setEnabled(true);137 118 auto url = URL(URL(URL(), baseURLString), urlString); 138 URLParser::setEnabled(false);139 auto oldURL = URL(URL(URL(), baseURLString), urlString);140 URLParser::setEnabled(wasEnabled);141 119 142 120 EXPECT_TRUE(eq(parts.protocol, url.protocol().toString())); … … 150 128 EXPECT_TRUE(eq(parts.string, url.string())); 151 129 152 EXPECT_TRUE(eq(parts.protocol, oldURL.protocol().toString()));153 EXPECT_TRUE(eq(parts.user, oldURL.user()));154 EXPECT_TRUE(eq(parts.password, oldURL.pass()));155 EXPECT_TRUE(eq(parts.host, oldURL.host()));156 EXPECT_EQ(parts.port, oldURL.port().value_or(0));157 EXPECT_TRUE(eq(parts.path, oldURL.path()));158 EXPECT_TRUE(eq(parts.query, oldURL.query()));159 EXPECT_TRUE(eq(parts.fragment, oldURL.fragmentIdentifier()));160 EXPECT_TRUE(eq(parts.string, oldURL.string()));161 162 EXPECT_TRUE(URLParser::allValuesEqual(url, oldURL));163 130 EXPECT_TRUE(URLParser::internalValuesConsistent(url)); 164 EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));165 131 166 132 if (testTabs == TestTabs::No) … … 178 144 static void checkURLDifferences(const String& urlString, const ExpectedParts& partsNew, const ExpectedParts& partsOld, TestTabs testTabs = TestTabs::Yes) 179 145 { 180 bool wasEnabled = URLParser::enabled(); 181 URLParser::setEnabled(true); 146 UNUSED_PARAM(partsOld); // FIXME: Remove all the old expected parts. 182 147 auto url = URL(URL(), urlString); 183 URLParser::setEnabled(false);184 auto oldURL = URL(URL(), urlString);185 URLParser::setEnabled(wasEnabled);186 148 187 149 EXPECT_TRUE(eq(partsNew.protocol, url.protocol().toString())); … … 195 157 EXPECT_TRUE(eq(partsNew.string, url.string())); 196 158 197 EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol().toString()));198 EXPECT_TRUE(eq(partsOld.user, oldURL.user()));199 EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));200 EXPECT_TRUE(eq(partsOld.host, oldURL.host()));201 EXPECT_EQ(partsOld.port, oldURL.port().value_or(0));202 EXPECT_TRUE(eq(partsOld.path, oldURL.path()));203 EXPECT_TRUE(eq(partsOld.query, oldURL.query()));204 EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));205 EXPECT_TRUE(eq(partsOld.string, oldURL.string()));206 207 EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));208 159 EXPECT_TRUE(URLParser::internalValuesConsistent(url)); 209 EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));210 160 211 161 if (testTabs == TestTabs::No) … … 223 173 static void checkRelativeURLDifferences(const String& urlString, const String& baseURLString, const ExpectedParts& partsNew, const ExpectedParts& partsOld, TestTabs testTabs = TestTabs::Yes) 224 174 { 225 bool wasEnabled = URLParser::enabled(); 226 URLParser::setEnabled(true); 175 UNUSED_PARAM(partsOld); // FIXME: Remove all the old expected parts. 227 176 auto url = URL(URL(URL(), baseURLString), urlString); 228 URLParser::setEnabled(false);229 auto oldURL = URL(URL(URL(), baseURLString), urlString);230 URLParser::setEnabled(wasEnabled);231 177 232 178 EXPECT_TRUE(eq(partsNew.protocol, url.protocol().toString())); … … 240 186 EXPECT_TRUE(eq(partsNew.string, url.string())); 241 187 242 EXPECT_TRUE(eq(partsOld.protocol, oldURL.protocol().toString()));243 EXPECT_TRUE(eq(partsOld.user, oldURL.user()));244 EXPECT_TRUE(eq(partsOld.password, oldURL.pass()));245 EXPECT_TRUE(eq(partsOld.host, oldURL.host()));246 EXPECT_EQ(partsOld.port, oldURL.port().value_or(0));247 EXPECT_TRUE(eq(partsOld.path, oldURL.path()));248 EXPECT_TRUE(eq(partsOld.query, oldURL.query()));249 EXPECT_TRUE(eq(partsOld.fragment, oldURL.fragmentIdentifier()));250 EXPECT_TRUE(eq(partsOld.string, oldURL.string()));251 252 EXPECT_FALSE(URLParser::allValuesEqual(url, oldURL));253 188 EXPECT_TRUE(URLParser::internalValuesConsistent(url)); 254 EXPECT_TRUE(URLParser::internalValuesConsistent(oldURL));255 189 256 190 if (testTabs == TestTabs::No)
Note:
See TracChangeset
for help on using the changeset viewer.