• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-2024 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 "js_url.h"
17 #include <regex>
18 #include "securec.h"
19 #include "tools/log.h"
20 #include "unicode/stringpiece.h"
21 #include "unicode/unistr.h"
22 #include "url_helper.h"
23 
24 namespace OHOS::Url {
25     std::map<std::string, int> g_head = {
26         {"ftp:", 21}, {"file:", -1}, {"gopher:", 70}, {"http:", 80},
27         {"https:", 443}, {"ws:", 80}, {"wss:", 443}
28     };
29 
30     std::vector<std::string> g_doubleSegment = {
31         "..", ".%2e", ".%2E", "%2e.", "%2E.",
32         "%2e%2e", "%2E%2E", "%2e%2E", "%2E%2e"
33     };
34 
35     std::vector<std::string> g_singlesegment = { ".", "%2e", "%2E" };
36     std::vector<std::string> g_specialSymbols = {
37         "@", "%40", "#", "%23", "=", "%3D", ":", "%3A",
38         "/", "%2F", ";", "%3B", "?", "%3F"
39     };
40     std::vector<char> g_specialcharacter = {
41         '\0', '\t', '\n', '\r', ' ', '#', '%', '/', ':', '?',
42         '@', '[', '\\', ']'
43     };
44 
45     std::bitset<static_cast<size_t>(BitsetStatusFlag::MAX_BIT_SIZE)> g_specialCharForBit;
46 
PreliminaryWork()47     void PreliminaryWork()
48     {
49         std::vector<char> g_specialSymbolsTmp = {'#', '%', '/', ':', '?', '@', '[', '\\', ']', '<', '>', '^', '|'};
50         size_t invalidCharLength = static_cast<size_t>(BitsetStatusFlag::BIT_ASCII_32);
51         for (size_t i = 0; i <= invalidCharLength; ++i) {
52             g_specialCharForBit.set(i);
53         }
54         size_t len = g_specialSymbolsTmp.size();
55         for (size_t i = 0; i < len; ++i) {
56             g_specialCharForBit.set(g_specialSymbolsTmp[i]);
57         }
58         g_specialCharForBit.set(static_cast<size_t>(BitsetStatusFlag::BIT_ASCII_127));
59     }
60 
CheckCharacter(std::string data,std::bitset<static_cast<size_t> (BitsetStatusFlag::MAX_BIT_SIZE)> rule)61     bool CheckCharacter(std::string data, std::bitset<static_cast<size_t>(BitsetStatusFlag::MAX_BIT_SIZE)> rule)
62     {
63         size_t dataLen = data.size();
64         for (size_t i = 0; i < dataLen; ++i) {
65             if (static_cast<int>(data[i]) >= 0 &&
66                 static_cast<int>(data[i]) < static_cast<int>(BitsetStatusFlag::MAX_BIT_SIZE)) {
67                 bool IsIllegal = rule.test(data[i]);
68                 if (IsIllegal) {
69                     return false;
70                 }
71             }
72         }
73         return true;
74     }
75 
ReplaceSpecialSymbols(std::string & input,std::string & oldstr,std::string & newstr)76     void ReplaceSpecialSymbols(std::string& input, std::string& oldstr, std::string& newstr)
77     {
78         size_t oldlen = oldstr.size();
79         while (true) {
80             size_t pos = 0;
81             if ((pos = input.find(oldstr)) != std::string::npos) {
82                 input.replace(pos, oldlen, newstr);
83                 continue;
84             }
85             break;
86         }
87     }
88 
89     template<typename T>
IsASCIITabOrNewline(const T ch)90     bool IsASCIITabOrNewline(const T ch)
91     {
92         return (ch == '\t' || ch == '\n' || ch == '\r');
93     }
94 
IsHexDigit(const char & ch)95     bool IsHexDigit(const char& ch)
96     {
97         if (isdigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
98             return true;
99         }
100         return false;
101     }
102 
DecodeSpecialChars(std::string input)103     std::string DecodeSpecialChars(std::string input)
104     {
105         std::string temp = input;
106         size_t len = temp.size();
107         if (input.empty()) {
108             return temp;
109         }
110         size_t pos = temp.find("%");
111         while (pos != std::string::npos && pos < len - 2) { // 2:end subscript backspace
112             if (IsHexDigit(temp[pos + 1]) && IsHexDigit(temp[pos + 2])) { // 2:Determine the second character after %
113                 std::string subStr = temp.substr(pos + 1, 2); // 2:Truncate the last two digits of the %
114                 int octNum = 0;
115                 if (sscanf_s(subStr.c_str(), "%x", &octNum) == -1) {
116                     HILOG_ERROR("URL:: DecodeSpecialChars sscanf_s is falie");
117                     return temp;
118                 }
119                 std::string convertedChar(1, static_cast<char>(octNum));
120                 temp.replace(pos, 3, convertedChar); // 3:Replace the percent character with the corresponding char
121                 len = len - 2; // 2:After the replacement, the length of the string is reduced by two
122             }
123             pos = temp.find("%", pos + 1);
124         }
125         return temp;
126     }
127 
DeleteC0OrSpace(std::string & str)128     void DeleteC0OrSpace(std::string& str)
129     {
130         if (str.empty()) {
131             return;
132         }
133         size_t i = 0;
134         size_t strlen = str.size();
135         while (i < strlen) {
136             if (str[i] >= '\0' && str[i] <= ' ') {
137                 i++;
138                 continue;
139             }
140             break;
141         }
142         str = str.substr(i);
143         strlen = str.size();
144         if (strlen == 0) {
145             return;
146         }
147         for (i = strlen - 1; i != 0; i--) {
148             if (str[i] >= '\0' && str[i] <= ' ') {
149                 str.pop_back();
150                 continue;
151             }
152             break;
153         }
154     }
155 
DeleteTabOrNewline(std::string & str1)156     void DeleteTabOrNewline(std::string& str1)
157     {
158         for (auto item = str1.begin(); item != str1.end();) {
159             if (IsASCIITabOrNewline(*item)) {
160                 item = str1.erase(item);
161             } else {
162                 ++item;
163             }
164         }
165     }
166 
IsSpecial(std::string scheme)167     bool IsSpecial(std::string scheme)
168     {
169         auto temp = g_head.count(scheme);
170         if (temp > 0) {
171             return true;
172         }
173         return false;
174     }
175 
AnalysisScheme(std::string & input,std::string & scheme,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)176     bool AnalysisScheme(std::string& input, std::string& scheme,
177         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
178     {
179         if (!isalpha(input[0])) {
180             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
181             return false;
182         } else {
183             size_t strlen = input.size();
184             for (size_t i = 0; i < strlen - 1; ++i) {
185                 if ((isalnum(input[i]) || input[i] == '+' || input[i] == '-' || input[i] == '.') &&
186                     isupper(input[i])) {
187                         input[i] = static_cast<size_t>(tolower(input[i]));
188                 }
189                 if (!isalnum(input[i]) && input[i] != '+' && input[i] != '-' && input[i] != '.') {
190                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
191                     // 0:Bit 0 Set to true,The URL analysis failed
192                     return false;
193                 }
194             }
195             scheme = input;
196             if (IsSpecial(scheme)) {
197                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
198             }
199             return true;
200         }
201     }
202 
AnalysisFragment(const std::string & input,std::string & fragment,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)203     void AnalysisFragment(const std::string& input, std::string& fragment,
204         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
205     {
206         fragment = input;
207         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT8));
208     }
209 
AnalysisQuery(const std::string & input,std::string & query,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)210     void AnalysisQuery(const std::string& input, std::string& query,
211         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
212     {
213         query = input;
214         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT7));
215     }
AnalysisUsernameAndPasswd(std::string & input,std::string & username,std::string & password,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)216     void AnalysisUsernameAndPasswd(std::string& input, std::string& username, std::string& password,
217         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
218     {
219         int pos = static_cast<int>(input.size()) - 1;
220         for (; pos >= 0; pos--) {
221             if (input[pos] == '@') {
222                 break;
223             }
224         }
225         std::string userAndPasswd = input.substr(0, pos);
226         input = input.substr(pos + 1);
227         if (userAndPasswd.empty()) {
228             return;
229         }
230         if (userAndPasswd.find('@') != std::string::npos) {
231             while (true) {
232                 size_t posTmp = 0;
233                 if ((posTmp = userAndPasswd.find('@')) != std::string::npos) {
234                     userAndPasswd = userAndPasswd.replace(posTmp, 1, "%40");
235                 } else {
236                     break;
237                 }
238             }
239         }
240         if (userAndPasswd.find(':') != std::string::npos) {
241             size_t position = userAndPasswd.find(':');
242             std::string user = userAndPasswd.substr(0, position);
243             std::string keyWord = userAndPasswd.substr(position + 1);
244             if (!user.empty()) {
245                 username = user;
246                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
247             }
248             if (!keyWord.empty()) {
249                 password = keyWord;
250                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT3));
251             }
252         } else {
253             username = userAndPasswd;
254             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
255         }
256     }
257 
AnalysisPath(std::string & input,std::vector<std::string> & path,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,bool isSpecial)258     void AnalysisPath(std::string& input, std::vector<std::string>& path,
259         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool isSpecial)
260     {
261         std::vector<std::string> temp;
262         size_t pos = 0;
263         while (((pos = input.find('/')) != std::string::npos) ||
264             ((pos = input.find('\\')) != std::string::npos && isSpecial)) {
265             temp.push_back(input.substr(0, pos));
266             input = input.substr(pos + 1);
267         }
268         temp.push_back(input);
269         size_t length = temp.size();
270         for (size_t it = 0; it < length; ++it) {
271             auto result = find(g_doubleSegment.begin(), g_doubleSegment.end(), temp[it]);
272             if (result != g_doubleSegment.end()) {
273                 if (path.empty() && it == length - 1) {
274                     path.emplace_back("");
275                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
276                 }
277                 if (path.empty()) {
278                     continue;
279                 }
280                 path.pop_back();
281                 if (it == length - 1) {
282                     path.emplace_back("");
283                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
284                 }
285                 continue;
286             }
287             result = find(g_singlesegment.begin(), g_singlesegment.end(), temp[it]);
288             if (result != g_singlesegment.end() && it == length - 1) {
289                 path.emplace_back("");
290                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
291                 continue;
292             }
293             if (result == g_singlesegment.end()) {
294                 path.push_back(temp[it]);
295                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
296             }
297         }
298     }
299 
AnalysisPort(std::string input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)300     void AnalysisPort(std::string input, UrlData& urlinfo,
301         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
302     {
303         if (input.size() == 0) {
304             return;
305         }
306         for (auto i : input) {
307             if (!isdigit(i)) {
308                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
309                 return;
310             }
311         }
312         if (input.size() >= 6) { //6:Maximum port number size
313             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
314             return;
315         }
316         int it = stoi(input);
317         const int maxPort = 65535; // 65535:Maximum port number
318         if (it > maxPort) {
319             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
320             return;
321         }
322         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
323         for (auto i : g_head) {
324             if (i.first == urlinfo.scheme && i.second == it) {
325                 urlinfo.port = -1;
326                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT5), 0);
327                 return;
328             }
329         }
330         urlinfo.port = it;
331     }
332 
AnalysisOpaqueHost(std::string input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)333     void AnalysisOpaqueHost(std::string input, std::string& host,
334         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
335     {
336         size_t strlen = input.size();
337         for (size_t i = 0; i < strlen; ++i) {
338             char ch = input[i];
339             auto result = find(g_specialcharacter.begin(), g_specialcharacter.end(), ch);
340             if (ch != '%' && (result != g_specialcharacter.end())) {
341                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
342                 return;
343             }
344         }
345         host = input;
346         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
347     }
348 
DealIpv4(std::string str)349     std::string DealIpv4(std::string str)
350     {
351         std::vector<std::string> temp;
352         size_t pos = str.rfind(":");
353         size_t index = pos;
354         size_t left = pos + 1;
355         char hexVal[3] = { 0 };
356         std::string val = "";
357         while ((pos = str.find(".", left)) != std::string::npos) {
358             val = str.substr(left, pos - left);
359             if (sprintf_s(hexVal, sizeof(hexVal), "%02x", stoi(val)) == -1) {
360                 HILOG_ERROR("URL:: sprintf_s is falie");
361                 return val;
362             }
363 
364             temp.push_back(hexVal);
365             left = pos + 1;
366         }
367         val = str.substr(left);
368         if (sprintf_s(hexVal, sizeof(hexVal), "%02x", stoi(val)) == -1) {
369             HILOG_ERROR("URL:: sprintf_s is falie");
370             return val;
371         }
372         temp.push_back(hexVal);
373         std::string res = str.substr(0, index);
374         res = res + ":" + temp[0] + temp[1] + ":" + temp[2] + temp[3]; // 2:subscript 3:subscript
375         return res;
376     }
377 
FormatIpv6(std::string & str)378     void FormatIpv6(std::string& str)
379     {
380         size_t pos = str.find("::");
381         size_t index = pos;
382         if (pos != std::string::npos) {
383             size_t left = 0;
384             int count = 0;
385             while ((pos = str.find(":", left)) != std::string::npos) {
386                 count++;
387                 left = pos + 1;
388             }
389             int size = 7 - (count - 2); // 7:point number 2:Continuous colon number
390             std::string temp = "";
391             for (int i = 0; i < size - 1; ++i) {
392                 temp += ":0";
393             }
394             temp += ":";
395             str.replace(index, 2, temp); // 2:jump"::"
396             if (index == 0) {
397                 str = "0" + str;
398             }
399         }
400     }
401 
RemoveLeadingZeros(std::vector<std::string> & ipv6)402     void RemoveLeadingZeros(std::vector<std::string> &ipv6)
403     {
404         size_t len = ipv6.size();
405         for (size_t i = 0; i < len; ++i) {
406             size_t strLen = ipv6[i].size();
407             size_t count = 0;
408             size_t j = 0;
409             for (j = 0; j < strLen; ++j) {
410                 if (ipv6[i][j] != '0') {
411                     break;
412                 }
413                 count++;
414             }
415             if (count == strLen) {
416                 ipv6[i] = "0";
417             } else if (count != 0) {
418                 ipv6[i] = ipv6[i].substr(j);
419             }
420         }
421     }
422 
ZeroCompression(std::vector<std::string> & ipv6)423     std::string ZeroCompression(std::vector<std::string> &ipv6)
424     {
425         size_t maxIndex = 0;
426         size_t maxSize = 0;
427         size_t index = 0;
428         size_t size = 0;
429         bool isNeedZeroCompression = false;
430         size_t len = ipv6.size();
431         for (size_t i = 0; i < len; ++i) {
432             index = i;
433             size = 0;
434             while (i < len && ipv6[i] == "0") {
435                 isNeedZeroCompression = true;
436                 size++;
437                 i++;
438             }
439             if (maxSize < size) {
440                 maxSize = size;
441                 maxIndex = index;
442             }
443         }
444         std::string res = "";
445         size_t ipv6Len = ipv6.size();
446         for (size_t i = 0; i < ipv6Len; ++i) {
447             if (isNeedZeroCompression && i == maxIndex) {
448                 if (maxIndex == 0) {
449                     res += "::";
450                 } else {
451                     res += ":";
452                 }
453                 i += maxSize - 1;
454                 continue;
455             }
456             res += ipv6[i];
457             i != (ipv6Len - 1) ? res += ":" : "";
458         }
459         return res;
460     }
461 
ToLower(std::string & str)462     void ToLower(std::string &str)
463     {
464         size_t strLen = str.size();
465         for (size_t i = 0; i < strLen; ++i) {
466             if (isupper(str[i])) {
467                 str[i] = static_cast<size_t>(tolower(str[i]));
468             }
469         }
470     }
471 
Compress(std::string str)472     std::string Compress(std::string str)
473     {
474         std::vector<std::string> temp;
475         size_t pos = 0;
476         size_t left = 0;
477         while ((pos = str.find(":", left)) != std::string::npos) {
478             temp.push_back(str.substr(left, pos - left));
479             left = pos + 1;
480         }
481         temp.push_back(str.substr(left));
482         RemoveLeadingZeros(temp);
483         std::string res = ZeroCompression(temp);
484         ToLower(res);
485         return res;
486     }
487 
IPv6Host(std::string & input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)488     void IPv6Host(std::string& input, std::string& host,
489         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
490     {
491         std::regex ipv6("(::|(:((:[0-9A-Fa-f]{1,4}){1,7}))|(([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|"
492                         "(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|:))|(([0-9A-Fa-f]{1,4}:){2}"
493                         "(((:[0-9A-Fa-f]{1,4}){1,5})|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})"
494                         "|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|:))|(([0-9A-Fa-f]{1,4}:){5}"
495                         "(((:[0-9A-Fa-f]{1,4}){1,2})|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|:))|"
496                         "(((:(:[0-9A-Fa-f]{1,4}){0,5}:)|(([0-9A-Fa-f]{1,4}:){1}(:[0-9A-Fa-f]{1,4}){0,4}:)"
497                         "|(([0-9A-Fa-f]{1,4}:){2}(:[0-9A-Fa-f]{1,4}){0,3}:)|(([0-9A-Fa-f]{1,4}:){3}"
498                         "(:[0-9A-Fa-f]{1,4}){0,2}:)|(([0-9A-Fa-f]{1,4}:){4}(:[0-9A-Fa-f]{1,4})?:)|"
499                         "(([0-9A-Fa-f]{1,4}:){5}:)|(([0-9A-Fa-f]{1,4}:){6}))((25[0-5]|2[0-4]\\d|1\\d{2}|"
500                         "[1-9]\\d|\\d)\\.){3}(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)))(%[a-zA-Z0-9._]+)?");
501         if (!std::regex_match(input, ipv6)) {
502             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
503             return;
504         }
505         size_t pos = 0;
506         pos = input.find('.');
507         if (pos != std::string::npos) {
508             input = DealIpv4(input);
509         }
510         FormatIpv6(input);
511         input = Compress(input);
512         host = "[" + input + "]";
513         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
514         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT10));
515     }
516 
IsRadix(std::string num,std::string radix)517     bool IsRadix(std::string num, std::string radix)
518     {
519         size_t len = num.size();
520         for (size_t i = 0; i < len; ++i) {
521             if (radix.find(num[i]) == std::string::npos) {
522                 return false;
523             }
524         }
525         return true;
526     }
527 
IsNumber(std::string num,int & radix)528     bool IsNumber(std::string num, int &radix)
529     {
530         size_t len = num.size();
531         if (len >= 2 && num[0] == '0' && (num[1] == 'x' || num[1] == 'X')) { // 2:hex head length
532             radix = 16; // 16:hex
533             std::string subStr = num.substr(2); // 2:jump 0x
534             if (subStr.empty()) {
535                 return true;
536             }
537             return IsRadix(subStr, "0123456789abcdefABCDEF");
538         } else if (len >= 1 && num[0] == '0') {
539             radix = 8; // 8:octal
540             std::string subStr = num.substr(1);
541             if (subStr.empty()) {
542                 return true;
543             }
544             return IsRadix(num.substr(1), "01234567");
545         } else if (IsRadix(num, "0123456789")) {
546             radix = 10; // 10:decimal
547             return true;
548         }
549         return false;
550     }
551 
BinaryConversion(std::string num,int radix)552     std::string BinaryConversion(std::string num, int radix)
553     {
554         int val = 0;
555         if (radix == 16) { // 16:hex
556             if (num.substr(2).empty()) { // 2:jump 0x
557                 return "0";
558             }
559             if (sscanf_s(num.c_str(), "%x", &val) == -1) {
560                 HILOG_ERROR("URL:: BinaryConversion sscanf_s is falie");
561                 return num;
562             }
563             return std::to_string(val);
564         } else if (radix == 8) { // 8:octal
565             if (num.substr(1).empty()) {
566                 return "0";
567             }
568             if (sscanf_s(num.c_str(), "%o", &val) == -1) {
569                 HILOG_ERROR("URL:: BinaryConversion sscanf_s is falie");
570                 return num;
571             }
572             return std::to_string(val);
573         } else {
574             return num;
575         }
576     }
577 
RemovalIpv4(std::vector<std::string> & temp,std::string str,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)578     bool RemovalIpv4(std::vector<std::string> &temp, std::string str,
579                      std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
580     {
581         size_t pos = 0;
582         size_t left = 0;
583         while ((pos = str.find(".", left)) != std::string::npos) {
584             temp.push_back(str.substr(left, pos - left));
585             left = pos + 1;
586         }
587 
588         if (left != str.size()) {
589             temp.push_back(str.substr(left));
590         }
591 
592         size_t tmpLen = temp.size();
593         std::vector<std::string> res;
594         for (size_t i = 0; i < tmpLen; ++i) {
595             int radix = 0;
596             if (IsNumber(temp[i], radix)) {
597                 res.push_back(BinaryConversion(temp[i], radix));
598             } else {
599                 return false;
600             }
601         }
602         temp = res;
603         bool isIpv4 = true;
604         for (size_t i = 0; i < tmpLen; ++i) {
605             if (temp[i] == "") {
606                 isIpv4 = false;
607                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
608                 if (i == tmpLen - 1) {
609                     temp.push_back("");
610                     flags.reset(static_cast<size_t>(BitsetStatusFlag::BIT0));
611                 }
612             }
613         }
614         return isIpv4;
615     }
616 
IsFormatIpv4(std::vector<std::string> nums)617     int IsFormatIpv4(std::vector<std::string> nums)
618     {
619         size_t len = nums.size();
620         for (size_t i = 0; i < len; ++i) {
621             if (nums[i].size() > 8) { // 8:ipv4 max value size
622                 return i;
623             }
624             if (!nums[i].empty() && stoi(nums[i]) > 255) { // 255:ipv4 max value
625                 return i;
626             }
627         }
628         return -1;
629     }
630 
SplitNum(std::string num,size_t & number)631     std::string SplitNum(std::string num, size_t& number)
632     {
633         if (num.size() > 8) { // 8:ipv4 max value size
634             number = num.size();
635             return num;
636         }
637         int val = stoi(num);
638         std::vector<std::string> nums;
639         std::string res = "";
640         while (val > 0) {
641             int numConver = val % 256; // 256:ipv4 max value
642             nums.push_back(std::to_string(numConver));
643             val /= 256; // 256:ipv4 max value
644         }
645         for (int i = static_cast<int>(nums.size()) - 1; i >= 0; --i) {
646             res += nums[i] + ".";
647         }
648         number = nums.size();
649         return res.substr(0, res.size() - 1);
650     }
651 
FormatIpv4(std::vector<std::string> nums,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)652     void FormatIpv4(std::vector<std::string> nums, std::string& host,
653         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
654     {
655         size_t len = nums.size();
656         int index = IsFormatIpv4(nums);
657         std::string res = "";
658         if (index == -1) {
659             for (size_t i = 0; i < len - 1; ++i) {
660                 res += nums[i] + ".";
661             }
662             for (size_t i = 0; i < 4 - len; ++i) { // 4:ipv4 max size
663                 res += "0.";
664             }
665             res += nums[len - 1];
666             host = res;
667             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
668         } else if (index == static_cast<int>(len - 1)) {
669             for (size_t i = 0; i < len - 1; ++i) {
670                 res += nums[i] + ".";
671             }
672             size_t number = 0;
673             std::string temp = SplitNum(nums[index], number);
674             if (number + (len - 1) > 4) { // 4:ipv4 max size
675                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
676                 return;
677             }
678             for (size_t i = 0; i < 4 - (len - 1 + number); ++i) { // 4:ipv4 max size
679                 temp = "0." + temp;
680             }
681             host = res + temp;
682             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
683         } else {
684             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
685             return;
686         }
687     }
688 
AnalyseIPv4(const std::string & input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)689     void AnalyseIPv4(const std::string& input, std::string& host,
690         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
691     {
692         bool isipv4 = false;
693         std::vector<std::string> temp;
694         isipv4 = RemovalIpv4(temp, input, flags);
695         size_t tempLen = temp.size();
696         size_t lastSize = temp[tempLen - 1].size();
697         if (isipv4 == true && lastSize > 8) { // 8: ipv4 last number size
698             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
699             return;
700         }
701         std::string res = "";
702         for (size_t i = 0; i < tempLen; ++i) {
703             res += temp[i];
704             if (i != tempLen - 1) {
705                 res += ".";
706             }
707         }
708         if (isipv4) {
709             if (tempLen > 4) { // 4:ipv4 max size
710                 ToLower(res);
711                 host = res;
712                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
713             } else if (tempLen == 4) { // 4:ipv4 max size
714                 if (IsFormatIpv4(temp) == -1) {
715                     host = res;
716                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
717                 } else {
718                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
719                 }
720             } else {
721                 FormatIpv4(temp, host, flags);
722             }
723         } else {
724             ToLower(res);
725             host = res;
726             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
727         }
728     }
729 
AnalysisHost(std::string & input,std::string & host,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,bool special)730     void AnalysisHost(std::string& input, std::string& host,
731         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool special)
732     {
733         if (input.empty()) {
734             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
735             return;
736         }
737         if (input[0] == '[') {
738             if ((input[input.length() - 1]) == ']') {
739                 size_t  b = input.length();
740                 input = input.substr(1, b - 2); // 2:Truncating Strings
741                 IPv6Host(input, host, flags);
742                 return;
743             } else {
744                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
745                 return;
746             }
747         }
748         if (!special) {
749             AnalysisOpaqueHost(input, host, flags);
750             return;
751         }
752         std::string decodeInput = DecodeSpecialChars(input);
753         if (!CheckCharacter(decodeInput, g_specialCharForBit)) {
754             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
755             return;
756         }
757         AnalyseIPv4(decodeInput, host, flags);
758     }
759 
ISFileNohost(const std::string & input)760     bool ISFileNohost(const std::string& input)
761     {
762         if ((isalpha(input[0]) && (input[1] == ':' || input[1] == '|'))) {
763             return true;
764         }
765         return false;
766     }
767 
AnalysisFilePath(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)768     void AnalysisFilePath(std::string& input, UrlData& urlinfo,
769         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
770     {
771         std::vector<std::string> temp;
772         size_t pos = 0;
773         while (((pos = input.find('/')) != std::string::npos) || ((pos = input.find('\\')) != std::string::npos)) {
774             temp.push_back(input.substr(0, pos));
775             input = input.substr(pos + 1);
776         }
777         temp.push_back(input);
778         size_t length = temp.size();
779         for (size_t i = 0; i < length; ++i) {
780             auto a = find(g_doubleSegment.begin(), g_doubleSegment.end(), temp[i]);
781             if (a != g_doubleSegment.end()) {
782                 if ((urlinfo.path.size() == 1) && ISFileNohost(urlinfo.path[0]) &&
783                     urlinfo.path[0].size() == 2) { // 2:The interception length is 2
784                     urlinfo.path[0][1] = ':';
785                 } else if (!urlinfo.path.empty()) {
786                     urlinfo.path.pop_back();
787                 }
788                 if (i == temp.size() - 1) {
789                     urlinfo.path.push_back("");
790                 }
791                 continue;
792             }
793             a = find(g_singlesegment.begin(), g_singlesegment.end(), temp[i]);
794             if (a != g_singlesegment.end()) {
795                 if (i == temp.size() - 1) {
796                     urlinfo.path.push_back("");
797                 }
798                 continue;
799             }
800             urlinfo.path.push_back(temp[i]);
801             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
802         }
803         std::string it = urlinfo.path[0];
804         if (isalpha(it[0]) && (it[1] == ':' || it[1] == '|')) {
805             if (it.size() == 2) { // 2:The length is 2
806                 it[1] = ':';
807                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4), 0);
808                 urlinfo.host.clear();
809             }
810         }
811     }
812 
AnalysisSpecialFile(std::string & temp,size_t pos,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)813     void AnalysisSpecialFile(std::string& temp, size_t pos, UrlData& urlinfo,
814         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
815     {
816         std::string strHost = temp.substr(0, pos);
817         std::string strPath = temp.substr(pos + 1);
818         bool special = true;
819         if (!ISFileNohost(strHost)) {
820             AnalysisHost(strHost, urlinfo.host, flags, special);
821         } else if (!ISFileNohost(strHost) && flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
822             return;
823         }
824         if (!ISFileNohost(strHost)) {
825             AnalysisFilePath(strPath, urlinfo, flags);
826         } else {
827             AnalysisFilePath(temp, urlinfo, flags);
828         }
829     }
AnalysisFile(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)830     void AnalysisFile(std::string& input, UrlData& urlinfo,
831         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
832     {
833         bool special = true;
834         if ((input[0] == '/' || input[0] == '\\') && (input[1] == '/' || input[1] == '\\')) {
835             std::string temp = input.substr(2); // 2:Intercept from 2 subscripts
836             size_t pos = 0;
837             if ((((pos = temp.find('/')) != std::string::npos) ||
838                 ((pos = temp.find('\\')) != std::string::npos)) && pos == 0) {
839                 temp = temp.substr(1);
840                 AnalysisFilePath(temp, urlinfo, flags);
841             } else if ((((pos = temp.find('/')) != std::string::npos) ||
842                 ((pos = temp.find('\\')) != std::string::npos)) && pos != 0) {
843                 AnalysisSpecialFile(temp, pos, urlinfo, flags);
844             } else {
845                 if (!temp.empty() && flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
846                     AnalysisHost(temp, urlinfo.host, flags, special);
847                 } else if (!temp.empty() && !flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
848                     AnalysisHost(temp, urlinfo.host, flags, special);
849                     return;
850                 }
851             }
852         } else {
853             if (input[0] == '/' || input[0] == '\\') {
854                 input = input.substr(1);
855             }
856             AnalysisFilePath(input, urlinfo, flags);
857         }
858     }
859 
AnalysisFilescheme(const std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)860     void AnalysisFilescheme(const std::string& input, UrlData& urlinfo,
861         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
862     {
863         std::string strPath = urlinfo.scheme + input;
864         urlinfo.scheme = "file:";
865         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
866         AnalysisFilePath(strPath, urlinfo, flags);
867     }
868 
AnalyInfoPath(std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,UrlData & urlinfo,const std::string & input)869     void AnalyInfoPath(std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags,
870         UrlData& urlinfo, const std::string& input)
871     {
872         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT9));
873         if (urlinfo.path.empty()) {
874             urlinfo.path.emplace_back("");
875         }
876         urlinfo.path[0] = input;
877         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
878         return;
879     }
880 
AnalyHostPath(std::string & strHost,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,UrlData & urlinfo)881     void AnalyHostPath(std::string &strHost, std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags,
882         UrlData& urlinfo)
883     {
884         size_t pos = 0;
885         if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos) {
886             std::string port = strHost.substr(pos + 1);
887             strHost = strHost.substr(0, pos);
888             AnalysisPort(port, urlinfo, flags);
889             if (flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
890                 return;
891             }
892         }
893     }
AnalyStrHost(std::string & strHost,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)894     void AnalyStrHost(std::string &strHost, UrlData& urlinfo,
895         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
896     {
897         if (strHost.find('@') != std::string::npos) {
898             AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
899         }
900         if (strHost.empty()) {
901             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
902             return;
903         }
904     }
905 
AnalysisNoDefaultProtocol(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)906     void AnalysisNoDefaultProtocol(std::string& input, UrlData& urlinfo,
907         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
908     {
909         if (urlinfo.scheme.size() == 2) { // 2:The length is 2
910             AnalysisFilescheme(input, urlinfo, flags);
911             return;
912         }
913         if (input[0] == '/' && input[1] == '/' && input[2] != '/') { // 2:The third character of the input
914             std::string hostandpath = input.substr(2); // 2:Intercept from 2 subscripts
915             if (hostandpath.empty()) {
916                 return;
917             }
918             size_t i = 0;
919             bool special = false;
920             std::string strHost = "";
921             if (hostandpath.find('/') != std::string::npos) {
922                 i = hostandpath.find('/');
923                 strHost = hostandpath.substr(0, i);
924                 std::string strPath = hostandpath.substr(i + 1);
925                 if (strHost.find('@') != std::string::npos) {
926                     AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
927                 }
928                 if (strHost.empty()) {
929                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
930                     return;
931                 }
932                 size_t pos = 0;
933                 if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos) {
934                     std::string port = strHost.substr(pos + 1);
935                     strHost = strHost.substr(0, pos);
936                     AnalysisPort(port, urlinfo, flags);
937                 }
938                 if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos &&
939                     flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
940                     return;
941                 }
942                 AnalysisHost(strHost, urlinfo.host, flags, special);
943                 AnalysisPath(strPath, urlinfo.path, flags, special);
944             } else {
945                 strHost = hostandpath;
946                 AnalyStrHost(strHost, urlinfo, flags);
947                 AnalyHostPath(strHost, flags, urlinfo);
948                 AnalysisHost(strHost, urlinfo.host, flags, special);
949             }
950         } else if (input[0] == '/' && input[1] == '/') {
951             std::string strOfPath = input.substr(1);
952             AnalysisPath(strOfPath, urlinfo.path, flags, false);
953         } else {
954             AnalyInfoPath(flags, urlinfo, input);
955         }
956     }
957 
AnalysisOnlyHost(const std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,size_t pos)958     void AnalysisOnlyHost(const std::string& input, UrlData& urlinfo,
959         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, size_t pos)
960     {
961         std::string strHost = input;
962         if (strHost.find('@') != std::string::npos) {
963             AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
964         }
965         if (strHost.empty()) {
966             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
967             return;
968         }
969         if (strHost[strHost.size() - 1] != ']') {
970             if ((pos = strHost.find_last_of(':')) != std::string::npos) {
971                 std::string port = strHost.substr(pos + 1);
972                 strHost = strHost.substr(0, pos);
973                 AnalysisPort(port, urlinfo, flags);
974             }
975             if ((pos = strHost.find_last_of(':')) != std::string::npos &&
976                 flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
977                 return;
978             }
979         }
980         AnalysisHost(strHost, urlinfo.host, flags, true);
981     }
982 
JudgePos(size_t & pos,const size_t & length,const std::string & input)983     void JudgePos(size_t &pos, const size_t &length, const std::string& input)
984     {
985         for (pos = 0; pos < length; pos++) {
986             if (input[pos] == '/' || input[pos] == '\\') {
987                 break;
988             }
989         }
990     }
991 
SkipSlashSymbol(std::string & input,size_t & pos)992     void SkipSlashSymbol(std::string& input, size_t& pos)
993     {
994         size_t inputLen = input.size();
995         while (pos < inputLen) {
996             if (input[pos] == '/' || input[pos] == '\\') {
997                 pos++;
998                 continue;
999             }
1000                 break;
1001         }
1002         input = input.substr(pos);
1003     }
1004 
ParsingHostAndPath(std::string & input,UrlData & urlinfo,size_t & pos,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1005     void ParsingHostAndPath(std::string& input, UrlData& urlinfo, size_t& pos,
1006         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
1007     {
1008         bool special = true;
1009         size_t length = input.size();
1010         JudgePos(pos, length, input);
1011         std::string strHost = input.substr(0, pos);
1012         std::string strPath = input.substr(pos + 1);
1013         if (strHost.find('@') != std::string::npos) {
1014             AnalysisUsernameAndPasswd(strHost, urlinfo.username, urlinfo.password, flags);
1015         }
1016         if (strHost.empty()) {
1017             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1018             return;
1019         }
1020         if (strHost[strHost.size() - 1] != ']' && (pos = strHost.find_last_of(':')) != std::string::npos) {
1021             pos = strHost.find_last_of(':');
1022             if (pos != std::string::npos) {
1023                 std::string port = strHost.substr(pos + 1);
1024                 strHost = strHost.substr(0, pos);
1025                 AnalysisPort(port, urlinfo, flags);
1026             }
1027         }
1028         if (strHost[strHost.size() - 1] != ']' && strHost.find_last_of(':') != std::string::npos &&
1029             flags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1030             return;
1031         }
1032         AnalysisHost(strHost, urlinfo.host, flags, special);
1033         AnalysisPath(strPath, urlinfo.path, flags, special);
1034     }
1035 
AnalysisHostAndPath(std::string & input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1036     void AnalysisHostAndPath(std::string& input, UrlData& urlinfo,
1037         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
1038     {
1039         if (flags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))) {
1040             size_t pos = 0;
1041             SkipSlashSymbol(input, pos);
1042             if (input.size() == 0) {
1043                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1044                 return;
1045             } else if ((input.find('/') != std::string::npos || input.find('\\') != std::string::npos)) {
1046                 ParsingHostAndPath(input, urlinfo, pos, flags);
1047             } else if (input.size() != 0 && input.find('/') == std::string::npos &&
1048                 input.find('\\') == std::string::npos) {
1049                 AnalysisOnlyHost(input, urlinfo, flags, pos);
1050             }
1051         } else {
1052             size_t inputLen = input.size();
1053             if (inputLen > 0) {
1054                 urlinfo.isSpecialPath = input[0] != '/' ? true : false;
1055             }
1056             AnalysisNoDefaultProtocol(input, urlinfo, flags);
1057         }
1058     }
1059 
AnalysisInput(std::string & input,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1060     void AnalysisInput(std::string& input, UrlData& urlData,
1061         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
1062     {
1063         size_t pos = 0;
1064         if (input.find('#') != std::string::npos) {
1065             pos = input.find('#');
1066             std::string fragment = input.substr(pos);
1067             AnalysisFragment(fragment, urlData.fragment, flags);
1068             input = input.substr(0, pos);
1069         }
1070         if (input.find('?') != std::string::npos) {
1071             pos = input.find('?');
1072             std::string query = input.substr(pos);
1073             AnalysisQuery(query, urlData.query, flags);
1074             input = input.substr(0, pos);
1075         }
1076         bool special = (flags.test(static_cast<size_t>(BitsetStatusFlag::BIT1)) ? true : false);
1077         std::string pathStr = input;
1078         AnalysisPath(pathStr, urlData.path, flags, special);
1079     }
1080 
BaseInfoToUrl(const UrlData & baseInfo,const std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & baseflags,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,bool inputIsEmpty)1081     void BaseInfoToUrl(const UrlData& baseInfo,
1082         const std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& baseflags, UrlData& urlData,
1083         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool inputIsEmpty)
1084     {
1085         urlData.scheme = baseInfo.scheme;
1086         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1),
1087             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1)));
1088         urlData.host = baseInfo.host;
1089         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1090         urlData.username = baseInfo.username;
1091         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2),
1092             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT2)));
1093         urlData.password = baseInfo.password;
1094         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT3),
1095             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT3)));
1096         urlData.port = baseInfo.port;
1097         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT5),
1098             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT5)));
1099         if (inputIsEmpty) {
1100             urlData.path = baseInfo.path;
1101             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1102                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1103             urlData.query = baseInfo.query;
1104             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT7),
1105                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT7)));
1106             urlData.fragment = baseInfo.fragment;
1107             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT8),
1108                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT8)));
1109         }
1110         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT9),
1111             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9)));
1112         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT10),
1113             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT10)));
1114     }
1115 
ShorteningPath(UrlData & urlData,UrlData & baseData,bool isFile)1116     void ShorteningPath(UrlData& urlData, UrlData& baseData, bool isFile)
1117     {
1118         if (baseData.path.empty()) {
1119             return;
1120         }
1121         if (urlData.path.size() == 1 && urlData.path[0].empty()) {
1122             urlData.path.pop_back();
1123             return;
1124         }
1125         if ((baseData.path.size() == 1) && isFile &&
1126             isalpha(baseData.path[0][0]) && (baseData.path[0][1] == ':')) {
1127             return;
1128         }
1129         baseData.path.pop_back();
1130     }
1131 
InitOnlyInput(std::string & input,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1132     void InitOnlyInput(std::string& input, UrlData& urlData,
1133         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
1134     {
1135         if (input.empty()) {
1136             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1137             return;
1138         }
1139         if (input.find(':') != std::string::npos) {
1140             size_t pos = input.find(':');
1141             pos++;
1142             std::string scheme = input.substr(0, pos);
1143             if (!AnalysisScheme(scheme, urlData.scheme, flags)) {
1144                 return;
1145             }
1146             if (input.find('#') != std::string::npos) {
1147                 size_t posTmp = input.find('#');
1148                 std::string fragment = input.substr(posTmp);
1149                 AnalysisFragment(fragment, urlData.fragment, flags);
1150                 input = input.substr(0, posTmp);
1151             }
1152             if (input.find('?') != std::string::npos) {
1153                 size_t position = input.find('?');
1154                 std::string query = input.substr(position);
1155                 AnalysisQuery(query, urlData.query, flags);
1156                 input = input.substr(0, position);
1157             }
1158             std::string str = input.substr(pos);
1159             if (urlData.scheme == "file:") {
1160                 AnalysisFile(str, urlData, flags);
1161             } else {
1162                 AnalysisHostAndPath(str, urlData, flags);
1163             }
1164         } else {
1165             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1166             return;
1167         }
1168     }
1169 
ToolHasBase(std::string input,std::string & strInput,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1170     void ToolHasBase(std::string input, std::string &strInput, UrlData &urlData,
1171         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
1172     {
1173         if (!input.empty() && input[0] == '/') {
1174             strInput = input.substr(1);
1175             AnalysisInput(strInput, urlData, flags);
1176         } else if (!input.empty() && input[0] != '/') {
1177             AnalysisInput(strInput, urlData, flags);
1178         }
1179     }
1180 
BasePathToStr(UrlData & urlData)1181     std::string BasePathToStr(UrlData &urlData)
1182     {
1183         std::string temp = "";
1184         size_t length = urlData.path.size();
1185         for (size_t i = 0; i < length; i++) {
1186             if (i < length - 1) {
1187                 temp += urlData.path[i] + "/";
1188             } else {
1189                 temp += urlData.path[i];
1190             }
1191         }
1192         return temp;
1193     }
1194 
URL(const std::string & input)1195     URL::URL(const std::string& input)
1196     {
1197         std::string str = input;
1198         PreliminaryWork();
1199         DeleteC0OrSpace(str);
1200         DeleteTabOrNewline(str);
1201         InitOnlyInput(str, urlData_, flags_);
1202     }
1203 
DelCont(std::string strBase,std::string & strInput,UrlData & baseInfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & baseflags)1204     void DelCont(std::string strBase, std::string &strInput, UrlData &baseInfo,
1205         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &baseflags)
1206     {
1207         DeleteC0OrSpace(strBase);
1208         DeleteTabOrNewline(strBase);
1209         DeleteC0OrSpace(strInput);
1210         DeleteTabOrNewline(strInput);
1211         InitOnlyInput(strBase, baseInfo, baseflags);
1212     }
1213 
URL(const std::string & input,const std::string & base)1214     URL::URL(const std::string& input, const std::string& base)
1215     {
1216         UrlData baseInfo;
1217         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> baseflags;
1218         std::string strBase = base;
1219         std::string strInput = input;
1220         if (strBase.empty()) {
1221             baseflags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1222         }
1223         DelCont(strBase, strInput, baseInfo, baseflags);
1224         if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1225             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1226             return;
1227         } else if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1228             InitOnlyInput(strInput, urlData_, flags_);
1229             if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1230                 return;
1231             }
1232             if ((input[0] == '/') && (input[1] == '/' || (input[1] == '\\' &&
1233                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))))) {
1234                 std::string newInput = baseInfo.scheme + input;
1235                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1236                 InitOnlyInput(newInput, urlData_, flags_);
1237                 return;
1238             }
1239             if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1240                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1241                 BaseInfoToUrl(baseInfo, baseflags, urlData_, flags_, input.empty());
1242                 ToolHasBase(input, strInput, urlData_, flags_);
1243                 if (!input.empty() && input[0] != '/' && urlData_.path.empty()) {
1244                     urlData_.path = baseInfo.path;
1245                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1246                         baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1247                 }
1248                 if (!input.empty() && input[0] != '/' && !urlData_.path.empty()) {
1249                     bool isFile = ((urlData_.scheme == "file:") ? true : false);
1250                     ShorteningPath(urlData_, baseInfo, isFile);
1251                     std::string basePathStr = BasePathToStr(baseInfo);
1252                     basePathStr == "" ? basePathStr = strInput : basePathStr += "/" + strInput;
1253                     urlData_.path.clear();
1254                     AnalysisInput(basePathStr, urlData_, flags_);
1255                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1256                 }
1257             } else if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1258                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1259                 return;
1260             }
1261         }
1262     }
1263 
URL(const std::string & input,const URL & base)1264     URL::URL(const std::string& input, const URL& base)
1265     {
1266         std::string strInput = input;
1267         UrlData baseInfo = base.urlData_;
1268         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> baseflags = base.flags_;
1269         DeleteC0OrSpace(strInput);
1270         DeleteTabOrNewline(strInput);
1271         InitOnlyInput(strInput, urlData_, flags_);
1272         if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1273             return;
1274         }
1275         if ((input[0] == '/') && (input[1] == '/' || (input[1] == '\\' &&
1276             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))))) {
1277             std::string newInput = baseInfo.scheme + input;
1278             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1279             InitOnlyInput(newInput, urlData_, flags_);
1280             return;
1281         }
1282         if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1283             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1284             BaseInfoToUrl(baseInfo, baseflags, urlData_, flags_, input.empty());
1285             ToolHasBase(input, strInput, urlData_, flags_);
1286             if (!input.empty() && input[0] != '/' && urlData_.path.empty()) {
1287                 urlData_.path = baseInfo.path;
1288                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1289                     baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1290             }
1291             if (!input.empty() && input[0] != '/' && !urlData_.path.empty()) {
1292                 bool isFile = ((urlData_.scheme == "file:") ? true : false);
1293                 ShorteningPath(urlData_, baseInfo, isFile);
1294                 std::string basePathStr = BasePathToStr(baseInfo);
1295                 basePathStr == "" ? basePathStr = strInput : basePathStr += "/" + strInput;
1296                 urlData_.path.clear();
1297                 AnalysisInput(basePathStr, urlData_, flags_);
1298                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1299             }
1300         } else if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1301             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1302             return;
1303         }
1304     }
1305 
GetHostname(napi_env env) const1306     napi_value URL::GetHostname(napi_env env) const
1307     {
1308         napi_value result;
1309         std::string temp = "";
1310         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1311             if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT10))) {
1312                 temp = EncodePercentEncoding(urlData_.host, URL_ENCODED_PERCENT_SIGN_CHARS);
1313             } else {
1314                 temp = urlData_.host;
1315             }
1316         }
1317         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1318         return result;
1319     }
1320 
GetSearch(napi_env env) const1321     napi_value URL::GetSearch(napi_env env) const
1322     {
1323         napi_value result;
1324         std::string temp = "";
1325         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT7)) && !(urlData_.query.size() == 1)) {
1326             temp = urlData_.query;
1327         }
1328         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1329         return result;
1330     }
1331 
GetEncodeSearch(napi_env env) const1332     napi_value URL::GetEncodeSearch(napi_env env) const
1333     {
1334         napi_value result;
1335         std::string temp = "";
1336         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT7)) && !(urlData_.query.size() == 1)) {
1337             temp = EncodePercentEncoding(urlData_.query, QUERY_PERCENT_SIGN_CHARS);
1338         }
1339         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1340         return result;
1341     }
1342 
GetUsername(napi_env env) const1343     napi_value URL::GetUsername(napi_env env) const
1344     {
1345         napi_value result;
1346         std::string temp = "";
1347         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT2))) {
1348             temp = EncodePercentEncoding(urlData_.username, USERINFO_PERCENT_SIGN_CHARS);
1349         }
1350         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1351         return result;
1352     }
1353 
GetPassword(napi_env env) const1354     napi_value URL::GetPassword(napi_env env) const
1355     {
1356         napi_value result;
1357         std::string temp = "";
1358         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT3))) {
1359             temp = EncodePercentEncoding(urlData_.password, USERINFO_PERCENT_SIGN_CHARS);
1360         }
1361         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1362         return result;
1363     }
1364 
GetFragment(napi_env env) const1365     napi_value URL::GetFragment(napi_env env) const
1366     {
1367         napi_value result;
1368         std::string temp = "";
1369         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT8)) && !(urlData_.fragment.size() == 1)) {
1370             temp = EncodePercentEncoding(urlData_.fragment, FRAGMENT_PERCENT_SIGN_CHARS);
1371         }
1372         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1373         return result;
1374     }
1375 
GetScheme(napi_env env) const1376     napi_value URL::GetScheme(napi_env env) const
1377     {
1378         napi_value result;
1379         std::string temp = "";
1380         if (!urlData_.scheme.empty()) {
1381             temp = urlData_.scheme;
1382         }
1383         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1384         return result;
1385     }
1386 
GetPath(napi_env env) const1387     napi_value URL::GetPath(napi_env env) const
1388     {
1389         napi_value result;
1390         std::string temp = "/";
1391         if (urlData_.isSpecialPath) {
1392             temp = "";
1393         }
1394         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1395             size_t length = urlData_.path.size();
1396             for (size_t i = 0; i < length; i++) {
1397                 if (i < length - 1) {
1398                     temp += urlData_.path[i] + "/";
1399                 } else {
1400                     temp += urlData_.path[i];
1401                 }
1402             }
1403         } else {
1404             bool special = IsSpecial(urlData_.scheme);
1405             if (!special) {
1406                 temp = "";
1407             }
1408         }
1409         temp = EncodePercentEncoding(temp, PATH_PERCENT_SIGN_CHARS);
1410         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1411         return result;
1412     }
1413 
GetPort(napi_env env) const1414     napi_value URL::GetPort(napi_env env) const
1415     {
1416         napi_value result;
1417         std::string temp = "";
1418         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1419             temp = std::to_string(urlData_.port);
1420         }
1421         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1422         return result;
1423     }
1424 
GetHost(napi_env env) const1425     napi_value URL::GetHost(napi_env env) const
1426     {
1427         napi_value result;
1428         std::string temp = urlData_.host;
1429         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1430             temp += ":";
1431             temp += std::to_string(urlData_.port);
1432         }
1433         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1434         return result;
1435     }
1436 
GetEncodeHost(napi_env env) const1437     napi_value URL::GetEncodeHost(napi_env env) const
1438     {
1439         napi_value result;
1440         std::string temp = urlData_.host;
1441         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1442             temp += ":";
1443             temp += std::to_string(urlData_.port);
1444         }
1445         if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT10))) {
1446             temp = EncodePercentEncoding(temp, URL_ENCODED_PERCENT_SIGN_CHARS);
1447         }
1448         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1449         return result;
1450     }
1451 
GetOnOrOff(napi_env env) const1452     napi_value URL::GetOnOrOff(napi_env env) const
1453     {
1454         napi_value result;
1455         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1456             bool flag = false;
1457             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
1458         } else {
1459             bool flag = true;
1460             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
1461         }
1462         return result;
1463     }
1464 
GetIsIpv6(napi_env env) const1465     napi_value URL::GetIsIpv6(napi_env env) const
1466     {
1467         napi_value result;
1468         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT10))) {
1469             NAPI_CALL(env, napi_get_boolean(env, true, &result));
1470         } else {
1471             NAPI_CALL(env, napi_get_boolean(env, false, &result));
1472         }
1473         return result;
1474     }
1475 
SetHostname(const std::string & input)1476     void URL::SetHostname(const std::string& input)
1477     {
1478         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1479             return;
1480         }
1481         std::string strHost = input;
1482         size_t length = strHost.size();
1483         for (size_t pos = 0; pos < length; pos++) {
1484             if ((strHost[pos] == ':') || (strHost[pos] == '?') || (strHost[pos] == '#') ||
1485                 (strHost[pos] == '/') || (strHost[pos] == '\\')) {
1486                 strHost = strHost.substr(0, pos);
1487                 break;
1488             }
1489         }
1490         if (strHost.size() == 0) {
1491             return;
1492         }
1493         bool special = IsSpecial(urlData_.scheme);
1494         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1495         std::string thisHostname = "";
1496         AnalysisHost(strHost, thisHostname, thisFlags, special);
1497         if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1498             if ((urlData_.scheme == "file:") && (thisHostname == "localhost")) {
1499                 thisHostname = "";
1500             }
1501             urlData_.host = thisHostname;
1502             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1503         }
1504     }
1505 
SetHref(const std::string & input)1506     void URL::SetHref(const std::string& input)
1507     {
1508         std::string str = input;
1509         DeleteC0OrSpace(str);
1510         DeleteTabOrNewline(str);
1511         UrlData thisNewUrl;
1512         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisNewFlags;
1513         InitOnlyInput(str, thisNewUrl, thisNewFlags);
1514         if (!thisNewFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1515             urlData_ = thisNewUrl;
1516             flags_ = thisNewFlags;
1517         }
1518     }
1519 
SetPath(const std::string & input)1520     void URL::SetPath(const std::string& input)
1521     {
1522         std::string strPath = EncodePercentEncoding(input, PATH_PERCENT_SIGN_CHARS);
1523         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9)) || strPath.empty()) {
1524             return;
1525         }
1526         std::string oldstr = "%3A";
1527         std::string newstr = ":";
1528         ReplaceSpecialSymbols(strPath, oldstr, newstr);
1529         bool special = IsSpecial(urlData_.scheme);
1530         if (urlData_.scheme == "file:") {
1531             UrlData thisFileDate;
1532             std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFileFlag;
1533             if ((strPath[0] == '/') || (strPath[0] == '\\' &&
1534                 flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT1)))) {
1535                 strPath = strPath.substr(1);
1536             }
1537             AnalysisFilePath(strPath, thisFileDate, thisFileFlag);
1538             if (thisFileFlag.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1539                 urlData_.path = thisFileDate.path;
1540                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1541             }
1542         } else {
1543             std::vector<std::string> thisPath;
1544             std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1545             if ((strPath[0] == '/') || (strPath[0] == '\\' &&
1546                 flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT1)))) {
1547                 strPath = strPath.substr(1);
1548             }
1549             AnalysisPath(strPath, thisPath, thisFlags, special);
1550             if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1551                 urlData_.path = thisPath;
1552                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1553             }
1554         }
1555     }
1556 
SplitString(const std::string & input,std::string & strHost,std::string & port)1557     void SplitString(const std::string& input, std::string& strHost, std::string& port)
1558     {
1559         size_t strlen = input.size();
1560         for (size_t pos = 0; pos < strlen; pos++) {
1561             if ((input[pos] == ':') || (input[pos] == '?') || (input[pos] == '#') ||
1562                 (input[pos] == '/') || (input[pos] == '\\')) {
1563                 strHost = input.substr(0, pos);
1564                 if (input[pos] == ':') {
1565                     pos++;
1566                     port = input.substr(pos);
1567                 }
1568                 break;
1569             }
1570         }
1571     }
1572 
SetHost(const std::string & input)1573     void URL::SetHost(const std::string& input)
1574     {
1575         if (input.empty() || flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1576             return;
1577         }
1578         std::string strHost = input;
1579         std::string port = "";
1580         SplitString(input, strHost, port);
1581         if (strHost.size() == 0) {
1582             return;
1583         }
1584         bool special = IsSpecial(urlData_.scheme);
1585         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> hostnameflags;
1586         std::string thisHostname = "";
1587         AnalysisHost(strHost, thisHostname, hostnameflags, special);
1588         if (hostnameflags.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1589             if ((urlData_.scheme == "file:") && (thisHostname == "localhost")) {
1590                 thisHostname = "";
1591             }
1592             urlData_.host = thisHostname;
1593             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1594         } else {
1595             return;
1596         }
1597         if (port.size() > 0) {
1598             size_t strlen = port.size();
1599             for (size_t pos = 0; pos < strlen; pos++) {
1600                 if ((port[pos] == '?') || (port[pos] == '#') || (port[pos] == '/') || (port[pos] == '\\')) {
1601                     port = port.substr(0, pos);
1602                     break;
1603                 }
1604             }
1605             if (port.size() > 0) {
1606                 std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1607                 UrlData thisport;
1608                 AnalysisPort(port, thisport, thisFlags);
1609                 if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1610                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
1611                     urlData_.port = thisport.port;
1612                 }
1613             }
1614         }
1615     }
1616 
SetPort(const std::string & input)1617     void URL::SetPort(const std::string& input)
1618     {
1619         std::string port = input;
1620         size_t portlen = port.size();
1621         for (size_t pos = 0; pos < portlen; pos++) {
1622             if ((port[pos] == '?') || (port[pos] == '#') || (port[pos] == '/') || (port[pos] == '\\')) {
1623                 port = port.substr(0, pos);
1624                 break;
1625             }
1626         }
1627         if (port.size() > 0) {
1628             std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1629             UrlData thisport;
1630             AnalysisPort(port, thisport, thisFlags);
1631             if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1632                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
1633                 urlData_.port = thisport.port;
1634             }
1635         }
1636     }
1637 
SetSearch(const std::string & input)1638     void URL::SetSearch(const std::string& input)
1639     {
1640         std::string temp;
1641         if (input.size() == 0) {
1642             urlData_.query = "";
1643             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT7), 0);
1644         } else {
1645             if (input[0] != '?') {
1646                 temp = "?";
1647                 temp += input;
1648             } else {
1649                 temp = input;
1650             }
1651             std::string oldstr = "#";
1652             std::string newstr = "%23";
1653             ReplaceSpecialSymbols(temp, oldstr, newstr);
1654             AnalysisQuery(temp, urlData_.query, flags_);
1655         }
1656     }
1657 
SetEncodeSearch(const std::string & input)1658     void URL::SetEncodeSearch(const std::string& input)
1659     {
1660         SetSearch(EncodePercentEncoding(input, QUERY_PERCENT_SIGN_CHARS));
1661     }
1662 
SetFragment(const std::string & input)1663     void URL::SetFragment(const std::string& input)
1664     {
1665         std::string temp;
1666         if (input.size() == 0) {
1667             urlData_.fragment = "";
1668             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT8), 0);
1669         } else {
1670             if (input[0] != '#') {
1671                 temp = "#";
1672                 temp += EncodePercentEncoding(input, FRAGMENT_PERCENT_SIGN_CHARS);
1673             } else {
1674                 temp = EncodePercentEncoding(input, FRAGMENT_PERCENT_SIGN_CHARS);
1675             }
1676             AnalysisFragment(temp, urlData_.fragment, flags_);
1677         }
1678     }
1679 
1680 
SetScheme(const std::string & input)1681     void URL::SetScheme(const std::string& input)
1682     {
1683         std::string strInput = input;
1684         bool special = IsSpecial(urlData_.scheme);
1685         bool inputIsSpecial = IsSpecial(input);
1686         if ((special != inputIsSpecial) || ((input == "file") &&
1687             (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT2)) ||
1688             flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT3)) ||
1689             flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))))) {
1690             return;
1691         }
1692         std::string thisScheme = "";
1693         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1694         if (AnalysisScheme(strInput, thisScheme, thisFlags)) {
1695             if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))) {
1696                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
1697             }
1698             urlData_.scheme = thisScheme;
1699         }
1700     }
1701 
SetUsername(const std::string & input)1702     void URL::SetUsername(const std::string& input)
1703     {
1704         if (input.size() == 0) {
1705             urlData_.username = "";
1706             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT2), 0);
1707         } else {
1708             std::string usname = EncodePercentEncoding(input, USERINFO_PERCENT_SIGN_CHARS);
1709             size_t len = g_specialSymbols.size() - 2; // 2:Maximum position of subscript
1710             for (size_t i = 0; i <= len; i += 2) {    // 2:Shift subscript right 2
1711                 ReplaceSpecialSymbols(usname, g_specialSymbols[i], g_specialSymbols[i + 1]);
1712             }
1713             urlData_.username = usname;
1714             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
1715         }
1716     }
1717 
SetPassword(const std::string & input)1718     void URL::SetPassword(const std::string& input)
1719     {
1720         if (input.size() == 0) {
1721             urlData_.password = "";
1722             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT3), 0);
1723         } else {
1724             std::string keyWord = EncodePercentEncoding(input, USERINFO_PERCENT_SIGN_CHARS);
1725             size_t len = g_specialSymbols.size() - 2; // 2:Maximum position of subscript
1726             for (size_t i = 0; i <= len; i += 2) {    // 2:Shift subscript right 2
1727                 ReplaceSpecialSymbols(keyWord, g_specialSymbols[i], g_specialSymbols[i + 1]);
1728             }
1729             urlData_.password = keyWord;
1730             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT3));
1731         }
1732     }
1733 
ContainsWideOrUnicodeChars(const std::string & str)1734     bool ContainsWideOrUnicodeChars(const std::string& str)
1735     {
1736         for (char c : str) {
1737             if (static_cast<unsigned char>(c) > 127) { // 127:Value range for non ASCII characters
1738                 return true;
1739             }
1740         }
1741         return false;
1742     }
1743 
HandleIllegalChar(std::wstring & inputStr,std::wstring::const_iterator it)1744     void URLSearchParams::HandleIllegalChar(std::wstring& inputStr, std::wstring::const_iterator it)
1745     {
1746         std::wstring::iterator iter = inputStr.begin();
1747         advance(iter, std::distance<std::wstring::const_iterator>(iter, it));
1748         while (iter != inputStr.end()) {
1749             char16_t ch = *iter;
1750             if (!((ch & 0xF800) == 0xD800)) {
1751                 ++iter;
1752                 continue;
1753             } else if ((ch & 0x400) != 0 || iter == inputStr.end() - 1) {
1754                 *iter = 0xFFFD;
1755             } else {
1756                 char16_t dh = *(iter + 1);
1757                 if ((dh & 0xFC00) == 0xDC00) {
1758                     ++iter;
1759                 } else {
1760                     *iter = 0xFFFD;
1761                 }
1762             }
1763             ++iter;
1764         }
1765     }
ToUSVString(std::string inputStr)1766     std::string URLSearchParams::ToUSVString(std::string inputStr)
1767     {
1768         std::wstring winput(inputStr.length(), L' ');
1769         std::copy(inputStr.begin(), inputStr.end(), winput.begin());
1770         std::wregex wexpr(L"(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])");
1771         std::wsmatch result;
1772         std::wstring::const_iterator iterStart = winput.begin();
1773         std::wstring::const_iterator iterEnd = winput.end();
1774         if (!regex_search(iterStart, iterEnd, result, wexpr)) {
1775             return inputStr;
1776         }
1777         HandleIllegalChar(winput, result[0].first);
1778         size_t inputLen = wcslen(winput.c_str());
1779         char *rePtr = nullptr;
1780         std::string reStr = "";
1781         size_t reSize = wcstombs(rePtr, winput.c_str(), 0) + 1;
1782         if (reSize > 0) {
1783             rePtr = new (std::nothrow) char[reSize];
1784             if (rePtr == nullptr) {
1785                 HILOG_ERROR("URLSearchParams:: memory allocation failed, rePtr is nullptr");
1786                 return reStr;
1787             }
1788             if (memset_s(rePtr, reSize, 0, reSize) != EOK) {
1789                 HILOG_ERROR("URLSearchParams:: ToUSVString memset_s failed");
1790                 delete[] rePtr;
1791                 return reStr;
1792             } else {
1793                 wcstombs(rePtr, winput.c_str(), inputLen);
1794                 reStr = rePtr;
1795             }
1796         }
1797         delete[] rePtr;
1798         return reStr;
1799     }
Get(napi_env env,napi_value buffer)1800     napi_value URLSearchParams::Get(napi_env env, napi_value buffer)
1801     {
1802         std::string name = "";
1803         size_t nameSize = 0;
1804         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1805             HILOG_ERROR("URLSearchParams:: can not get buffer size");
1806             return nullptr;
1807         }
1808         name.reserve(nameSize + 1);
1809         name.resize(nameSize);
1810         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1811             HILOG_ERROR("URLSearchParams:: can not get buffer value");
1812             return nullptr;
1813         }
1814         std::string sname = name;
1815         if (ContainsWideOrUnicodeChars(name)) {
1816             sname = ToUSVString(name);
1817         }
1818         napi_value result = nullptr;
1819         if (searchParams.size() == 0) {
1820             return result;
1821         }
1822         size_t size = searchParams.size() - 1;
1823         for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1824             if (searchParams[i] == sname) {
1825                 napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &result);
1826                 return result;
1827             }
1828         }
1829         return result;
1830     }
GetAll(napi_env env,napi_value buffer)1831     napi_value URLSearchParams::GetAll(napi_env env, napi_value buffer)
1832     {
1833         std::string name = "";
1834         size_t nameSize = 0;
1835         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1836             HILOG_ERROR("URLSearchParams:: can not get buffer size");
1837             return nullptr;
1838         }
1839         name.reserve(nameSize + 1);
1840         name.resize(nameSize);
1841         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1842             HILOG_ERROR("URLSearchParams:: can not get buffer value");
1843             return nullptr;
1844         }
1845         std::string sname = name;
1846         if (ContainsWideOrUnicodeChars(name)) {
1847             sname = ToUSVString(name);
1848         }
1849         napi_value result = nullptr;
1850         napi_value napiStr = nullptr;
1851         NAPI_CALL(env, napi_create_array(env, &result));
1852         size_t flag = 0;
1853         if (searchParams.size() == 0) {
1854             return result;
1855         }
1856         size_t size = searchParams.size() - 1;
1857         for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1858             if (searchParams[i] == sname) {
1859                 napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &napiStr);
1860                 NAPI_CALL(env, napi_set_element(env, result, flag, napiStr));
1861                 flag++;
1862             }
1863         }
1864         return result;
1865     }
Append(napi_env env,napi_value buffer,napi_value temp)1866     void URLSearchParams::Append(napi_env env, napi_value buffer, napi_value temp)
1867     {
1868         std::string name = "";
1869         size_t nameSize = 0;
1870         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1871             HILOG_ERROR("URLSearchParams:: can not get buffer size");
1872             return;
1873         }
1874         name.reserve(nameSize + 1);
1875         name.resize(nameSize);
1876         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1877             HILOG_ERROR("URLSearchParams:: can not get buffer value");
1878             return;
1879         }
1880         std::string tempName = name;
1881         std::string value = "";
1882         size_t valueSize = 0;
1883         if (napi_get_value_string_utf8(env, temp, nullptr, 0, &valueSize) != napi_ok) {
1884             HILOG_ERROR("URLSearchParams:: can not get temp size");
1885             return;
1886         }
1887         value.reserve(valueSize + 1);
1888         value.resize(valueSize);
1889         if (napi_get_value_string_utf8(env, temp, value.data(), valueSize + 1, &valueSize) != napi_ok) {
1890             HILOG_ERROR("URLSearchParams:: can not get temp value");
1891             return;
1892         }
1893         std::string tempValue = value;
1894         searchParams.push_back(tempName);
1895         searchParams.push_back(tempValue);
1896     }
Delete(napi_env env,napi_value buffer)1897     void URLSearchParams::Delete(napi_env env, napi_value buffer)
1898     {
1899         std::string name = "";
1900         size_t nameSize = 0;
1901         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1902             HILOG_ERROR("URLSearchParams:: can not get buffer size");
1903             return;
1904         }
1905         name.reserve(nameSize + 1);
1906         name.resize(nameSize);
1907         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1908             HILOG_ERROR("URLSearchParams:: can not get buffer value");
1909             return;
1910         }
1911         std::string sname = name;
1912         if (ContainsWideOrUnicodeChars(name)) {
1913             sname = ToUSVString(name);
1914         }
1915         for (auto iter = searchParams.begin(); iter != searchParams.end();) {
1916             if (*iter == sname) {
1917                 iter = searchParams.erase(iter, iter + 2); // 2:Searching for the number and number of keys and values
1918             } else {
1919                 iter += 2; // 2:Searching for the number and number of keys and values
1920             }
1921         }
1922     }
Entries(napi_env env) const1923     napi_value URLSearchParams::Entries(napi_env env) const
1924     {
1925         napi_value resend = nullptr;
1926         napi_value firNapiStr = nullptr;
1927         napi_value secNapiStr = nullptr;
1928         napi_create_array(env, &resend);
1929         if (searchParams.size() == 0) {
1930             return resend;
1931         }
1932         size_t size = searchParams.size() - 1;
1933         for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1934             napi_value result = nullptr;
1935             napi_create_array(env, &result);
1936             napi_create_string_utf8(env, searchParams[i].c_str(), searchParams[i].length(), &firNapiStr);
1937             napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &secNapiStr);
1938             napi_set_element(env, result, 0, firNapiStr);
1939             napi_set_element(env, result, 1, secNapiStr);
1940             napi_set_element(env, resend, i / 2, result); // 2:Find the number of keys
1941         }
1942         return resend;
1943     }
1944 
IsHas(napi_env env,napi_value name) const1945     napi_value URLSearchParams::IsHas(napi_env env, napi_value name) const
1946     {
1947         size_t bufferSize = 0;
1948         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
1949             HILOG_ERROR("URLSearchParams:: can not get name size");
1950             return nullptr;
1951         }
1952         std::string buf = "";
1953         buf.reserve(bufferSize + 1);
1954         buf.resize(bufferSize);
1955         if (napi_get_value_string_utf8(env, name, buf.data(), bufferSize + 1, &bufferSize) != napi_ok) {
1956             HILOG_ERROR("URLSearchParams:: can not get name value");
1957             return nullptr;
1958         }
1959         bool flag = false;
1960         napi_value result = nullptr;
1961         size_t lenStr = searchParams.size();
1962         for (size_t i = 0; i != lenStr; i += 2) { // 2:Searching for the number and number of keys and values
1963             if (searchParams[i] == buf) {
1964                 flag = true;
1965                 napi_get_boolean(env, flag, &result);
1966                 return result;
1967             }
1968         }
1969         napi_get_boolean(env, flag, &result);
1970         return result;
1971     }
Set(napi_env env,napi_value name,napi_value value)1972     void URLSearchParams::Set(napi_env env, napi_value name, napi_value value)
1973     {
1974         std::string buffer = "";
1975         size_t bufferSize = 0;
1976         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
1977             HILOG_ERROR("URLSearchParams:: can not get name size");
1978             return;
1979         }
1980         buffer.reserve(bufferSize + 1);
1981         buffer.resize(bufferSize);
1982         if (napi_get_value_string_utf8(env, name, buffer.data(), bufferSize + 1, &bufferSize) != napi_ok) {
1983             HILOG_ERROR("URLSearchParams:: can not get name value");
1984             return;
1985         }
1986         std::string cppName = buffer;
1987         std::string temp = "";
1988         size_t tempSize = 0;
1989         if (napi_get_value_string_utf8(env, value, nullptr, 0, &tempSize) != napi_ok) {
1990             HILOG_ERROR("URLSearchParams:: can not get value size");
1991             return;
1992         }
1993         temp.reserve(tempSize + 1);
1994         temp.resize(tempSize);
1995         if (napi_get_value_string_utf8(env, value, temp.data(), tempSize + 1, &tempSize) != napi_ok) {
1996             HILOG_ERROR("URLSearchParams:: can not get value value");
1997             return;
1998         }
1999         std::string cppValue = temp;
2000         bool flag = false;
2001         for (auto it = searchParams.begin(); it < (searchParams.end() - 1) && !searchParams.empty();) {
2002             if (*it == cppName) {
2003                 if (!flag) {
2004                     *(it + 1) = cppValue;
2005                     flag = true;
2006                     it += 2; // 2:Searching for the number and number of keys and values
2007                 } else {
2008                     it = searchParams.erase(it, it + 2); // 2:Searching for the number and number of keys and values
2009                 }
2010             } else {
2011                 it += 2; // 2:Searching for the number and number of keys and values
2012             }
2013         }
2014         if (!flag) {
2015             searchParams.push_back(cppName);
2016             searchParams.push_back(cppValue);
2017         }
2018     }
Sort()2019     void URLSearchParams::Sort()
2020     {
2021         size_t len = searchParams.size();
2022         if (len <= 2 || (len % 2 != 0)) { // 2: Iterate over key-value pairs
2023             return;
2024         }
2025         size_t i = 0;
2026         for (; i < len - 2; i += 2) { // 2:Iterate over key-value pairs
2027             size_t j = i + 2; // 2:Iterate over key-value pairs
2028             for (; j < len; j += 2) { // 2:Iterate over key-value pairs
2029                 bool tmp = (searchParams[i] > searchParams[j]);
2030                 if (tmp) {
2031                     const std::string curKey = searchParams[i];
2032                     const std::string curVal = searchParams[i + 1];
2033                     searchParams[i] = searchParams[j];
2034                     searchParams[i + 1] = searchParams[j + 1];
2035                     searchParams[j] = curKey;
2036                     searchParams[j + 1] = curVal;
2037                 }
2038             }
2039         }
2040     }
IterByKeys(napi_env env)2041     napi_value URLSearchParams::IterByKeys(napi_env env)
2042     {
2043         std::vector<std::string> toKeys;
2044         napi_value result = nullptr;
2045         napi_value napiStr = nullptr;
2046         napi_create_array(env, &result);
2047         size_t stepSize = 2; // 2:Searching for the number and number of keys and values
2048         size_t lenStr = searchParams.size();
2049         if (lenStr % 2 == 0) { // 2:Get the number of values
2050             for (auto it = searchParams.begin(); it != searchParams.end(); it += stepSize) {
2051                 toKeys.push_back(*it);
2052             }
2053             size_t lenToKeys = toKeys.size();
2054             for (size_t i = 0; i < lenToKeys; i++) {
2055                 napi_create_string_utf8(env, toKeys[i].c_str(), toKeys[i].length(), &napiStr);
2056                 napi_set_element(env, result, i, napiStr);
2057             }
2058         }
2059         return result;
2060     }
IterByValues(napi_env env)2061     napi_value URLSearchParams::IterByValues(napi_env env)
2062     {
2063         std::vector<std::string> toKeys;
2064         napi_value result = nullptr;
2065         napi_value napiStr = nullptr;
2066         napi_create_array(env, &result);
2067         size_t stepSize = 2; // 2:Searching for the number and number of keys and values
2068         size_t lenStr = searchParams.size();
2069         if (lenStr % 2 == 0) { // 2:Get the number of values
2070             for (auto it = searchParams.begin();
2071                 it != searchParams.end();
2072                 it += stepSize) {
2073                 toKeys.push_back(*(it + 1));
2074             }
2075             size_t lenToKeys = toKeys.size();
2076             for (size_t i = 0; i < lenToKeys; i++) {
2077                 napi_create_string_utf8(env, toKeys[i].c_str(), toKeys[i].length(), &napiStr);
2078                 napi_set_element(env, result, i, napiStr);
2079             }
2080         }
2081         return result;
2082     }
SetArray(napi_env env,const std::vector<std::string> vec)2083     void URLSearchParams::SetArray(napi_env env, const std::vector<std::string> vec)
2084     {
2085         searchParams = vec;
2086     }
GetArray(napi_env env) const2087     napi_value URLSearchParams::GetArray(napi_env env) const
2088     {
2089         napi_value arr = nullptr;
2090         napi_create_array(env, &arr);
2091         size_t length = searchParams.size();
2092         for (size_t i = 0; i < length; i++) {
2093             napi_value result = nullptr;
2094             napi_create_string_utf8(env, searchParams[i].c_str(), searchParams[i].size(), &result);
2095             napi_set_element(env, arr, i, result);
2096         }
2097         return arr;
2098     }
2099 } // namespace OHOS::Url
2100