• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "js_url.h"
17 #include <regex>
18 #include <sstream>
19 #include "securec.h"
20 #include "unicode/stringpiece.h"
21 #include "unicode/unistr.h"
22 #include "utils/log.h"
23 namespace OHOS::Url {
24     std::map<std::string, int> g_head = {
25         {"ftp:", 21}, {"file:", -1}, {"gopher:", 70}, {"http:", 80},
26         {"https:", 443}, {"ws:", 80}, {"wss:", 443}
27     };
28 
29     std::vector<std::string> g_doubleSegment = {
30         "..", ".%2e", ".%2E", "%2e.", "%2E.",
31         "%2e%2e", "%2E%2E", "%2e%2E", "%2E%2e"
32     };
33 
34     std::vector<std::string> g_singlesegment = { ".", "%2e", "%2E" };
35     std::vector<std::string> g_specialSymbols = {
36         "@", "%40", "#", "%23", "=", "%3D", ":", "%3A",
37         "/", "%2F", ";", "%3B", "?", "%3F"
38     };
39     std::vector<char> g_specialcharacter = {
40         '\0', '\t', '\n', '\r', ' ', '#', '%', '/', ':', '?',
41         '@', '[', '\\', ']'
42     };
43 
44     std::bitset<static_cast<size_t>(BitsetStatusFlag::MAX_BIT_SIZE)> g_specialCharForBit;
45 
PreliminaryWork()46     void PreliminaryWork()
47     {
48         std::vector<char> g_specialSymbolsTmp = {'#', '%', '/', ':', '?', '@', '[', '\\', ']', '<', '>', '^', '|'};
49         size_t invalidCharLength = static_cast<size_t>(BitsetStatusFlag::BIT_ASCII_32);
50         for (size_t i = 0; i <= invalidCharLength; ++i) {
51             g_specialCharForBit.set(i);
52         }
53         size_t len = g_specialSymbolsTmp.size();
54         for (size_t i = 0; i < len; ++i) {
55             g_specialCharForBit.set(g_specialSymbolsTmp[i]);
56         }
57         g_specialCharForBit.set(static_cast<size_t>(BitsetStatusFlag::BIT_ASCII_127));
58     }
59 
CheckCharacter(std::string data,std::bitset<static_cast<size_t> (BitsetStatusFlag::MAX_BIT_SIZE)> rule)60     bool CheckCharacter(std::string data, std::bitset<static_cast<size_t>(BitsetStatusFlag::MAX_BIT_SIZE)> rule)
61     {
62         size_t dataLen = data.size();
63         for (size_t i = 0; i < dataLen; ++i) {
64             if (static_cast<int>(data[i]) >= 0 &&
65                 static_cast<int>(data[i]) < static_cast<int>(BitsetStatusFlag::MAX_BIT_SIZE)) {
66                 bool IsIllegal = rule.test(data[i]);
67                 if (IsIllegal) {
68                     return false;
69                 }
70             }
71         }
72         return true;
73     }
74 
ReplaceSpecialSymbols(std::string & input,std::string & oldstr,std::string & newstr)75     void ReplaceSpecialSymbols(std::string& input, std::string& oldstr, std::string& newstr)
76     {
77         size_t oldlen = oldstr.size();
78         while (true) {
79             size_t pos = 0;
80             if ((pos = input.find(oldstr)) != std::string::npos) {
81                 input.replace(pos, oldlen, newstr);
82                 continue;
83             }
84             break;
85         }
86     }
87 
88     template<typename T>
IsASCIITabOrNewline(const T ch)89     bool IsASCIITabOrNewline(const T ch)
90     {
91         return (ch == '\t' || ch == '\n' || ch == '\r');
92     }
93 
IsHexDigit(const char & ch)94     bool IsHexDigit(const char& ch)
95     {
96         if (isdigit(ch) || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
97             return true;
98         }
99         return false;
100     }
101 
DecodeSpecialChars(std::string input)102     std::string DecodeSpecialChars(std::string input)
103     {
104         std::string temp = input;
105         size_t len = temp.size();
106         if (input.empty()) {
107             return temp;
108         }
109         size_t pos = temp.find("%");
110         while (pos != std::string::npos && pos < len - 2) { // 2:end subscript backspace
111             if (IsHexDigit(temp[pos + 1]) && IsHexDigit(temp[pos + 2])) { // 2:Determine the second character after %
112                 std::string subStr = temp.substr(pos + 1, 2); // 2:Truncate the last two digits of the %
113                 int octNum = 0;
114                 if (sscanf_s(subStr.c_str(), "%x", &octNum) == -1) {
115                     HILOG_ERROR("sscanf_s is falie");
116                     return temp;
117                 }
118                 std::string convertedChar(1, static_cast<char>(octNum));
119                 temp.replace(pos, 3, convertedChar); // 3:Replace the percent character with the corresponding char
120                 len = len - 2; // 2:After the replacement, the length of the string is reduced by two
121             }
122             pos = temp.find("%", pos + 1);
123         }
124         return temp;
125     }
126 
DeleteC0OrSpace(std::string & str)127     void DeleteC0OrSpace(std::string& str)
128     {
129         if (str.empty()) {
130             return;
131         }
132         size_t i = 0;
133         size_t strlen = str.size();
134         while (i < strlen) {
135             if (str[i] >= '\0' && str[i] <= ' ') {
136                 i++;
137                 continue;
138             }
139             break;
140         }
141         str = str.substr(i);
142         strlen = str.size();
143         if (strlen == 0) {
144             return;
145         }
146         for (i = strlen - 1; i != 0; i--) {
147             if (str[i] >= '\0' && str[i] <= ' ') {
148                 str.pop_back();
149                 continue;
150             }
151             break;
152         }
153     }
154 
DeleteTabOrNewline(std::string & str1)155     void DeleteTabOrNewline(std::string& str1)
156     {
157         for (auto item = str1.begin(); item != str1.end();) {
158             if (IsASCIITabOrNewline(*item)) {
159                 item = str1.erase(item);
160             } else {
161                 ++item;
162             }
163         }
164     }
165 
IsSpecial(std::string scheme)166     bool IsSpecial(std::string scheme)
167     {
168         auto temp = g_head.count(scheme);
169         if (temp > 0) {
170             return true;
171         }
172         return false;
173     }
174 
AnalysisScheme(std::string & input,std::string & scheme,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)175     bool AnalysisScheme(std::string& input, std::string& scheme,
176         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
177     {
178         if (!isalpha(input[0])) {
179             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
180             return false;
181         } else {
182             size_t strlen = input.size();
183             for (size_t i = 0; i < strlen - 1; ++i) {
184                 if ((isalnum(input[i]) || input[i] == '+' || input[i] == '-' || input[i] == '.') &&
185                     isupper(input[i])) {
186                         input[i] = static_cast<size_t>(tolower(input[i]));
187                 }
188                 if (!isalnum(input[i]) && input[i] != '+' && input[i] != '-' && input[i] != '.') {
189                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
190                     // 0:Bit 0 Set to true,The URL analysis failed
191                     return false;
192                 }
193             }
194             scheme = input;
195             if (IsSpecial(scheme)) {
196                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
197             }
198             return true;
199         }
200     }
201 
AnalysisFragment(const std::string & input,std::string & fragment,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)202     void AnalysisFragment(const std::string& input, std::string& fragment,
203         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
204     {
205         fragment = input;
206         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT8));
207     }
208 
AnalysisQuery(const std::string & input,std::string & query,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)209     void AnalysisQuery(const std::string& input, std::string& query,
210         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
211     {
212         query = input;
213         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT7));
214     }
AnalysisUsernameAndPasswd(std::string & input,std::string & username,std::string & password,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)215     void AnalysisUsernameAndPasswd(std::string& input, std::string& username, std::string& password,
216         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
217     {
218         int pos = static_cast<int>(input.size()) - 1;
219         for (; pos >= 0; pos--) {
220             if (input[pos] == '@') {
221                 break;
222             }
223         }
224         std::string userAndPasswd = input.substr(0, pos);
225         input = input.substr(pos + 1);
226         if (userAndPasswd.empty()) {
227             return;
228         }
229         if (userAndPasswd.find('@') != std::string::npos) {
230             while (true) {
231                 size_t posTmp = 0;
232                 if ((posTmp = userAndPasswd.find('@')) != std::string::npos) {
233                     userAndPasswd = userAndPasswd.replace(posTmp, 1, "%40");
234                 } else {
235                     break;
236                 }
237             }
238         }
239         if (userAndPasswd.find(':') != std::string::npos) {
240             size_t position = userAndPasswd.find(':');
241             std::string user = userAndPasswd.substr(0, position);
242             std::string keyWord = userAndPasswd.substr(position + 1);
243             if (!user.empty()) {
244                 username = user;
245                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
246             }
247             if (!keyWord.empty()) {
248                 password = keyWord;
249                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT3));
250             }
251         } else {
252             username = userAndPasswd;
253             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
254         }
255     }
256 
AnalysisPath(std::string & input,std::vector<std::string> & path,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags,bool isSpecial)257     void AnalysisPath(std::string& input, std::vector<std::string>& path,
258         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool isSpecial)
259     {
260         std::vector<std::string> temp;
261         size_t pos = 0;
262         while (((pos = input.find('/')) != std::string::npos) ||
263             ((pos = input.find('\\')) != std::string::npos && isSpecial)) {
264             temp.push_back(input.substr(0, pos));
265             input = input.substr(pos + 1);
266         }
267         temp.push_back(input);
268         size_t length = temp.size();
269         for (size_t it = 0; it < length; ++it) {
270             auto result = find(g_doubleSegment.begin(), g_doubleSegment.end(), temp[it]);
271             if (result != g_doubleSegment.end()) {
272                 if (path.empty() && it == length - 1) {
273                     path.emplace_back("");
274                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
275                 }
276                 if (path.empty()) {
277                     continue;
278                 }
279                 path.pop_back();
280                 if (it == length - 1) {
281                     path.emplace_back("");
282                     flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
283                 }
284                 continue;
285             }
286             result = find(g_singlesegment.begin(), g_singlesegment.end(), temp[it]);
287             if (result != g_singlesegment.end() && it == length - 1) {
288                 path.emplace_back("");
289                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
290                 continue;
291             }
292             if (result == g_singlesegment.end()) {
293                 path.push_back(temp[it]);
294                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
295             }
296         }
297     }
298 
AnalysisPort(std::string input,UrlData & urlinfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)299     void AnalysisPort(std::string input, UrlData& urlinfo,
300         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
301     {
302         if (input.size() == 0) {
303             return;
304         }
305         for (auto i : input) {
306             if (!isdigit(i)) {
307                 flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
308                 return;
309             }
310         }
311         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         AnalysisPath(input, urlData.path, flags, special);
1077     }
1078 
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)1079     void BaseInfoToUrl(const UrlData& baseInfo,
1080         const std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& baseflags, UrlData& urlData,
1081         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags, bool inputIsEmpty)
1082     {
1083         urlData.scheme = baseInfo.scheme;
1084         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT1),
1085             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1)));
1086         urlData.host = baseInfo.host;
1087         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1088         urlData.username = baseInfo.username;
1089         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT2),
1090             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT2)));
1091         urlData.password = baseInfo.password;
1092         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT3),
1093             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT3)));
1094         urlData.port = baseInfo.port;
1095         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT5),
1096             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT5)));
1097         if (inputIsEmpty) {
1098             urlData.path = baseInfo.path;
1099             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1100                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1101             urlData.query = baseInfo.query;
1102             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT7),
1103                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT7)));
1104             urlData.fragment = baseInfo.fragment;
1105             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT8),
1106                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT8)));
1107         }
1108         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT9),
1109             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9)));
1110         flags.set(static_cast<size_t>(BitsetStatusFlag::BIT10),
1111             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT10)));
1112     }
1113 
ShorteningPath(UrlData & baseData,bool isFile)1114     void ShorteningPath(UrlData& baseData, bool isFile)
1115     {
1116         if (baseData.path.empty()) {
1117             return;
1118         }
1119         if ((baseData.path.size() == 1) && isFile &&
1120             isalpha(baseData.path[0][0]) && (baseData.path[0][1] == ':')) {
1121             return;
1122         }
1123         baseData.path.pop_back();
1124     }
1125 
InitOnlyInput(std::string & input,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1126     void InitOnlyInput(std::string& input, UrlData& urlData,
1127         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)>& flags)
1128     {
1129         if (input.empty()) {
1130             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1131             return;
1132         }
1133         if (input.find(':') != std::string::npos) {
1134             size_t pos = input.find(':');
1135             pos++;
1136             std::string scheme = input.substr(0, pos);
1137             if (!AnalysisScheme(scheme, urlData.scheme, flags)) {
1138                 return;
1139             }
1140             if (input.find('#') != std::string::npos) {
1141                 size_t posTmp = input.find('#');
1142                 std::string fragment = input.substr(posTmp);
1143                 AnalysisFragment(fragment, urlData.fragment, flags);
1144                 input = input.substr(0, posTmp);
1145             }
1146             if (input.find('?') != std::string::npos) {
1147                 size_t position = input.find('?');
1148                 std::string query = input.substr(position);
1149                 AnalysisQuery(query, urlData.query, flags);
1150                 input = input.substr(0, position);
1151             }
1152             std::string str = input.substr(pos);
1153             if (urlData.scheme == "file:") {
1154                 AnalysisFile(str, urlData, flags);
1155             } else {
1156                 AnalysisHostAndPath(str, urlData, flags);
1157             }
1158         } else {
1159             flags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1160             return;
1161         }
1162     }
1163 
ToolHasBase(std::string input,std::string & strInput,UrlData & urlData,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & flags)1164     void ToolHasBase(std::string input, std::string &strInput, UrlData &urlData,
1165         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &flags)
1166     {
1167         if (!input.empty() && input[0] == '/') {
1168             strInput = input.substr(1);
1169             AnalysisInput(strInput, urlData, flags);
1170         } else if (!input.empty() && input[0] != '/') {
1171             AnalysisInput(strInput, urlData, flags);
1172         }
1173     }
1174 
URL(const std::string & input)1175     URL::URL(const std::string& input)
1176     {
1177         std::string str = input;
1178         PreliminaryWork();
1179         DeleteC0OrSpace(str);
1180         DeleteTabOrNewline(str);
1181         InitOnlyInput(str, urlData_, flags_);
1182     }
1183 
DelCont(std::string strBase,std::string & strInput,UrlData & baseInfo,std::bitset<static_cast<size_t> (BitsetStatusFlag::BIT_STATUS_11)> & baseflags)1184     void DelCont(std::string strBase, std::string &strInput, UrlData &baseInfo,
1185         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> &baseflags)
1186     {
1187         DeleteC0OrSpace(strBase);
1188         DeleteTabOrNewline(strBase);
1189         DeleteC0OrSpace(strInput);
1190         DeleteTabOrNewline(strInput);
1191         InitOnlyInput(strBase, baseInfo, baseflags);
1192     }
1193 
URL(const std::string & input,const std::string & base)1194     URL::URL(const std::string& input, const std::string& base)
1195     {
1196         UrlData baseInfo;
1197         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> baseflags;
1198         std::string strBase = base;
1199         std::string strInput = input;
1200         if (strBase.empty()) {
1201             baseflags.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1202         }
1203         DelCont(strBase, strInput, baseInfo, baseflags);
1204         if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1205             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1206             return;
1207         } else if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1208             InitOnlyInput(strInput, urlData_, flags_);
1209             if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1210                 return;
1211             }
1212             if ((input[0] == '/') && (input[1] == '/' || (input[1] == '\\' &&
1213                 baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))))) {
1214                 std::string newInput = baseInfo.scheme + input;
1215                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1216                 InitOnlyInput(newInput, urlData_, flags_);
1217                 return;
1218             }
1219             if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1220                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1221                 BaseInfoToUrl(baseInfo, baseflags, urlData_, flags_, input.empty());
1222                 ToolHasBase(input, strInput, urlData_, flags_);
1223                 if (!input.empty() && input[0] != '/' && urlData_.path.empty()) {
1224                     urlData_.path = baseInfo.path;
1225                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1226                         baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1227                 }
1228                 if (!input.empty() && input[0] != '/' && !urlData_.path.empty()) {
1229                     bool isFile = ((urlData_.scheme == "file:") ? true : false);
1230                     ShorteningPath(baseInfo, isFile);
1231                     baseInfo.path.insert(baseInfo.path.end(), urlData_.path.begin(), urlData_.path.end());
1232                     urlData_.path = baseInfo.path;
1233                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1234                 }
1235             } else if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1236                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1237                 return;
1238             }
1239         }
1240     }
1241 
URL(const std::string & input,const URL & base)1242     URL::URL(const std::string& input, const URL& base)
1243     {
1244         std::string strInput = input;
1245         UrlData baseInfo = base.urlData_;
1246         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> baseflags = base.flags_;
1247         DeleteC0OrSpace(strInput);
1248         DeleteTabOrNewline(strInput);
1249         InitOnlyInput(strInput, urlData_, flags_);
1250         if (!flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1251             return;
1252         }
1253         if ((input[0] == '/') && (input[1] == '/' || (input[1] == '\\' &&
1254             baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))))) {
1255             std::string newInput = baseInfo.scheme + input;
1256             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1257             InitOnlyInput(newInput, urlData_, flags_);
1258             return;
1259         }
1260         if (!baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1261             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0), 0);
1262             BaseInfoToUrl(baseInfo, baseflags, urlData_, flags_, input.empty());
1263             if (!input.empty() && input[0] == '/') {
1264                 strInput = input.substr(1);
1265                 AnalysisInput(strInput, urlData_, flags_);
1266             }
1267             if (!input.empty() && input[0] != '/') {
1268                 AnalysisInput(strInput, urlData_, flags_);
1269                 if (urlData_.path.empty()) {
1270                     urlData_.path = baseInfo.path;
1271                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6),
1272                         baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT6)));
1273                 } else {
1274                     bool isFile = ((urlData_.scheme == "file:") ? true : false);
1275                     ShorteningPath(baseInfo, isFile);
1276                     baseInfo.path.insert(baseInfo.path.end(), urlData_.path.begin(), urlData_.path.end());
1277                     urlData_.path = baseInfo.path;
1278                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1279                 }
1280             }
1281         } else if (baseflags.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1282             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT0));
1283             return;
1284         }
1285     }
1286 
GetHostname(napi_env env) const1287     napi_value URL::GetHostname(napi_env env) const
1288     {
1289         napi_value result;
1290         std::string temp = "";
1291         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1292             temp = urlData_.host;
1293         }
1294         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1295         return result;
1296     }
1297 
GetSearch(napi_env env) const1298     napi_value URL::GetSearch(napi_env env) const
1299     {
1300         napi_value result;
1301         std::string temp = "";
1302         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT7)) && !(urlData_.query.size() == 1)) {
1303             temp = urlData_.query;
1304         }
1305         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1306         return result;
1307     }
1308 
GetUsername(napi_env env) const1309     napi_value URL::GetUsername(napi_env env) const
1310     {
1311         napi_value result;
1312         std::string temp = "";
1313         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT2))) {
1314             temp = urlData_.username;
1315         }
1316         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1317         return result;
1318     }
1319 
GetPassword(napi_env env) const1320     napi_value URL::GetPassword(napi_env env) const
1321     {
1322         napi_value result;
1323         std::string temp = "";
1324         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT3))) {
1325             temp = urlData_.password;
1326         }
1327         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1328         return result;
1329     }
1330 
GetFragment(napi_env env) const1331     napi_value URL::GetFragment(napi_env env) const
1332     {
1333         napi_value result;
1334         std::string temp = "";
1335         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT8)) && !(urlData_.fragment.size() == 1)) {
1336             temp = urlData_.fragment;
1337         }
1338         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1339         return result;
1340     }
1341 
GetScheme(napi_env env) const1342     napi_value URL::GetScheme(napi_env env) const
1343     {
1344         napi_value result;
1345         std::string temp = "";
1346         if (!urlData_.scheme.empty()) {
1347             temp = urlData_.scheme;
1348         }
1349         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1350         return result;
1351     }
1352 
GetPath(napi_env env) const1353     napi_value URL::GetPath(napi_env env) const
1354     {
1355         napi_value result;
1356         std::string temp = "/";
1357         if (urlData_.isSpecialPath) {
1358             temp = "";
1359         }
1360         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1361             size_t length = urlData_.path.size();
1362             for (size_t i = 0; i < length; i++) {
1363                 if (i < length - 1) {
1364                     temp += urlData_.path[i] + "/";
1365                 } else {
1366                     temp += urlData_.path[i];
1367                 }
1368             }
1369         } else {
1370             bool special = IsSpecial(urlData_.scheme);
1371             if (!special) {
1372                 temp = "";
1373             }
1374         }
1375         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1376         return result;
1377     }
1378 
1379 
GetPort(napi_env env) const1380     napi_value URL::GetPort(napi_env env) const
1381     {
1382         napi_value result;
1383         std::string temp = "";
1384         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1385             temp = std::to_string(urlData_.port);
1386         }
1387         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1388         return result;
1389     }
1390 
GetHost(napi_env env) const1391     napi_value URL::GetHost(napi_env env) const
1392     {
1393         napi_value result;
1394         std::string temp = urlData_.host;
1395         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1396             temp += ":";
1397             temp += std::to_string(urlData_.port);
1398         }
1399         NAPI_CALL(env, napi_create_string_utf8(env, temp.c_str(), temp.size(), &result));
1400         return result;
1401     }
1402 
GetOnOrOff(napi_env env) const1403     napi_value URL::GetOnOrOff(napi_env env) const
1404     {
1405         napi_value result;
1406         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1407             bool flag = false;
1408             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
1409         } else {
1410             bool flag = true;
1411             NAPI_CALL(env, napi_get_boolean(env, flag, &result));
1412         }
1413         return result;
1414     }
1415 
GetIsIpv6(napi_env env) const1416     napi_value URL::GetIsIpv6(napi_env env) const
1417     {
1418         napi_value result;
1419         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT10))) {
1420             NAPI_CALL(env, napi_get_boolean(env, true, &result));
1421         } else {
1422             NAPI_CALL(env, napi_get_boolean(env, false, &result));
1423         }
1424         return result;
1425     }
1426 
SetHostname(const std::string & input)1427     void URL::SetHostname(const std::string& input)
1428     {
1429         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1430             return;
1431         }
1432         std::string strHost = input;
1433         size_t length = strHost.size();
1434         for (size_t pos = 0; pos < length; pos++) {
1435             if ((strHost[pos] == ':') || (strHost[pos] == '?') || (strHost[pos] == '#') ||
1436                 (strHost[pos] == '/') || (strHost[pos] == '\\')) {
1437                 strHost = strHost.substr(0, pos);
1438                 break;
1439             }
1440         }
1441         if (strHost.size() == 0) {
1442             return;
1443         }
1444         bool special = IsSpecial(urlData_.scheme);
1445         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1446         std::string thisHostname = "";
1447         AnalysisHost(strHost, thisHostname, thisFlags, special);
1448         if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1449             if ((urlData_.scheme == "file:") && (thisHostname == "localhost")) {
1450                 thisHostname = "";
1451             }
1452             urlData_.host = thisHostname;
1453             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1454         }
1455     }
1456 
SetHref(const std::string & input)1457     void URL::SetHref(const std::string& input)
1458     {
1459         std::string str = input;
1460         DeleteC0OrSpace(str);
1461         DeleteTabOrNewline(str);
1462         UrlData thisNewUrl;
1463         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisNewFlags;
1464         InitOnlyInput(str, thisNewUrl, thisNewFlags);
1465         if (!thisNewFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT0))) {
1466             urlData_ = thisNewUrl;
1467             flags_ = thisNewFlags;
1468         }
1469     }
1470 
SetPath(const std::string & input)1471     void URL::SetPath(const std::string& input)
1472     {
1473         std::string strPath = input;
1474         if (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9)) || strPath.empty()) {
1475             return;
1476         }
1477         std::string oldstr = "%3A";
1478         std::string newstr = ":";
1479         ReplaceSpecialSymbols(strPath, oldstr, newstr);
1480         bool special = IsSpecial(urlData_.scheme);
1481         if (urlData_.scheme == "file:") {
1482             UrlData thisFileDate;
1483             std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFileFlag;
1484             if ((strPath[0] == '/') || (strPath[0] == '\\' &&
1485                 flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT1)))) {
1486                 strPath = strPath.substr(1);
1487             }
1488             AnalysisFilePath(strPath, thisFileDate, thisFileFlag);
1489             if (thisFileFlag.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1490                 urlData_.path = thisFileDate.path;
1491                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1492             }
1493         } else {
1494             std::vector<std::string> thisPath;
1495             std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1496             if ((strPath[0] == '/') || (strPath[0] == '\\' &&
1497                 flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT1)))) {
1498                 strPath = strPath.substr(1);
1499             }
1500             AnalysisPath(strPath, thisPath, thisFlags, special);
1501             if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT6))) {
1502                 urlData_.path = thisPath;
1503                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT6));
1504             }
1505         }
1506     }
1507 
SplitString(const std::string & input,std::string & strHost,std::string & port)1508     void SplitString(const std::string& input, std::string& strHost, std::string& port)
1509     {
1510         size_t strlen = input.size();
1511         for (size_t pos = 0; pos < strlen; pos++) {
1512             if ((input[pos] == ':') || (input[pos] == '?') || (input[pos] == '#') ||
1513                 (input[pos] == '/') || (input[pos] == '\\')) {
1514                 strHost = input.substr(0, pos);
1515                 if (input[pos] == ':') {
1516                     pos++;
1517                     port = input.substr(pos);
1518                 }
1519                 break;
1520             }
1521         }
1522     }
1523 
SetHost(const std::string & input)1524     void URL::SetHost(const std::string& input)
1525     {
1526         if (input.empty() || flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT9))) {
1527             return;
1528         }
1529         std::string strHost = input;
1530         std::string port = "";
1531         SplitString(input, strHost, port);
1532         if (strHost.size() == 0) {
1533             return;
1534         }
1535         bool special = IsSpecial(urlData_.scheme);
1536         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> hostnameflags;
1537         std::string thisHostname = "";
1538         AnalysisHost(strHost, thisHostname, hostnameflags, special);
1539         if (hostnameflags.test(static_cast<size_t>(BitsetStatusFlag::BIT4))) {
1540             if ((urlData_.scheme == "file:") && (thisHostname == "localhost")) {
1541                 thisHostname = "";
1542             }
1543             urlData_.host = thisHostname;
1544             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT4));
1545         } else {
1546             return;
1547         }
1548         if (port.size() > 0) {
1549             size_t strlen = port.size();
1550             for (size_t pos = 0; pos < strlen; pos++) {
1551                 if ((port[pos] == '?') || (port[pos] == '#') || (port[pos] == '/') || (port[pos] == '\\')) {
1552                     port = port.substr(0, pos);
1553                     break;
1554                 }
1555             }
1556             if (port.size() > 0) {
1557                 std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1558                 UrlData thisport;
1559                 AnalysisPort(port, thisport, thisFlags);
1560                 if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1561                     flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
1562                     urlData_.port = thisport.port;
1563                 }
1564             }
1565         }
1566     }
1567 
SetPort(const std::string & input)1568     void URL::SetPort(const std::string& input)
1569     {
1570         std::string port = input;
1571         size_t portlen = port.size();
1572         for (size_t pos = 0; pos < portlen; pos++) {
1573             if ((port[pos] == '?') || (port[pos] == '#') || (port[pos] == '/') || (port[pos] == '\\')) {
1574                 port = port.substr(0, pos);
1575                 break;
1576             }
1577         }
1578         if (port.size() > 0) {
1579             std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1580             UrlData thisport;
1581             AnalysisPort(port, thisport, thisFlags);
1582             if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT5))) {
1583                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT5));
1584                 urlData_.port = thisport.port;
1585             }
1586         }
1587     }
1588 
SetSearch(const std::string & input)1589     void URL::SetSearch(const std::string& input)
1590     {
1591         std::string temp;
1592         if (input.size() == 0) {
1593             urlData_.query = "";
1594             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT7), 0);
1595         } else {
1596             if (input[0] != '?') {
1597                 temp = "?";
1598                 temp += input;
1599             } else {
1600                 temp = input;
1601             }
1602             std::string oldstr = "#";
1603             std::string newstr = "%23";
1604             ReplaceSpecialSymbols(temp, oldstr, newstr);
1605             AnalysisQuery(temp, urlData_.query, flags_);
1606         }
1607     }
1608 
SetFragment(const std::string & input)1609     void URL::SetFragment(const std::string& input)
1610     {
1611         std::string temp;
1612         if (input.size() == 0) {
1613             urlData_.fragment = "";
1614             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT8), 0);
1615         } else {
1616             if (input[0] != '#') {
1617                 temp = "#";
1618                 temp += input;
1619             } else {
1620                 temp = input;
1621             }
1622             AnalysisFragment(temp, urlData_.fragment, flags_);
1623         }
1624     }
1625 
SetScheme(const std::string & input)1626     void URL::SetScheme(const std::string& input)
1627     {
1628         std::string strInput = input;
1629         bool special = IsSpecial(urlData_.scheme);
1630         bool inputIsSpecial = IsSpecial(input);
1631         if ((special != inputIsSpecial) || ((input == "file") &&
1632             (flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT2)) ||
1633             flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT3)) ||
1634             flags_.test(static_cast<size_t>(BitsetStatusFlag::BIT5))))) {
1635             return;
1636         }
1637         std::string thisScheme = "";
1638         std::bitset<static_cast<size_t>(BitsetStatusFlag::BIT_STATUS_11)> thisFlags;
1639         if (AnalysisScheme(strInput, thisScheme, thisFlags)) {
1640             if (thisFlags.test(static_cast<size_t>(BitsetStatusFlag::BIT1))) {
1641                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT1));
1642             }
1643             urlData_.scheme = thisScheme;
1644         }
1645     }
1646 
SetUsername(const std::string & input)1647     void URL::SetUsername(const std::string& input)
1648     {
1649         if (input.size() == 0) {
1650             urlData_.username = "";
1651             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT2), 0);
1652         } else {
1653                 std::string usname = input;
1654             size_t len = g_specialSymbols.size() - 2; // 2:Maximum position of subscript
1655             for (size_t i = 0; i <= len; i += 2) { // 2:Shift subscript right 2
1656             ReplaceSpecialSymbols(usname, g_specialSymbols[i], g_specialSymbols[i + 1]);
1657             }
1658                 urlData_.username = usname;
1659                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT2));
1660         }
1661     }
1662 
SetPassword(const std::string & input)1663     void URL::SetPassword(const std::string& input)
1664     {
1665         if (input.size() == 0) {
1666             urlData_.password = "";
1667             flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT3), 0);
1668         } else {
1669                 std::string keyWord = input;
1670             size_t len = g_specialSymbols.size() - 2; // 2:Maximum position of subscript
1671             for (size_t i = 0; i <= len; i += 2) { // 2:Shift subscript right 2
1672             ReplaceSpecialSymbols(keyWord, g_specialSymbols[i], g_specialSymbols[i + 1]);
1673             }
1674                 urlData_.password = keyWord;
1675                 flags_.set(static_cast<size_t>(BitsetStatusFlag::BIT3));
1676         }
1677     }
1678 
HandleIllegalChar(std::wstring & inputStr,std::wstring::const_iterator it)1679     void URLSearchParams::HandleIllegalChar(std::wstring& inputStr, std::wstring::const_iterator it)
1680     {
1681         std::wstring::iterator iter = inputStr.begin();
1682         advance(iter, std::distance<std::wstring::const_iterator>(iter, it));
1683         while (iter != inputStr.end()) {
1684             char16_t ch = *iter;
1685             if (!((ch & 0xF800) == 0xD800)) {
1686                 ++iter;
1687                 continue;
1688             } else if ((ch & 0x400) != 0 || iter == inputStr.end() - 1) {
1689                 *iter = 0xFFFD;
1690             } else {
1691                 char16_t dh = *(iter + 1);
1692                 if ((dh & 0xFC00) == 0xDC00) {
1693                     ++iter;
1694                 } else {
1695                     *iter = 0xFFFD;
1696                 }
1697             }
1698             ++iter;
1699         }
1700     }
ToUSVString(std::string inputStr)1701     std::string URLSearchParams::ToUSVString(std::string inputStr)
1702     {
1703         std::wstring winput(inputStr.length(), L' ');
1704         std::copy(inputStr.begin(), inputStr.end(), winput.begin());
1705         std::wregex wexpr(L"(?:[^\\uD800-\\uDBFF]|^)[\\uDC00-\\uDFFF]|[\\uD800-\\uDBFF](?![\\uDC00-\\uDFFF])");
1706         std::wsmatch result;
1707         std::wstring::const_iterator iterStart = winput.begin();
1708         std::wstring::const_iterator iterEnd = winput.end();
1709         if (!regex_search(iterStart, iterEnd, result, wexpr)) {
1710             return inputStr;
1711         }
1712         HandleIllegalChar(winput, result[0].first);
1713         size_t inputLen = wcslen(winput.c_str());
1714         char *rePtr = nullptr;
1715         std::string reStr = "";
1716         size_t reSize = wcstombs(rePtr, winput.c_str(), 0) + 1;
1717         if (reSize > 0) {
1718             rePtr = new char[reSize];
1719             if (memset_s(rePtr, reSize, 0, reSize) != EOK) {
1720                 HILOG_ERROR("ToUSVString memset_s failed");
1721                 delete[] rePtr;
1722                 return reStr;
1723             } else {
1724                 wcstombs(rePtr, winput.c_str(), inputLen);
1725                 reStr = rePtr;
1726             }
1727         }
1728         delete[] rePtr;
1729         return reStr;
1730     }
Get(napi_env env,napi_value buffer)1731     napi_value URLSearchParams::Get(napi_env env, napi_value buffer)
1732     {
1733         std::string name = "";
1734         size_t nameSize = 0;
1735         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1736             HILOG_ERROR("can not get buffer size");
1737             return nullptr;
1738         }
1739         name.reserve(nameSize);
1740         name.resize(nameSize);
1741         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1742             HILOG_ERROR("can not get buffer value");
1743             return nullptr;
1744         }
1745         std::string temp = name;
1746         std::string sname = ToUSVString(temp);
1747         napi_value result = nullptr;
1748         if (searchParams.size() == 0) {
1749             return result;
1750         }
1751         size_t size = searchParams.size() - 1;
1752         for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1753             if (searchParams[i] == sname) {
1754                 napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &result);
1755                 return result;
1756             }
1757         }
1758         return result;
1759     }
GetAll(napi_env env,napi_value buffer)1760     napi_value URLSearchParams::GetAll(napi_env env, napi_value buffer)
1761     {
1762         std::string name = "";
1763         size_t nameSize = 0;
1764         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1765             HILOG_ERROR("can not get buffer size");
1766             return nullptr;
1767         }
1768         name.reserve(nameSize);
1769         name.resize(nameSize);
1770         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1771             HILOG_ERROR("can not get buffer value");
1772             return nullptr;
1773         }
1774         std::string sname = ToUSVString(name);
1775 
1776         napi_value result = nullptr;
1777         napi_value napiStr = nullptr;
1778         NAPI_CALL(env, napi_create_array(env, &result));
1779         size_t flag = 0;
1780         if (searchParams.size() == 0) {
1781             return result;
1782         }
1783         size_t size = searchParams.size() - 1;
1784         for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1785             if (searchParams[i] == sname) {
1786                 napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &napiStr);
1787                 NAPI_CALL(env, napi_set_element(env, result, flag, napiStr));
1788                 flag++;
1789             }
1790         }
1791         return result;
1792     }
Append(napi_env env,napi_value buffer,napi_value temp)1793     void URLSearchParams::Append(napi_env env, napi_value buffer, napi_value temp)
1794     {
1795         std::string name = "";
1796         size_t nameSize = 0;
1797         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1798             HILOG_ERROR("can not get buffer size");
1799             return;
1800         }
1801         name.reserve(nameSize);
1802         name.resize(nameSize);
1803         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1804             HILOG_ERROR("can not get buffer value");
1805             return;
1806         }
1807         std::string tempName = name;
1808         std::string value = "";
1809         size_t valueSize = 0;
1810         if (napi_get_value_string_utf8(env, temp, nullptr, 0, &valueSize) != napi_ok) {
1811             HILOG_ERROR("can not get temp size");
1812             return;
1813         }
1814         value.reserve(valueSize);
1815         value.resize(valueSize);
1816         if (napi_get_value_string_utf8(env, temp, value.data(), valueSize + 1, &valueSize) != napi_ok) {
1817             HILOG_ERROR("can not get temp value");
1818             return;
1819         }
1820         std::string tempValue = value;
1821         searchParams.push_back(tempName);
1822         searchParams.push_back(tempValue);
1823     }
Delete(napi_env env,napi_value buffer)1824     void URLSearchParams::Delete(napi_env env, napi_value buffer)
1825     {
1826         std::string name = "";
1827         size_t nameSize = 0;
1828         if (napi_get_value_string_utf8(env, buffer, nullptr, 0, &nameSize) != napi_ok) {
1829             HILOG_ERROR("can not get buffer size");
1830             return;
1831         }
1832         name.reserve(nameSize);
1833         name.resize(nameSize);
1834         if (napi_get_value_string_utf8(env, buffer, name.data(), nameSize + 1, &nameSize) != napi_ok) {
1835             HILOG_ERROR("can not get buffer value");
1836             return;
1837         }
1838         std::string sname = ToUSVString(name);
1839         for (auto iter = searchParams.begin(); iter != searchParams.end();) {
1840             if (*iter == sname) {
1841                 iter = searchParams.erase(iter, iter + 2); // 2:Searching for the number and number of keys and values
1842             } else {
1843                 iter += 2; // 2:Searching for the number and number of keys and values
1844             }
1845         }
1846     }
Entries(napi_env env) const1847     napi_value URLSearchParams::Entries(napi_env env) const
1848     {
1849         napi_value resend = nullptr;
1850         napi_value firNapiStr = nullptr;
1851         napi_value secNapiStr = nullptr;
1852         napi_create_array(env, &resend);
1853         if (searchParams.size() == 0) {
1854             return resend;
1855         }
1856         size_t size = searchParams.size() - 1;
1857         for (size_t i = 0; i < size; i += 2) { // 2:Searching for the number and number of keys and values
1858             napi_value result = nullptr;
1859             napi_create_array(env, &result);
1860             napi_create_string_utf8(env, searchParams[i].c_str(), searchParams[i].length(), &firNapiStr);
1861             napi_create_string_utf8(env, searchParams[i + 1].c_str(), searchParams[i + 1].length(), &secNapiStr);
1862             napi_set_element(env, result, 0, firNapiStr);
1863             napi_set_element(env, result, 1, secNapiStr);
1864             napi_set_element(env, resend, i / 2, result); // 2:Find the number of keys
1865         }
1866         return resend;
1867     }
1868 
IsHas(napi_env env,napi_value name) const1869     napi_value URLSearchParams::IsHas(napi_env env, napi_value name) const
1870     {
1871         size_t bufferSize = 0;
1872         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
1873             HILOG_ERROR("can not get name size");
1874             return nullptr;
1875         }
1876         std::string buf = "";
1877         buf.resize(bufferSize);
1878         if (napi_get_value_string_utf8(env, name, buf.data(), bufferSize + 1, &bufferSize) != napi_ok) {
1879             HILOG_ERROR("can not get name value");
1880             return nullptr;
1881         }
1882         bool flag = false;
1883         napi_value result = nullptr;
1884         size_t lenStr = searchParams.size();
1885         for (size_t i = 0; i != lenStr; i += 2) { // 2:Searching for the number and number of keys and values
1886             if (searchParams[i] == buf) {
1887                 flag = true;
1888                 napi_get_boolean(env, flag, &result);
1889                 return result;
1890             }
1891         }
1892         napi_get_boolean(env, flag, &result);
1893         return result;
1894     }
Set(napi_env env,napi_value name,napi_value value)1895     void URLSearchParams::Set(napi_env env, napi_value name, napi_value value)
1896     {
1897         std::string buffer = "";
1898         size_t bufferSize = 0;
1899         if (napi_get_value_string_utf8(env, name, nullptr, 0, &bufferSize) != napi_ok) {
1900             HILOG_ERROR("can not get name size");
1901             return;
1902         }
1903         buffer.reserve(bufferSize);
1904         buffer.resize(bufferSize);
1905         if (napi_get_value_string_utf8(env, name, buffer.data(), bufferSize + 1, &bufferSize) != napi_ok) {
1906             HILOG_ERROR("can not get name value");
1907             return;
1908         }
1909         std::string cppName = buffer;
1910         std::string temp = "";
1911         size_t tempSize = 0;
1912         if (napi_get_value_string_utf8(env, value, nullptr, 0, &tempSize) != napi_ok) {
1913             HILOG_ERROR("can not get value size");
1914             return;
1915         }
1916         temp.reserve(tempSize);
1917         temp.resize(tempSize);
1918         if (napi_get_value_string_utf8(env, value, temp.data(), tempSize + 1, &tempSize) != napi_ok) {
1919             HILOG_ERROR("can not get value value");
1920             return;
1921         }
1922         std::string cppValue = temp;
1923         bool flag = false;
1924         for (auto it = searchParams.begin(); it < (searchParams.end() - 1) && !searchParams.empty();) {
1925             if (*it == cppName) {
1926                 if (!flag) {
1927                     *(it + 1) = cppValue;
1928                     flag = true;
1929                     it += 2; // 2:Searching for the number and number of keys and values
1930                 } else {
1931                     it = searchParams.erase(it, it + 2); // 2:Searching for the number and number of keys and values
1932                 }
1933             } else {
1934                 it += 2; // 2:Searching for the number and number of keys and values
1935             }
1936         }
1937         if (!flag) {
1938             searchParams.push_back(cppName);
1939             searchParams.push_back(cppValue);
1940         }
1941     }
Sort()1942     void URLSearchParams::Sort()
1943     {
1944         size_t len = searchParams.size();
1945         if (len <= 2 && (len % 2 != 0)) { // 2: Iterate over key-value pairs
1946             return;
1947         }
1948         size_t i = 0;
1949         for (; i < len - 2; i += 2) { // 2:Iterate over key-value pairs
1950             size_t j = i + 2; // 2:Iterate over key-value pairs
1951             for (; j < len; j += 2) { // 2:Iterate over key-value pairs
1952                 bool tmp = (searchParams[i] > searchParams[j]);
1953                 if (tmp) {
1954                     const std::string curKey = searchParams[i];
1955                     const std::string curVal = searchParams[i + 1];
1956                     searchParams[i] = searchParams[j];
1957                     searchParams[i + 1] = searchParams[j + 1];
1958                     searchParams[j] = curKey;
1959                     searchParams[j + 1] = curVal;
1960                 }
1961             }
1962         }
1963     }
IterByKeys(napi_env env)1964     napi_value URLSearchParams::IterByKeys(napi_env env)
1965     {
1966         std::vector<std::string> toKeys;
1967         napi_value result = nullptr;
1968         napi_value napiStr = nullptr;
1969         napi_create_array(env, &result);
1970         size_t stepSize = 2; // 2:Searching for the number and number of keys and values
1971         size_t lenStr = searchParams.size();
1972         if (lenStr % 2 == 0) { // 2:Get the number of values
1973             for (auto it = searchParams.begin(); it != searchParams.end(); it += stepSize) {
1974                 toKeys.push_back(*it);
1975             }
1976             size_t lenToKeys = toKeys.size();
1977             for (size_t i = 0; i < lenToKeys; i++) {
1978                 napi_create_string_utf8(env, toKeys[i].c_str(), toKeys[i].length(), &napiStr);
1979                 napi_set_element(env, result, i, napiStr);
1980             }
1981         }
1982         return result;
1983     }
IterByValues(napi_env env)1984     napi_value URLSearchParams::IterByValues(napi_env env)
1985     {
1986         std::vector<std::string> toKeys;
1987         napi_value result = nullptr;
1988         napi_value napiStr = nullptr;
1989         napi_create_array(env, &result);
1990         size_t stepSize = 2; // 2:Searching for the number and number of keys and values
1991         size_t lenStr = searchParams.size();
1992         if (lenStr % 2 == 0) { // 2:Get the number of values
1993             for (auto it = searchParams.begin();
1994                 it != searchParams.end();
1995                 it += stepSize) {
1996                 toKeys.push_back(*(it + 1));
1997             }
1998             size_t lenToKeys = toKeys.size();
1999             for (size_t i = 0; i < lenToKeys; i++) {
2000                 napi_create_string_utf8(env, toKeys[i].c_str(), toKeys[i].length(), &napiStr);
2001                 napi_set_element(env, result, i, napiStr);
2002             }
2003         }
2004         return result;
2005     }
SetArray(napi_env env,const std::vector<std::string> vec)2006     void URLSearchParams::SetArray(napi_env env, const std::vector<std::string> vec)
2007     {
2008         searchParams = vec;
2009     }
GetArray(napi_env env) const2010     napi_value URLSearchParams::GetArray(napi_env env) const
2011     {
2012         napi_value arr = nullptr;
2013         napi_create_array(env, &arr);
2014         size_t length = searchParams.size();
2015         for (size_t i = 0; i < length; i++) {
2016             napi_value result = nullptr;
2017             napi_create_string_utf8(env, searchParams[i].c_str(), searchParams[i].size(), &result);
2018             napi_set_element(env, arr, i, result);
2019         }
2020         return arr;
2021     }
2022 } // namespace OHOS::Url
2023