Skip to content

Commit c45b2be

Browse files
Optimize string allocation in uri_parser_rfc3986 when getting IPv6 hosts and url paths (#21550)
Co-authored-by: Tim Düsterhus <timwolla@googlemail.com>
1 parent 5bb980b commit c45b2be

File tree

2 files changed

+31
-13
lines changed

2 files changed

+31
-13
lines changed

UPGRADING

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,5 +264,8 @@ PHP 8.6 UPGRADE NOTES
264264
. Improved performance of intval('+0b...', 2) and intval('0b...', 2).
265265
. Improved performance of str_split().
266266

267+
- URI:
268+
. Reduced allocations when reading RFC3986 IPv6/IPFuture hosts and paths.
269+
267270
- Zip:
268271
. Avoid string copies in ZipArchive::addFromString().

ext/uri/uri_parser_rfc3986.c

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -237,13 +237,12 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_host_read(void
237237
if (has_text_range(&uriparser_uri->hostText)) {
238238
if (uriparser_uri->hostData.ip6 != NULL || uriparser_uri->hostData.ipFuture.first != NULL) {
239239
/* the textual representation of the host is always accessible in the .hostText field no matter what the host is */
240-
smart_str host_str = {0};
241-
242-
smart_str_appendc(&host_str, '[');
243-
smart_str_appendl(&host_str, uriparser_uri->hostText.first, get_text_range_length(&uriparser_uri->hostText));
244-
smart_str_appendc(&host_str, ']');
245-
246-
ZVAL_NEW_STR(retval, smart_str_extract(&host_str));
240+
zend_string *host_str = zend_string_concat3(
241+
"[", 1,
242+
uriparser_uri->hostText.first, get_text_range_length(&uriparser_uri->hostText),
243+
"]", 1
244+
);
245+
ZVAL_NEW_STR(retval, host_str);
247246
} else {
248247
ZVAL_STRINGL(retval, uriparser_uri->hostText.first, get_text_range_length(&uriparser_uri->hostText));
249248
}
@@ -349,20 +348,36 @@ ZEND_ATTRIBUTE_NONNULL static zend_result php_uri_parser_rfc3986_path_read(void
349348
const UriUriA *uriparser_uri = get_uri_for_reading(uri, read_mode);
350349

351350
if (uriparser_uri->pathHead != NULL) {
352-
smart_str str = {0};
351+
size_t total_len = 0;
352+
const bool need_leading_slash = uriparser_uri->absolutePath || uriHasHostA(uriparser_uri);
353+
354+
if (need_leading_slash) {
355+
total_len++;
356+
}
357+
358+
for (const UriPathSegmentA *p = uriparser_uri->pathHead; p; p = p->next) {
359+
total_len += get_text_range_length(&p->text);
360+
if (p->next) {
361+
total_len++;
362+
}
363+
}
364+
365+
zend_string *str = zend_string_alloc(total_len, false);
366+
char *out = ZSTR_VAL(str);
353367

354-
if (uriparser_uri->absolutePath || uriHasHostA(uriparser_uri)) {
355-
smart_str_appendc(&str, '/');
368+
if (need_leading_slash) {
369+
*(out++) = '/';
356370
}
357371

358372
for (const UriPathSegmentA *p = uriparser_uri->pathHead; p; p = p->next) {
359-
smart_str_appendl(&str, p->text.first, get_text_range_length(&p->text));
373+
out = zend_mempcpy(out, p->text.first, get_text_range_length(&p->text));
360374
if (p->next) {
361-
smart_str_appendc(&str, '/');
375+
*(out++) = '/';
362376
}
363377
}
364378

365-
ZVAL_NEW_STR(retval, smart_str_extract(&str));
379+
*out = '\0';
380+
ZVAL_NEW_STR(retval, str);
366381
} else if (uriparser_uri->absolutePath) {
367382
ZVAL_CHAR(retval, '/');
368383
} else {

0 commit comments

Comments
 (0)