Skip to content

Implement "Followup improvements for ext/uri" RFC - WHATWG URL building - #22268

Open
kocsismate wants to merge 8 commits into
php:masterfrom
kocsismate:uri-followup4
Open

Implement "Followup improvements for ext/uri" RFC - WHATWG URL building#22268
kocsismate wants to merge 8 commits into
php:masterfrom
kocsismate:uri-followup4

Conversation

@kocsismate

Copy link
Copy Markdown
Member

@kocsismate
kocsismate requested a review from TimWolla as a code owner June 10, 2026 15:10
@kocsismate kocsismate changed the title IImplement "Followup improvements for ext/uri" RFC - WHATWG URL building Implement "Followup improvements for ext/uri" RFC - WHATWG URL building Jun 10, 2026
@kocsismate
kocsismate marked this pull request as draft June 10, 2026 16:12
goto failure;
}

if (lexbor_base_url != NULL) {

@kocsismate kocsismate Jun 25, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's a big shame is that apparently it's not possible to properly use the builder with a base URL :(

  • if we try to add the base URL after the input URL is built, then legitimate relative URLs are rejected (e.g. /foo + https://example.com), because /foo is not a valid URL on its own
  • If we try to build the input URL with the base URL in the same time, then the parsing algorithm must be used (currently, only setters are used with a hack on line 821). Then the complication is to find some URL component that is suitable for parsing:
    • for special, full URLs: scheme + host is needed at least (e.g. https://example.com)
    • for non-special full URLs: scheme is needed at least (e.g. https://)
    • for relative URLs: the path is needed at least (e.g. /foo/bar)

And in the 2nd case, the question arises if it's ok to parse only the minimally required components and then set the rest of the components, or the whole input URL must be built and parsed all at once.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have limited knowledge of lexbor, but can we build a string out of the components we have in the builder, and then call the parser with that? Assuming that we can build the string unambiguously, any errors from missing components would be reported by the parser.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the idea! Unfortunately, - as far as I can see the situation - the main blocker is achiveving unambiguous recomposition. E.g.

$builder = new Uri\WhatWg\UrlBuilder();
$builder->setScheme("git");
$builder->setPath("//refs/heads/main");
$builder->build();

This would be recomposed as git://refs/heads/main, however it should rather be git:////refs/heads/main. So overall, we would end up reimplementing the WHATWG URL spec to prevent some cases. Since it's very long specification with a lot of special cases, I wouldn't even dare to attempt this. :(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just brainstorming, but would that work?

  • base = parse base url
  • url = clone base
  • for each component in builder:
    • lxb_url_parse_basic(..., url, base, ..., override_state, ...) (with override_state the state corresponding to this component, e.g. LXB_URL_STATE_PATH_START_STATE for the path)

@kocsismate
kocsismate marked this pull request as ready for review June 25, 2026 08:19
@kocsismate
kocsismate requested a review from ndossche June 25, 2026 13:32
@kocsismate

Copy link
Copy Markdown
Member Author

May I have a review soon so that this can potentially be included into alpha 2 at least? :)

Comment thread ext/uri/php_uri.c Outdated
Comment thread ext/uri/uri_parser_whatwg.c
Comment thread ext/uri/uri_parser_whatwg.c Outdated
Comment thread ext/uri/uri_parser_whatwg.c Outdated
* The URL is initialized as LXB_URL_SCHEMEL_TYPE__UNDEF but this would prevent the scheme to be updated
* in case of non-special schemes due to https://github.com/php/php-src/blob/27d7b799c0a13578ee0506b428b8ddc209ffb010/ext/lexbor/lexbor/url/url.c#L1402
*/
if (!php_uri_parser_whatwg_is_special_scheme(scheme)) {

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll try to check if it's something that we can omit somehow...

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't find any way how this workaround could be eliminated...

Comment thread ext/uri/php_uri.c
Comment thread ext/uri/uri_parser_whatwg.c Outdated
Comment thread ext/uri/uri_parser_whatwg.c Outdated

@TimWolla TimWolla left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had a very superficial first look.

Comment thread ext/uri/uri_parser_whatwg.c Outdated
Comment thread ext/uri/uri_parser_whatwg.c Outdated
Comment thread ext/uri/uri_parser_whatwg.c
@TimWolla
TimWolla self-requested a review July 17, 2026 18:25

@TimWolla TimWolla left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looked at some tests and some of the C files. Not yet through the PR, but you can likely already make some changes in response to this review.

Comment thread ext/uri/uri_parser_whatwg.c Outdated
Comment thread ext/uri/tests/whatwg/builder/scheme_error_c0_control_space_char.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/scheme_error_empty_string.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/scheme_success_non_special.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/username_error_missing_host.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/username_success_empty_opaque_host.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/fragment_error_unicode_char.phpt Outdated

@TimWolla TimWolla left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went through all tests now. Didn't deeply look at the C code yet, but I'm not super stoked about needing to reimplement the component validation ourselves.

Comment thread ext/uri/tests/whatwg/builder/fragment_success_tab_newline.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/host_error_ipv6_closing_brace_opaque.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/host_error_percent_encoding3.phpt
Comment thread ext/uri/tests/whatwg/builder/password_error_empty_opaque_host.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/port_success_default.phpt Outdated
Comment thread ext/uri/tests/whatwg/builder/port_success_non_default.phpt Outdated
$builder->setHost("example.com");
$builder->setFragment("\tfoo");
$errors = [];
$url = $builder->build(errors: $errors);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this is the only test testing $errors.

Comment thread ext/uri/tests/whatwg/builder/username_success_special_char.phpt
Comment thread ext/uri/uri_parser_whatwg.c Outdated

@arnaud-lb arnaud-lb left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've only done a partial review yet

Comment thread ext/uri/php_uri.c Outdated
kocsismate added a commit to kocsismate/php-src that referenced this pull request Aug 8, 2026
kocsismate added a commit that referenced this pull request Aug 10, 2026
lexborisov added a commit to lexbor/lexbor that referenced this pull request Aug 12, 2026
Added lxb_url_parse_host_ipv6() — a public entry point to the IPv6
parser from the WHATWG specification:
https://url.spec.whatwg.org/#concept-ipv6-parser

The address is accepted both with and without the surrounding square
brackets: "::1" and "[::1]" give the same result.

#402

The API was requested in #402 for use by php/php-src#22268.

Suggested-by: Máté Kocsis (@kocsismate)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants