• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <regex>
17 #include <vector>
18 #include "hilog/log.h"
19 #include "string_ex.h"
20 #include "uri.h"
21 
22 using std::string;
23 using std::regex;
24 using OHOS::HiviewDFX::HiLog;
25 
26 namespace OHOS {
27 namespace {
28     const string NOT_CACHED = "NOT VALID";
29     const string EMPTY = "";
30     const size_t NOT_FOUND = string::npos;
31     const int NOT_CALCULATED = -2;
32     const int PORT_NONE = -1;
33     const char SCHEME_SEPARATOR = ':';
34     const char SCHEME_FRAGMENT = '#';
35     const char LEFT_SEPARATOR = '/';
36     const char RIGHT_SEPARATOR = '\\';
37     const char QUERY_FLAG = '?';
38     const char USER_HOST_SEPARATOR = '@';
39     const char PORT_SEPARATOR = ':';
40     const size_t POS_INC = 1;
41     const size_t POS_INC_MORE = 2;
42     const size_t POS_INC_AGAIN = 3;
43     const regex SCHEME_REGEX("[a-zA-Z][a-zA-Z|\\d|+|-|.]*$");
44     const HiviewDFX::HiLogLabel LABEL = {LOG_CORE, 0xD001800, "URI"};
45 }; // namespace
46 
Uri(const string & uriString)47 Uri::Uri(const string& uriString)
48 {
49     cachedSsi_ = NOT_FOUND;
50     cachedFsi_ = NOT_FOUND;
51     port_ = NOT_CALCULATED;
52 
53     if (uriString.empty()) {
54         return;
55     }
56 
57     uriString_ = uriString;
58     scheme_ = NOT_CACHED;
59     ssp_ = NOT_CACHED;
60     authority_ = NOT_CACHED;
61     host_ = NOT_CACHED;
62     userInfo_ = NOT_CACHED;
63     query_ = NOT_CACHED;
64     path_ = NOT_CACHED;
65     fragment_ = NOT_CACHED;
66 
67     if (!CheckScheme()) {
68         uriString_ = EMPTY;
69         HiLog::Error(LABEL, "Scheme wrong!");
70     }
71 }
72 
CheckScheme()73 bool Uri::CheckScheme()
74 {
75     scheme_ = ParseScheme();
76     if (scheme_.empty()) {
77         return true;
78     }
79     return regex_match(scheme_, SCHEME_REGEX);
80 }
81 
GetScheme()82 string Uri::GetScheme()
83 {
84     if (uriString_.empty()) {
85         return EMPTY;
86     }
87 
88     if (scheme_ == NOT_CACHED) {
89         scheme_ = ParseScheme();
90     }
91     return scheme_;
92 }
93 
ParseScheme()94 string Uri::ParseScheme()
95 {
96     size_t ssi = FindSchemeSeparator();
97     return (ssi == NOT_FOUND) ? EMPTY : uriString_.substr(0, ssi);
98 }
99 
GetSchemeSpecificPart()100 string Uri::GetSchemeSpecificPart()
101 {
102     if (uriString_.empty()) {
103         return EMPTY;
104     }
105 
106     return (ssp_ == NOT_CACHED) ? (ssp_ = ParseSsp()) : ssp_;
107 }
108 
ParseSsp()109 string Uri::ParseSsp()
110 {
111     size_t ssi = FindSchemeSeparator();
112     size_t fsi = FindFragmentSeparator();
113 
114     size_t start = (ssi == NOT_FOUND) ? 0 : (ssi + 1);
115     size_t end = (fsi == NOT_FOUND) ? uriString_.size() : fsi;
116 
117     // Return everything between ssi and fsi.
118     string ssp = EMPTY;
119     if (end > start) {
120         ssp = uriString_.substr(start, end - start);
121     }
122 
123     return ssp;
124 }
125 
GetAuthority()126 string Uri::GetAuthority()
127 {
128     if (uriString_.empty()) {
129         return EMPTY;
130     }
131 
132     if (authority_ == NOT_CACHED) {
133         authority_ = ParseAuthority();
134     }
135     return authority_;
136 }
137 
ParseAuthority()138 string Uri::ParseAuthority()
139 {
140     size_t ssi = FindSchemeSeparator();
141     if (ssi == NOT_FOUND) {
142         return EMPTY;
143     }
144 
145     size_t length = uriString_.length();
146     // If "//" follows the scheme separator, we have an authority.
147     if ((length > (ssi + POS_INC_MORE)) && (uriString_.at(ssi + POS_INC) == LEFT_SEPARATOR) &&
148         (uriString_.at(ssi + POS_INC_MORE) == LEFT_SEPARATOR)) {
149         // Look for the start of the path, query, or fragment, or the end of the string.
150         size_t start = ssi + POS_INC_AGAIN;
151         size_t end = start;
152 
153         while (end < length) {
154             char ch = uriString_.at(end);
155             if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR) || (ch == QUERY_FLAG) ||
156                 (ch == SCHEME_FRAGMENT)) {
157                 break;
158             }
159 
160             end++;
161         }
162 
163         return uriString_.substr(start, end - start);
164     } else {
165         return EMPTY;
166     }
167 }
168 
GetUserInfo()169 string Uri::GetUserInfo()
170 {
171     if (uriString_.empty()) {
172         return EMPTY;
173     }
174 
175     if (userInfo_ == NOT_CACHED) {
176         userInfo_ = ParseUserInfo();
177     }
178     return userInfo_;
179 }
180 
ParseUserInfo()181 string Uri::ParseUserInfo()
182 {
183     string authority = GetAuthority();
184     if (authority.empty()) {
185         return EMPTY;
186     }
187 
188     size_t end = authority.find_last_of(USER_HOST_SEPARATOR);
189     return (end == NOT_FOUND) ? EMPTY : authority.substr(0, end);
190 }
191 
GetHost()192 string Uri::GetHost()
193 {
194     if (uriString_.empty()) {
195         return EMPTY;
196     }
197 
198     if (host_ == NOT_CACHED) {
199         host_ = ParseHost();
200     }
201     return host_;
202 }
203 
ParseHost()204 string Uri::ParseHost()
205 {
206     string authority = GetAuthority();
207     if (authority.empty()) {
208         return EMPTY;
209     }
210 
211     // Parse out user info and then port.
212     size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
213     size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
214     size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
215     size_t end = (portSeparator == NOT_FOUND) ? authority.size() : portSeparator;
216 
217     string host = EMPTY;
218     if (start < end) {
219         host = authority.substr(start, end - start);
220     }
221 
222     return host;
223 }
224 
GetPort()225 int Uri::GetPort()
226 {
227     if (uriString_.empty()) {
228         return PORT_NONE;
229     }
230 
231     if (port_ == NOT_CALCULATED) {
232         port_ = ParsePort();
233     }
234     return port_;
235 }
236 
ParsePort()237 int Uri::ParsePort()
238 {
239     string authority = GetAuthority();
240     if (authority.empty()) {
241         return PORT_NONE;
242     }
243 
244     // Make sure we look for the port separtor *after* the user info separator.
245     size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
246     size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
247     size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
248     if (portSeparator == NOT_FOUND) {
249         return PORT_NONE;
250     }
251 
252     start = portSeparator + 1;
253     string portString = authority.substr(start);
254 
255     int value = PORT_NONE;
256     return StrToInt(portString, value) ? value : PORT_NONE;
257 }
258 
GetQuery()259 string Uri::GetQuery()
260 {
261     if (uriString_.empty()) {
262         return EMPTY;
263     }
264 
265     if (query_ == NOT_CACHED) {
266         query_ = ParseQuery();
267     }
268     return query_;
269 }
270 
ParseQuery()271 string Uri::ParseQuery()
272 {
273     size_t ssi = FindSchemeSeparator();
274     if (ssi == NOT_FOUND) {
275         ssi = 0;
276     }
277     size_t qsi = uriString_.find_first_of(QUERY_FLAG, ssi);
278     if (qsi == NOT_FOUND) {
279         return EMPTY;
280     }
281 
282     size_t start = qsi + 1;
283     size_t fsi = FindFragmentSeparator();
284     if (fsi == NOT_FOUND) {
285         return uriString_.substr(start);
286     }
287 
288     if (fsi < qsi) {
289         // Invalid.
290         return EMPTY;
291     }
292 
293     return uriString_.substr(start, fsi - start);
294 }
295 
GetPath()296 string Uri::GetPath()
297 {
298     if (uriString_.empty()) {
299         return EMPTY;
300     }
301 
302     if (path_ == NOT_CACHED) {
303         path_ = ParsePath();
304     }
305     return path_;
306 }
307 
GetPathSegments(std::vector<std::string> & segments)308 void Uri::GetPathSegments(std::vector<std::string>& segments)
309 {
310     if (uriString_.empty()) {
311         return;
312     }
313     if (path_ == NOT_CACHED) {
314         path_ = ParsePath();
315     }
316 
317     size_t previous = 0;
318     size_t current;
319     while ((current = path_.find(LEFT_SEPARATOR, previous)) != std::string::npos) {
320         if (previous < current) {
321             segments.emplace_back(path_.substr(previous, current - previous));
322         }
323         previous = current + POS_INC;
324     }
325     // Add in the final path segment.
326     if (previous < path_.length()) {
327         segments.emplace_back(path_.substr(previous));
328     }
329 }
330 
ParsePath()331 string Uri::ParsePath()
332 {
333     size_t ssi = FindSchemeSeparator();
334     // If the URI is absolute.
335     if (ssi != NOT_FOUND) {
336         // Is there anything after the ':'?
337         if ((ssi + 1) == uriString_.length()) {
338             // Opaque URI.
339             return EMPTY;
340         }
341 
342         // A '/' after the ':' means this is hierarchical.
343         if (uriString_.at(ssi + 1) != LEFT_SEPARATOR) {
344             // Opaque URI.
345             return EMPTY;
346         }
347     } else {
348         // All relative URIs are hierarchical.
349     }
350 
351     return ParsePath(ssi);
352 }
353 
ParsePath(size_t ssi)354 string Uri::ParsePath(size_t ssi)
355 {
356     size_t length = uriString_.length();
357 
358     // Find start of path.
359     size_t pathStart = (ssi == NOT_FOUND) ? 0 : (ssi + POS_INC);
360     if ((length > (pathStart + POS_INC)) && (uriString_.at(pathStart) == LEFT_SEPARATOR) &&
361         (uriString_.at(pathStart + POS_INC) == LEFT_SEPARATOR)) {
362         // Skip over authority to path.
363         pathStart += POS_INC_MORE;
364 
365         while (pathStart < length) {
366             char ch = uriString_.at(pathStart);
367             if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
368                 return EMPTY;
369             }
370 
371             if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR)) {
372                 break;
373             }
374 
375             pathStart++;
376         }
377     }
378 
379     // Find end of path.
380     size_t pathEnd = pathStart;
381     while (pathEnd < length) {
382         char ch = uriString_.at(pathEnd);
383         if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
384             break;
385         }
386 
387         pathEnd++;
388     }
389 
390     return uriString_.substr(pathStart, pathEnd - pathStart);
391 }
392 
GetFragment()393 string Uri::GetFragment()
394 {
395     if (uriString_.empty()) {
396         return EMPTY;
397     }
398 
399     if (fragment_ == NOT_CACHED) {
400         fragment_ = ParseFragment();
401     }
402     return fragment_;
403 }
404 
ParseFragment()405 string Uri::ParseFragment()
406 {
407     size_t fsi = FindFragmentSeparator();
408     return (fsi == NOT_FOUND) ? EMPTY : uriString_.substr(fsi + 1);
409 }
410 
FindSchemeSeparator()411 size_t Uri::FindSchemeSeparator()
412 {
413     if (cachedSsi_ == NOT_FOUND) {
414         cachedSsi_ = uriString_.find_first_of(SCHEME_SEPARATOR);
415     }
416     return cachedSsi_;
417 }
418 
FindFragmentSeparator()419 size_t Uri::FindFragmentSeparator()
420 {
421     if (cachedFsi_ == NOT_FOUND) {
422         cachedFsi_ = uriString_.find_first_of(SCHEME_FRAGMENT, FindSchemeSeparator());
423     }
424     return cachedFsi_;
425 }
426 
IsHierarchical()427 bool Uri::IsHierarchical()
428 {
429     if (uriString_.empty()) {
430         return false;
431     }
432 
433     size_t ssi = FindSchemeSeparator();
434     if (ssi == NOT_FOUND) {
435         // All relative URIs are hierarchical.
436         return true;
437     }
438 
439     if (uriString_.length() == (ssi + 1)) {
440         // No ssp.
441         return false;
442     }
443 
444     // If the ssp starts with a '/', this is hierarchical.
445     return (uriString_.at(ssi + 1) == LEFT_SEPARATOR);
446 }
447 
IsOpaque()448 bool Uri::IsOpaque()
449 {
450     if (uriString_.empty()) {
451         return false;
452     }
453 
454     return !IsHierarchical();
455 }
456 
IsAbsolute()457 bool Uri::IsAbsolute()
458 {
459     if (uriString_.empty()) {
460         return false;
461     }
462 
463     return !IsRelative();
464 }
465 
IsRelative()466 bool Uri::IsRelative()
467 {
468     if (uriString_.empty()) {
469         return false;
470     }
471 
472     // Note: We return true if the index is 0
473     return FindSchemeSeparator() == NOT_FOUND;
474 }
475 
Equals(const Uri & other) const476 bool Uri::Equals(const Uri& other) const
477 {
478     return ToString() == other.ToString();
479 }
480 
CompareTo(const Uri & other) const481 int Uri::CompareTo(const Uri& other) const
482 {
483     return ToString().compare(other.ToString());
484 }
485 
ToString() const486 string Uri::ToString() const
487 {
488     return uriString_;
489 }
490 
operator ==(const Uri & other) const491 bool Uri::operator==(const Uri& other) const
492 {
493     return ToString() == other.ToString();
494 }
495 
Marshalling(Parcel & parcel) const496 bool Uri::Marshalling(Parcel& parcel) const
497 {
498     if (IsAsciiString(uriString_)) {
499         return parcel.WriteString16(Str8ToStr16(uriString_));
500     }
501 
502     return false;
503 }
504 
Unmarshalling(Parcel & parcel)505 Uri* Uri::Unmarshalling(Parcel& parcel)
506 {
507     return new Uri(Str16ToStr8(parcel.ReadString16()));
508 }
509 } // namespace OHOS
510