Coverage Report

Created: 2026-01-18 06:49

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/php-src/ext/uri/uriparser/src/UriCommon.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
/* 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 "UriCommon.c"
47
#    undef URI_PASS_ANSI
48
#  endif
49
#  ifdef URI_ENABLE_UNICODE
50
#    define URI_PASS_UNICODE 1
51
#    include "UriCommon.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
#  ifndef URI_DOXYGEN
63
#    include <uriparser/Uri.h>
64
#    include "UriCommon.h"
65
#    include "UriSets.h"
66
#  endif
67
68
#  include <assert.h>
69
70
/*extern*/ const URI_CHAR * const URI_FUNC(SafeToPointTo) = _UT("X");
71
/*extern*/ const URI_CHAR * const URI_FUNC(ConstPwd) = _UT(".");
72
/*extern*/ const URI_CHAR * const URI_FUNC(ConstParent) = _UT("..");
73
74
0
void URI_FUNC(ResetUri)(URI_TYPE(Uri) * uri) {
75
0
    if (uri == NULL) {
76
0
        return;
77
0
    }
78
0
    memset(uri, 0, sizeof(URI_TYPE(Uri)));
79
0
}
Unexecuted instantiation: uriResetUriA
Unexecuted instantiation: uriResetUriW
80
81
0
int URI_FUNC(FreeUriPath)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
82
0
    assert(uri != NULL);
83
0
    assert(memory != NULL);
84
85
0
    if (uri->pathHead != NULL) {
86
0
        URI_TYPE(PathSegment) * segWalk = uri->pathHead;
87
0
        while (segWalk != NULL) {
88
0
            URI_TYPE(PathSegment) * const next = segWalk->next;
89
0
            if ((uri->owner == URI_TRUE)
90
0
                && (segWalk->text.first != segWalk->text.afterLast)) {
91
0
                memory->free(memory, (URI_CHAR *)segWalk->text.first);
92
0
            }
93
0
            segWalk->text.first = NULL;
94
0
            segWalk->text.afterLast = NULL;
95
0
            segWalk->next = NULL;
96
0
            memory->free(memory, segWalk);
97
0
            segWalk = next;
98
0
        }
99
0
        uri->pathHead = NULL;
100
0
        uri->pathTail = NULL;
101
0
    }
102
103
0
    return URI_SUCCESS;
104
0
}
Unexecuted instantiation: uriFreeUriPathA
Unexecuted instantiation: uriFreeUriPathW
105
106
/* Compares two text ranges for equal text content */
107
0
int URI_FUNC(CompareRange)(const URI_TYPE(TextRange) * a, const URI_TYPE(TextRange) * b) {
108
0
    int diff;
109
110
    /* NOTE: Both NULL means equal! */
111
0
    if ((a == NULL) || (b == NULL)) {
112
0
        return ((a == NULL) ? 0 : 1) - ((b == NULL) ? 0 : 1);
113
0
    }
114
115
    /* NOTE: Both NULL means equal! */
116
0
    if ((a->first == NULL) || (b->first == NULL)) {
117
0
        return ((a->first == NULL) ? 0 : 1) - ((b->first == NULL) ? 0 : 1);
118
0
    }
119
120
0
    diff = ((int)(a->afterLast - a->first) - (int)(b->afterLast - b->first));
121
0
    if (diff > 0) {
122
0
        return 1;
123
0
    } else if (diff < 0) {
124
0
        return -1;
125
0
    }
126
127
0
    diff = URI_STRNCMP(a->first, b->first, (a->afterLast - a->first));
128
129
0
    if (diff > 0) {
130
0
        return 1;
131
0
    } else if (diff < 0) {
132
0
        return -1;
133
0
    }
134
135
0
    return diff;
136
0
}
Unexecuted instantiation: uriCompareRangeA
Unexecuted instantiation: uriCompareRangeW
137
138
UriBool URI_FUNC(CopyRange)(URI_TYPE(TextRange) * destRange,
139
                            const URI_TYPE(TextRange) * sourceRange,
140
0
                            UriMemoryManager * memory) {
141
0
    const int lenInChars = (int)(sourceRange->afterLast - sourceRange->first);
142
0
    const int lenInBytes = lenInChars * sizeof(URI_CHAR);
143
0
    URI_CHAR * dup = memory->malloc(memory, lenInBytes);
144
0
    if (dup == NULL) {
145
0
        return URI_FALSE;
146
0
    }
147
0
    memcpy(dup, sourceRange->first, lenInBytes);
148
0
    destRange->first = dup;
149
0
    destRange->afterLast = dup + lenInChars;
150
151
0
    return URI_TRUE;
152
0
}
Unexecuted instantiation: uriCopyRangeA
Unexecuted instantiation: uriCopyRangeW
153
154
UriBool URI_FUNC(CopyRangeAsNeeded)(URI_TYPE(TextRange) * destRange,
155
                                    const URI_TYPE(TextRange) * sourceRange,
156
0
                                    UriMemoryManager * memory) {
157
0
    if (sourceRange->first == NULL) {
158
0
        destRange->first = NULL;
159
0
        destRange->afterLast = NULL;
160
0
    } else if (sourceRange->first == sourceRange->afterLast) {
161
0
        destRange->first = URI_FUNC(SafeToPointTo);
162
0
        destRange->afterLast = URI_FUNC(SafeToPointTo);
163
0
    } else {
164
0
        return URI_FUNC(CopyRange)(destRange, sourceRange, memory);
165
0
    }
166
167
0
    return URI_TRUE;
168
0
}
Unexecuted instantiation: uriCopyRangeAsNeededA
Unexecuted instantiation: uriCopyRangeAsNeededW
169
170
UriBool URI_FUNC(RemoveDotSegmentsEx)(URI_TYPE(Uri) * uri, UriBool relative,
171
0
                                      UriBool pathOwned, UriMemoryManager * memory) {
172
0
    URI_TYPE(PathSegment) * walker;
173
0
    if ((uri == NULL) || (uri->pathHead == NULL)) {
174
0
        return URI_TRUE;
175
0
    }
176
177
0
    walker = uri->pathHead;
178
0
    walker->reserved = NULL; /* Prev pointer */
179
0
    do {
180
0
        UriBool removeSegment = URI_FALSE;
181
0
        int len = (int)(walker->text.afterLast - walker->text.first);
182
0
        switch (len) {
183
0
        case 1:
184
0
            if ((walker->text.first)[0] == _UT('.')) {
185
                /* "." segment -> remove if not essential */
186
0
                URI_TYPE(PathSegment) * const prev = walker->reserved;
187
0
                URI_TYPE(PathSegment) * const nextBackup = walker->next;
188
189
                /*
190
                 * Is this dot segment essential,
191
                 * i.e. is there a chance of changing semantics by dropping this dot
192
                 * segment?
193
                 *
194
                 * For example, changing "./http://foo" into "http://foo" would change
195
                 * semantics and hence the dot segment is essential to that case and
196
                 * cannot be removed.
197
                 *
198
                 * Other examples that would change semantics are:
199
                 * - cutting "/.//" down to "//"
200
                 * - cutting "scheme:/.//" down to "scheme://".
201
                 */
202
0
                removeSegment = URI_TRUE;
203
0
                if ((walker == uri->pathHead) && (walker->next != NULL)) {
204
                    /* Detect case "/.//" (with or without scheme) */
205
0
                    if ((walker->next->text.first == walker->next->text.afterLast)
206
0
                        && (URI_FUNC(HasHost)(uri) == URI_FALSE)) {
207
0
                        removeSegment = URI_FALSE;
208
                        /* Detect case "./withcolon:" */
209
0
                    } else if (relative) {
210
0
                        const URI_CHAR * ch = walker->next->text.first;
211
0
                        for (; ch < walker->next->text.afterLast; ch++) {
212
0
                            if (*ch == _UT(':')) {
213
0
                                removeSegment = URI_FALSE;
214
0
                                break;
215
0
                            }
216
0
                        }
217
0
                    }
218
0
                }
219
220
0
                if (removeSegment) {
221
                    /* .. then let's go remove that segment. */
222
                    /* Last segment? */
223
0
                    if (walker->next != NULL) {
224
                        /* Not last segment, i.e. first or middle segment
225
                         * OLD: (prev|NULL) <- walker <- next
226
                         * NEW: (prev|NULL) <----------- next */
227
0
                        walker->next->reserved = prev;
228
229
0
                        if (prev == NULL) {
230
                            /* First but not last segment
231
                             * OLD: head -> walker -> next
232
                             * NEW: head -----------> next */
233
0
                            uri->pathHead = walker->next;
234
0
                        } else {
235
                            /* Middle segment
236
                             * OLD: prev -> walker -> next
237
                             * NEW: prev -----------> next */
238
0
                            prev->next = walker->next;
239
0
                        }
240
241
0
                        if (pathOwned && (walker->text.first != walker->text.afterLast)) {
242
0
                            memory->free(memory, (URI_CHAR *)walker->text.first);
243
0
                        }
244
0
                        memory->free(memory, walker);
245
0
                    } else {
246
                        /* Last segment */
247
0
                        if (pathOwned && (walker->text.first != walker->text.afterLast)) {
248
0
                            memory->free(memory, (URI_CHAR *)walker->text.first);
249
0
                        }
250
251
0
                        if (prev == NULL) {
252
                            /* Last and first */
253
0
                            if (URI_FUNC(HasHost)(uri)) {
254
                                /* Replace "." with empty segment to represent trailing
255
                                 * slash */
256
0
                                walker->text.first = URI_FUNC(SafeToPointTo);
257
0
                                walker->text.afterLast = URI_FUNC(SafeToPointTo);
258
0
                            } else {
259
0
                                memory->free(memory, walker);
260
261
0
                                uri->pathHead = NULL;
262
0
                                uri->pathTail = NULL;
263
0
                            }
264
0
                        } else {
265
                            /* Last but not first, replace "." with empty segment to
266
                             * represent trailing slash */
267
0
                            walker->text.first = URI_FUNC(SafeToPointTo);
268
0
                            walker->text.afterLast = URI_FUNC(SafeToPointTo);
269
0
                        }
270
0
                    }
271
272
0
                    walker = nextBackup;
273
0
                }
274
0
            }
275
0
            break;
276
277
0
        case 2:
278
0
            if (((walker->text.first)[0] == _UT('.'))
279
0
                && ((walker->text.first)[1] == _UT('.'))) {
280
                /* Path ".." -> remove this and the previous segment */
281
0
                URI_TYPE(PathSegment) * const prev = walker->reserved;
282
0
                URI_TYPE(PathSegment) * prevPrev;
283
0
                URI_TYPE(PathSegment) * const nextBackup = walker->next;
284
285
0
                removeSegment = URI_TRUE;
286
0
                if (relative) {
287
0
                    if (prev == NULL) {
288
                        /* We cannot remove traversal beyond because the
289
                         * URI is relative and may be resolved later.
290
                         * So we can simplify "a/../b/d" to "b/d" but
291
                         * we cannot simplify "../b/d" (outside of reference resolution).
292
                         */
293
0
                        removeSegment = URI_FALSE;
294
0
                    } else if ((prev != NULL)
295
0
                               && ((prev->text.afterLast - prev->text.first) == 2)
296
0
                               && ((prev->text.first)[0] == _UT('.'))
297
0
                               && ((prev->text.first)[1] == _UT('.'))) {
298
                        /* We need to protect against mis-simplifying "a/../../b" to
299
                         * "a/b". */
300
0
                        removeSegment = URI_FALSE;
301
0
                    }
302
0
                }
303
304
0
                if (removeSegment) {
305
0
                    if (prev != NULL) {
306
                        /* Not first segment */
307
0
                        prevPrev = prev->reserved;
308
0
                        if (prevPrev != NULL) {
309
                            /* Not even prev is the first one
310
                             * OLD: prevPrev -> prev -> walker -> (next|NULL)
311
                             * NEW: prevPrev -------------------> (next|NULL) */
312
0
                            prevPrev->next = walker->next;
313
0
                            if (walker->next != NULL) {
314
                                /* Update parent relationship as well
315
                                 * OLD: prevPrev <- prev <- walker <- next
316
                                 * NEW: prevPrev <------------------- next */
317
0
                                walker->next->reserved = prevPrev;
318
0
                            } else {
319
                                /* Last segment -> insert "" segment to represent trailing
320
                                 * slash, update tail */
321
0
                                URI_TYPE(PathSegment) * const segment = memory->calloc(
322
0
                                    memory, 1, sizeof(URI_TYPE(PathSegment)));
323
0
                                if (segment == NULL) {
324
0
                                    if (pathOwned
325
0
                                        && (walker->text.first
326
0
                                            != walker->text.afterLast)) {
327
0
                                        memory->free(memory,
328
0
                                                     (URI_CHAR *)walker->text.first);
329
0
                                    }
330
0
                                    memory->free(memory, walker);
331
332
0
                                    if (pathOwned
333
0
                                        && (prev->text.first != prev->text.afterLast)) {
334
0
                                        memory->free(memory,
335
0
                                                     (URI_CHAR *)prev->text.first);
336
0
                                    }
337
0
                                    memory->free(memory, prev);
338
339
0
                                    return URI_FALSE; /* Raises malloc error */
340
0
                                }
341
0
                                segment->text.first = URI_FUNC(SafeToPointTo);
342
0
                                segment->text.afterLast = URI_FUNC(SafeToPointTo);
343
0
                                prevPrev->next = segment;
344
0
                                uri->pathTail = segment;
345
0
                            }
346
347
0
                            if (pathOwned
348
0
                                && (walker->text.first != walker->text.afterLast)) {
349
0
                                memory->free(memory, (URI_CHAR *)walker->text.first);
350
0
                            }
351
0
                            memory->free(memory, walker);
352
353
0
                            if (pathOwned && (prev->text.first != prev->text.afterLast)) {
354
0
                                memory->free(memory, (URI_CHAR *)prev->text.first);
355
0
                            }
356
0
                            memory->free(memory, prev);
357
358
0
                            walker = nextBackup;
359
0
                        } else {
360
                            /* Prev is the first segment */
361
0
                            if (walker->next != NULL) {
362
0
                                uri->pathHead = walker->next;
363
0
                                walker->next->reserved = NULL;
364
365
0
                                if (pathOwned
366
0
                                    && (walker->text.first != walker->text.afterLast)) {
367
0
                                    memory->free(memory, (URI_CHAR *)walker->text.first);
368
0
                                }
369
0
                                memory->free(memory, walker);
370
0
                            } else {
371
                                /* Reuse segment for "" path segment to represent trailing
372
                                 * slash, update tail */
373
0
                                URI_TYPE(PathSegment) * const segment = walker;
374
0
                                if (pathOwned
375
0
                                    && (segment->text.first != segment->text.afterLast)) {
376
0
                                    memory->free(memory, (URI_CHAR *)segment->text.first);
377
0
                                }
378
0
                                segment->text.first = URI_FUNC(SafeToPointTo);
379
0
                                segment->text.afterLast = URI_FUNC(SafeToPointTo);
380
0
                                uri->pathHead = segment;
381
0
                                uri->pathTail = segment;
382
0
                            }
383
384
0
                            if (pathOwned && (prev->text.first != prev->text.afterLast)) {
385
0
                                memory->free(memory, (URI_CHAR *)prev->text.first);
386
0
                            }
387
0
                            memory->free(memory, prev);
388
389
0
                            walker = nextBackup;
390
0
                        }
391
0
                    } else {
392
0
                        URI_TYPE(PathSegment) * const anotherNextBackup = walker->next;
393
0
                        int freeWalker = URI_TRUE;
394
395
                        /* First segment */
396
0
                        if (walker->next != NULL) {
397
                            /* First segment of multiple -> update head
398
                             * OLD: head -> walker -> next
399
                             * NEW: head -----------> next */
400
0
                            uri->pathHead = walker->next;
401
402
                            /* Update parent link as well
403
                             * OLD: head <- walker <- next
404
                             * NEW: head <----------- next */
405
0
                            walker->next->reserved = NULL;
406
0
                        } else {
407
0
                            if (uri->absolutePath) {
408
                                /* First and only segment -> update head
409
                                 * OLD: head -> walker -> NULL
410
                                 * NEW: head -----------> NULL */
411
0
                                uri->pathHead = NULL;
412
413
                                /* Last segment -> update tail
414
                                 * OLD: tail -> walker
415
                                 * NEW: tail -> NULL */
416
0
                                uri->pathTail = NULL;
417
0
                            } else {
418
                                /* Reuse segment for "" path segment to represent trailing
419
                                 * slash, then update head and tail */
420
0
                                if (pathOwned
421
0
                                    && (walker->text.first != walker->text.afterLast)) {
422
0
                                    memory->free(memory, (URI_CHAR *)walker->text.first);
423
0
                                }
424
0
                                walker->text.first = URI_FUNC(SafeToPointTo);
425
0
                                walker->text.afterLast = URI_FUNC(SafeToPointTo);
426
0
                                freeWalker = URI_FALSE;
427
0
                            }
428
0
                        }
429
430
0
                        if (freeWalker) {
431
0
                            if (pathOwned
432
0
                                && (walker->text.first != walker->text.afterLast)) {
433
0
                                memory->free(memory, (URI_CHAR *)walker->text.first);
434
0
                            }
435
0
                            memory->free(memory, walker);
436
0
                        }
437
438
0
                        walker = anotherNextBackup;
439
0
                    }
440
0
                }
441
0
            }
442
0
            break;
443
0
        } /* end of switch */
444
445
0
        if (!removeSegment) {
446
            /* .. then let's move to the next element, and start again. */
447
0
            if (walker->next != NULL) {
448
0
                walker->next->reserved = walker;
449
0
            } else {
450
                /* Last segment -> update tail */
451
0
                uri->pathTail = walker;
452
0
            }
453
0
            walker = walker->next;
454
0
        }
455
0
    } while (walker != NULL);
456
457
0
    return URI_TRUE;
458
0
}
Unexecuted instantiation: uriRemoveDotSegmentsExA
Unexecuted instantiation: uriRemoveDotSegmentsExW
459
460
/* Properly removes "." and ".." path segments */
461
UriBool URI_FUNC(RemoveDotSegmentsAbsolute)(URI_TYPE(Uri) * uri,
462
0
                                            UriMemoryManager * memory) {
463
0
    const UriBool ABSOLUTE = URI_FALSE;
464
0
    if (uri == NULL) {
465
0
        return URI_TRUE;
466
0
    }
467
0
    return URI_FUNC(RemoveDotSegmentsEx)(uri, ABSOLUTE, uri->owner, memory);
468
0
}
Unexecuted instantiation: uriRemoveDotSegmentsAbsoluteA
Unexecuted instantiation: uriRemoveDotSegmentsAbsoluteW
469
470
0
unsigned char URI_FUNC(HexdigToInt)(URI_CHAR hexdig) {
471
0
    switch (hexdig) {
472
0
    case URI_SET_DIGIT(_UT):
473
0
        return (unsigned char)(9 + hexdig - _UT('9'));
474
0
    case URI_SET_HEX_LETTER_LOWER(_UT):
475
0
        return (unsigned char)(15 + hexdig - _UT('f'));
476
0
    case URI_SET_HEX_LETTER_UPPER(_UT):
477
0
        return (unsigned char)(15 + hexdig - _UT('F'));
478
479
0
    default:
480
0
        return 0;
481
0
    }
482
0
}
Unexecuted instantiation: uriHexdigToIntA
Unexecuted instantiation: uriHexdigToIntW
483
484
0
URI_CHAR URI_FUNC(HexToLetterEx)(unsigned int value, UriBool uppercase) {
485
0
    switch (value) {
486
0
    case 0:
487
0
        return _UT('0');
488
0
    case 1:
489
0
        return _UT('1');
490
0
    case 2:
491
0
        return _UT('2');
492
0
    case 3:
493
0
        return _UT('3');
494
0
    case 4:
495
0
        return _UT('4');
496
0
    case 5:
497
0
        return _UT('5');
498
0
    case 6:
499
0
        return _UT('6');
500
0
    case 7:
501
0
        return _UT('7');
502
0
    case 8:
503
0
        return _UT('8');
504
0
    case 9:
505
0
        return _UT('9');
506
507
0
    case 10:
508
0
        return (uppercase == URI_TRUE) ? _UT('A') : _UT('a');
509
0
    case 11:
510
0
        return (uppercase == URI_TRUE) ? _UT('B') : _UT('b');
511
0
    case 12:
512
0
        return (uppercase == URI_TRUE) ? _UT('C') : _UT('c');
513
0
    case 13:
514
0
        return (uppercase == URI_TRUE) ? _UT('D') : _UT('d');
515
0
    case 14:
516
0
        return (uppercase == URI_TRUE) ? _UT('E') : _UT('e');
517
0
    default:
518
0
        return (uppercase == URI_TRUE) ? _UT('F') : _UT('f');
519
0
    }
520
0
}
Unexecuted instantiation: uriHexToLetterExA
Unexecuted instantiation: uriHexToLetterExW
521
522
/* Checks if a URI has the host component set. */
523
0
UriBool URI_FUNC(HasHost)(const URI_TYPE(Uri) * uri) {
524
    /* NOTE: .hostData.ipFuture.first is not being checked,   *
525
     *       because we do check .hostText.first and          *
526
     *       .hostData.ipFuture.first has to be identical to  *
527
     *       .hostText.first if set, and hence there is       *
528
     *       no more information to be gained.                */
529
0
    return (uri != NULL)
530
0
           && ((uri->hostText.first != NULL) || (uri->hostData.ip4 != NULL)
531
0
               || (uri->hostData.ip6 != NULL));
532
0
}
Unexecuted instantiation: uriHasHostA
Unexecuted instantiation: uriHasHostW
533
534
/* Copies the path segment list from one URI to another. */
535
UriBool URI_FUNC(CopyPath)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
536
0
                           UriMemoryManager * memory) {
537
0
    if (source->pathHead == NULL) {
538
        /* No path component */
539
0
        dest->pathHead = NULL;
540
0
        dest->pathTail = NULL;
541
0
    } else {
542
        /* Copy list but not the text contained */
543
0
        URI_TYPE(PathSegment) * sourceWalker = source->pathHead;
544
0
        URI_TYPE(PathSegment) * destPrev = NULL;
545
0
        do {
546
0
            URI_TYPE(PathSegment) * cur =
547
0
                memory->malloc(memory, sizeof(URI_TYPE(PathSegment)));
548
0
            if (cur == NULL) {
549
                /* Fix broken list */
550
0
                if (destPrev != NULL) {
551
0
                    destPrev->next = NULL;
552
0
                }
553
0
                return URI_FALSE; /* Raises malloc error */
554
0
            }
555
556
            /* From this functions usage we know that *
557
             * the dest URI cannot be uri->owner      */
558
0
            cur->text = sourceWalker->text;
559
0
            if (destPrev == NULL) {
560
                /* First segment ever */
561
0
                dest->pathHead = cur;
562
0
            } else {
563
0
                destPrev->next = cur;
564
0
            }
565
0
            destPrev = cur;
566
0
            sourceWalker = sourceWalker->next;
567
0
        } while (sourceWalker != NULL);
568
0
        dest->pathTail = destPrev;
569
0
        dest->pathTail->next = NULL;
570
0
    }
571
572
0
    dest->absolutePath = source->absolutePath;
573
0
    return URI_TRUE;
574
0
}
Unexecuted instantiation: uriCopyPathA
Unexecuted instantiation: uriCopyPathW
575
576
/* Copies the authority part of an URI over to another. */
577
UriBool URI_FUNC(CopyAuthority)(URI_TYPE(Uri) * dest, const URI_TYPE(Uri) * source,
578
0
                                UriMemoryManager * memory) {
579
    /* From this functions usage we know that *
580
     * the dest URI cannot be uri->owner      */
581
582
    /* Copy userInfo */
583
0
    dest->userInfo = source->userInfo;
584
585
    /* Copy hostText */
586
0
    dest->hostText = source->hostText;
587
588
    /* Copy hostData */
589
0
    if (source->hostData.ip4 != NULL) {
590
0
        dest->hostData.ip4 = memory->malloc(memory, sizeof(UriIp4));
591
0
        if (dest->hostData.ip4 == NULL) {
592
0
            return URI_FALSE; /* Raises malloc error */
593
0
        }
594
0
        *(dest->hostData.ip4) = *(source->hostData.ip4);
595
0
        dest->hostData.ip6 = NULL;
596
0
        dest->hostData.ipFuture.first = NULL;
597
0
        dest->hostData.ipFuture.afterLast = NULL;
598
0
    } else if (source->hostData.ip6 != NULL) {
599
0
        dest->hostData.ip4 = NULL;
600
0
        dest->hostData.ip6 = memory->malloc(memory, sizeof(UriIp6));
601
0
        if (dest->hostData.ip6 == NULL) {
602
0
            return URI_FALSE; /* Raises malloc error */
603
0
        }
604
0
        *(dest->hostData.ip6) = *(source->hostData.ip6);
605
0
        dest->hostData.ipFuture.first = NULL;
606
0
        dest->hostData.ipFuture.afterLast = NULL;
607
0
    } else {
608
0
        dest->hostData.ip4 = NULL;
609
0
        dest->hostData.ip6 = NULL;
610
0
        dest->hostData.ipFuture = source->hostData.ipFuture;
611
0
    }
612
613
    /* Copy portText */
614
0
    dest->portText = source->portText;
615
616
0
    return URI_TRUE;
617
0
}
Unexecuted instantiation: uriCopyAuthorityA
Unexecuted instantiation: uriCopyAuthorityW
618
619
0
UriBool URI_FUNC(FixAmbiguity)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
620
0
    URI_TYPE(PathSegment) * segment;
621
622
0
    if (/* Case 1: absolute path, empty first segment */
623
0
        (uri->absolutePath && (uri->pathHead != NULL)
624
0
         && (uri->pathHead->text.afterLast == uri->pathHead->text.first))
625
626
        /* Case 2: relative path, empty first and second segment */
627
0
        || (!uri->absolutePath && (uri->pathHead != NULL) && (uri->pathHead->next != NULL)
628
0
            && (uri->pathHead->text.afterLast == uri->pathHead->text.first)
629
0
            && (uri->pathHead->next->text.afterLast
630
0
                == uri->pathHead->next->text.first))) {
631
        /* NOOP */
632
0
    } else {
633
0
        return URI_TRUE;
634
0
    }
635
636
0
    segment = memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
637
0
    if (segment == NULL) {
638
0
        return URI_FALSE; /* Raises malloc error */
639
0
    }
640
641
    /* Insert "." segment in front */
642
0
    segment->next = uri->pathHead;
643
0
    segment->text.first = URI_FUNC(ConstPwd);
644
0
    segment->text.afterLast = URI_FUNC(ConstPwd) + 1;
645
0
    uri->pathHead = segment;
646
0
    return URI_TRUE;
647
0
}
Unexecuted instantiation: uriFixAmbiguityA
Unexecuted instantiation: uriFixAmbiguityW
648
649
static UriBool URI_FUNC(PrependNewDotSegment)(URI_TYPE(Uri) * uri,
650
0
                                              UriMemoryManager * memory) {
651
0
    assert(uri != NULL);
652
0
    assert(memory != NULL);
653
654
0
    URI_TYPE(PathSegment) * const segment =
655
0
        memory->malloc(memory, 1 * sizeof(URI_TYPE(PathSegment)));
656
657
0
    if (segment == NULL) {
658
0
        return URI_FALSE; /* i.e. raise malloc error */
659
0
    }
660
661
0
    segment->next = uri->pathHead;
662
663
0
    URI_TYPE(TextRange) dotRange;
664
0
    dotRange.first = URI_FUNC(ConstPwd);
665
0
    dotRange.afterLast = URI_FUNC(ConstPwd) + 1;
666
667
0
    if (uri->owner == URI_TRUE) {
668
0
        if (URI_FUNC(CopyRange)(&(segment->text), &dotRange, memory) == URI_FALSE) {
669
0
            memory->free(memory, segment);
670
0
            return URI_FALSE; /* i.e. raise malloc error */
671
0
        }
672
0
    } else {
673
0
        segment->text = dotRange; /* copies all members */
674
0
    }
675
676
0
    uri->pathHead = segment;
677
678
0
    return URI_TRUE;
679
0
}
Unexecuted instantiation: UriCommon.c:uriPrependNewDotSegmentA
Unexecuted instantiation: UriCommon.c:uriPrependNewDotSegmentW
680
681
/* When dropping a scheme from a URI without a host and with a colon (":")
682
 * in the first path segment, a consecutive reparse would rightfully
683
 * mis-classify the first path segment as a scheme due to the colon.
684
 * To protect against this case, we prepend an artificial "." segment
685
 * to the path in here; the function is called after the scheme has
686
 * just been dropped.
687
 *
688
 * 0. We start with parsed URI "scheme:path1:/path2/path3".
689
 * 1. We drop the scheme naively and yield "path1:/path2/path3".
690
 * 2. We prepend "." and yield unambiguous "./path1:/path2/path3".
691
 *
692
 * From the view of the RFC 3986 grammar, this is replacing rule path-rootless
693
 * by path-noscheme content.
694
 *
695
 * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
696
 * Returns URI_FALSE to signal out-of-memory.
697
 */
698
0
UriBool URI_FUNC(FixPathNoScheme)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
699
0
    assert(uri != NULL);
700
0
    assert(memory != NULL);
701
702
0
    if ((uri->absolutePath == URI_TRUE) || (uri->pathHead == NULL)
703
0
        || (uri->scheme.first != NULL) || URI_FUNC(HasHost)(uri)) {
704
0
        return URI_TRUE; /* i.e. nothing to do */
705
0
    }
706
707
    /* Check for troublesome first path segment containing a colon */
708
0
    UriBool colonFound = URI_FALSE;
709
0
    const URI_CHAR * walker = uri->pathHead->text.first;
710
711
0
    while (walker < uri->pathHead->text.afterLast) {
712
0
        if (walker[0] == _UT(':')) {
713
0
            colonFound = URI_TRUE;
714
0
            break;
715
0
        }
716
0
        walker++;
717
0
    }
718
719
0
    assert((walker == uri->pathHead->text.afterLast) || (colonFound == URI_TRUE));
720
721
0
    if (colonFound == URI_FALSE) {
722
0
        return URI_TRUE; /* i.e. nothing to do */
723
0
    }
724
725
    /* Insert "." segment in front */
726
0
    return URI_FUNC(PrependNewDotSegment)(uri, memory);
727
0
}
Unexecuted instantiation: uriFixPathNoSchemeA
Unexecuted instantiation: uriFixPathNoSchemeW
728
729
/* When dropping a host from a URI without a scheme, an absolute path
730
 * and and empty first path segment, a consecutive reparse would rightfully
731
 * mis-classify the first path segment as a host marker due to the "//".
732
 * To protect against this case, we prepend an artificial "." segment
733
 * to the path in here; the function is called after the host has
734
 * just been dropped.
735
 *
736
 * 0. We start with parsed URI "//host//path1/path2".
737
 * 1. We drop the host naively and yield "//path1/path2".
738
 * 2. We insert "./" and yield unambiguous "/.//path1/path2".
739
 *
740
 * Returns URI_TRUE for (a) nothing to do or (b) successful changes.
741
 * Returns URI_FALSE to signal out-of-memory.
742
 */
743
UriBool URI_FUNC(EnsureThatPathIsNotMistakenForHost)(URI_TYPE(Uri) * uri,
744
0
                                                     UriMemoryManager * memory) {
745
0
    assert(uri != NULL);
746
0
    assert(memory != NULL);
747
748
0
    if ((URI_FUNC(HasHost)(uri) == URI_TRUE) || (uri->absolutePath == URI_FALSE)
749
0
        || (uri->pathHead == NULL)
750
0
        || (uri->pathHead == uri->pathTail) /* i.e. no second slash */
751
0
        || (uri->pathHead->text.first != uri->pathHead->text.afterLast)) {
752
0
        return URI_TRUE; /* i.e. nothing to do */
753
0
    }
754
755
    /* Insert "." segment in front */
756
0
    return URI_FUNC(PrependNewDotSegment)(uri, memory);
757
0
}
Unexecuted instantiation: uriEnsureThatPathIsNotMistakenForHostA
Unexecuted instantiation: uriEnsureThatPathIsNotMistakenForHostW
758
759
0
void URI_FUNC(FixEmptyTrailSegment)(URI_TYPE(Uri) * uri, UriMemoryManager * memory) {
760
    /* Fix path if only one empty segment */
761
0
    if (!uri->absolutePath && !URI_FUNC(HasHost)(uri) && (uri->pathHead != NULL)
762
0
        && (uri->pathHead->next == NULL)
763
0
        && (uri->pathHead->text.first == uri->pathHead->text.afterLast)) {
764
0
        memory->free(memory, uri->pathHead);
765
0
        uri->pathHead = NULL;
766
        uri->pathTail = NULL;
767
0
    }
768
0
}
Unexecuted instantiation: uriFixEmptyTrailSegmentA
Unexecuted instantiation: uriFixEmptyTrailSegmentW
769
770
#endif