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