Implement "Followup improvements for ext/uri" RFC - URL building with base URL - #23526
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 ^^
|
@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. |
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. |
2850224 to
ec0eaf3
Compare
Oh right, thanks for noticing it again. There was an existing test for this case with incorrect expectation. Now, it should be fixed 🤔 I hope there aren't more edge cases which I missed. |
|
@kocsismate I was able to fix a couple of discrepancies in my polyfill and now I have the same results as yours for the For $builder = new Uri\WhatWg\UrlBuilder();
$builder->setScheme("foo");
$url = $builder->build();
var_dump($url->toAsciiString());
var_dump($url);
var_dump($url->equals(new Uri\WhatWg\Url($url->toAsciiString())));Currently the test expects My implementations always populates the That's all... for now 😉 |
|
Thanks, Ignace, for the tests! I can confirm that this case is a real issue. And I found a couple of other edge cases (e.g. empty string for query/fragment. Regarding, the |
|
Submitted #23636 to fix the incompatibilites with parsing + some other bugs. |
ec0eaf3 to
3ab79ce
Compare
… 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().
Collect soft errors on success and attach earlier errors to validation exceptions. Reset the output on error-free success and avoid freeing it twice after a failed reference assignment.
Inherit the entire base authority when none is supplied, and reuse normal URL building for a replacement authority. This preserves credential encoding and normalized host validation without inheriting unrelated base components.
Use reference resolution for relative paths while keeping path delimiters inside the component. Preserve file drive handling, clear inherited fragments, and inherit the query only for an empty path.
Reject empty references, new authorities and query references against opaque bases. Keep fragment-only references working after tab and newline removal.
3ab79ce to
70c4c10
Compare
|
Small bug: <?php
$u = (new Uri\WhatWg\UrlBuilder())->setPath("D:/c")->build(new Uri\WhatWg\Url("file:///C:/a/b"));
var_dump($u->toAsciiString()); // string(12) "file:///D:/c"
var_dump($u->withPath("/q")->toAsciiString()); // string(12) "file:///D:/c", but expected "file:///q"Seems to be because |
| (lxb_char_t *) Z_STRVAL_P(query), Z_STRLEN_P(query), | ||
| LXB_URL_STATE_QUERY_STATE, LXB_ENCODING_AUTO | ||
| ); | ||
| php_uri_parser_whatwg_build_errors_and_throw(status, "query", &errors); |
There was a problem hiding this comment.
It seems that the term "query" and "query string" are used mixed in this file.
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).