Skip to content

Conversation

kocsismate
Copy link
Member

No description provided.

Comment on lines +102 to +107
ZEND_ATTRIBUTE_NONNULL static UriUriA *get_uri_for_writing(uri_internal_t *internal_uri)
{
php_uri_parser_rfc3986_uris *uriparser_uris = internal_uri->uri;

return &uriparser_uris->uri;
}
Copy link
Member

Choose a reason for hiding this comment

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

From what I see, the implementation now has exactly the bug that #19588 was supposed to avoid: You are not resetting the normalized URI when writing and during cloning the normalized URI is cloned.

Consider this test case:

<?php

$uri = \Uri\Rfc3986\Uri::parse('https://example.com/path-%65xample/');
var_dump($uri->getPath());
var_dump($uri->getRawPath());

$newUri = $uri->withPath('/updated-path');
var_dump($newUri->getPath());
var_dump($newUri->getRawPath());

Comment on lines +290 to +311
ZVAL_STR(value, zend_long_to_str(Z_LVAL_P(value)));
result = uriSetPortTextMmA(uriparser_uri, Z_STRVAL_P(value), Z_STRVAL_P(value) + Z_STRLEN_P(value), mm);
Copy link
Member

Choose a reason for hiding this comment

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

Storing the stringified long into the zval, just to pull it out of the zval sounds like a needless layer of indirection. You can just store it as a zend_string * directly. You are also modifying the value of the zval which can have unintended consequences.

This is also leaking memory. See this example:

<?php

$uri = \Uri\Rfc3986\Uri::parse('https://example.com/');
$port = 123;
$newUri = $uri->withPort($port);
var_dump($newUri, $port);

}

if (result != URI_SUCCESS) {
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified port is malformed", 0);
Copy link
Member

Choose a reason for hiding this comment

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

There is URI_ERROR_SETPORT_HOST_NOT_SET as a port-specific error code, that we should handle to output a better message:

Suggested change
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified port is malformed", 0);
switch (result) {
case URI_SUCCESS:
return SUCCESS;
case URI_ERROR_SETPORT_HOST_NOT_SET:
zend_throw_exception(uri_invalid_uri_exception_ce, "Cannot set a port without having a host", 0);
return FAILURE;
default:
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified port is malformed", 0);
return FAILURE;
}

The same applies for the other error codes that have a special meaning.

return &uriparser_uris->uri;
}

ZEND_ATTRIBUTE_NONNULL static void reset_normalized_uri_after_writing(uri_internal_t *internal_uri)
Copy link
Member

Choose a reason for hiding this comment

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

Having a separate method for this is risky (it's easy to forget to call it). I would suggest one of two options:

  • Do not clone the normalized URI, as I did in uri: Do not copy the normalized URI when cloning RFC 3986 URIs #19588: This is likely the most performant solution when expecting that most URIs are modified after being cloned.
  • Reset the normalized URI in get_uri_for_writing(): We expect the modification to succeed in most cases, in the worst case we're needlessly invalidating the normalized URI and it will just get renormalized.

Both options would reliably fix the issue and leave little room for human error in the implementation.

@nielsdos
Copy link
Member

It's probably best to commit the uriparser changes separately and base the PHP changes off on top of that.

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.

3 participants