Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,8 @@ PHP NEWS
. Fixed handling of port numbers > 65535 with the internal
`php_uri_parse_to_struct()` API. (timwolla)
. Fix Uri\WhatWg\Url::withHost(). (timwolla)
. Fixed bug GH-19944 (validate Uri\WhatWg\Url::withPort() boundaries).
(alexandre-daubois)

- Windows:
. Fix GH-19722 (_get_osfhandle asserts in debug mode when given a socket).
Expand Down
43 changes: 43 additions & 0 deletions ext/uri/tests/gh19944.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
--TEST--
GH-19944 (Uri\WhatWg\Url withPort boundaries validation)
--EXTENSIONS--
uri
--FILE--
<?php

try {
$result = new \Uri\WhatWg\Url('https://example.com:432')->withPort(-1)->toAsciiString();
echo "ERROR: Expected exception but got: " . $result . "\n";
} catch (Uri\WhatWg\InvalidUrlException $e) {
echo "EXPECTED: " . $e->getMessage() . "\n";
var_dump($e->errors[0]->type === \Uri\WhatWg\UrlValidationErrorType::PortOutOfRange);
}

try {
new \Uri\WhatWg\Url('https://example.com')->withPort(65536);
echo "ERROR: Expected exception for 65536\n";
} catch (Uri\WhatWg\InvalidUrlException $e) {
echo "Expected exception for 65536\n";
}

try {
$url = new \Uri\WhatWg\Url('https://example.com')->withPort(0);
echo "Port 0 works: " . $url->getPort() . "\n";

$url = new \Uri\WhatWg\Url('https://example.com')->withPort(65535);
echo "Port 65535 works: " . $url->getPort() . "\n";

$url = new \Uri\WhatWg\Url('https://example.com')->withPort(null);
var_dump($url->getPort());
} catch (Exception $e) {
echo "ERROR: Valid ports failed: " . $e->getMessage() . "\n";
}

?>
--EXPECT--
EXPECTED: The specified port is malformed (PortOutOfRange)
bool(true)
Expected exception for 65536
Port 0 works: 0
Port 65535 works: 65535
NULL
52 changes: 52 additions & 0 deletions ext/uri/uri_parser_whatwg.c
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,26 @@ static const char *fill_errors(zval *errors)
return result;
}

static void create_port_out_of_range_error(zval *error_array, const char *context)
{
array_init(error_array);

zval error;
object_init_ex(&error, php_uri_ce_whatwg_url_validation_error);
zend_update_property_string(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZEND_STRL("context"), context);

zval error_type;
zend_object *enum_obj = zend_enum_get_case_cstr(php_uri_ce_whatwg_url_validation_error_type, "PortOutOfRange");
ZVAL_OBJ(&error_type, enum_obj);
zend_update_property(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZEND_STRL("type"), &error_type);

zval failure;
ZVAL_TRUE(&failure);
zend_update_property(php_uri_ce_whatwg_url_validation_error, Z_OBJ(error), ZEND_STRL("failure"), &failure);

add_index_zval(error_array, 0, &error);
}

static void throw_invalid_url_exception_during_write(zval *errors, const char *component)
{
zval err;
Expand All @@ -236,6 +256,27 @@ static void throw_invalid_url_exception_during_write(zval *errors, const char *c
}
}

static void throw_port_out_of_range_exception(zval *errors, const char *context)
{
zval err;
create_port_out_of_range_error(&err, context);

zend_object *exception = zend_throw_exception_ex(
php_uri_ce_whatwg_invalid_url_exception,
0,
"The specified %s is malformed (PortOutOfRange)",
"port"
);

zend_update_property(exception->ce, exception, ZEND_STRL("errors"), &err);
if (errors) {
zval_ptr_dtor(errors);
ZVAL_COPY_VALUE(errors, &err);
} else {
zval_ptr_dtor(&err);
}
}

static lxb_status_t serialize_to_smart_str_callback(const lxb_char_t *data, size_t length, void *ctx)
{
smart_str *uri_str = ctx;
Expand Down Expand Up @@ -410,6 +451,17 @@ static zend_result php_uri_parser_whatwg_port_write(void *uri, zval *value, zval
lxb_url_t *lexbor_uri = uri;
lexbor_str_t str = {0};

if (Z_TYPE_P(value) == IS_LONG) {
zend_long port = Z_LVAL_P(value);
if (port < 0 || port > 65535) {
char context[32];
snprintf(context, sizeof(context), ZEND_LONG_FMT, port);
throw_port_out_of_range_exception(errors, context);

return FAILURE;
}
}

zval_long_or_null_to_lexbor_str(value, &str);

if (lxb_url_api_port_set(lexbor_uri, &lexbor_parser, str.data, str.length) != LXB_STATUS_OK) {
Expand Down