Skip to content

Commit fb1370d

Browse files
committed
src/UriNormalize.c: Normalize IPv6 addresses
1 parent 41a7e68 commit fb1370d

4 files changed

Lines changed: 103 additions & 106 deletions

File tree

src/UriNormalize.c

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,6 +573,64 @@ static void URI_FUNC(AdvancePastLeadingZeros)(
573573
*first = remainderFirst;
574574
}
575575

576+
static int URI_FUNC(NormalizeIpv6)(URI_CHAR * dest, const UriIp6 *ip6) {
577+
int start = -1;
578+
int end = -1;
579+
for (int i = 0; i < 16; i += 2) {
580+
if (ip6->data[i] > 0) {
581+
continue;
582+
}
583+
int j = i;
584+
for (; j < 16; j++) {
585+
if (ip6->data[j] > 0) {
586+
break;
587+
}
588+
}
589+
if ((j % 2) == 1) {
590+
j--;
591+
}
592+
593+
if (start == -1 || (j - i) > (end - start)) {
594+
start = i;
595+
end = j;
596+
}
597+
i = j;
598+
}
599+
600+
int written = 0;
601+
for (int i = 0; i < 16; i += 2) {
602+
if ((i > 0 && !(i > start && i < end)) || (i == 0 && start == 0) || (i == 14 && end == 16)) {
603+
memcpy(dest + written, _UT(":"), 1 * sizeof(URI_CHAR));
604+
written++;
605+
}
606+
607+
if (i >= start && i < end) {
608+
continue;
609+
}
610+
611+
const uint16_t value = (ip6->data[i] << 8) + ip6->data[i + 1];
612+
size_t length = 1 + (value > 0xf) + (value > 0xff) + (value > 0xfff);
613+
614+
if (value > 0xfff) {
615+
dest[written++] = URI_FUNC(HexToLetterEx)(
616+
(value >> 12) & 0xf, URI_FALSE);
617+
}
618+
if (value > 0xff) {
619+
dest[written++] = URI_FUNC(HexToLetterEx)(
620+
(value >> 8) & 0xf, URI_FALSE);
621+
}
622+
if (value > 0xf) {
623+
dest[written++] = URI_FUNC(HexToLetterEx)(
624+
(value >> 4) & 0xf, URI_FALSE);
625+
}
626+
dest[written++] = URI_FUNC(HexToLetterEx)(
627+
(value >> 0) & 0xf, URI_FALSE);
628+
}
629+
dest[written] = _UT('\0');
630+
631+
return written;
632+
}
633+
576634
static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
577635
unsigned int inMask, unsigned int * outMask, UriMemoryManager * memory) {
578636
unsigned int revertMask = URI_NORMALIZED;
@@ -609,7 +667,16 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
609667
*outMask |= URI_NORMALIZE_SCHEME;
610668
}
611669

612-
if (normalizeHostCase) {
670+
if (uri->hostData.ip6 != NULL) {
671+
URI_CHAR out[46];
672+
int length = URI_FUNC(NormalizeIpv6)(out, uri->hostData.ip6);
673+
if (
674+
(uri->hostText.afterLast - uri->hostText.first) != length
675+
|| URI_STRNCMP(out, uri->hostText.first, length) != 0
676+
) {
677+
*outMask |= URI_NORMALIZE_HOST;
678+
}
679+
} else if (normalizeHostCase) {
613680
*outMask |= URI_NORMALIZE_HOST;
614681
} else {
615682
const UriBool normalizeHostPrecent = URI_FUNC(ContainsUglyPercentEncoding)(
@@ -635,7 +702,25 @@ static URI_INLINE int URI_FUNC(NormalizeSyntaxEngine)(URI_TYPE(Uri) * uri,
635702

636703
/* Host */
637704
if (inMask & URI_NORMALIZE_HOST) {
638-
if (uri->hostData.ipFuture.first != NULL) {
705+
if (uri->hostData.ip6 != NULL) {
706+
URI_CHAR out[46];
707+
int lenInChars = URI_FUNC(NormalizeIpv6)(out, uri->hostData.ip6);
708+
if (uri->owner) {
709+
memory->free(memory, (URI_CHAR *)uri->hostText.first);
710+
uri->hostText.first = NULL;
711+
uri->hostText.afterLast = NULL;
712+
}
713+
URI_CHAR * buffer = memory->malloc(memory, lenInChars * sizeof(URI_CHAR));
714+
if (buffer == NULL) {
715+
URI_FUNC(PreventLeakage)(uri, revertMask, memory);
716+
return URI_ERROR_MALLOC;
717+
}
718+
memcpy(buffer, out, lenInChars * sizeof(URI_CHAR));
719+
uri->hostText.first = buffer;
720+
uri->hostText.afterLast = buffer + lenInChars;
721+
722+
revertMask |= URI_NORMALIZE_HOST;
723+
} else if (uri->hostData.ipFuture.first != NULL) {
639724
/* IPvFuture */
640725
if (uri->owner) {
641726
URI_FUNC(LowercaseInplace)(uri->hostData.ipFuture.first,

src/UriRecompose.c

Lines changed: 7 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -310,103 +310,13 @@ static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(U
310310
(*charsRequired) += charsToWrite + extra;
311311
}
312312
}
313-
} else if (uri->hostData.ip6 != NULL) {
314-
/* IPv6 */
315-
int i = 0;
316-
if (dest != NULL) {
317-
if (written + 1 <= maxChars) {
318-
memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR));
319-
written += 1;
320-
} else {
321-
dest[0] = _UT('\0');
322-
if (charsWritten != NULL) {
323-
*charsWritten = 0;
324-
}
325-
return URI_ERROR_TOSTRING_TOO_LONG;
326-
}
327-
} else {
328-
// Detect and avoid integer overflow
329-
if (1 > (size_t)INT_MAX - *charsRequired) {
330-
return URI_ERROR_TOSTRING_TOO_LONG;
331-
}
332-
333-
(*charsRequired) += 1;
334-
}
335-
336-
for (; i < 16; i++) {
337-
const unsigned char value = uri->hostData.ip6->data[i];
338-
if (dest != NULL) {
339-
if (written + 2 <= maxChars) {
340-
URI_CHAR text[3];
341-
text[0] = URI_FUNC(HexToLetterEx)(
342-
value / 16, URI_FALSE);
343-
text[1] = URI_FUNC(HexToLetterEx)(
344-
value % 16, URI_FALSE);
345-
text[2] = _UT('\0');
346-
memcpy(dest + written, text, 2 * sizeof(URI_CHAR));
347-
written += 2;
348-
} else {
349-
dest[0] = _UT('\0');
350-
if (charsWritten != NULL) {
351-
*charsWritten = 0;
352-
}
353-
return URI_ERROR_TOSTRING_TOO_LONG;
354-
}
355-
} else {
356-
// Detect and avoid integer overflow
357-
if (2 > (size_t)INT_MAX - *charsRequired) {
358-
return URI_ERROR_TOSTRING_TOO_LONG;
359-
}
360-
361-
(*charsRequired) += 2;
362-
}
363-
if (((i & 1) == 1) && (i < 15)) {
364-
if (dest != NULL) {
365-
if (written + 1 <= maxChars) {
366-
memcpy(dest + written, _UT(":"),
367-
1 * sizeof(URI_CHAR));
368-
written += 1;
369-
} else {
370-
dest[0] = _UT('\0');
371-
if (charsWritten != NULL) {
372-
*charsWritten = 0;
373-
}
374-
return URI_ERROR_TOSTRING_TOO_LONG;
375-
}
376-
} else {
377-
// Detect and avoid integer overflow
378-
if (1 > (size_t)INT_MAX - *charsRequired) {
379-
return URI_ERROR_TOSTRING_TOO_LONG;
380-
}
381-
382-
(*charsRequired) += 1;
383-
}
384-
}
385-
}
386-
387-
if (dest != NULL) {
388-
if (written + 1 <= maxChars) {
389-
memcpy(dest + written, _UT("]"), 1 * sizeof(URI_CHAR));
390-
written += 1;
391-
} else {
392-
dest[0] = _UT('\0');
393-
if (charsWritten != NULL) {
394-
*charsWritten = 0;
395-
}
396-
return URI_ERROR_TOSTRING_TOO_LONG;
397-
}
398-
} else {
399-
// Detect and avoid integer overflow
400-
if (1 > (size_t)INT_MAX - *charsRequired) {
401-
return URI_ERROR_TOSTRING_TOO_LONG;
402-
}
403-
404-
(*charsRequired) += 1;
405-
}
406-
} else if (uri->hostData.ipFuture.first != NULL) {
313+
} else if (
314+
uri->hostData.ip6 != NULL
315+
|| uri->hostData.ipFuture.first != NULL
316+
) {
407317
/* IPvFuture */
408-
const size_t charsToWrite = uri->hostData.ipFuture.afterLast
409-
- uri->hostData.ipFuture.first;
318+
const size_t charsToWrite = uri->hostText.afterLast
319+
- uri->hostText.first;
410320
if (dest != NULL) {
411321
if (written + 1 <= maxChars) {
412322
memcpy(dest + written, _UT("["), 1 * sizeof(URI_CHAR));
@@ -430,7 +340,7 @@ static URI_INLINE int URI_FUNC(ToStringEngine)(URI_CHAR * dest, const URI_TYPE(U
430340
return URI_ERROR_TOSTRING_TOO_LONG;
431341
}
432342

433-
memcpy(dest + written, uri->hostData.ipFuture.first,
343+
memcpy(dest + written, uri->hostText.first,
434344
charsToWrite * sizeof(URI_CHAR));
435345
written += charsToWrite;
436346
} else {

test/SetHostAuto.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ TEST(SetHostAuto, NonNullValueAppliedNonEmptyIp6) {
165165

166166
EXPECT_EQ(uriSetHostAutoA(&uri, first, afterLast), URI_SUCCESS);
167167

168-
assertUriEqual(&uri, "scheme://[0000:0000:0000:0000:0000:0000:0000:0001]/path");
168+
assertUriEqual(&uri, "scheme://[::1]/path");
169169

170170
uriFreeUriMembersA(&uri);
171171
}

test/SetHostIp6.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -294,7 +294,7 @@ TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorNull) {
294294

295295
EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
296296

297-
assertUriEqual(&uri, "scheme://[0000:0000:0000:0000:0000:0000:0000:0001]");
297+
assertUriEqual(&uri, "scheme://[::1]");
298298

299299
uriFreeUriMembersA(&uri);
300300
}
@@ -306,7 +306,9 @@ TEST(SetHostIp6, MutationTesting) {
306306

307307
EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
308308

309-
assertUriEqual(&uri, "scheme://[0001:0023:0456:7890:0000:0000:052b:db00]");
309+
assertUriEqual(&uri, "scheme://[1:23:456:7890::5.43.219.0]");
310+
uriNormalizeSyntaxA(&uri);
311+
assertUriEqual(&uri, "scheme://[1:23:456:7890::52b:db00");
310312

311313
uriFreeUriMembersA(&uri);
312314
}
@@ -318,7 +320,7 @@ TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIp4) {
318320

319321
EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
320322

321-
assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]");
323+
assertUriEqual(&uri, "//[::1]");
322324

323325
uriFreeUriMembersA(&uri);
324326
}
@@ -330,7 +332,7 @@ TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIp6) {
330332

331333
EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
332334

333-
assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0002]");
335+
assertUriEqual(&uri, "//[::2]");
334336

335337
uriFreeUriMembersA(&uri);
336338
}
@@ -342,7 +344,7 @@ TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorIpFuture) {
342344

343345
EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
344346

345-
assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]");
347+
assertUriEqual(&uri, "//[::1]");
346348

347349
uriFreeUriMembersA(&uri);
348350
}
@@ -354,7 +356,7 @@ TEST(SetHostIp6, NonNullValueAppliedNonEmptyPriorRegName) {
354356

355357
EXPECT_EQ(uriSetHostIp6A(&uri, first, afterLast), URI_SUCCESS);
356358

357-
assertUriEqual(&uri, "//[0000:0000:0000:0000:0000:0000:0000:0001]");
359+
assertUriEqual(&uri, "//[::1]");
358360

359361
uriFreeUriMembersA(&uri);
360362
}

0 commit comments

Comments
 (0)