📄 kurl.cpp
字号:
parse(parseBuffer.data(), 0); } else { m_string = relative; invalidate(); } return; } switch (str[0]) { case '\0': // the reference must be empty - the RFC says this is a // reference to the same document *this = base; break; case '#': { // must be fragment-only reference appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer); parse(parseBuffer.data(), 0); break; } case '?': { // query-only reference, special case needed for non-URL results appendASCII(base.m_string.left(base.m_pathEnd), str, len, parseBuffer); parse(parseBuffer.data(), 0); break; } case '/': // must be net-path or absolute-path reference if (str[1] == '/') { // net-path appendASCII(base.m_string.left(base.m_schemeEnd + 1), str, len, parseBuffer); parse(parseBuffer.data(), 0); } else { // abs-path appendASCII(base.m_string.left(base.m_portEnd), str, len, parseBuffer); parse(parseBuffer.data(), 0); } break; default: { // must be relative-path reference // Base part plus relative part plus one possible slash added in between plus terminating \0 byte. parseBuffer.resize(base.m_pathEnd + 1 + len + 1); char* bufferPos = parseBuffer.data(); // first copy everything before the path from the base unsigned baseLength = base.m_string.length(); const UChar* baseCharacters = base.m_string.characters(); CharBuffer baseStringBuffer(baseLength); copyASCII(baseCharacters, baseLength, baseStringBuffer.data()); const char* baseString = baseStringBuffer.data(); const char* baseStringStart = baseString; const char* pathStart = baseStringStart + base.m_portEnd; while (baseStringStart < pathStart) *bufferPos++ = *baseStringStart++; char* bufferPathStart = bufferPos; // now copy the base path const char* baseStringEnd = baseString + base.m_pathEnd; // go back to the last slash while (baseStringEnd > baseStringStart && baseStringEnd[-1] != '/') baseStringEnd--; if (baseStringEnd == baseStringStart) { // no path in base, add a path separator if necessary if (base.m_schemeEnd + 1 != base.m_pathEnd && *str && *str != '?' && *str != '#') *bufferPos++ = '/'; } else { bufferPos += copyPathRemovingDots(bufferPos, baseStringStart, 0, baseStringEnd - baseStringStart); } const char* relStringStart = str; const char* relStringPos = relStringStart; while (*relStringPos && *relStringPos != '?' && *relStringPos != '#') { if (relStringPos[0] == '.' && bufferPos[-1] == '/') { if (isPathSegmentEndChar(relStringPos[1])) { // skip over "." segment relStringPos += 1; if (relStringPos[0] == '/') relStringPos++; continue; } else if (relStringPos[1] == '.' && isPathSegmentEndChar(relStringPos[2])) { // skip over ".." segment and rewind the last segment // the RFC leaves it up to the app to decide what to do with excess // ".." segments - we choose to drop them since some web content // relies on this. relStringPos += 2; if (relStringPos[0] == '/') relStringPos++; if (bufferPos > bufferPathStart + 1) bufferPos--; while (bufferPos > bufferPathStart + 1 && bufferPos[-1] != '/') bufferPos--; continue; } } *bufferPos = *relStringPos; relStringPos++; bufferPos++; } // all done with the path work, now copy any remainder // of the relative reference; this will also add a null terminator strcpy(bufferPos, relStringPos); parse(parseBuffer.data(), 0); ASSERT(strlen(parseBuffer.data()) + 1 <= parseBuffer.size()); break; } } }}KURL KURL::copy() const{ KURL result = *this; result.m_string = result.m_string.copy(); return result;}bool KURL::hasPath() const{ return m_pathEnd != m_portEnd;}String KURL::lastPathComponent() const{ if (!hasPath()) return String(); int end = m_pathEnd - 1; if (m_string[end] == '/') --end; int start = m_string.reverseFind('/', end); if (start < m_portEnd) return String(); ++start; return m_string.substring(start, end - start + 1);}String KURL::protocol() const{ return m_string.left(m_schemeEnd);}String KURL::host() const{ int start = hostStart(); return decodeURLEscapeSequences(m_string.substring(start, m_hostEnd - start));}unsigned short KURL::port() const{ if (m_hostEnd == m_portEnd) return 0; int number = m_string.substring(m_hostEnd + 1, m_portEnd - m_hostEnd - 1).toInt(); if (number < 0 || number > 0xFFFF) return 0; return number;}String KURL::pass() const{ if (m_passwordEnd == m_userEnd) return String(); return decodeURLEscapeSequences(m_string.substring(m_userEnd + 1, m_passwordEnd - m_userEnd - 1)); }String KURL::user() const{ return decodeURLEscapeSequences(m_string.substring(m_userStart, m_userEnd - m_userStart));}String KURL::ref() const{ if (m_fragmentEnd == m_queryEnd) return String(); return m_string.substring(m_queryEnd + 1, m_fragmentEnd - (m_queryEnd + 1));}bool KURL::hasRef() const{ return m_fragmentEnd != m_queryEnd;}#ifdef NDEBUGstatic inline void assertProtocolIsGood(const char*){}#elsestatic void assertProtocolIsGood(const char* protocol){ const char* p = protocol; while (*p) { ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z')); ++p; }}#endifbool KURL::protocolIs(const char* protocol) const{ // Do the comparison without making a new string object. assertProtocolIsGood(protocol); if (!m_isValid) return false; for (int i = 0; i < m_schemeEnd; ++i) { if (!protocol[i] || toASCIILower(m_string[i]) != protocol[i]) return false; } return !protocol[m_schemeEnd]; // We should have consumed all characters in the argument.}String KURL::query() const{ if (m_queryEnd == m_pathEnd) return String(); return m_string.substring(m_pathEnd + 1, m_queryEnd - (m_pathEnd + 1)); }String KURL::path() const{ return decodeURLEscapeSequences(m_string.substring(m_portEnd, m_pathEnd - m_portEnd)); }void KURL::setProtocol(const String& s){ // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, // and to avoid changing more than just the protocol. if (!m_isValid) { parse(s + ":" + m_string); return; } parse(s + m_string.substring(m_schemeEnd));}void KURL::setHost(const String& s){ if (!m_isValid) return; // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, // and to avoid changing more than just the host. bool slashSlashNeeded = m_userStart == m_schemeEnd + 1; parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + s + m_string.substring(m_hostEnd));}void KURL::setPort(unsigned short i){ if (!m_isValid) return; if (i) { bool colonNeeded = m_portEnd == m_hostEnd; int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1); parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd)); } else parse(m_string.left(m_hostEnd) + m_string.substring(m_portEnd));}void KURL::setHostAndPort(const String& hostAndPort){ if (!m_isValid) return; // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, // and to avoid changing more than just host and port. bool slashSlashNeeded = m_userStart == m_schemeEnd + 1; parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + hostAndPort + m_string.substring(m_portEnd));}void KURL::setUser(const String& user){ if (!m_isValid) return; // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, // and to avoid changing more than just the user login. String u; int end = m_userEnd; if (!user.isEmpty()) { u = user; if (m_userStart == m_schemeEnd + 1) u = "//" + u; // Add '@' if we didn't have one before. if (end == m_hostEnd || (end == m_passwordEnd && m_string[end] != '@')) u.append('@'); } else { // Remove '@' if we now have neither user nor password. if (m_userEnd == m_passwordEnd && end != m_hostEnd && m_string[end] == '@') end += 1; } parse(m_string.left(m_userStart) + u + m_string.substring(end));}void KURL::setPass(const String& password){ if (!m_isValid) return; // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations, // and to avoid changing more than just the user password. String p; int end = m_passwordEnd; if (!password.isEmpty()) { p = ":" + password + "@"; if (m_userEnd == m_schemeEnd + 1) p = "//" + p; // Eat the existing '@' since we are going to add our own. if (end != m_hostEnd && m_string[end] == '@') end += 1; } else { // Remove '@' if we now have neither user nor password. if (m_userStart == m_userEnd && end != m_hostEnd && m_string[end] == '@') end += 1; } parse(m_string.left(m_userEnd) + p + m_string.substring(end));}void KURL::setRef(const String& s){ if (!m_isValid) return; // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations. parse(m_string.left(m_queryEnd) + (s.isNull() ? "" : "#" + s));}void KURL::removeRef(){ if (!m_isValid) return; parse(m_string.left(m_queryEnd));} void KURL::setQuery(const String& query){ if (!m_isValid) return; // FIXME: '#' and non-ASCII characters must be encoded and escaped. // Usually, the query is encoded using document encoding, not UTF-8, but we don't have // access to the document in this function. if ((query.isEmpty() || query[0] != '?') && !query.isNull()) parse(m_string.left(m_pathEnd) + "?" + query + m_string.substring(m_queryEnd)); else parse(m_string.left(m_pathEnd) + query + m_string.substring(m_queryEnd));}void KURL::setPath(const String& s){ if (!m_isValid) return; // FIXME: encodeWithURLEscapeSequences does not correctly escape '#' and '?', so fragment and query parts // may be inadvertently affected. parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(s) + m_string.substring(m_pathEnd));}String KURL::prettyURL() const{ if (!m_isValid) return m_string; Vector<UChar> result; append(result, protocol()); result.append(':'); Vector<UChar> authority; if (m_hostEnd != m_passwordEnd) { if (m_userEnd != m_userStart) { append(authority, user()); authority.append('@'); } append(authority, host()); if (port() != 0) { authority.append(':'); append(authority, String::number(port())); } } if (!authority.isEmpty()) { result.append('/'); result.append('/'); result.append(authority);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -