Line data Source code
1 : /**
2 : Copyright (c) 2016-2019 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
4 :
5 : Permission is hereby granted, free of charge, to any person obtaining a copy
6 : of this software and associated documentation files (the "Software"), to deal
7 : in the Software without restriction, including without limitation the rights
8 : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 : copies of the Software, and to permit persons to whom the Software is
10 : furnished to do so, subject to the following conditions:
11 :
12 : The above copyright notice and this permission notice shall be included in
13 : all copies or substantial portions of the Software.
14 :
15 : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 : THE SOFTWARE.
22 : **/
23 :
24 : #include "SPString.h"
25 : #include "SPValid.h"
26 : #include "SPData.h"
27 :
28 : namespace STAPPLER_VERSIONIZED stappler::data {
29 :
30 : using NextToken = chars::Chars<char, '=', '&', ';', '[', ']', '+', '%'>;
31 : using NextKey = chars::Chars<char, '&', ';', '+'>;
32 :
33 : template <typename Interface>
34 : class UrlencodeParser {
35 : public:
36 : using Reader = StringView;
37 :
38 : enum class Literal {
39 : None,
40 : String,
41 : Percent,
42 : Open,
43 : Close,
44 : Delim,
45 : };
46 :
47 : enum class VarState {
48 : Key,
49 : SubKey,
50 : SubKeyEnd,
51 : Value,
52 : End,
53 : };
54 :
55 3325 : UrlencodeParser(ValueTemplate<Interface> &target, size_t length = maxOf<size_t>(), size_t maxVarSize = maxOf<size_t>())
56 3325 : : target(&target), length(length), maxVarSize(maxVarSize) { }
57 :
58 : size_t read(const uint8_t * s, size_t count);
59 :
60 : ValueTemplate<Interface> *flushString(StringView &r, ValueTemplate<Interface> *, VarState state);
61 :
62 : ValueTemplate<Interface> & data() { return *target; }
63 : const ValueTemplate<Interface> & data() const { return *target; }
64 :
65 : protected:
66 : void bufferize(Reader &r);
67 : void bufferize(char c);
68 : void flush(Reader &r);
69 :
70 : ValueTemplate<Interface> *target;
71 : size_t length = maxOf<size_t>();
72 : size_t maxVarSize = maxOf<size_t>();
73 :
74 : bool skip = false;
75 : VarState state = VarState::Key;
76 : Literal literal = Literal::None;
77 :
78 : BufferTemplate<Interface> buf;
79 : ValueTemplate<Interface> *current = nullptr;
80 : };
81 :
82 : template <typename Interface>
83 400 : void UrlencodeParser<Interface>::bufferize(Reader &r) {
84 400 : if (!skip) {
85 400 : if (buf.size() + r.size() > maxVarSize) {
86 0 : buf.clear();
87 0 : skip = true;
88 : } else {
89 400 : buf.put(r.data(), r.size());
90 : }
91 : }
92 400 : }
93 :
94 : template <typename Interface>
95 200 : void UrlencodeParser<Interface>::bufferize(char c) {
96 200 : if (!skip) {
97 200 : if (buf.size() + 1 > maxVarSize) {
98 0 : buf.clear();
99 0 : skip = true;
100 : } else {
101 200 : buf.putc(c);
102 200 : return;
103 : }
104 : }
105 0 : buf.putc(c);
106 : }
107 :
108 : template <typename Interface>
109 6125 : void UrlencodeParser<Interface>::flush(Reader &r) {
110 6125 : if (!skip) {
111 6125 : if (r.size() < maxVarSize) {
112 6125 : current = flushString(r, current, state);
113 : } else {
114 0 : skip = true;
115 : }
116 6125 : buf.clear();
117 : }
118 6125 : }
119 :
120 : template <typename Interface>
121 3325 : size_t UrlencodeParser<Interface>::read(const uint8_t * s, size_t count) {
122 3325 : if (count >= length) {
123 3325 : count = length;
124 3325 : length = 0;
125 : }
126 3325 : Reader r((const char *)s, count);
127 :
128 9650 : while (!r.empty()) {
129 6325 : Reader str;
130 6325 : if (state == VarState::Value) {
131 1275 : str = r.readUntil<NextKey>();
132 : } else {
133 5050 : str = r.readUntil<NextToken>();
134 : }
135 :
136 6325 : if (buf.empty() && (!r.empty() || length == 0) && !r.is('+') && !r.is('%')) {
137 5925 : flush(str);
138 : } else {
139 400 : bufferize(str);
140 400 : if (!r.empty() && !r.is('+') && !r.is('%')) {
141 200 : Reader tmp = buf.get();
142 200 : flush(tmp);
143 : }
144 : }
145 :
146 6325 : char c = r[0];
147 6325 : if (c == '+') {
148 0 : bufferize(' ');
149 0 : ++ r;
150 : } else {
151 6325 : ++ r;
152 6325 : if (c == '%') {
153 200 : if (r.is("5B")) {
154 0 : c = '[';
155 0 : r += 2;
156 200 : } else if (r.is("5D")) {
157 0 : c = ']';
158 0 : r += 2;
159 : } else {
160 200 : bufferize('%');
161 200 : c = 0;
162 : }
163 : }
164 :
165 6325 : if (c != 0) {
166 5475 : switch (state) {
167 3950 : case VarState::Key:
168 3950 : switch (c) {
169 350 : case '[': state = VarState::SubKey; break;
170 3600 : case '=': state = VarState::Value; break;
171 0 : case '&': case ';': state = VarState::Key; break;
172 0 : default: state = VarState::End; break;
173 : }
174 3950 : break;
175 450 : case VarState::SubKey:
176 450 : switch (c) {
177 450 : case ']': state = VarState::SubKeyEnd; break;
178 0 : default: state = VarState::End; break;
179 : }
180 450 : break;
181 450 : case VarState::SubKeyEnd:
182 450 : switch (c) {
183 100 : case '[': state = VarState::SubKey; break;
184 350 : case '=': state = VarState::Value; break;
185 0 : case '&': case ';': state = VarState::Key; break;
186 0 : default: state = VarState::End; break;
187 : }
188 450 : break;
189 625 : case VarState::Value:
190 625 : switch (c) {
191 625 : case '&': case ';': state = VarState::Key; skip = false; break;
192 0 : default: state = VarState::End; break;
193 : }
194 625 : break;
195 0 : default:
196 0 : break;
197 : }
198 : }
199 : }
200 6325 : if (skip) {
201 0 : break;
202 : }
203 : }
204 :
205 3325 : if (!buf.empty()) {
206 0 : auto tmp = buf.get();
207 0 : flush(tmp);
208 : }
209 :
210 3325 : return count;
211 : }
212 :
213 : template <typename Interface>
214 6125 : auto UrlencodeParser<Interface>::flushString(StringView &r, ValueTemplate<Interface> *cur, VarState varState)
215 : -> ValueTemplate<Interface> * {
216 6125 : auto str = string::urldecode<Interface>(r);
217 :
218 6125 : switch (varState) {
219 3950 : case VarState::Key:
220 3950 : if (!str.empty()) {
221 3950 : if (target->hasValue(str)) {
222 200 : cur = &target->getValue(str);
223 : } else {
224 3750 : cur = &target->setValue(ValueTemplate<Interface>(true), str);
225 : }
226 : }
227 3950 : break;
228 450 : case VarState::SubKey:
229 450 : if (cur) {
230 450 : if (!str.empty() && valid::validateNumber(str)) {
231 150 : auto num = StringView(str).readInteger().get();
232 150 : if (cur->isArray()) {
233 100 : if (num < int64_t(cur->size())) {
234 50 : cur = &cur->getValue(num);
235 150 : return cur;
236 50 : } else if (num == int64_t(cur->size())) {
237 50 : cur = &cur->addValue(ValueTemplate<Interface>(true));
238 50 : return cur;
239 : }
240 50 : } else if (!cur->isDictionary() && num == 0) {
241 50 : cur->setArray(typename ValueTemplate<Interface>::ArrayType());
242 50 : cur = &cur->addValue(ValueTemplate<Interface>(true));
243 50 : return cur;
244 : }
245 : }
246 300 : if (str.empty()) {
247 200 : if (!cur->isArray()) {
248 100 : cur->setArray(typename ValueTemplate<Interface>::ArrayType());
249 : }
250 200 : cur = &cur->addValue(ValueTemplate<Interface>(true));
251 : } else {
252 100 : if (!cur->isDictionary()) {
253 50 : cur->setDict(typename ValueTemplate<Interface>::DictionaryType());
254 : }
255 100 : if (cur->hasValue(str)) {
256 50 : cur = &cur->getValue(str);
257 : } else {
258 50 : cur = &cur->setValue(ValueTemplate<Interface>(true), str);
259 : }
260 : }
261 : }
262 300 : break;
263 1275 : case VarState::Value:
264 : case VarState::End:
265 1275 : if (cur) {
266 1275 : if (!str.empty()) {
267 1275 : cur->setString(str);
268 : }
269 1275 : cur = nullptr;
270 : }
271 1275 : break;
272 450 : default:
273 450 : break;
274 : }
275 :
276 5975 : return cur;
277 6125 : }
278 :
279 : template <>
280 3300 : auto readUrlencoded<memory::PoolInterface>(StringView r, size_t maxVarSize) -> ValueTemplate<memory::PoolInterface> {
281 3300 : ValueTemplate<memory::PoolInterface> ret;
282 3300 : UrlencodeParser<memory::PoolInterface> parser(ret, r.size(), maxVarSize);
283 3300 : parser.read((const uint8_t *)r.data(), r.size());
284 6600 : return ret;
285 3300 : }
286 :
287 : template <>
288 25 : auto readUrlencoded<memory::StandartInterface>(StringView r, size_t maxVarSize) -> ValueTemplate<memory::StandartInterface> {
289 25 : ValueTemplate<memory::StandartInterface> ret;
290 25 : UrlencodeParser<memory::StandartInterface> parser(ret, r.size(), maxVarSize);
291 25 : parser.read((const uint8_t *)r.data(), r.size());
292 50 : return ret;
293 25 : }
294 :
295 :
296 : }
|