Implement "Followup improvements for ext/uri" RFC - URL building with base URL - #23526
Implement "Followup improvements for ext/uri" RFC - URL building with base URL#23526kocsismate wants to merge 2 commits into
Conversation
| } | ||
| } | ||
|
|
||
| ZEND_ATTRIBUTE_NONNULL_ARGS(1, 2, 3, 4, 5, 6, 7, 8, 9) lxb_url_t *php_uri_parser_whatwg_resolve_reference_from_zval( |
There was a problem hiding this comment.
Overall, this code below is pretty much hacky, works coincidentally, and to be honest I wish it wouldn't exist. 😅 On the other hand, it gets the job done! So thank you @arnaud-lb for the suggestion, your idea works indeed :) I would have never thought about it.
Due to the above mentioned implementation difficulties though, IMO we should prioritize if the feature is worth more or the sanity of our code ^^
| string(4) "user" | ||
| ["password"]=> | ||
| string(4) "pass" |
There was a problem hiding this comment.
Is this right? In #22268 (comment) you mention parsing rules. Resolving //example.net:124/foo/bar/baz drops user:pass. Are they here intentionally preserved? How is the builder generally supposed to work? From the RFC, your comments, and this test here it's not really clear to me what's actually intended behaviour. Like, generally, should this resolve the builder components against the base like parsing or replace the defined components of the base and keep the rest?
There was a problem hiding this comment.
Thanks for catching this. This was due to a small oversight in the implementation: the username and password should have been removed. it's going to be fixed with my new push.
|
@kocsismate is the following expected? ### Rfc3986
$builder = new Uri\Rfc3986\UriBuilder();
$builder->setPort(123);
try {
var_dump($builder->build(new Uri\Rfc3986\Uri("https://example.com"))->toAsciiString());
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
// Uri\InvalidUriException: Cannot set a port without having a host
### WhatWg
$builder = new Uri\WhatWg\UrlBuilder();
$builder->setPort(123);
try {
var_dump($builder->build(new Uri\WhatWg\Url("https://example.com"))->toAsciiString());
} catch (Throwable $e) {
echo $e::class, ': ', $e->getMessage(), "\n";
}
// string(24) "https://example.com:123/"I would expect RFC3986 to behave like WHATWG here. While trying to come up with tests for here and some more for #23342 I got stuck one way or another. The follow up RFC does not really spell out what the merging behaviour should be. The discussion and comments point towards resolution, but that also does not seem to be how everything consistently works? For me it seems like WHATWG behaves sanely in the example above and RFC3986 does not, but then there are situations where WHATWG seems wrong too: A) see above; B) setting a fragment drops the query; C) fragments are appended instead of replaced; D) setting a username without a host results in Possible that I am having a dumb day, but I cannot really make sense of what the expected behaviour is. Could you please clarify how both RFC3986 and WHATWG are supposed to merge with a base URI/URL? Must the builder components form a valid reference on their own before resolving or can the base provide missing parts like the host? Would love to add some tests to lock in the findings, but I really could use a hint first. |
… base URL RFC: https://wiki.php.net/rfc/uri_followup#uri_building Add support for passing a non-null $baseUrl parameter for Uri\WhatWg\UrlBuilder::build().
07a63c7 to
9ca23f1
Compare
9ca23f1 to
2850224
Compare
Ah no, it should be the other way around, and this was also due to a small ordering issue in the builder's code. The merging behavior should be the very same what is done during parsing. E.g. For each
(Given that the resulting The same goes for RFC 3986.
Answered above.
Can you please elaborate upon this?
Ah, this is an "annoying" behavior of the WHATWG URL spec (because our use-case is not really supported by the spec). That's why I had to add e.g. D) setting a username without a host results in https://example.comnew/a; and more. This is the same category as A, and it's fixed with the code reordering. |
I see why it is. But it also makes it very restrictive and rather surprising for "normal" usage. Like, not being able to append a port is kinda unfortunate. But fair enough. Having some way to have "component overlays" would be neat. Like, how I expected it - just to replace/append/remove from a given URL. Probably that's something for the future, maybe
I believe it was: $base = https://example.com/a?old"
$builder->setFragment("new");
$builder->build($base); // https://example.com/a#newBut I will need to double check tomorrow. |
RFC: https://wiki.php.net/rfc/uri_followup#uri_building
Add support for passing a non-null $baseUrl parameter for Uri\WhatWg\UrlBuilder::build().
This PR is not complete yet (tests are missing).