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 "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 "UriDefsAnsi.h"
57 # else
58 # include "UriDefsUnicode.h"
59 # include <wchar.h>
60 # endif
61
62
63
64 #ifndef URI_DOXYGEN
65 # include "Uri.h"
66 # include "UriCommon.h"
67 # include "UriMemory.h"
68 #endif
69
70
71
72 #include <limits.h>
73
74
75
76 static int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
77 const URI_TYPE(QueryList) * queryList,
78 int maxChars, int * charsWritten, int * charsRequired,
79 UriBool spaceToPlus, UriBool normalizeBreaks);
80
81 static UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
82 int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
83 const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
84 UriBool plusToSpace, UriBreakConversion breakConversion,
85 UriMemoryManager * memory);
86
87
88
URI_FUNC(ComposeQueryCharsRequired)89 int URI_FUNC(ComposeQueryCharsRequired)(const URI_TYPE(QueryList) * queryList,
90 int * charsRequired) {
91 const UriBool spaceToPlus = URI_TRUE;
92 const UriBool normalizeBreaks = URI_TRUE;
93
94 return URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, charsRequired,
95 spaceToPlus, normalizeBreaks);
96 }
97
98
99
URI_FUNC(ComposeQueryCharsRequiredEx)100 int URI_FUNC(ComposeQueryCharsRequiredEx)(const URI_TYPE(QueryList) * queryList,
101 int * charsRequired, UriBool spaceToPlus, UriBool normalizeBreaks) {
102 if ((queryList == NULL) || (charsRequired == NULL)) {
103 return URI_ERROR_NULL;
104 }
105
106 return URI_FUNC(ComposeQueryEngine)(NULL, queryList, 0, NULL,
107 charsRequired, spaceToPlus, normalizeBreaks);
108 }
109
110
111
URI_FUNC(ComposeQuery)112 int URI_FUNC(ComposeQuery)(URI_CHAR * dest,
113 const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten) {
114 const UriBool spaceToPlus = URI_TRUE;
115 const UriBool normalizeBreaks = URI_TRUE;
116
117 return URI_FUNC(ComposeQueryEx)(dest, queryList, maxChars, charsWritten,
118 spaceToPlus, normalizeBreaks);
119 }
120
121
122
URI_FUNC(ComposeQueryEx)123 int URI_FUNC(ComposeQueryEx)(URI_CHAR * dest,
124 const URI_TYPE(QueryList) * queryList, int maxChars, int * charsWritten,
125 UriBool spaceToPlus, UriBool normalizeBreaks) {
126 if ((dest == NULL) || (queryList == NULL)) {
127 return URI_ERROR_NULL;
128 }
129
130 if (maxChars < 1) {
131 return URI_ERROR_OUTPUT_TOO_LARGE;
132 }
133
134 return URI_FUNC(ComposeQueryEngine)(dest, queryList, maxChars,
135 charsWritten, NULL, spaceToPlus, normalizeBreaks);
136 }
137
138
139
URI_FUNC(ComposeQueryMalloc)140 int URI_FUNC(ComposeQueryMalloc)(URI_CHAR ** dest,
141 const URI_TYPE(QueryList) * queryList) {
142 const UriBool spaceToPlus = URI_TRUE;
143 const UriBool normalizeBreaks = URI_TRUE;
144
145 return URI_FUNC(ComposeQueryMallocEx)(dest, queryList,
146 spaceToPlus, normalizeBreaks);
147 }
148
149
150
URI_FUNC(ComposeQueryMallocEx)151 int URI_FUNC(ComposeQueryMallocEx)(URI_CHAR ** dest,
152 const URI_TYPE(QueryList) * queryList,
153 UriBool spaceToPlus, UriBool normalizeBreaks) {
154 return URI_FUNC(ComposeQueryMallocExMm)(dest, queryList, spaceToPlus,
155 normalizeBreaks, NULL);
156 }
157
158
159
URI_FUNC(ComposeQueryMallocExMm)160 int URI_FUNC(ComposeQueryMallocExMm)(URI_CHAR ** dest,
161 const URI_TYPE(QueryList) * queryList,
162 UriBool spaceToPlus, UriBool normalizeBreaks,
163 UriMemoryManager * memory) {
164 int charsRequired;
165 int res;
166 URI_CHAR * queryString;
167
168 if (dest == NULL) {
169 return URI_ERROR_NULL;
170 }
171
172 URI_CHECK_MEMORY_MANAGER(memory); /* may return */
173
174 /* Calculate space */
175 res = URI_FUNC(ComposeQueryCharsRequiredEx)(queryList, &charsRequired,
176 spaceToPlus, normalizeBreaks);
177 if (res != URI_SUCCESS) {
178 return res;
179 }
180 charsRequired++;
181
182 /* Allocate space */
183 queryString = memory->malloc(memory, charsRequired * sizeof(URI_CHAR));
184 if (queryString == NULL) {
185 return URI_ERROR_MALLOC;
186 }
187
188 /* Put query in */
189 res = URI_FUNC(ComposeQueryEx)(queryString, queryList, charsRequired,
190 NULL, spaceToPlus, normalizeBreaks);
191 if (res != URI_SUCCESS) {
192 memory->free(memory, queryString);
193 return res;
194 }
195
196 *dest = queryString;
197 return URI_SUCCESS;
198 }
199
200
201
URI_FUNC(ComposeQueryEngine)202 int URI_FUNC(ComposeQueryEngine)(URI_CHAR * dest,
203 const URI_TYPE(QueryList) * queryList,
204 int maxChars, int * charsWritten, int * charsRequired,
205 UriBool spaceToPlus, UriBool normalizeBreaks) {
206 UriBool firstItem = URI_TRUE;
207 int ampersandLen = 0; /* increased to 1 from second item on */
208 URI_CHAR * write = dest;
209
210 /* Subtract terminator */
211 if (dest == NULL) {
212 *charsRequired = 0;
213 } else {
214 maxChars--;
215 }
216
217 while (queryList != NULL) {
218 const URI_CHAR * const key = queryList->key;
219 const URI_CHAR * const value = queryList->value;
220 const int worstCase = (normalizeBreaks == URI_TRUE ? 6 : 3);
221 const int keyLen = (key == NULL) ? 0 : (int)URI_STRLEN(key);
222 int keyRequiredChars;
223 const int valueLen = (value == NULL) ? 0 : (int)URI_STRLEN(value);
224 int valueRequiredChars;
225
226 if ((keyLen >= INT_MAX / worstCase) || (valueLen >= INT_MAX / worstCase)) {
227 return URI_ERROR_OUTPUT_TOO_LARGE;
228 }
229 keyRequiredChars = worstCase * keyLen;
230 valueRequiredChars = worstCase * valueLen;
231
232 if (dest == NULL) {
233 (*charsRequired) += ampersandLen + keyRequiredChars + ((value == NULL)
234 ? 0
235 : 1 + valueRequiredChars);
236
237 if (firstItem == URI_TRUE) {
238 ampersandLen = 1;
239 firstItem = URI_FALSE;
240 }
241 } else {
242 if ((write - dest) + ampersandLen + keyRequiredChars > maxChars) {
243 return URI_ERROR_OUTPUT_TOO_LARGE;
244 }
245
246 /* Copy key */
247 if (firstItem == URI_TRUE) {
248 ampersandLen = 1;
249 firstItem = URI_FALSE;
250 } else {
251 write[0] = _UT('&');
252 write++;
253 }
254 write = URI_FUNC(EscapeEx)(key, key + keyLen,
255 write, spaceToPlus, normalizeBreaks);
256
257 if (value != NULL) {
258 if ((write - dest) + 1 + valueRequiredChars > maxChars) {
259 return URI_ERROR_OUTPUT_TOO_LARGE;
260 }
261
262 /* Copy value */
263 write[0] = _UT('=');
264 write++;
265 write = URI_FUNC(EscapeEx)(value, value + valueLen,
266 write, spaceToPlus, normalizeBreaks);
267 }
268 }
269
270 queryList = queryList->next;
271 }
272
273 if (dest != NULL) {
274 write[0] = _UT('\0');
275 if (charsWritten != NULL) {
276 *charsWritten = (int)(write - dest) + 1; /* .. for terminator */
277 }
278 }
279
280 return URI_SUCCESS;
281 }
282
283
284
URI_FUNC(AppendQueryItem)285 UriBool URI_FUNC(AppendQueryItem)(URI_TYPE(QueryList) ** prevNext,
286 int * itemCount, const URI_CHAR * keyFirst, const URI_CHAR * keyAfter,
287 const URI_CHAR * valueFirst, const URI_CHAR * valueAfter,
288 UriBool plusToSpace, UriBreakConversion breakConversion,
289 UriMemoryManager * memory) {
290 const int keyLen = (int)(keyAfter - keyFirst);
291 const int valueLen = (int)(valueAfter - valueFirst);
292 URI_CHAR * key;
293 URI_CHAR * value;
294
295 if ((prevNext == NULL) || (itemCount == NULL)
296 || (keyFirst == NULL) || (keyAfter == NULL)
297 || (keyFirst > keyAfter) || (valueFirst > valueAfter)
298 || ((keyFirst == keyAfter)
299 && (valueFirst == NULL) && (valueAfter == NULL))) {
300 return URI_TRUE;
301 }
302
303 /* Append new empty item */
304 *prevNext = memory->malloc(memory, 1 * sizeof(URI_TYPE(QueryList)));
305 if (*prevNext == NULL) {
306 return URI_FALSE; /* Raises malloc error */
307 }
308 (*prevNext)->next = NULL;
309
310
311 /* Fill key */
312 key = memory->malloc(memory, (keyLen + 1) * sizeof(URI_CHAR));
313 if (key == NULL) {
314 memory->free(memory, *prevNext);
315 *prevNext = NULL;
316 return URI_FALSE; /* Raises malloc error */
317 }
318
319 key[keyLen] = _UT('\0');
320 if (keyLen > 0) {
321 /* Copy 1:1 */
322 memcpy(key, keyFirst, keyLen * sizeof(URI_CHAR));
323
324 /* Unescape */
325 URI_FUNC(UnescapeInPlaceEx)(key, plusToSpace, breakConversion);
326 }
327 (*prevNext)->key = key;
328
329
330 /* Fill value */
331 if (valueFirst != NULL) {
332 value = memory->malloc(memory, (valueLen + 1) * sizeof(URI_CHAR));
333 if (value == NULL) {
334 memory->free(memory, key);
335 memory->free(memory, *prevNext);
336 *prevNext = NULL;
337 return URI_FALSE; /* Raises malloc error */
338 }
339
340 value[valueLen] = _UT('\0');
341 if (valueLen > 0) {
342 /* Copy 1:1 */
343 memcpy(value, valueFirst, valueLen * sizeof(URI_CHAR));
344
345 /* Unescape */
346 URI_FUNC(UnescapeInPlaceEx)(value, plusToSpace, breakConversion);
347 }
348 (*prevNext)->value = value;
349 } else {
350 value = NULL;
351 }
352 (*prevNext)->value = value;
353
354 (*itemCount)++;
355 return URI_TRUE;
356 }
357
358
359
URI_FUNC(FreeQueryList)360 void URI_FUNC(FreeQueryList)(URI_TYPE(QueryList) * queryList) {
361 URI_FUNC(FreeQueryListMm)(queryList, NULL);
362 }
363
364
365
URI_FUNC(FreeQueryListMm)366 int URI_FUNC(FreeQueryListMm)(URI_TYPE(QueryList) * queryList,
367 UriMemoryManager * memory) {
368 URI_CHECK_MEMORY_MANAGER(memory); /* may return */
369 while (queryList != NULL) {
370 URI_TYPE(QueryList) * nextBackup = queryList->next;
371 memory->free(memory, (URI_CHAR *)queryList->key); /* const cast */
372 memory->free(memory, (URI_CHAR *)queryList->value); /* const cast */
373 memory->free(memory, queryList);
374 queryList = nextBackup;
375 }
376 return URI_SUCCESS;
377 }
378
379
380
URI_FUNC(DissectQueryMalloc)381 int URI_FUNC(DissectQueryMalloc)(URI_TYPE(QueryList) ** dest, int * itemCount,
382 const URI_CHAR * first, const URI_CHAR * afterLast) {
383 const UriBool plusToSpace = URI_TRUE;
384 const UriBreakConversion breakConversion = URI_BR_DONT_TOUCH;
385
386 return URI_FUNC(DissectQueryMallocEx)(dest, itemCount, first, afterLast,
387 plusToSpace, breakConversion);
388 }
389
390
391
URI_FUNC(DissectQueryMallocEx)392 int URI_FUNC(DissectQueryMallocEx)(URI_TYPE(QueryList) ** dest, int * itemCount,
393 const URI_CHAR * first, const URI_CHAR * afterLast,
394 UriBool plusToSpace, UriBreakConversion breakConversion) {
395 return URI_FUNC(DissectQueryMallocExMm)(dest, itemCount, first, afterLast,
396 plusToSpace, breakConversion, NULL);
397 }
398
399
400
URI_FUNC(DissectQueryMallocExMm)401 int URI_FUNC(DissectQueryMallocExMm)(URI_TYPE(QueryList) ** dest, int * itemCount,
402 const URI_CHAR * first, const URI_CHAR * afterLast,
403 UriBool plusToSpace, UriBreakConversion breakConversion,
404 UriMemoryManager * memory) {
405 const URI_CHAR * walk = first;
406 const URI_CHAR * keyFirst = first;
407 const URI_CHAR * keyAfter = NULL;
408 const URI_CHAR * valueFirst = NULL;
409 const URI_CHAR * valueAfter = NULL;
410 URI_TYPE(QueryList) ** prevNext = dest;
411 int nullCounter;
412 int * itemsAppended = (itemCount == NULL) ? &nullCounter : itemCount;
413
414 if ((dest == NULL) || (first == NULL) || (afterLast == NULL)) {
415 return URI_ERROR_NULL;
416 }
417
418 if (first > afterLast) {
419 return URI_ERROR_RANGE_INVALID;
420 }
421
422 URI_CHECK_MEMORY_MANAGER(memory); /* may return */
423
424 *dest = NULL;
425 *itemsAppended = 0;
426
427 /* Parse query string */
428 for (; walk < afterLast; walk++) {
429 switch (*walk) {
430 case _UT('&'):
431 if (valueFirst != NULL) {
432 valueAfter = walk;
433 } else {
434 keyAfter = walk;
435 }
436
437 if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended,
438 keyFirst, keyAfter, valueFirst, valueAfter,
439 plusToSpace, breakConversion, memory)
440 == URI_FALSE) {
441 /* Free list we built */
442 *itemsAppended = 0;
443 URI_FUNC(FreeQueryListMm)(*dest, memory);
444 return URI_ERROR_MALLOC;
445 }
446
447 /* Make future items children of the current */
448 if ((prevNext != NULL) && (*prevNext != NULL)) {
449 prevNext = &((*prevNext)->next);
450 }
451
452 if (walk + 1 < afterLast) {
453 keyFirst = walk + 1;
454 } else {
455 keyFirst = NULL;
456 }
457 keyAfter = NULL;
458 valueFirst = NULL;
459 valueAfter = NULL;
460 break;
461
462 case _UT('='):
463 /* NOTE: WE treat the first '=' as a separator, */
464 /* all following go into the value part */
465 if (keyAfter == NULL) {
466 keyAfter = walk;
467 if (walk + 1 <= afterLast) {
468 valueFirst = walk + 1;
469 valueAfter = walk + 1;
470 }
471 }
472 break;
473
474 default:
475 break;
476 }
477 }
478
479 if (valueFirst != NULL) {
480 /* Must be key/value pair */
481 valueAfter = walk;
482 } else {
483 /* Must be key only */
484 keyAfter = walk;
485 }
486
487 if (URI_FUNC(AppendQueryItem)(prevNext, itemsAppended, keyFirst, keyAfter,
488 valueFirst, valueAfter, plusToSpace, breakConversion, memory)
489 == URI_FALSE) {
490 /* Free list we built */
491 *itemsAppended = 0;
492 URI_FUNC(FreeQueryListMm)(*dest, memory);
493 return URI_ERROR_MALLOC;
494 }
495
496 return URI_SUCCESS;
497 }
498
499
500
501 #endif
502