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