Coverage Report

Created: 2026-07-25 06:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/uri/uriparser/src/UriNormalize.c
Line
Count
Source
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
 *     1. Redistributions  of  source  code   must  retain  the  above
13
 *        copyright notice, this list  of conditions and the following
14
 *        disclaimer.
15
 *
16
 *     2. 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
 *     3. Neither the  name of the  copyright holder nor the  names of
22
 *        its 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
30
 * THE  COPYRIGHT HOLDER  OR CONTRIBUTORS  BE LIABLE  FOR ANY  DIRECT,
31
 * INDIRECT, 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
/**
41
 * @file UriNormalize.c
42
 * Holds the RFC 3986 %URI normalization implementation.
43
 * NOTE: This source file includes itself twice.
44
 */
45
46
/* What encodings are enabled? */
47
#include <uriparser/UriDefsConfig.h>
48
#if (!defined(URI_PASS_ANSI) && !defined(URI_PASS_UNICODE))
49
/* Include SELF twice */
50
#  ifdef URI_ENABLE_ANSI
51
#    define URI_PASS_ANSI 1
52
#    include "UriNormalize.c"
53
#    undef URI_PASS_ANSI
54
#  endif
55
#  ifdef URI_ENABLE_UNICODE
56
#    define URI_PASS_UNICODE 1
57
#    include "UriNormalize.c"
58
#    undef URI_PASS_UNICODE
59
#  endif
60
#else
61
#  ifdef URI_PASS_ANSI
62
#    include <uriparser/UriDefsAnsi.h>
63
#  else
64
#    include <uriparser/UriDefsUnicode.h>
65
#    include <wchar.h>
66
#  endif
67
68
#  ifndef URI_DOXYGEN
69
#    include <uriparser/Uri.h>
70
#    include "UriNormalizeBase.h"
71
#    include "UriCommon.h"
72
#    include "UriMemory.h"
73
#  endif
74
75
#  include <assert.h>
76
#  include <stdint.h>  // SIZE_MAX
77
78
static int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri, unsigned int inMask,
79
                                           unsigned int * outMask,
80
                                           UriMemoryManager * memory);
81
82
static UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask, unsigned int maskTest,
83
                                        URI_TYPE(TextRange) * range,
84
                                        UriMemoryManager * memory);
85
static UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri, unsigned int * revertMask,
86
                                         UriMemoryManager * memory);
87
88
static void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
89
                                                const URI_CHAR ** afterLast);
90
static UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
91
                                                  const URI_CHAR ** afterLast,
92
                                                  UriMemoryManager * memory);
93
static void URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst,
94
                                               const URI_CHAR * inAfterLast,
95
                                               const URI_CHAR * outFirst,
96
                                               const URI_CHAR ** outAfterLast);
97
98
static UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first,
99
                                                  const URI_CHAR * afterLast);
100
static UriBool URI_FUNC(ContainsUglyPercentEncoding)(const URI_CHAR * first,
101
                                                     const URI_CHAR * afterLast);
102
103
static void URI_FUNC(LowercaseInplace)(const URI_CHAR * first,
104
                                       const URI_CHAR * afterLast);
105
static void URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first,
106
                                                            const URI_CHAR * afterLast);
107
static UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
108
                                         const URI_CHAR ** afterLast,
109
                                         UriMemoryManager * memory);
110
111
void URI_FUNC(PreventLeakage)(URI_TYPE(Uri) * uri, unsigned int revertMask,
112
0
                              UriMemoryManager * memory) {
113
0
    if (revertMask & URI_NORMALIZE_SCHEME) {
114
        /* NOTE: A scheme cannot be the empty string
115
         *       so no need to compare .first with .afterLast, here. */
116
0
        memory->free(memory, (URI_CHAR *)uri->scheme.first);
117
0
        uri->scheme.first = NULL;
118
0
        uri->scheme.afterLast = NULL;
119
0
    }
120
121
0
    if (revertMask & URI_NORMALIZE_USER_INFO) {
122
0
        if (uri->userInfo.first != uri->userInfo.afterLast) {
123
0
            memory->free(memory, (URI_CHAR *)uri->userInfo.first);
124
0
        }
125
0
        uri->userInfo.first = NULL;
126
0
        uri->userInfo.afterLast = NULL;
127
0
    }
128
129
0
    if (revertMask & URI_NORMALIZE_HOST) {
130
0
        if (uri->hostData.ipFuture.first != NULL) {
131
            /* IPvFuture */
132
            /* NOTE: An IPvFuture address cannot be the empty string
133
             *       so no need to compare .first with .afterLast, here. */
134
0
            memory->free(memory, (URI_CHAR *)uri->hostData.ipFuture.first);
135
0
            uri->hostData.ipFuture.first = NULL;
136
0
            uri->hostData.ipFuture.afterLast = NULL;
137
0
            uri->hostText.first = NULL;
138
0
            uri->hostText.afterLast = NULL;
139
0
        } else if (uri->hostText.first != NULL) {
140
            /* Regname */
141
0
            if (uri->hostText.first != uri->hostText.afterLast) {
142
0
                memory->free(memory, (URI_CHAR *)uri->hostText.first);
143
0
            }
144
0
            uri->hostText.first = NULL;
145
0
            uri->hostText.afterLast = NULL;
146
0
        }
147
0
    }
148
149
    /* NOTE: Port cannot happen! */
150
151
0
    if (revertMask & URI_NORMALIZE_PATH) {
152
0
        URI_TYPE(PathSegment) * walker = uri->pathHead;
153
0
        while (walker != NULL) {
154
0
            URI_TYPE(PathSegment) * const next = walker->next;
155
0
            if (walker->text.afterLast > walker->text.first) {
156
0
                memory->free(memory, (URI_CHAR *)walker->text.first);
157
0
            }
158
0
            memory->free(memory, walker);
159
0
            walker = next;
160
0
        }
161
0
        uri->pathHead = NULL;
162
0
        uri->pathTail = NULL;
163
0
    }
164
165
0
    if (revertMask & URI_NORMALIZE_QUERY) {
166
0
        if (uri->query.first != uri->query.afterLast) {
167
0
            memory->free(memory, (URI_CHAR *)uri->query.first);
168
0
        }
169
0
        uri->query.first = NULL;
170
0
        uri->query.afterLast = NULL;
171
0
    }
172
173
0
    if (revertMask & URI_NORMALIZE_FRAGMENT) {
174
0
        if (uri->fragment.first != uri->fragment.afterLast) {
175
0
            memory->free(memory, (URI_CHAR *)uri->fragment.first);
176
0
        }
177
0
        uri->fragment.first = NULL;
178
0
        uri->fragment.afterLast = NULL;
179
0
    }
180
0
}
Unexecuted instantiation: uriPreventLeakageA
Unexecuted instantiation: uriPreventLeakageW
181
182
static URI_INLINE UriBool URI_FUNC(ContainsUppercaseLetters)(const URI_CHAR * first,
183
0
                                                             const URI_CHAR * afterLast) {
184
0
    if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
185
0
        const URI_CHAR * i = first;
186
0
        for (; i < afterLast; i++) {
187
            /* 6.2.2.1 Case Normalization: uppercase letters in scheme or host */
188
0
            if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
189
0
                return URI_TRUE;
190
0
            }
191
0
        }
192
0
    }
193
0
    return URI_FALSE;
194
0
}
Unexecuted instantiation: UriNormalize.c:uriContainsUppercaseLettersA
Unexecuted instantiation: UriNormalize.c:uriContainsUppercaseLettersW
195
196
static URI_INLINE UriBool URI_FUNC(ContainsUglyPercentEncoding)(
197
0
    const URI_CHAR * first, const URI_CHAR * afterLast) {
198
0
    if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
199
0
        const URI_CHAR * i = first;
200
0
        for (; i + 2 < afterLast; i++) {
201
0
            if (i[0] == _UT('%')) {
202
                /* 6.2.2.1 Case Normalization: *
203
                 * lowercase percent-encodings */
204
0
                if (((i[1] >= _UT('a')) && (i[1] <= _UT('f')))
205
0
                    || ((i[2] >= _UT('a')) && (i[2] <= _UT('f')))) {
206
0
                    return URI_TRUE;
207
0
                } else {
208
                    /* 6.2.2.2 Percent-Encoding Normalization: *
209
                     * percent-encoded unreserved characters   */
210
0
                    const unsigned char left = URI_FUNC(HexdigToInt)(i[1]);
211
0
                    const unsigned char right = URI_FUNC(HexdigToInt)(i[2]);
212
0
                    const int code = 16 * left + right;
213
0
                    if (uriIsUnreserved(code)) {
214
0
                        return URI_TRUE;
215
0
                    }
216
0
                }
217
0
            }
218
0
        }
219
0
    }
220
0
    return URI_FALSE;
221
0
}
Unexecuted instantiation: UriNormalize.c:uriContainsUglyPercentEncodingA
Unexecuted instantiation: UriNormalize.c:uriContainsUglyPercentEncodingW
222
223
static URI_INLINE void URI_FUNC(LowercaseInplace)(const URI_CHAR * first,
224
0
                                                  const URI_CHAR * afterLast) {
225
0
    if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
226
0
        URI_CHAR * i = (URI_CHAR *)first;
227
0
        const int lowerUpperDiff = (_UT('a') - _UT('A'));
228
0
        for (; i < afterLast; i++) {
229
0
            if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
230
0
                *i = (URI_CHAR)(*i + lowerUpperDiff);
231
0
            }
232
0
        }
233
0
    }
234
0
}
Unexecuted instantiation: UriNormalize.c:uriLowercaseInplaceA
Unexecuted instantiation: UriNormalize.c:uriLowercaseInplaceW
235
236
static URI_INLINE void
237
URI_FUNC(LowercaseInplaceExceptPercentEncoding)(const URI_CHAR * first,
238
0
                                                const URI_CHAR * afterLast) {
239
0
    if ((first != NULL) && (afterLast != NULL) && (afterLast > first)) {
240
0
        URI_CHAR * i = (URI_CHAR *)first;
241
0
        const int lowerUpperDiff = (_UT('a') - _UT('A'));
242
0
        for (; i < afterLast; i++) {
243
0
            if ((*i >= _UT('A')) && (*i <= _UT('Z'))) {
244
0
                *i = (URI_CHAR)(*i + lowerUpperDiff);
245
0
            } else if (*i == _UT('%')) {
246
0
                if (i + 3 >= afterLast) {
247
0
                    return;
248
0
                }
249
0
                i += 2;
250
0
            }
251
0
        }
252
0
    }
253
0
}
Unexecuted instantiation: UriNormalize.c:uriLowercaseInplaceExceptPercentEncodingA
Unexecuted instantiation: UriNormalize.c:uriLowercaseInplaceExceptPercentEncodingW
254
255
static URI_INLINE UriBool URI_FUNC(LowercaseMalloc)(const URI_CHAR ** first,
256
                                                    const URI_CHAR ** afterLast,
257
0
                                                    UriMemoryManager * memory) {
258
0
    const int lowerUpperDiff = (_UT('a') - _UT('A'));
259
0
    URI_CHAR * buffer;
260
0
    size_t i = 0;
261
262
0
    if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
263
0
        || (*afterLast == NULL)) {
264
0
        return URI_FALSE;
265
0
    }
266
267
0
    const size_t lenInChars = *afterLast - *first;
268
0
    if (lenInChars == 0) {
269
0
        return URI_TRUE;
270
0
    }
271
272
    // Detect and avoid integer overflow
273
0
    if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) {
274
0
        return URI_FALSE;
275
0
    }
276
277
0
    buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR));
278
0
    if (buffer == NULL) {
279
0
        return URI_FALSE;
280
0
    }
281
282
0
    for (; i < lenInChars; i++) {
283
0
        if (((*first)[i] >= _UT('A')) && ((*first)[i] <= _UT('Z'))) {
284
0
            buffer[i] = (URI_CHAR)((*first)[i] + lowerUpperDiff);
285
0
        } else {
286
0
            buffer[i] = (*first)[i];
287
0
        }
288
0
    }
289
290
0
    *first = buffer;
291
0
    *afterLast = buffer + lenInChars;
292
0
    return URI_TRUE;
293
0
}
Unexecuted instantiation: UriNormalize.c:uriLowercaseMallocA
Unexecuted instantiation: UriNormalize.c:uriLowercaseMallocW
294
295
/* NOTE: Implementation must stay inplace-compatible */
296
static URI_INLINE void
297
URI_FUNC(FixPercentEncodingEngine)(const URI_CHAR * inFirst, const URI_CHAR * inAfterLast,
298
                                   const URI_CHAR * outFirst,
299
0
                                   const URI_CHAR ** outAfterLast) {
300
0
    URI_CHAR * write = (URI_CHAR *)outFirst;
301
0
    const size_t lenInChars = inAfterLast - inFirst;
302
0
    size_t i = 0;
303
304
    /* All but last two */
305
0
    for (; i + 2 < lenInChars; i++) {
306
0
        if (inFirst[i] != _UT('%')) {
307
0
            write[0] = inFirst[i];
308
0
            write++;
309
0
        } else {
310
            /* 6.2.2.2 Percent-Encoding Normalization: *
311
             * percent-encoded unreserved characters   */
312
0
            const URI_CHAR one = inFirst[i + 1];
313
0
            const URI_CHAR two = inFirst[i + 2];
314
0
            const unsigned char left = URI_FUNC(HexdigToInt)(one);
315
0
            const unsigned char right = URI_FUNC(HexdigToInt)(two);
316
0
            const int code = 16 * left + right;
317
0
            if (uriIsUnreserved(code)) {
318
0
                write[0] = (URI_CHAR)(code);
319
0
                write++;
320
0
            } else {
321
                /* 6.2.2.1 Case Normalization: *
322
                 * uppercase percent-encodings */
323
0
                write[0] = _UT('%');
324
0
                write[1] = URI_FUNC(HexToLetterEx)(left, URI_TRUE);
325
0
                write[2] = URI_FUNC(HexToLetterEx)(right, URI_TRUE);
326
0
                write += 3;
327
0
            }
328
329
0
            i += 2; /* For the two chars of the percent group we just ate */
330
0
        }
331
0
    }
332
333
    /* Last two */
334
0
    for (; i < lenInChars; i++) {
335
0
        write[0] = inFirst[i];
336
0
        write++;
337
0
    }
338
339
0
    *outAfterLast = write;
340
0
}
Unexecuted instantiation: UriNormalize.c:uriFixPercentEncodingEngineA
Unexecuted instantiation: UriNormalize.c:uriFixPercentEncodingEngineW
341
342
static URI_INLINE void URI_FUNC(FixPercentEncodingInplace)(const URI_CHAR * first,
343
0
                                                           const URI_CHAR ** afterLast) {
344
    /* Death checks */
345
0
    if ((first == NULL) || (afterLast == NULL) || (*afterLast == NULL)) {
346
0
        return;
347
0
    }
348
349
    /* Fix inplace */
350
0
    URI_FUNC(FixPercentEncodingEngine)(first, *afterLast, first, afterLast);
351
0
}
Unexecuted instantiation: UriNormalize.c:uriFixPercentEncodingInplaceA
Unexecuted instantiation: UriNormalize.c:uriFixPercentEncodingInplaceW
352
353
static URI_INLINE UriBool URI_FUNC(FixPercentEncodingMalloc)(const URI_CHAR ** first,
354
                                                             const URI_CHAR ** afterLast,
355
0
                                                             UriMemoryManager * memory) {
356
0
    URI_CHAR * buffer;
357
358
    /* Death checks */
359
0
    if ((first == NULL) || (afterLast == NULL) || (*first == NULL)
360
0
        || (*afterLast == NULL)) {
361
0
        return URI_FALSE;
362
0
    }
363
364
    /* Old text length */
365
0
    const size_t lenInChars = *afterLast - *first;
366
0
    if (lenInChars == 0) {
367
0
        return URI_TRUE;
368
0
    }
369
370
    // Detect and avoid integer overflow
371
0
    if (lenInChars > SIZE_MAX / sizeof(URI_CHAR)) {
372
0
        return URI_FALSE;
373
0
    }
374
375
    /* New buffer */
376
0
    buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR));
377
0
    if (buffer == NULL) {
378
0
        return URI_FALSE;
379
0
    }
380
381
    /* Fix on copy */
382
0
    URI_FUNC(FixPercentEncodingEngine)(*first, *afterLast, buffer, afterLast);
383
0
    *first = buffer;
384
0
    return URI_TRUE;
385
0
}
Unexecuted instantiation: UriNormalize.c:uriFixPercentEncodingMallocA
Unexecuted instantiation: UriNormalize.c:uriFixPercentEncodingMallocW
386
387
static URI_INLINE UriBool URI_FUNC(MakeRangeOwner)(unsigned int * revertMask,
388
                                                   unsigned int maskTest,
389
                                                   URI_TYPE(TextRange) * range,
390
0
                                                   UriMemoryManager * memory) {
391
0
    if (((*revertMask & maskTest) == 0) && (range->first != NULL)
392
0
        && (range->afterLast != NULL) && (range->afterLast > range->first)) {
393
0
        if (URI_FUNC(CopyRange)(range, range, memory) == URI_FALSE) {
394
0
            return URI_FALSE;
395
0
        }
396
0
        *revertMask |= maskTest;
397
0
    }
398
0
    return URI_TRUE;
399
0
}
Unexecuted instantiation: UriNormalize.c:uriMakeRangeOwnerA
Unexecuted instantiation: UriNormalize.c:uriMakeRangeOwnerW
400
401
static URI_INLINE UriBool URI_FUNC(MakeOwnerEngine)(URI_TYPE(Uri) * uri,
402
                                                    unsigned int * revertMask,
403
0
                                                    UriMemoryManager * memory) {
404
0
    URI_TYPE(PathSegment) * walker = uri->pathHead;
405
0
    if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_SCHEME, &(uri->scheme),
406
0
                                  memory)
407
0
        || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_USER_INFO,
408
0
                                     &(uri->userInfo), memory)
409
0
        || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_QUERY, &(uri->query),
410
0
                                     memory)
411
0
        || !URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_FRAGMENT, &(uri->fragment),
412
0
                                     memory)) {
413
0
        return URI_FALSE; /* Raises malloc error */
414
0
    }
415
416
    /* Host */
417
0
    if ((*revertMask & URI_NORMALIZE_HOST) == 0) {
418
0
        if (uri->hostData.ipFuture.first != NULL) {
419
            /* IPvFuture */
420
0
            if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST,
421
0
                                          &(uri->hostData.ipFuture), memory)) {
422
0
                return URI_FALSE; /* Raises malloc error */
423
0
            }
424
0
            uri->hostText.first = uri->hostData.ipFuture.first;
425
0
            uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
426
0
        } else if (uri->hostText.first != NULL) {
427
            /* Regname */
428
0
            if (!URI_FUNC(MakeRangeOwner)(revertMask, URI_NORMALIZE_HOST,
429
0
                                          &(uri->hostText), memory)) {
430
0
                return URI_FALSE; /* Raises malloc error */
431
0
            }
432
0
        }
433
0
    }
434
435
    /* Path */
436
0
    if ((*revertMask & URI_NORMALIZE_PATH) == 0) {
437
0
        while (walker != NULL) {
438
0
            if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(walker->text), memory)) {
439
                /* Free allocations done so far and kill path */
440
441
                /* Kill path to one before walker (if any) */
442
0
                URI_TYPE(PathSegment) * ranger = uri->pathHead;
443
0
                while (ranger != walker) {
444
0
                    URI_TYPE(PathSegment) * const next = ranger->next;
445
0
                    if ((ranger->text.first != NULL) && (ranger->text.afterLast != NULL)
446
0
                        && (ranger->text.afterLast > ranger->text.first)) {
447
0
                        memory->free(memory, (URI_CHAR *)ranger->text.first);
448
0
                    }
449
0
                    memory->free(memory, ranger);
450
0
                    ranger = next;
451
0
                }
452
453
                /* Kill path from walker */
454
0
                while (walker != NULL) {
455
0
                    URI_TYPE(PathSegment) * const next = walker->next;
456
0
                    memory->free(memory, walker);
457
0
                    walker = next;
458
0
                }
459
460
0
                uri->pathHead = NULL;
461
0
                uri->pathTail = NULL;
462
0
                return URI_FALSE; /* Raises malloc error */
463
0
            }
464
0
            walker = walker->next;
465
0
        }
466
0
        *revertMask |= URI_NORMALIZE_PATH;
467
0
    }
468
469
    /* Port text, must come last so we don't have to undo that one if it fails. *
470
     * Otherwise we would need and extra enum flag for it although the port      *
471
     * cannot go unnormalized...                                                */
472
0
    if (!URI_FUNC(MakeRangeOwner)(revertMask, 0, &(uri->portText), memory)) {
473
0
        return URI_FALSE; /* Raises malloc error */
474
0
    }
475
476
0
    return URI_TRUE;
477
0
}
Unexecuted instantiation: UriNormalize.c:uriMakeOwnerEngineA
Unexecuted instantiation: UriNormalize.c:uriMakeOwnerEngineW
478
479
0
unsigned int URI_FUNC(NormalizeSyntaxMaskRequired)(const URI_TYPE(Uri) * uri) {
480
0
    unsigned int outMask = URI_NORMALIZED; /* for NULL uri */
481
0
    URI_FUNC(NormalizeSyntaxMaskRequiredEx)(uri, &outMask);
482
0
    return outMask;
483
0
}
Unexecuted instantiation: uriNormalizeSyntaxMaskRequiredA
Unexecuted instantiation: uriNormalizeSyntaxMaskRequiredW
484
485
int URI_FUNC(NormalizeSyntaxMaskRequiredEx)(const URI_TYPE(Uri) * uri,
486
0
                                            unsigned int * outMask) {
487
0
    UriMemoryManager * const memory = NULL; /* no use of memory manager */
488
489
0
#  if defined(__GNUC__) \
490
0
      && ((__GNUC__ > 4) \
491
0
          || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2)))
492
    /* Slower code that fixes a warning, not sure if this is a smart idea */
493
0
    URI_TYPE(Uri) writeableClone;
494
0
#  endif
495
496
0
    if ((uri == NULL) || (outMask == NULL)) {
497
0
        return URI_ERROR_NULL;
498
0
    }
499
500
0
#  if defined(__GNUC__) \
501
0
      && ((__GNUC__ > 4) \
502
0
          || ((__GNUC__ == 4) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 2)))
503
    /* Slower code that fixes a warning, not sure if this is a smart idea */
504
0
    memcpy(&writeableClone, uri, 1 * sizeof(URI_TYPE(Uri)));
505
0
    URI_FUNC(NormalizeSyntaxEngine)(&writeableClone, 0, outMask, memory);
506
#  else
507
    URI_FUNC(NormalizeSyntaxEngine)((URI_TYPE(Uri) *)uri, 0, outMask, memory);
508
#  endif
509
0
    return URI_SUCCESS;
510
0
}
Unexecuted instantiation: uriNormalizeSyntaxMaskRequiredExA
Unexecuted instantiation: uriNormalizeSyntaxMaskRequiredExW
511
512
0
int URI_FUNC(NormalizeSyntaxEx)(URI_TYPE(Uri) * uri, unsigned int mask) {
513
0
    return URI_FUNC(NormalizeSyntaxExMm)(uri, mask, NULL);
514
0
}
Unexecuted instantiation: uriNormalizeSyntaxExA
Unexecuted instantiation: uriNormalizeSyntaxExW
515
516
int URI_FUNC(NormalizeSyntaxExMm)(URI_TYPE(Uri) * uri, unsigned int mask,
517
0
                                  UriMemoryManager * memory) {
518
0
    URI_CHECK_MEMORY_MANAGER(memory); /* may return */
519
0
    return URI_FUNC(NormalizeSyntaxEngine)(uri, mask, NULL, memory);
520
0
}
Unexecuted instantiation: uriNormalizeSyntaxExMmA
Unexecuted instantiation: uriNormalizeSyntaxExMmW
521
522
0
int URI_FUNC(NormalizeSyntax)(URI_TYPE(Uri) * uri) {
523
0
    return URI_FUNC(NormalizeSyntaxEx)(uri, (unsigned int)-1);
524
0
}
Unexecuted instantiation: uriNormalizeSyntaxA
Unexecuted instantiation: uriNormalizeSyntaxW
525
526
static const URI_CHAR * URI_FUNC(PastLeadingZeros)(const URI_CHAR * first,
527
0
                                                   const URI_CHAR * afterLast) {
528
0
    assert(first != NULL);
529
0
    assert(afterLast != NULL);
530
0
    assert(first != afterLast);
531
532
    /* Find the first non-zero character */
533
0
    const URI_CHAR * remainderFirst = first;
534
0
    while ((remainderFirst < afterLast) && (remainderFirst[0] == _UT('0'))) {
535
0
        remainderFirst++;
536
0
    }
537
538
    /* Is the string /all/ zeros? */
539
0
    if (remainderFirst == afterLast) {
540
        /* Yes, and length is >=1 because we ruled out the empty string earlier;
541
         * pull back onto rightmost zero */
542
0
        assert(remainderFirst > first);
543
0
        remainderFirst--;
544
0
        assert(remainderFirst[0] == _UT('0'));
545
0
    }
546
547
0
    return remainderFirst;
548
0
}
Unexecuted instantiation: UriNormalize.c:uriPastLeadingZerosA
Unexecuted instantiation: UriNormalize.c:uriPastLeadingZerosW
549
550
static void URI_FUNC(DropLeadingZerosInplace)(URI_CHAR * first,
551
0
                                              const URI_CHAR ** afterLast) {
552
0
    assert(first != NULL);
553
0
    assert(afterLast != NULL);
554
0
    assert(*afterLast != NULL);
555
556
0
    if (first == *afterLast) {
557
0
        return;
558
0
    }
559
560
0
    const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(first, *afterLast);
561
562
0
    if (remainderFirst > first) {
563
0
        const size_t remainderLen = *afterLast - remainderFirst;
564
0
        memmove(first, remainderFirst, remainderLen * sizeof(URI_CHAR));
565
0
        first[remainderLen] = _UT('\0');
566
0
        *afterLast = first + remainderLen;
567
0
    }
568
0
}
Unexecuted instantiation: UriNormalize.c:uriDropLeadingZerosInplaceA
Unexecuted instantiation: UriNormalize.c:uriDropLeadingZerosInplaceW
569
570
static void URI_FUNC(AdvancePastLeadingZeros)(const URI_CHAR ** first,
571
0
                                              const URI_CHAR * afterLast) {
572
0
    assert(first != NULL);
573
0
    assert(*first != NULL);
574
0
    assert(afterLast != NULL);
575
576
0
    if (*first == afterLast) {
577
0
        return;
578
0
    }
579
580
0
    const URI_CHAR * const remainderFirst = URI_FUNC(PastLeadingZeros)(*first, afterLast);
581
582
    /* Cut off leading zeros */
583
0
    *first = remainderFirst;
584
0
}
Unexecuted instantiation: UriNormalize.c:uriAdvancePastLeadingZerosA
Unexecuted instantiation: UriNormalize.c:uriAdvancePastLeadingZerosW
585
586
static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
587
                                                      unsigned int inMask,
588
                                                      unsigned int * outMask,
589
0
                                                      UriMemoryManager * memory) {
590
0
    unsigned int revertMask = URI_NORMALIZED;
591
592
    /* Not just doing inspection? -> memory manager required! */
593
0
    if (outMask == NULL) {
594
0
        assert(memory != NULL);
595
0
    }
596
597
0
    if (uri == NULL) {
598
0
        if (outMask != NULL) {
599
0
            *outMask = URI_NORMALIZED;
600
0
            return URI_SUCCESS;
601
0
        } else {
602
0
            return URI_ERROR_NULL;
603
0
        }
604
0
    }
605
606
0
    if (outMask != NULL) {
607
        /* Reset mask */
608
0
        *outMask = URI_NORMALIZED;
609
0
    } else if (inMask == URI_NORMALIZED) {
610
        /* Nothing to do */
611
0
        return URI_SUCCESS;
612
0
    }
613
614
    /* Scheme, host */
615
0
    if (outMask != NULL) {
616
0
        const UriBool normalizeScheme =
617
0
            URI_FUNC(ContainsUppercaseLetters)(uri->scheme.first, uri->scheme.afterLast);
618
0
        const UriBool normalizeHostCase = URI_FUNC(ContainsUppercaseLetters)(
619
0
            uri->hostText.first, uri->hostText.afterLast);
620
0
        if (normalizeScheme) {
621
0
            *outMask |= URI_NORMALIZE_SCHEME;
622
0
        }
623
624
0
        if (normalizeHostCase) {
625
0
            *outMask |= URI_NORMALIZE_HOST;
626
0
        } else {
627
0
            const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)(
628
0
                uri->hostText.first, uri->hostText.afterLast);
629
0
            if (normalizeHostPrecent) {
630
0
                *outMask |= URI_NORMALIZE_HOST;
631
0
            }
632
0
        }
633
0
    } else {
634
        /* Scheme */
635
0
        if ((inMask & URI_NORMALIZE_SCHEME) && (uri->scheme.first != NULL)) {
636
0
            if (uri->owner) {
637
0
                URI_FUNC(LowercaseInplace)(uri->scheme.first, uri->scheme.afterLast);
638
0
            } else {
639
0
                if (!URI_FUNC(LowercaseMalloc)(&(uri->scheme.first),
640
0
                                               &(uri->scheme.afterLast), memory)) {
641
0
                    URI_FUNC(PreventLeakage)(uri, revertMask, memory);
642
0
                    return URI_ERROR_MALLOC;
643
0
                }
644
0
                revertMask |= URI_NORMALIZE_SCHEME;
645
0
            }
646
0
        }
647
648
        /* Host */
649
0
        if (inMask & URI_NORMALIZE_HOST) {
650
0
            if (uri->hostData.ipFuture.first != NULL) {
651
                /* IPvFuture */
652
0
                if (uri->owner) {
653
0
                    URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first,
654
0
                                               uri->hostData.ipFuture.afterLast);
655
0
                } else {
656
0
                    if (!URI_FUNC(LowercaseMalloc)(&(uri->hostData.ipFuture.first),
657
0
                                                   &(uri->hostData.ipFuture.afterLast),
658
0
                                                   memory)) {
659
0
                        URI_FUNC(PreventLeakage)(uri, revertMask, memory);
660
0
                        return URI_ERROR_MALLOC;
661
0
                    }
662
0
                    revertMask |= URI_NORMALIZE_HOST;
663
0
                }
664
0
                uri->hostText.first = uri->hostData.ipFuture.first;
665
0
                uri->hostText.afterLast = uri->hostData.ipFuture.afterLast;
666
0
            } else if ((uri->hostText.first != NULL) && (uri->hostData.ip4 == NULL)) {
667
                /* Regname or IPv6 */
668
0
                if (uri->owner) {
669
0
                    URI_FUNC(FixPercentEncodingInplace)(uri->hostText.first,
670
0
                                                        &(uri->hostText.afterLast));
671
0
                } else {
672
0
                    if (!URI_FUNC(FixPercentEncodingMalloc)(
673
0
                            &(uri->hostText.first), &(uri->hostText.afterLast), memory)) {
674
0
                        URI_FUNC(PreventLeakage)(uri, revertMask, memory);
675
0
                        return URI_ERROR_MALLOC;
676
0
                    }
677
0
                    revertMask |= URI_NORMALIZE_HOST;
678
0
                }
679
680
0
                URI_FUNC(LowercaseInplaceExceptPercentEncoding)(uri->hostText.first,
681
0
                                                                uri->hostText.afterLast);
682
0
            }
683
0
        }
684
0
    }
685
686
    /* Port */
687
0
    if (outMask != NULL) {
688
        /* Is there a port even? */
689
0
        if (uri->portText.first != NULL) {
690
            /* Determine whether the port is already normalized, i.e. either "", "0" or no
691
             * leading zeros */
692
0
            const size_t portLen = uri->portText.afterLast - uri->portText.first;
693
0
            if ((portLen > 1) && (uri->portText.first[0] == _UT('0'))) {
694
0
                *outMask |= URI_NORMALIZE_PORT;
695
0
            }
696
0
        }
697
0
    } else {
698
        /* Normalize the port, i.e. drop leading zeros (except for string "0") */
699
0
        if ((inMask & URI_NORMALIZE_PORT) && (uri->portText.first != NULL)) {
700
0
            if (uri->owner) {
701
0
                URI_FUNC(DropLeadingZerosInplace)((URI_CHAR *)uri->portText.first,
702
0
                                                  &(uri->portText.afterLast));
703
0
            } else {
704
0
                URI_FUNC(AdvancePastLeadingZeros)(&(uri->portText.first),
705
0
                                                  uri->portText.afterLast);
706
0
            }
707
0
        }
708
0
    }
709
710
    /* User info */
711
0
    if (outMask != NULL) {
712
0
        const UriBool normalizeUserInfo = URI_FUNC(ContainsUglyPercentEncoding)(
713
0
            uri->userInfo.first, uri->userInfo.afterLast);
714
0
        if (normalizeUserInfo) {
715
0
            *outMask |= URI_NORMALIZE_USER_INFO;
716
0
        }
717
0
    } else {
718
0
        if ((inMask & URI_NORMALIZE_USER_INFO) && (uri->userInfo.first != NULL)) {
719
0
            if (uri->owner) {
720
0
                URI_FUNC(FixPercentEncodingInplace)(uri->userInfo.first,
721
0
                                                    &(uri->userInfo.afterLast));
722
0
            } else {
723
0
                if (!URI_FUNC(FixPercentEncodingMalloc)(
724
0
                        &(uri->userInfo.first), &(uri->userInfo.afterLast), memory)) {
725
0
                    URI_FUNC(PreventLeakage)(uri, revertMask, memory);
726
0
                    return URI_ERROR_MALLOC;
727
0
                }
728
0
                revertMask |= URI_NORMALIZE_USER_INFO;
729
0
            }
730
0
        }
731
0
    }
732
733
    /* Path */
734
0
    if (outMask != NULL) {
735
0
        const URI_TYPE(PathSegment) * walker = uri->pathHead;
736
0
        while (walker != NULL) {
737
0
            const URI_CHAR * const first = walker->text.first;
738
0
            const URI_CHAR * const afterLast = walker->text.afterLast;
739
0
            if ((first != NULL) && (afterLast != NULL) && (afterLast > first)
740
0
                && ((((afterLast - first) == 1) && (first[0] == _UT('.')))
741
0
                    || (((afterLast - first) == 2) && (first[0] == _UT('.'))
742
0
                        && (first[1] == _UT('.')))
743
0
                    || URI_FUNC(ContainsUglyPercentEncoding)(first, afterLast))) {
744
0
                *outMask |= URI_NORMALIZE_PATH;
745
0
                break;
746
0
            }
747
0
            walker = walker->next;
748
0
        }
749
0
    } else if (inMask & URI_NORMALIZE_PATH) {
750
0
        URI_TYPE(PathSegment) * walker;
751
0
        const UriBool relative =
752
0
            ((uri->scheme.first == NULL) && !uri->absolutePath) ? URI_TRUE : URI_FALSE;
753
754
        /* Fix percent-encoding for each segment */
755
0
        walker = uri->pathHead;
756
0
        if (uri->owner) {
757
0
            while (walker != NULL) {
758
0
                URI_FUNC(FixPercentEncodingInplace)(walker->text.first,
759
0
                                                    &(walker->text.afterLast));
760
0
                walker = walker->next;
761
0
            }
762
0
        } else {
763
0
            while (walker != NULL) {
764
0
                if (!URI_FUNC(FixPercentEncodingMalloc)(
765
0
                        &(walker->text.first), &(walker->text.afterLast), memory)) {
766
0
                    URI_FUNC(PreventLeakage)(uri, revertMask, memory);
767
0
                    return URI_ERROR_MALLOC;
768
0
                }
769
0
                walker = walker->next;
770
0
            }
771
0
            revertMask |= URI_NORMALIZE_PATH;
772
0
        }
773
774
        /* 6.2.2.3 Path Segment Normalization */
775
0
        if (!URI_FUNC(RemoveDotSegmentsEx)(
776
0
                uri, relative,
777
0
                (uri->owner == URI_TRUE) || ((revertMask & URI_NORMALIZE_PATH) != 0),
778
0
                memory)) {
779
0
            URI_FUNC(PreventLeakage)(uri, revertMask, memory);
780
0
            return URI_ERROR_MALLOC;
781
0
        }
782
0
        URI_FUNC(FixEmptyTrailSegment)(uri, memory);
783
0
    }
784
785
    /* Query, fragment */
786
0
    if (outMask != NULL) {
787
0
        const UriBool normalizeQuery =
788
0
            URI_FUNC(ContainsUglyPercentEncoding)(uri->query.first, uri->query.afterLast);
789
0
        const UriBool normalizeFragment = URI_FUNC(ContainsUglyPercentEncoding)(
790
0
            uri->fragment.first, uri->fragment.afterLast);
791
0
        if (normalizeQuery) {
792
0
            *outMask |= URI_NORMALIZE_QUERY;
793
0
        }
794
795
0
        if (normalizeFragment) {
796
0
            *outMask |= URI_NORMALIZE_FRAGMENT;
797
0
        }
798
0
    } else {
799
        /* Query */
800
0
        if ((inMask & URI_NORMALIZE_QUERY) && (uri->query.first != NULL)) {
801
0
            if (uri->owner) {
802
0
                URI_FUNC(FixPercentEncodingInplace)(uri->query.first,
803
0
                                                    &(uri->query.afterLast));
804
0
            } else {
805
0
                if (!URI_FUNC(FixPercentEncodingMalloc)(
806
0
                        &(uri->query.first), &(uri->query.afterLast), memory)) {
807
0
                    URI_FUNC(PreventLeakage)(uri, revertMask, memory);
808
0
                    return URI_ERROR_MALLOC;
809
0
                }
810
0
                revertMask |= URI_NORMALIZE_QUERY;
811
0
            }
812
0
        }
813
814
        /* Fragment */
815
0
        if ((inMask & URI_NORMALIZE_FRAGMENT) && (uri->fragment.first != NULL)) {
816
0
            if (uri->owner) {
817
0
                URI_FUNC(FixPercentEncodingInplace)(uri->fragment.first,
818
0
                                                    &(uri->fragment.afterLast));
819
0
            } else {
820
0
                if (!URI_FUNC(FixPercentEncodingMalloc)(
821
0
                        &(uri->fragment.first), &(uri->fragment.afterLast), memory)) {
822
0
                    URI_FUNC(PreventLeakage)(uri, revertMask, memory);
823
0
                    return URI_ERROR_MALLOC;
824
0
                }
825
0
                revertMask |= URI_NORMALIZE_FRAGMENT;
826
0
            }
827
0
        }
828
0
    }
829
830
    /* Dup all not duped yet */
831
0
    if ((outMask == NULL) && !uri->owner) {
832
0
        if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) {
833
0
            URI_FUNC(PreventLeakage)(uri, revertMask, memory);
834
0
            return URI_ERROR_MALLOC;
835
0
        }
836
0
        uri->owner = URI_TRUE;
837
0
    }
838
839
0
    return URI_SUCCESS;
840
0
}
Unexecuted instantiation: UriNormalize.c:uriNormalizeSyntaxEngineA
Unexecuted instantiation: UriNormalize.c:uriNormalizeSyntaxEngineW
841
842
0
int URI_FUNC(MakeOwnerMm)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
843
0
    unsigned int revertMask = URI_NORMALIZED;
844
845
0
    URI_CHECK_MEMORY_MANAGER(memory); /* may return */
846
847
0
    if (uri == NULL) {
848
0
        return URI_ERROR_NULL;
849
0
    }
850
851
0
    if (uri->owner == URI_TRUE) {
852
0
        return URI_SUCCESS;
853
0
    }
854
855
0
    if (!URI_FUNC(MakeOwnerEngine)(uri, &revertMask, memory)) {
856
0
        URI_FUNC(PreventLeakage)(uri, revertMask, memory);
857
0
        return URI_ERROR_MALLOC;
858
0
    }
859
860
0
    uri->owner = URI_TRUE;
861
862
0
    return URI_SUCCESS;
863
0
}
Unexecuted instantiation: uriMakeOwnerMmA
Unexecuted instantiation: uriMakeOwnerMmW
864
865
0
int URI_FUNC(MakeOwner)(URI_TYPE(Uri) * uri) {
866
0
    return URI_FUNC(MakeOwnerMm)(uri, NULL);
867
0
}
Unexecuted instantiation: uriMakeOwnerA
Unexecuted instantiation: uriMakeOwnerW
868
869
#endif