• 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 
~Uri()73 Uri::~Uri()
74 {
75     HiLog::Debug(LABEL, "Uri has been destroyed");
76 }
77 
CheckScheme()78 bool Uri::CheckScheme()
79 {
80     scheme_ = ParseScheme();
81     if (scheme_.empty()) {
82         return true;
83     }
84     return regex_match(scheme_, SCHEME_REGEX);
85 }
86 
GetScheme()87 string Uri::GetScheme()
88 {
89     if (uriString_.empty()) {
90         return EMPTY;
91     }
92 
93     if (scheme_ == NOT_CACHED) {
94         scheme_ = ParseScheme();
95     }
96     return scheme_;
97 }
98 
ParseScheme()99 string Uri::ParseScheme()
100 {
101     size_t ssi = FindSchemeSeparator();
102     return (ssi == NOT_FOUND) ? EMPTY : uriString_.substr(0, ssi);
103 }
104 
GetSchemeSpecificPart()105 string Uri::GetSchemeSpecificPart()
106 {
107     if (uriString_.empty()) {
108         return EMPTY;
109     }
110 
111     return (ssp_ == NOT_CACHED) ? (ssp_ = ParseSsp()) : ssp_;
112 }
113 
ParseSsp()114 string Uri::ParseSsp()
115 {
116     size_t ssi = FindSchemeSeparator();
117     size_t fsi = FindFragmentSeparator();
118 
119     size_t start = (ssi == NOT_FOUND) ? 0 : (ssi + 1);
120     size_t end = (fsi == NOT_FOUND) ? uriString_.size() : fsi;
121 
122     // Return everything between ssi and fsi.
123     string ssp = EMPTY;
124     if (end > start) {
125         ssp = uriString_.substr(start, end - start);
126     }
127 
128     return ssp;
129 }
130 
GetAuthority()131 string Uri::GetAuthority()
132 {
133     if (uriString_.empty()) {
134         return EMPTY;
135     }
136 
137     if (authority_ == NOT_CACHED) {
138         authority_ = ParseAuthority();
139     }
140     return authority_;
141 }
142 
ParseAuthority()143 string Uri::ParseAuthority()
144 {
145     size_t ssi = FindSchemeSeparator();
146     if (ssi == NOT_FOUND) {
147         return EMPTY;
148     }
149 
150     size_t length = uriString_.length();
151     // If "//" follows the scheme separator, we have an authority.
152     if ((length > (ssi + POS_INC_MORE)) && (uriString_.at(ssi + POS_INC) == LEFT_SEPARATOR) &&
153         (uriString_.at(ssi + POS_INC_MORE) == LEFT_SEPARATOR)) {
154         // Look for the start of the path, query, or fragment, or the end of the string.
155         size_t start = ssi + POS_INC_AGAIN;
156         size_t end = start;
157 
158         while (end < length) {
159             char ch = uriString_.at(end);
160             if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR) || (ch == QUERY_FLAG) ||
161                 (ch == SCHEME_FRAGMENT)) {
162                 break;
163             }
164 
165             end++;
166         }
167 
168         return uriString_.substr(start, end - start);
169     } else {
170         return EMPTY;
171     }
172 }
173 
GetUserInfo()174 string Uri::GetUserInfo()
175 {
176     if (uriString_.empty()) {
177         return EMPTY;
178     }
179 
180     if (userInfo_ == NOT_CACHED) {
181         userInfo_ = ParseUserInfo();
182     }
183     return userInfo_;
184 }
185 
ParseUserInfo()186 string Uri::ParseUserInfo()
187 {
188     string authority = GetAuthority();
189     if (authority.empty()) {
190         return EMPTY;
191     }
192 
193     size_t end = authority.find_last_of(USER_HOST_SEPARATOR);
194     return (end == NOT_FOUND) ? EMPTY : authority.substr(0, end);
195 }
196 
GetHost()197 string Uri::GetHost()
198 {
199     if (uriString_.empty()) {
200         return EMPTY;
201     }
202 
203     if (host_ == NOT_CACHED) {
204         host_ = ParseHost();
205     }
206     return host_;
207 }
208 
ParseHost()209 string Uri::ParseHost()
210 {
211     string authority = GetAuthority();
212     if (authority.empty()) {
213         return EMPTY;
214     }
215 
216     // Parse out user info and then port.
217     size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
218     size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
219     size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
220     size_t end = (portSeparator == NOT_FOUND) ? authority.size() : portSeparator;
221 
222     string host = EMPTY;
223     if (start < end) {
224         host = authority.substr(start, end - start);
225     }
226 
227     return host;
228 }
229 
GetPort()230 int Uri::GetPort()
231 {
232     if (uriString_.empty()) {
233         return PORT_NONE;
234     }
235 
236     if (port_ == NOT_CALCULATED) {
237         port_ = ParsePort();
238     }
239     return port_;
240 }
241 
ParsePort()242 int Uri::ParsePort()
243 {
244     string authority = GetAuthority();
245     if (authority.empty()) {
246         return PORT_NONE;
247     }
248 
249     // Make sure we look for the port separtor *after* the user info separator.
250     size_t userInfoSeparator = authority.find_last_of(USER_HOST_SEPARATOR);
251     size_t start = (userInfoSeparator == NOT_FOUND) ? 0 : (userInfoSeparator + 1);
252     size_t portSeparator = authority.find_first_of(PORT_SEPARATOR, start);
253     if (portSeparator == NOT_FOUND) {
254         return PORT_NONE;
255     }
256 
257     start = portSeparator + 1;
258     string portString = authority.substr(start);
259 
260     int value = PORT_NONE;
261     return StrToInt(portString, value) ? value : PORT_NONE;
262 }
263 
GetQuery()264 string Uri::GetQuery()
265 {
266     if (uriString_.empty()) {
267         return EMPTY;
268     }
269 
270     if (query_ == NOT_CACHED) {
271         query_ = ParseQuery();
272     }
273     return query_;
274 }
275 
ParseQuery()276 string Uri::ParseQuery()
277 {
278     size_t ssi = FindSchemeSeparator();
279     if (ssi == NOT_FOUND) {
280         ssi = 0;
281     }
282     size_t qsi = uriString_.find_first_of(QUERY_FLAG, ssi);
283     if (qsi == NOT_FOUND) {
284         return EMPTY;
285     }
286 
287     size_t start = qsi + 1;
288     size_t fsi = FindFragmentSeparator();
289     if (fsi == NOT_FOUND) {
290         return uriString_.substr(start);
291     }
292 
293     if (fsi < qsi) {
294         // Invalid.
295         return EMPTY;
296     }
297 
298     return uriString_.substr(start, fsi - start);
299 }
300 
GetPath()301 string Uri::GetPath()
302 {
303     if (uriString_.empty()) {
304         return EMPTY;
305     }
306 
307     if (path_ == NOT_CACHED) {
308         path_ = ParsePath();
309     }
310     return path_;
311 }
312 
GetPathSegments(std::vector<std::string> & segments)313 void Uri::GetPathSegments(std::vector<std::string>& segments)
314 {
315     if (uriString_.empty()) {
316         return;
317     }
318     if (path_ == NOT_CACHED) {
319         path_ = ParsePath();
320     }
321 
322     size_t previous = 0;
323     size_t current;
324     while ((current = path_.find(LEFT_SEPARATOR, previous)) != std::string::npos) {
325         if (previous < current) {
326             segments.emplace_back(path_.substr(previous, current - previous));
327         }
328         previous = current + POS_INC;
329     }
330     // Add in the final path segment.
331     if (previous < path_.length()) {
332         segments.emplace_back(path_.substr(previous));
333     }
334 }
335 
ParsePath()336 string Uri::ParsePath()
337 {
338     size_t ssi = FindSchemeSeparator();
339     // If the URI is absolute.
340     if (ssi != NOT_FOUND) {
341         // Is there anything after the ':'?
342         if ((ssi + 1) == uriString_.length()) {
343             // Opaque URI.
344             return EMPTY;
345         }
346 
347         // A '/' after the ':' means this is hierarchical.
348         if (uriString_.at(ssi + 1) != LEFT_SEPARATOR) {
349             // Opaque URI.
350             return EMPTY;
351         }
352     } else {
353         // All relative URIs are hierarchical.
354     }
355 
356     return ParsePath(ssi);
357 }
358 
ParsePath(size_t ssi)359 string Uri::ParsePath(size_t ssi)
360 {
361     size_t length = uriString_.length();
362 
363     // Find start of path.
364     size_t pathStart = (ssi == NOT_FOUND) ? 0 : (ssi + POS_INC);
365     if ((length > (pathStart + POS_INC)) && (uriString_.at(pathStart) == LEFT_SEPARATOR) &&
366         (uriString_.at(pathStart + POS_INC) == LEFT_SEPARATOR)) {
367         // Skip over authority to path.
368         pathStart += POS_INC_MORE;
369 
370         while (pathStart < length) {
371             char ch = uriString_.at(pathStart);
372             if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
373                 return EMPTY;
374             }
375 
376             if ((ch == LEFT_SEPARATOR) || (ch == RIGHT_SEPARATOR)) {
377                 break;
378             }
379 
380             pathStart++;
381         }
382     }
383 
384     // Find end of path.
385     size_t pathEnd = pathStart;
386     while (pathEnd < length) {
387         char ch = uriString_.at(pathEnd);
388         if ((ch == QUERY_FLAG) || (ch == SCHEME_FRAGMENT)) {
389             break;
390         }
391 
392         pathEnd++;
393     }
394 
395     return uriString_.substr(pathStart, pathEnd - pathStart);
396 }
397 
GetFragment()398 string Uri::GetFragment()
399 {
400     if (uriString_.empty()) {
401         return EMPTY;
402     }
403 
404     if (fragment_ == NOT_CACHED) {
405         fragment_ = ParseFragment();
406     }
407     return fragment_;
408 }
409 
ParseFragment()410 string Uri::ParseFragment()
411 {
412     size_t fsi = FindFragmentSeparator();
413     return (fsi == NOT_FOUND) ? EMPTY : uriString_.substr(fsi + 1);
414 }
415 
FindSchemeSeparator()416 size_t Uri::FindSchemeSeparator()
417 {
418     if (cachedSsi_ == NOT_FOUND) {
419         cachedSsi_ = uriString_.find_first_of(SCHEME_SEPARATOR);
420     }
421     return cachedSsi_;
422 }
423 
FindFragmentSeparator()424 size_t Uri::FindFragmentSeparator()
425 {
426     if (cachedFsi_ == NOT_FOUND) {
427         cachedFsi_ = uriString_.find_first_of(SCHEME_FRAGMENT, FindSchemeSeparator());
428     }
429     return cachedFsi_;
430 }
431 
IsHierarchical()432 bool Uri::IsHierarchical()
433 {
434     if (uriString_.empty()) {
435         return false;
436     }
437 
438     size_t ssi = FindSchemeSeparator();
439     if (ssi == NOT_FOUND) {
440         // All relative URIs are hierarchical.
441         return true;
442     }
443 
444     if (uriString_.length() == (ssi + 1)) {
445         // No ssp.
446         return false;
447     }
448 
449     // If the ssp starts with a '/', this is hierarchical.
450     return (uriString_.at(ssi + 1) == LEFT_SEPARATOR);
451 }
452 
IsOpaque()453 bool Uri::IsOpaque()
454 {
455     if (uriString_.empty()) {
456         return false;
457     }
458 
459     return !IsHierarchical();
460 }
461 
IsAbsolute()462 bool Uri::IsAbsolute()
463 {
464     if (uriString_.empty()) {
465         return false;
466     }
467 
468     return !IsRelative();
469 }
470 
IsRelative()471 bool Uri::IsRelative()
472 {
473     if (uriString_.empty()) {
474         return false;
475     }
476 
477     // Note: We return true if the index is 0
478     return FindSchemeSeparator() == NOT_FOUND;
479 }
480 
Equals(const Uri & other) const481 bool Uri::Equals(const Uri& other) const
482 {
483     return ToString() == other.ToString();
484 }
485 
CompareTo(const Uri & other) const486 int Uri::CompareTo(const Uri& other) const
487 {
488     return ToString().compare(other.ToString());
489 }
490 
ToString() const491 string Uri::ToString() const
492 {
493     return uriString_;
494 }
495 
operator ==(const Uri & other) const496 bool Uri::operator==(const Uri& other) const
497 {
498     return ToString() == other.ToString();
499 }
500 
Marshalling(Parcel & parcel) const501 bool Uri::Marshalling(Parcel& parcel) const
502 {
503     if (IsAsciiString(uriString_)) {
504         return parcel.WriteString16(Str8ToStr16(uriString_));
505     }
506 
507     return false;
508 }
509 
Unmarshalling(Parcel & parcel)510 Uri* Uri::Unmarshalling(Parcel& parcel)
511 {
512     return new Uri(Str16ToStr8(parcel.ReadString16()));
513 }
514 } // namespace OHOS
515