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,unsigned char currentChar,size_t count,unsigned char * chars)52 bool CheckUTF8Enble(const std::string_view inputString, size_t i,
53 unsigned char currentChar, size_t count, unsigned char* chars)
54 {
55 if (count == 0) {
56 return false;
57 }
58 size_t index = count - 1;
59 chars[index] = currentChar;
60 unsigned char charactor;
61 while (i < inputString.size() && index > 0) {
62 if (PercentCharDecodable(inputString, i, charactor)) {
63 // 6, 0x2, subChar need begin with 10XXXXXX
64 if (((charactor >> 6) ^ 0x2) != 0) {
65 return false;
66 }
67 i += (HEX_PAIR_LENGTH + 1);
68 index--;
69 chars[index] = charactor;
70 } else {
71 return false;
72 }
73 }
74 return index == 0;
75 }
76
DecodePercentEncoding(const std::string_view inputString)77 std::string DecodePercentEncoding(const std::string_view inputString)
78 {
79 if (inputString.find("%") == std::string_view::npos) {
80 return std::string(inputString);
81 }
82 std::string result;
83 result.reserve(inputString.size());
84 size_t i = 0;
85 unsigned char chars[CHARS_LENGTH];
86 unsigned char ch;
87 while (i < inputString.size()) {
88 // convert to decimal characters and append to the result
89 if (PercentCharDecodable(inputString, i, ch)) {
90 size_t length = GetCharLength(ch);
91 if (CheckUTF8Enble(inputString, i + HEX_PAIR_LENGTH + 1, ch, length, chars)) {
92 AppendChars(result, i, length, chars);
93 } else {
94 result += inputString.substr(i, (HEX_PAIR_LENGTH + 1));
95 i += (HEX_PAIR_LENGTH + 1);
96 }
97 } else {
98 // normal character
99 result += inputString[i];
100 ++i;
101 }
102 }
103 return result;
104 }
105
StringAnalyzing(std::string_view inputString,std::vector<KeyValue> & results)106 void StringAnalyzing(std::string_view inputString, std::vector<KeyValue>& results)
107 {
108 if (!inputString.empty() && ('?' == inputString.front() || '&' == inputString.front())) {
109 inputString.remove_prefix(1);
110 }
111 auto segmentProcess = [](const std::string_view current, std::vector<KeyValue>& res) {
112 if (current.empty()) {
113 res.emplace_back("", "");
114 return;
115 }
116 auto equalIndex = current.find('=');
117 std::string name;
118 std::string value;
119 std::string decodeName;
120 std::string decodeValue;
121 if (equalIndex == std::string_view::npos) {
122 name = std::string(current);
123 } else {
124 name = std::string(current.substr(0, equalIndex));
125 value = std::string(current.substr(equalIndex + 1));
126 }
127 std::replace(name.begin(), name.end(), '+', ' ');
128 decodeName = DecodePercentEncoding(name);
129 if (!value.empty()) {
130 std::replace(value.begin(), value.end(), '+', ' ');
131 decodeValue = DecodePercentEncoding(value);
132 }
133 res.emplace_back(decodeName, decodeValue);
134 };
135 while (!inputString.empty()) {
136 auto segmentIndex = inputString.find('&');
137 segmentProcess(inputString.substr(0, segmentIndex), results);
138 inputString.remove_prefix(segmentIndex + 1);
139 if (segmentIndex == std::string_view::npos) {
140 break;
141 }
142 }
143 }
144 } // namespace OHOS::Url