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