Mercurial > embed
comparison liburiparser/src/UriQuery.c @ 82:3c05ebba5cb8
uriparser: removal, closes #1716
jansson: removal, closes #1715
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 25 Jul 2019 21:03:12 +0200 |
parents | 7fdaf1411e6f |
children | 7937ccab4d14 |
comparison
equal
deleted
inserted
replaced
81:7fdaf1411e6f | 82:3c05ebba5cb8 |
---|---|
1 /* | |
2 * uriparser - RFC 3986 URI parsing library | |
3 * | |
4 * Copyright (C) 2007, Weijia Song <songweijia@gmail.com> | |
5 * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org> | |
6 * All rights reserved. | |
7 * | |
8 * Redistribution and use in source and binary forms, with or without | |
9 * modification, are permitted provided that the following conditions | |
10 * are met: | |
11 * | |
12 * * Redistributions of source code must retain the above | |
13 * copyright notice, this list of conditions and the following | |
14 * disclaimer. | |
15 * | |
16 * * Redistributions in binary form must reproduce the above | |
17 * copyright notice, this list of conditions and the following | |
18 * disclaimer in the documentation and/or other materials | |
19 * provided with the distribution. | |
20 * | |
21 * * Neither the name of the <ORGANIZATION> nor the names of its | |
22 * contributors may be used to endorse or promote products | |
23 * derived from this software without specific prior written | |
24 * permission. | |
25 * | |
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
29 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
30 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
32 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
33 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, | |
35 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED | |
37 * OF THE POSSIBILITY OF SUCH DAMAGE. | |
38 */ | |
39 | |
40 /* What encodings are enabled? */ | |
41 #include <uriparser/UriDefsConfig.h> | |
42 #if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE)) | |
43 /* Include SELF twice */ | |
44 # ifdef URI_ENABLE_ANSI | |
45 # define URI_PASS_ANSI 1 | |
46 # include "UriQuery.c" | |
47 # undef URI_PASS_ANSI | |
48 # endif | |
49 # ifdef URI_ENABLE_UNICODE | |
50 # define URI_PASS_UNICODE 1 | |
51 # include "UriQuery.c" | |
52 # undef URI_PASS_UNICODE | |
53 # endif | |
54 #else | |
55 # ifdef URI_PASS_ANSI | |
56 # include <uriparser/UriDefsAnsi.h> | |
57 # else | |
58 # include <uriparser/UriDefsUnicode.h> | |
59 # include <wchar.h> | |
60 # endif | |
61 | |
62 | |
63 | |
64 #ifndef URI_DOXYGEN | |
65 # include <uriparser/Uri.h> | |
66 # include "UriCommon.h" | |
67 #endif | |
68 | |
69 | |
70 | |
71 static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, | |
72 const URI_TYPE(QueryList) * queryList, | |
73 int maxChars, int * charsWritten, int * charsRequired, | |
74 UriBool spaceToPlus, UriBool normalizeBreaks); | |
75 | |
76 static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, | |
77 int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, | |
78 const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, | |
79 UriBool plusToSpace, UriBreakConversion breakConversion); | |
80 | |
81 | |
82 | |
83 int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList, | |
84 int * charsRequired) { | |
85 const UriBool spaceToPlus = URI_TRUE; | |
86 const UriBool normalizeBreaks = URI_TRUE; | |
87 | |
88 return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired, | |
89 spaceToPlus, normalizeBreaks); | |
90 } | |
91 | |
92 | |
93 | |
94 int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList, | |
95 int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) { | |
96 if ((queryList == NULL) || (charsRequired == NULL)) { | |
97 return URI_ERROR_NULL; | |
98 } | |
99 | |
100 return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL, | |
101 charsRequired, spaceToPlus, normalizeBreaks); | |
102 } | |
103 | |
104 | |
105 | |
106 int URI_FUNC(ComposeQuery)(URI_CHAR * dest, | |
107 const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) { | |
108 const UriBool spaceToPlus = URI_TRUE; | |
109 const UriBool normalizeBreaks = URI_TRUE; | |
110 | |
111 return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten, | |
112 spaceToPlus, normalizeBreaks); | |
113 } | |
114 | |
115 | |
116 | |
117 int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest, | |
118 const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten, | |
119 UriBool spaceToPlus, UriBool normalizeBreaks) { | |
120 if ((dest == NULL) || (queryList == NULL)) { | |
121 return URI_ERROR_NULL; | |
122 } | |
123 | |
124 if (maxChars < 1) { | |
125 return URI_ERROR_OUTPUT_TOO_LARGE; | |
126 } | |
127 | |
128 return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars, | |
129 charsWritten, NULL, spaceToPlus, normalizeBreaks); | |
130 } | |
131 | |
132 | |
133 | |
134 int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest, | |
135 const URI_TYPE(QueryList) * queryList) { | |
136 const UriBool spaceToPlus = URI_TRUE; | |
137 const UriBool normalizeBreaks = URI_TRUE; | |
138 | |
139 return URI_FUNC(ComposeQueryMallocEx)(dest, queryList, | |
140 spaceToPlus, normalizeBreaks); | |
141 } | |
142 | |
143 | |
144 | |
145 int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest, | |
146 const URI_TYPE(QueryList) * queryList, | |
147 UriBool spaceToPlus, UriBool normalizeBreaks) { | |
148 int charsRequired; | |
149 int res; | |
150 URI_CHAR * queryString; | |
151 | |
152 if (dest == NULL) { | |
153 return URI_ERROR_NULL; | |
154 } | |
155 | |
156 /* Calculate space */ | |
157 res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired, | |
158 spaceToPlus, normalizeBreaks); | |
159 if (res != URI_SUCCESS) { | |
160 return res; | |
161 } | |
162 charsRequired++; | |
163 | |
164 /* Allocate space */ | |
165 queryString = malloc(charsRequired * sizeof(URI_CHAR)); | |
166 if (queryString == NULL) { | |
167 return URI_ERROR_MALLOC; | |
168 } | |
169 | |
170 /* Put query in */ | |
171 res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired, | |
172 NULL, spaceToPlus, normalizeBreaks); | |
173 if (res != URI_SUCCESS) { | |
174 free(queryString); | |
175 return res; | |
176 } | |
177 | |
178 *dest = queryString; | |
179 return URI_SUCCESS; | |
180 } | |
181 | |
182 | |
183 | |
184 int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest, | |
185 const URI_TYPE(QueryList) * queryList, | |
186 int maxChars, int * charsWritten, int * charsRequired, | |
187 UriBool spaceToPlus, UriBool normalizeBreaks) { | |
188 UriBool firstItem = URI_TRUE; | |
189 int ampersandLen = 0; | |
190 URI_CHAR * write = dest; | |
191 | |
192 /* Subtract terminator */ | |
193 if (dest == NULL) { | |
194 *charsRequired = 0; | |
195 } else { | |
196 maxChars--; | |
197 } | |
198 | |
199 while (queryList != NULL) { | |
200 const URI_CHAR * const key = queryList->key; | |
201 const URI_CHAR * const value = queryList->value; | |
202 const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3); | |
203 const int keyLen = (key == NULL) ? 0 : (int)URI_STRLEN(key); | |
204 const int keyRequiredChars = worstCase * keyLen; | |
205 const int valueLen = (value == NULL) ? 0 : (int)URI_STRLEN(value); | |
206 const int valueRequiredChars = worstCase * valueLen; | |
207 | |
208 if (dest == NULL) { | |
209 if (firstItem == URI_TRUE) { | |
210 ampersandLen = 1; | |
211 firstItem = URI_FALSE; | |
212 } | |
213 | |
214 (*charsRequired) += ampersandLen + keyRequiredChars + ((value == NULL) | |
215 ? 0 | |
216 : 1 + valueRequiredChars); | |
217 } else { | |
218 URI_CHAR * afterKey; | |
219 | |
220 if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) { | |
221 return URI_ERROR_OUTPUT_TOO_LARGE; | |
222 } | |
223 | |
224 /* Copy key */ | |
225 if (firstItem == URI_TRUE) { | |
226 firstItem = URI_FALSE; | |
227 } else { | |
228 write[0] = _UT('&'); | |
229 write++; | |
230 } | |
231 afterKey = URI_FUNC(EscapeEx)(key, key + keyLen, | |
232 write, spaceToPlus, normalizeBreaks); | |
233 write += (afterKey - write); | |
234 | |
235 if (value != NULL) { | |
236 URI_CHAR * afterValue; | |
237 | |
238 if ((write - dest) + 1 + valueRequiredChars > maxChars) { | |
239 return URI_ERROR_OUTPUT_TOO_LARGE; | |
240 } | |
241 | |
242 /* Copy value */ | |
243 write[0] = _UT('='); | |
244 write++; | |
245 afterValue = URI_FUNC(EscapeEx)(value, value + valueLen, | |
246 write, spaceToPlus, normalizeBreaks); | |
247 write += (afterValue - write); | |
248 } | |
249 } | |
250 | |
251 queryList = queryList->next; | |
252 } | |
253 | |
254 if (dest != NULL) { | |
255 write[0] = _UT('\0'); | |
256 if (charsWritten != NULL) { | |
257 *charsWritten = (int)(write - dest) + 1; /* .. for terminator */ | |
258 } | |
259 } | |
260 | |
261 return URI_SUCCESS; | |
262 } | |
263 | |
264 | |
265 | |
266 UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext, | |
267 int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter, | |
268 const URI_CHAR * valueFirst, const URI_CHAR * valueAfter, | |
269 UriBool plusToSpace, UriBreakConversion breakConversion) { | |
270 const int keyLen = (int)(keyAfter - keyFirst); | |
271 const int valueLen = (int)(valueAfter - valueFirst); | |
272 URI_CHAR * key; | |
273 URI_CHAR * value; | |
274 | |
275 if ((prevNext == NULL) || (itemCount == NULL) | |
276 || (keyFirst == NULL) || (keyAfter == NULL) | |
277 || (keyFirst > keyAfter) || (valueFirst > valueAfter) | |
278 || ((keyFirst == keyAfter) | |
279 && (valueFirst == NULL) && (valueAfter == NULL))) { | |
280 return URI_TRUE; | |
281 } | |
282 | |
283 /* Append new empty item */ | |
284 *prevNext = malloc(1 * sizeof(URI_TYPE(QueryList))); | |
285 if (*prevNext == NULL) { | |
286 return URI_FALSE; /* Raises malloc error */ | |
287 } | |
288 (*prevNext)->next = NULL; | |
289 | |
290 | |
291 /* Fill key */ | |
292 key = malloc((keyLen + 1) * sizeof(URI_CHAR)); | |
293 if (key == NULL) { | |
294 free(*prevNext); | |
295 *prevNext = NULL; | |
296 return URI_FALSE; /* Raises malloc error */ | |
297 } | |
298 | |
299 key[keyLen] = _UT('\0'); | |
300 if (keyLen > 0) { | |
301 /* Copy 1:1 */ | |
302 memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR)); | |
303 | |
304 /* Unescape */ | |
305 URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion); | |
306 } | |
307 (*prevNext)->key = key; | |
308 | |
309 | |
310 /* Fill value */ | |
311 if (valueFirst != NULL) { | |
312 value = malloc((valueLen + 1) * sizeof(URI_CHAR)); | |
313 if (value == NULL) { | |
314 free(key); | |
315 free(*prevNext); | |
316 *prevNext = NULL; | |
317 return URI_FALSE; /* Raises malloc error */ | |
318 } | |
319 | |
320 value[valueLen] = _UT('\0'); | |
321 if (valueLen > 0) { | |
322 /* Copy 1:1 */ | |
323 memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR)); | |
324 | |
325 /* Unescape */ | |
326 URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion); | |
327 } | |
328 (*prevNext)->value = value; | |
329 } else { | |
330 value = NULL; | |
331 } | |
332 (*prevNext)->value = value; | |
333 | |
334 (*itemCount)++; | |
335 return URI_TRUE; | |
336 } | |
337 | |
338 | |
339 | |
340 void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList) { | |
341 while (queryList != NULL) { | |
342 URI_TYPE(QueryList) * nextBackup = queryList->next; | |
343 free((URI_CHAR *)queryList->key); /* const cast */ | |
344 free((URI_CHAR *)queryList->value); /* const cast */ | |
345 free(queryList); | |
346 queryList = nextBackup; | |
347 } | |
348 } | |
349 | |
350 | |
351 | |
352 int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount, | |
353 const URI_CHAR * first, const URI_CHAR * afterLast) { | |
354 const UriBool plusToSpace = URI_TRUE; | |
355 const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH; | |
356 | |
357 return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast, | |
358 plusToSpace, breakConversion); | |
359 } | |
360 | |
361 | |
362 | |
363 int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount, | |
364 const URI_CHAR * first, const URI_CHAR * afterLast, | |
365 UriBool plusToSpace, UriBreakConversion breakConversion) { | |
366 const URI_CHAR * walk = first; | |
367 const URI_CHAR * keyFirst = first; | |
368 const URI_CHAR * keyAfter = NULL; | |
369 const URI_CHAR * valueFirst = NULL; | |
370 const URI_CHAR * valueAfter = NULL; | |
371 URI_TYPE(QueryList) ** prevNext = dest; | |
372 int nullCounter; | |
373 int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount; | |
374 | |
375 if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) { | |
376 return URI_ERROR_NULL; | |
377 } | |
378 | |
379 if (first > afterLast) { | |
380 return URI_ERROR_RANGE_INVALID; | |
381 } | |
382 | |
383 *dest = NULL; | |
384 *itemsAppended = 0; | |
385 | |
386 /* Parse query string */ | |
387 for (; walk < afterLast; walk++) { | |
388 switch (*walk) { | |
389 case _UT('&'): | |
390 if (valueFirst != NULL) { | |
391 valueAfter = walk; | |
392 } else { | |
393 keyAfter = walk; | |
394 } | |
395 | |
396 if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, | |
397 keyFirst, keyAfter, valueFirst, valueAfter, | |
398 plusToSpace, breakConversion) | |
399 == URI_FALSE) { | |
400 /* Free list we built */ | |
401 *itemsAppended = 0; | |
402 URI_FUNC(FreeQueryList)(*dest); | |
403 return URI_ERROR_MALLOC; | |
404 } | |
405 | |
406 /* Make future items children of the current */ | |
407 if ((prevNext != NULL) && (*prevNext != NULL)) { | |
408 prevNext = &((*prevNext)->next); | |
409 } | |
410 | |
411 if (walk + 1 < afterLast) { | |
412 keyFirst = walk + 1; | |
413 } else { | |
414 keyFirst = NULL; | |
415 } | |
416 keyAfter = NULL; | |
417 valueFirst = NULL; | |
418 valueAfter = NULL; | |
419 break; | |
420 | |
421 case _UT('='): | |
422 /* NOTE: WE treat the first '=' as a separator, */ | |
423 /* all following go into the value part */ | |
424 if (keyAfter == NULL) { | |
425 keyAfter = walk; | |
426 if (walk + 1 <= afterLast) { | |
427 valueFirst = walk + 1; | |
428 valueAfter = walk + 1; | |
429 } | |
430 } | |
431 break; | |
432 | |
433 default: | |
434 break; | |
435 } | |
436 } | |
437 | |
438 if (valueFirst != NULL) { | |
439 /* Must be key/value pair */ | |
440 valueAfter = walk; | |
441 } else { | |
442 /* Must be key only */ | |
443 keyAfter = walk; | |
444 } | |
445 | |
446 if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter, | |
447 valueFirst, valueAfter, plusToSpace, breakConversion) | |
448 == URI_FALSE) { | |
449 /* Free list we built */ | |
450 *itemsAppended = 0; | |
451 URI_FUNC(FreeQueryList)(*dest); | |
452 return URI_ERROR_MALLOC; | |
453 } | |
454 | |
455 return URI_SUCCESS; | |
456 } | |
457 | |
458 | |
459 | |
460 #endif |