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