📄 uri.cpp
字号:
bool URI::operator == (const std::string& uri) const
{
URI parsedURI(uri);
return equals(parsedURI);
}
bool URI::operator != (const URI& uri) const
{
return !equals(uri);
}
bool URI::operator != (const std::string& uri) const
{
URI parsedURI(uri);
return !equals(parsedURI);
}
bool URI::equals(const URI& uri) const
{
return _scheme == uri._scheme
&& _userInfo == uri._userInfo
&& _host == uri._host
&& getPort() == uri.getPort()
&& _path == uri._path
&& _query == uri._query
&& _fragment == uri._fragment;
}
void URI::normalize()
{
removeDotSegments(!isRelative());
}
void URI::removeDotSegments(bool removeLeading)
{
if (_path.empty()) return;
bool leadingSlash = *(_path.begin()) == '/';
bool trailingSlash = *(_path.rbegin()) == '/';
std::vector<std::string> segments;
std::vector<std::string> normalizedSegments;
getPathSegments(segments);
for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
{
if (*it == "..")
{
if (!normalizedSegments.empty())
{
if (normalizedSegments.back() == "..")
normalizedSegments.push_back(*it);
else
normalizedSegments.pop_back();
}
else if (!removeLeading)
{
normalizedSegments.push_back(*it);
}
}
else if (*it != ".")
{
normalizedSegments.push_back(*it);
}
}
buildPath(normalizedSegments, leadingSlash, trailingSlash);
}
void URI::getPathSegments(std::vector<std::string>& segments)
{
getPathSegments(_path, segments);
}
void URI::getPathSegments(const std::string& path, std::vector<std::string>& segments)
{
std::string::const_iterator it = path.begin();
std::string::const_iterator end = path.end();
std::string seg;
while (it != end)
{
if (*it == '/')
{
if (!seg.empty())
{
segments.push_back(seg);
seg.clear();
}
}
else seg += *it;
++it;
}
if (!seg.empty())
segments.push_back(seg);
}
void URI::encode(const std::string& str, const std::string& reserved, std::string& encodedStr)
{
for (std::string::const_iterator it = str.begin(); it != str.end(); ++it)
{
char c = *it;
if (c >= 'a' && c <= 'z' ||
c >= 'A' && c <= 'Z' ||
c >= '0' && c <= '9' ||
c == '-' || c == '_' ||
c == '.' || c == '~')
{
encodedStr += c;
}
else if (c <= 0x20 || c >= 0x7F || ILLEGAL.find(c) != std::string::npos || reserved.find(c) != std::string::npos)
{
encodedStr += '%';
encodedStr += NumberFormatter::formatHex((unsigned) (unsigned char) c, 2);
}
else encodedStr += c;
}
}
void URI::decode(const std::string& str, std::string& decodedStr)
{
std::string::const_iterator it = str.begin();
std::string::const_iterator end = str.end();
while (it != end)
{
char c = *it++;
if (c == '%')
{
if (it == end) throw SyntaxException("URI encoding: no hex digit following percent sign", str);
char hi = *it++;
if (it == end) throw SyntaxException("URI encoding: two hex digits must follow percent sign", str);
char lo = *it++;
if (hi >= '0' && hi <= '9')
c = hi - '0';
else if (hi >= 'A' && hi <= 'F')
c = hi - 'A' + 10;
else if (hi >= 'a' && hi <= 'f')
c = hi - 'a' + 10;
else throw SyntaxException("URI encoding: not a hex digit");
c *= 16;
if (lo >= '0' && lo <= '9')
c += lo - '0';
else if (lo >= 'A' && lo <= 'F')
c += lo - 'A' + 10;
else if (lo >= 'a' && lo <= 'f')
c += lo - 'a' + 10;
else throw SyntaxException("URI encoding: not a hex digit");
}
decodedStr += c;
}
}
bool URI::isWellKnownPort() const
{
return _port == getWellKnownPort();
}
unsigned short URI::getWellKnownPort() const
{
if (_scheme == "ftp")
return 21;
else if (_scheme == "ssh")
return 22;
else if (_scheme == "telnet")
return 23;
else if (_scheme == "http")
return 80;
else if (_scheme == "nntp")
return 119;
else if (_scheme == "ldap")
return 389;
else if (_scheme == "https")
return 443;
else
return 0;
}
void URI::parse(const std::string& uri)
{
std::string::const_iterator it = uri.begin();
std::string::const_iterator end = uri.end();
if (it == end) return;
if (*it != '/' && *it != '.' && *it != '?' && *it != '#')
{
std::string scheme;
while (it != end && *it != ':' && *it != '?' && *it != '#' && *it != '/') scheme += *it++;
if (it != end && *it == ':')
{
++it;
if (it == end) throw SyntaxException("URI scheme must be followed by authority or path", uri);
setScheme(scheme);
if (*it == '/')
{
++it;
if (it != end && *it == '/')
{
++it;
parseAuthority(it, end);
}
else --it;
}
parsePathEtc(it, end);
}
else
{
it = uri.begin();
parsePathEtc(it, end);
}
}
else parsePathEtc(it, end);
}
void URI::parseAuthority(std::string::const_iterator& it, const std::string::const_iterator& end)
{
std::string userInfo;
std::string part;
while (it != end && *it != '/' && *it != '?' && *it != '#')
{
if (*it == '@')
{
userInfo = part;
part.clear();
}
else part += *it;
++it;
}
std::string::const_iterator pbeg = part.begin();
std::string::const_iterator pend = part.end();
parseHostAndPort(pbeg, pend);
_userInfo = userInfo;
}
void URI::parseHostAndPort(std::string::const_iterator& it, const std::string::const_iterator& end)
{
if (it == end) return;
std::string host;
if (*it == '[')
{
// IPv6 address
while (it != end && *it != ']') host += *it++;
if (it == end) throw SyntaxException("unterminated IPv6 address");
host += *it++;
}
else
{
while (it != end && *it != ':') host += *it++;
}
if (it != end && *it == ':')
{
++it;
std::string port;
while (it != end) port += *it++;
if (!port.empty())
{
int nport = 0;
if (NumberParser::tryParse(port, nport) && nport > 0 && nport < 65536)
_port = (unsigned short) nport;
else
throw SyntaxException("bad or invalid port number", port);
}
else _port = getWellKnownPort();
}
else _port = getWellKnownPort();
_host = host;
toLowerInPlace(_host);
}
void URI::parsePath(std::string::const_iterator& it, const std::string::const_iterator& end)
{
std::string path;
while (it != end && *it != '?' && *it != '#') path += *it++;
decode(path, _path);
}
void URI::parsePathEtc(std::string::const_iterator& it, const std::string::const_iterator& end)
{
if (it == end) return;
if (*it != '?' && *it != '#')
parsePath(it, end);
if (it != end && *it == '?')
{
++it;
parseQuery(it, end);
}
if (it != end && *it == '#')
{
++it;
parseFragment(it, end);
}
}
void URI::parseQuery(std::string::const_iterator& it, const std::string::const_iterator& end)
{
std::string query;
while (it != end && *it != '#') query += *it++;
decode(query, _query);
}
void URI::parseFragment(std::string::const_iterator& it, const std::string::const_iterator& end)
{
std::string fragment;
while (it != end) fragment += *it++;
decode(fragment, _fragment);
}
void URI::mergePath(const std::string& path)
{
std::vector<std::string> segments;
std::vector<std::string> normalizedSegments;
bool addLeadingSlash = false;
if (!_path.empty())
{
getPathSegments(segments);
bool endsWithSlash = *(_path.rbegin()) == '/';
if (!endsWithSlash && !segments.empty())
segments.pop_back();
addLeadingSlash = _path[0] == '/';
}
getPathSegments(path, segments);
addLeadingSlash = addLeadingSlash || !path.empty() && path[0] == '/';
bool hasTrailingSlash = !path.empty() && *(path.rbegin()) == '/';
bool addTrailingSlash = false;
for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
{
if (*it == "..")
{
addTrailingSlash = true;
if (!normalizedSegments.empty())
normalizedSegments.pop_back();
}
else if (*it != ".")
{
addTrailingSlash = false;
normalizedSegments.push_back(*it);
}
else addTrailingSlash = true;
}
buildPath(normalizedSegments, addLeadingSlash, hasTrailingSlash || addTrailingSlash);
}
void URI::buildPath(const std::vector<std::string>& segments, bool leadingSlash, bool trailingSlash)
{
_path.clear();
bool first = true;
for (std::vector<std::string>::const_iterator it = segments.begin(); it != segments.end(); ++it)
{
if (first)
{
first = false;
if (leadingSlash)
_path += '/';
else if (_scheme.empty() && (*it).find(':') != std::string::npos)
_path.append("./");
}
else _path += '/';
_path.append(*it);
}
if (trailingSlash)
_path += '/';
}
Foundation_END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -