2 * uriparser - RFC 3986 URI parsing library
4 * Copyright (C) 2007, Weijia Song <songweijia@gmail.com>
5 * Copyright (C) 2007, Sebastian Pipping <sebastian@pipping.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * * Redistributions of source code must retain the above
13 * copyright notice, this list of conditions and the following
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.
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
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.
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"
49 # ifdef URI_ENABLE_UNICODE
50 # define URI_PASS_UNICODE 1
51 # include "UriQuery.c"
52 # undef URI_PASS_UNICODE
56 # include "UriDefsAnsi.h"
58 # include "UriDefsUnicode.h"
66 # include "UriCommon.h"
67 # include "UriMemory.h"
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
);
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
);
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
;
94 return URI_FUNC(ComposeQueryCharsRequiredEx
)(queryList
, charsRequired
,
95 spaceToPlus
, normalizeBreaks
);
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
;
106 return URI_FUNC(ComposeQueryEngine
)(NULL
, queryList
, 0, NULL
,
107 charsRequired
, spaceToPlus
, normalizeBreaks
);
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
;
117 return URI_FUNC(ComposeQueryEx
)(dest
, queryList
, maxChars
, charsWritten
,
118 spaceToPlus
, normalizeBreaks
);
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
;
131 return URI_ERROR_OUTPUT_TOO_LARGE
;
134 return URI_FUNC(ComposeQueryEngine
)(dest
, queryList
, maxChars
,
135 charsWritten
, NULL
, spaceToPlus
, normalizeBreaks
);
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
;
145 return URI_FUNC(ComposeQueryMallocEx
)(dest
, queryList
,
146 spaceToPlus
, normalizeBreaks
);
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
);
160 int URI_FUNC(ComposeQueryMallocExMm
)(URI_CHAR
** dest
,
161 const URI_TYPE(QueryList
) * queryList
,
162 UriBool spaceToPlus
, UriBool normalizeBreaks
,
163 UriMemoryManager
* memory
) {
166 URI_CHAR
* queryString
;
169 return URI_ERROR_NULL
;
172 URI_CHECK_MEMORY_MANAGER(memory
); /* may return */
174 /* Calculate space */
175 res
= URI_FUNC(ComposeQueryCharsRequiredEx
)(queryList
, &charsRequired
,
176 spaceToPlus
, normalizeBreaks
);
177 if (res
!= URI_SUCCESS
) {
183 queryString
= memory
->malloc(memory
, charsRequired
* sizeof(URI_CHAR
));
184 if (queryString
== NULL
) {
185 return URI_ERROR_MALLOC
;
189 res
= URI_FUNC(ComposeQueryEx
)(queryString
, queryList
, charsRequired
,
190 NULL
, spaceToPlus
, normalizeBreaks
);
191 if (res
!= URI_SUCCESS
) {
192 memory
->free(memory
, queryString
);
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
;
210 /* Subtract terminator */
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
;
226 if ((keyLen
>= INT_MAX
/ worstCase
) || (valueLen
>= INT_MAX
/ worstCase
)) {
227 return URI_ERROR_OUTPUT_TOO_LARGE
;
229 keyRequiredChars
= worstCase
* keyLen
;
230 valueRequiredChars
= worstCase
* valueLen
;
233 (*charsRequired
) += ampersandLen
+ keyRequiredChars
+ ((value
== NULL
)
235 : 1 + valueRequiredChars
);
237 if (firstItem
== URI_TRUE
) {
239 firstItem
= URI_FALSE
;
242 if ((write
- dest
) + ampersandLen
+ keyRequiredChars
> maxChars
) {
243 return URI_ERROR_OUTPUT_TOO_LARGE
;
247 if (firstItem
== URI_TRUE
) {
249 firstItem
= URI_FALSE
;
254 write
= URI_FUNC(EscapeEx
)(key
, key
+ keyLen
,
255 write
, spaceToPlus
, normalizeBreaks
);
258 if ((write
- dest
) + 1 + valueRequiredChars
> maxChars
) {
259 return URI_ERROR_OUTPUT_TOO_LARGE
;
265 write
= URI_FUNC(EscapeEx
)(value
, value
+ valueLen
,
266 write
, spaceToPlus
, normalizeBreaks
);
270 queryList
= queryList
->next
;
274 write
[0] = _UT('\0');
275 if (charsWritten
!= NULL
) {
276 *charsWritten
= (int)(write
- dest
) + 1; /* .. for terminator */
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
);
295 if ((prevNext
== NULL
) || (itemCount
== NULL
)
296 || (keyFirst
== NULL
) || (keyAfter
== NULL
)
297 || (keyFirst
> keyAfter
) || (valueFirst
> valueAfter
)
298 || ((keyFirst
== keyAfter
)
299 && (valueFirst
== NULL
) && (valueAfter
== NULL
))) {
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 */
308 (*prevNext
)->next
= NULL
;
312 key
= memory
->malloc(memory
, (keyLen
+ 1) * sizeof(URI_CHAR
));
314 memory
->free(memory
, *prevNext
);
316 return URI_FALSE
; /* Raises malloc error */
319 key
[keyLen
] = _UT('\0');
322 memcpy(key
, keyFirst
, keyLen
* sizeof(URI_CHAR
));
325 URI_FUNC(UnescapeInPlaceEx
)(key
, plusToSpace
, breakConversion
);
327 (*prevNext
)->key
= key
;
331 if (valueFirst
!= NULL
) {
332 value
= memory
->malloc(memory
, (valueLen
+ 1) * sizeof(URI_CHAR
));
334 memory
->free(memory
, key
);
335 memory
->free(memory
, *prevNext
);
337 return URI_FALSE
; /* Raises malloc error */
340 value
[valueLen
] = _UT('\0');
343 memcpy(value
, valueFirst
, valueLen
* sizeof(URI_CHAR
));
346 URI_FUNC(UnescapeInPlaceEx
)(value
, plusToSpace
, breakConversion
);
348 (*prevNext
)->value
= value
;
352 (*prevNext
)->value
= value
;
360 void URI_FUNC(FreeQueryList
)(URI_TYPE(QueryList
) * queryList
) {
361 URI_FUNC(FreeQueryListMm
)(queryList
, NULL
);
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
;
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
;
386 return URI_FUNC(DissectQueryMallocEx
)(dest
, itemCount
, first
, afterLast
,
387 plusToSpace
, breakConversion
);
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
);
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
;
412 int * itemsAppended
= (itemCount
== NULL
) ? &nullCounter
: itemCount
;
414 if ((dest
== NULL
) || (first
== NULL
) || (afterLast
== NULL
)) {
415 return URI_ERROR_NULL
;
418 if (first
> afterLast
) {
419 return URI_ERROR_RANGE_INVALID
;
422 URI_CHECK_MEMORY_MANAGER(memory
); /* may return */
427 /* Parse query string */
428 for (; walk
< afterLast
; walk
++) {
431 if (valueFirst
!= NULL
) {
437 if (URI_FUNC(AppendQueryItem
)(prevNext
, itemsAppended
,
438 keyFirst
, keyAfter
, valueFirst
, valueAfter
,
439 plusToSpace
, breakConversion
, memory
)
441 /* Free list we built */
443 URI_FUNC(FreeQueryListMm
)(*dest
, memory
);
444 return URI_ERROR_MALLOC
;
447 /* Make future items children of the current */
448 if ((prevNext
!= NULL
) && (*prevNext
!= NULL
)) {
449 prevNext
= &((*prevNext
)->next
);
452 if (walk
+ 1 < afterLast
) {
463 /* NOTE: WE treat the first '=' as a separator, */
464 /* all following go into the value part */
465 if (keyAfter
== NULL
) {
467 if (walk
+ 1 <= afterLast
) {
468 valueFirst
= walk
+ 1;
469 valueAfter
= walk
+ 1;
479 if (valueFirst
!= NULL
) {
480 /* Must be key/value pair */
483 /* Must be key only */
487 if (URI_FUNC(AppendQueryItem
)(prevNext
, itemsAppended
, keyFirst
, keyAfter
,
488 valueFirst
, valueAfter
, plusToSpace
, breakConversion
, memory
)
490 /* Free list we built */
492 URI_FUNC(FreeQueryListMm
)(*dest
, memory
);
493 return URI_ERROR_MALLOC
;