Files
distributedschedule_dms_fwk/utils/native/source/uri.cpp
T
2021-06-02 02:21:10 +08:00

511 lines
12 KiB
C++

/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "uri.h"
#include <regex>
#include <vector>
#include "hilog/log.h"
#include "string_ex.h"
using std::string;
using std::regex;
using OHOS::HiviewDFX::HiLog;
namespace OHOS {
namespace {
const string NOT_CACHED = "NOT VALID";
const string EMPTY = "";
const size_t NOT_FOUND = string::npos;
const int NOT_CALCULATED = -2;
const int PORT_NONE = -1;
const char SCHEME_SEPARATOR = ':';
const char SCHEME_FRAGMENT = '#';
const char LEFT_SEPARATOR = '/';
const char RIGHT_SEPARATOR = '\\';
const char QUERY_FLAG = '?';
const char USER_HOST_SEPARATOR = '@';
const char PORT_SEPARATOR = ':';
const size_t POS_INC = 1;
const size_t POS_INC_MORE = 2;
const size_t POS_INC_AGAIN = 3;
const regex SCHEME_REGEX("[a-zA-Z][a-zA-Z|\\d|+|-|.]*$");
const HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0xD001800, "URI"};
}; // namespace
Uri::Uri(const string& uriString)
{
cachedSsi_ = NOT_FOUND;
cachedFsi_ = NOT_FOUND;
port_ = NOT_CALCULATED;
if (uriString.empty()) {
HiLog::Error(LABEL, "Input empty!");
return;
}
uriString_ = uriString;
scheme_ = NOT_CACHED;
ssp_ = NOT_CACHED;
authority_ = NOT_CACHED;
host_ = NOT_CACHED;
userInfo_ = NOT_CACHED;
query_ = NOT_CACHED;
path_ = NOT_CACHED;
fragment_ = NOT_CACHED;
if (!CheckScheme()) {
uriString_ = EMPTY;
HiLog::Error(LABEL, "Scheme wrong!");
}
}
bool Uri::CheckScheme()
{
scheme_ = ParseScheme();
if (scheme_.empty()) {
return true;
}
return regex_match(scheme_, SCHEME_REGEX);
}
string Uri::GetScheme()
{
if (uriString_.empty()) {
return EMPTY;
}
if (scheme_ == NOT_CACHED) {
scheme_ = ParseScheme();
}
return scheme_;
}
string Uri::ParseScheme()
{
size_t ssi = FindSchemeSeparator();
return (ssi == NOT_FOUND) ? EMPTY : uriString_.substr(0, ssi);
}
string Uri::GetSchemeSpecificPart()
{
if (uriString_.empty()) {
return EMPTY;
}
return (ssp_ == NOT_CACHED) ? (ssp_ = ParseSsp()) : ssp_;
}
string Uri::ParseSsp()
{
size_t ssi = FindSchemeSeparator();
size_t fsi = FindFragmentSeparator();
size_t start = (ssi == NOT_FOUND) ? 0 : (ssi + 1);
size_t end = (fsi == NOT_FOUND) ? uriString_.size() : fsi;
// Return everything between ssi and fsi.
string ssp = EMPTY;
if (end > start) {
ssp = uriString_.substr(start, end - start);
}
return ssp;
}
string Uri::GetAuthority()
{
if (uriString_.empty()) {
return EMPTY;
}
if (authority_ == NOT_CACHED) {
authority_ = ParseAuthority();
}
return authority_;
}
string Uri::ParseAuthority()
{
size_t ssi = FindSchemeSeparator();
if (ssi == NOT_FOUND) {
return EMPTY;
}
size_t length = uriString_.length();
// If "//" follows the scheme separator, we have an authority.
if ((length > (ssi + POS_INC_MORE)) && (uriString_.at(ssi + POS_INC) == LEFT_SEPARATOR) &&
(uriString_.at(ssi + POS_INC_MORE) == LEFT_SEPARATOR)) {
// Look for the start of the path, query, or fragment, or the end of the string.
size_t start = ssi + POS_INC_AGAIN;
size_t end = start;
while (end < length) {
char ch = uriString_.at(end);
if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR) || (ch == QUERY_FLAG) ||
(ch == SCHEME_FRAGMENT)) {
break;
}
end++;
}
return uriString_.substr(start, end - start);
} else {
return EMPTY;
}
}
string Uri::GetUserInfo()
{
if (uriString_.empty()) {
return EMPTY;
}
if (userInfo_ == NOT_CACHED) {
userInfo_ = ParseUserInfo();
}
return userInfo_;
}
string Uri::ParseUserInfo()
{
string authority = GetAuthority();
if (authority.empty()) {
return EMPTY;
}
size_t end = authority.find_last_of(USER_HOST_SEPARATOR);
return (end == NOT_FOUND) ? EMPTY : authority.substr(0, end);
}
string Uri::GetHost()
{
if (uriString_.empty()) {
return EMPTY;
}
if (host_ == NOT_CACHED) {
host_ = ParseHost();
}
return host_;
}
string Uri::ParseHost()
{
string authority = GetAuthority();
if (authority.empty()) {
return EMPTY;
}
// Parse out user info and then port.
size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
size_t end = (portSeparator == NOT_FOUND) ? authority.size() : portSeparator;
string host = EMPTY;
if (start < end) {
host = authority.substr(start, end - start);
}
return host;
}
int Uri::GetPort()
{
if (uriString_.empty()) {
return PORT_NONE;
}
if (port_ == NOT_CALCULATED) {
port_ = ParsePort();
}
return port_;
}
int Uri::ParsePort()
{
string authority = GetAuthority();
if (authority.empty()) {
return PORT_NONE;
}
// Make sure we look for the port separtor *after* the user info separator.
size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
if (portSeparator == NOT_FOUND) {
return PORT_NONE;
}
start = portSeparator + 1;
string portString = authority.substr(start);
int value = PORT_NONE;
return StrToInt(portString, value) ? value : PORT_NONE;
}
string Uri::GetQuery()
{
if (uriString_.empty()) {
return EMPTY;
}
if (query_ == NOT_CACHED) {
query_ = ParseQuery();
}
return query_;
}
string Uri::ParseQuery()
{
size_t ssi = FindSchemeSeparator();
if (ssi == NOT_FOUND) {
ssi = 0;
}
size_t qsi = uriString_.find_first_of(QUERY_FLAG, ssi);
if (qsi == NOT_FOUND) {
return EMPTY;
}
size_t start = qsi + 1;
size_t fsi = FindFragmentSeparator();
if (fsi == NOT_FOUND) {
return uriString_.substr(start);
}
if (fsi < qsi) {
// Invalid.
return EMPTY;
}
return uriString_.substr(start, fsi - start);
}
string Uri::GetPath()
{
if (uriString_.empty()) {
return EMPTY;
}
if (path_ == NOT_CACHED) {
path_ = ParsePath();
}
return path_;
}
void Uri::GetPathSegments(std::vector<std::string>& segments)
{
if (uriString_.empty()) {
return;
}
if (path_ == NOT_CACHED) {
path_ = ParsePath();
}
size_t previous = 0;
size_t current;
while ((current = path_.find(LEFT_SEPARATOR, previous)) != std::string::npos) {
if (previous < current) {
segments.emplace_back(path_.substr(previous, current - previous));
}
previous = current + POS_INC;
}
// Add in the final path segment.
if (previous < path_.length()) {
segments.emplace_back(path_.substr(previous));
}
}
string Uri::ParsePath()
{
size_t ssi = FindSchemeSeparator();
// If the URI is absolute.
if (ssi != NOT_FOUND) {
// Is there anything after the ':'?
if ((ssi + 1) == uriString_.length()) {
// Opaque URI.
return EMPTY;
}
// A '/' after the ':' means this is hierarchical.
if (uriString_.at(ssi + 1) != LEFT_SEPARATOR) {
// Opaque URI.
return EMPTY;
}
} else {
// All relative URIs are hierarchical.
}
return ParsePath(ssi);
}
string Uri::ParsePath(size_t ssi)
{
size_t length = uriString_.length();
// Find start of path.
size_t pathStart = (ssi == NOT_FOUND) ? 0 : (ssi + POS_INC);
if ((length > (pathStart + POS_INC)) && (uriString_.at(pathStart) == LEFT_SEPARATOR) &&
(uriString_.at(pathStart + POS_INC) == LEFT_SEPARATOR)) {
// Skip over authority to path.
pathStart += POS_INC_MORE;
while (pathStart < length) {
char ch = uriString_.at(pathStart);
if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
return EMPTY;
}
if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR)) {
break;
}
pathStart++;
}
}
// Find end of path.
size_t pathEnd = pathStart;
while (pathEnd < length) {
char ch = uriString_.at(pathEnd);
if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
break;
}
pathEnd++;
}
return uriString_.substr(pathStart, pathEnd - pathStart);
}
string Uri::GetFragment()
{
if (uriString_.empty()) {
return EMPTY;
}
if (fragment_ == NOT_CACHED) {
fragment_ = ParseFragment();
}
return fragment_;
}
string Uri::ParseFragment()
{
size_t fsi = FindFragmentSeparator();
return (fsi == NOT_FOUND) ? EMPTY : uriString_.substr(fsi + 1);
}
size_t Uri::FindSchemeSeparator()
{
if (cachedSsi_ == NOT_FOUND) {
cachedSsi_ = uriString_.find_first_of(SCHEME_SEPARATOR);
}
return cachedSsi_;
}
size_t Uri::FindFragmentSeparator()
{
if (cachedFsi_ == NOT_FOUND) {
cachedFsi_ = uriString_.find_first_of(SCHEME_FRAGMENT, FindSchemeSeparator());
}
return cachedFsi_;
}
bool Uri::IsHierarchical()
{
if (uriString_.empty()) {
return false;
}
size_t ssi = FindSchemeSeparator();
if (ssi == NOT_FOUND) {
// All relative URIs are hierarchical.
return true;
}
if (uriString_.length() == (ssi + 1)) {
// No ssp.
return false;
}
// If the ssp starts with a '/', this is hierarchical.
return (uriString_.at(ssi + 1) == LEFT_SEPARATOR);
}
bool Uri::IsOpaque()
{
if (uriString_.empty()) {
return false;
}
return !IsHierarchical();
}
bool Uri::IsAbsolute()
{
if (uriString_.empty()) {
return false;
}
return !IsRelative();
}
bool Uri::IsRelative()
{
if (uriString_.empty()) {
return false;
}
// Note: We return true if the index is 0
return FindSchemeSeparator() == NOT_FOUND;
}
bool Uri::Equals(const Uri& other) const
{
return ToString() == other.ToString();
}
int Uri::CompareTo(const Uri& other) const
{
return ToString().compare(other.ToString());
}
string Uri::ToString() const
{
return uriString_;
}
bool Uri::operator==(const Uri& other) const
{
return ToString() == other.ToString();
}
bool Uri::Marshalling(Parcel& parcel) const
{
if (IsAsciiString(uriString_)) {
return parcel.WriteString16(Str8ToStr16(uriString_));
}
return false;
}
Uri* Uri::Unmarshalling(Parcel& parcel)
{
return new Uri(Str16ToStr8(parcel.ReadString16()));
}
} // namespace OHOS