1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "url_helper.h"
17
18 #include <chrono>
19 #include <vector>
20
21 #include "tools/log.h"
22
23 namespace OHOS::Url {
EncodePercentEncoding(const std::string_view inputString,const uint16_t codeMap[])24 std::string EncodePercentEncoding(const std::string_view inputString, const uint16_t codeMap[])
25 {
26 auto firstToEncode = std::find_if(inputString.begin(), inputString.end(), [codeMap](char current) {
27 uint8_t currentValue = static_cast<uint8_t>(current);
28 return NeedEncode(codeMap, currentValue);
29 });
30 if (firstToEncode == inputString.end()) {
31 return std::string(inputString);
32 }
33 std::string encodeString;
34 encodeString.reserve(inputString.length() * PERCENT_ENCODING_LENGTH);
35 encodeString.append(inputString.data(), firstToEncode - inputString.begin());
36 for (auto index = firstToEncode; index != inputString.end(); ++index) {
37 uint8_t currentValue = static_cast<uint8_t>(*index);
38 if (NeedEncode(codeMap, currentValue)) {
39 encodeString.push_back('%');
40 encodeString.push_back(HEX_CHAR_MAP[currentValue >> SHIFT_SIZE]);
41 encodeString.push_back(HEX_CHAR_MAP[currentValue & 0x0F]);
42 } else {
43 encodeString.push_back(*index);
44 }
45 }
46 return encodeString;
47 }
48
49 // 110XXXXX 10XXXXXXX
50 // 1110XXXX 10XXXXXXX 10XXXXXXX
51 // 11110XXX 10XXXXXXX 10XXXXXXX 10XXXXXXXX
CheckUTF8Enble(const std::string_view inputString,size_t i,char currentChar,int count,char * chars)52 bool CheckUTF8Enble(const std::string_view inputString, size_t i, char currentChar, int count, char* chars)
53 {
54 if (count <= 0) {
55 return false;
56 }
57 int index = count - 1;
58 chars[index] = currentChar;
59 char charactor;
60 while (i < inputString.size() && index > 0) {
61 if (PercentCharDecodable(inputString, i, charactor)) {
62 // 6, 0x2, subChar need begin with 10XXXXXX
63 if (((charactor >> 6) ^ 0x2) != 0) {
64 return false;
65 }
66 i += (HEX_PAIR_LENGTH + 1);
67 index--;
68 chars[index] = charactor;
69 } else {
70 return false;
71 }
72 }
73 return index == 0;
74 }
75
DecodePercentEncoding(const std::string_view inputString)76 std::string DecodePercentEncoding(const std::string_view inputString)
77 {
78 if (inputString.find("%") == std::string_view::npos) {
79 return std::string(inputString);
80 }
81 std::string result;
82 result.reserve(inputString.size());
83 size_t i = 0;
84 char chars[CHARS_LENGTH];
85 char ch;
86 while (i < inputString.size()) {
87 // convert to decimal characters and append to the result
88 if (PercentCharDecodable(inputString, i, ch)) {
89 auto length = GetCharLength(ch);
90 if (CheckUTF8Enble(inputString, i + HEX_PAIR_LENGTH + 1, ch, length, chars)) {
91 AppendChars(result, i, length, chars);
92 } else {
93 result += inputString.substr(i, (HEX_PAIR_LENGTH + 1));
94 i += (HEX_PAIR_LENGTH + 1);
95 }
96 } else {
97 // normal character
98 result += inputString[i];
99 ++i;
100 }
101 }
102 return result;
103 }
104
StringAnalyzing(std::string_view inputString,std::vector<KeyValue> & results)105 void StringAnalyzing(std::string_view inputString, std::vector<KeyValue>& results)
106 {
107 if (!inputString.empty() && ('?' == inputString.front() || '&' == inputString.front())) {
108 inputString.remove_prefix(1);
109 }
110 auto segmentProcess = [](const std::string_view current, std::vector<KeyValue>& res) {
111 if (current.empty()) {
112 res.emplace_back("", "");
113 return;
114 }
115 auto equalIndex = current.find('=');
116 std::string name;
117 std::string value;
118 std::string decodeName;
119 std::string decodeValue;
120 if (equalIndex == std::string_view::npos) {
121 name = std::string(current);
122 } else {
123 name = std::string(current.substr(0, equalIndex));
124 value = std::string(current.substr(equalIndex + 1));
125 }
126 std::replace(name.begin(), name.end(), '+', ' ');
127 decodeName = DecodePercentEncoding(name);
128 if (!value.empty()) {
129 std::replace(value.begin(), value.end(), '+', ' ');
130 decodeValue = DecodePercentEncoding(value);
131 }
132 res.emplace_back(decodeName, decodeValue);
133 };
134 while (!inputString.empty()) {
135 auto segmentIndex = inputString.find('&');
136 segmentProcess(inputString.substr(0, segmentIndex), results);
137 inputString.remove_prefix(segmentIndex + 1);
138 if (segmentIndex == std::string_view::npos) {
139 break;
140 }
141 }
142 }
143 } // namespace OHOS::Url