Skip to content

Commit 5f00673

Browse files
authored
uri: Fix handling of large port numbers in URI struct (#19905)
* uri: Fix handling of large port numbers in URI struct * uri: Explain the choice of type for `php_uri.port` * NEWS
1 parent c7485a0 commit 5f00673

File tree

7 files changed

+153
-5
lines changed

7 files changed

+153
-5
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ PHP NEWS
5959
conditions. (timwolla)
6060
. Further clean up the internal API. (timwolla)
6161
. Fixed bug GH-19892 (Refcounting on zend_empty_array). (ilutov, timwolla)
62+
. Fixed handling of port numbers > 65535 with the internal
63+
`php_uri_parse_to_struct()` API. (timwolla)
6264

6365
- Windows:
6466
. Fix GH-19722 (_get_osfhandle asserts in debug mode when given a socket).

ext/standard/ftp_fopen_wrapper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ static php_stream *php_ftp_fopen_connect(php_stream_wrapper *wrapper, const char
155155
if (resource->port == 0)
156156
resource->port = 21;
157157

158-
transport_len = (int)spprintf(&transport, 0, "tcp://%s:%d", ZSTR_VAL(resource->host), resource->port);
158+
transport_len = (int)spprintf(&transport, 0, "tcp://%s:" ZEND_LONG_FMT, ZSTR_VAL(resource->host), resource->port);
159159
stream = php_stream_xport_create(transport, transport_len, REPORT_ERRORS, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, NULL, context, NULL, NULL);
160160
efree(transport);
161161
if (stream == NULL) {

ext/standard/http_fopen_wrapper.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
446446
use_proxy = 1;
447447
transport_string = zend_string_copy(Z_STR_P(tmpzval));
448448
} else {
449-
transport_string = zend_strpprintf(0, "%s://%s:%d", use_ssl ? "ssl" : "tcp", ZSTR_VAL(resource->host), resource->port);
449+
transport_string = zend_strpprintf(0, "%s://%s:" ZEND_LONG_FMT, use_ssl ? "ssl" : "tcp", ZSTR_VAL(resource->host), resource->port);
450450
}
451451
}
452452

@@ -1083,7 +1083,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
10831083
header_info.location = NULL;
10841084
}
10851085
if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) {
1086-
spprintf(&new_path, 0, "%s://%s:%d%s", ZSTR_VAL(resource->scheme),
1086+
spprintf(&new_path, 0, "%s://%s:" ZEND_LONG_FMT "%s", ZSTR_VAL(resource->scheme),
10871087
ZSTR_VAL(resource->host), resource->port, loc_path);
10881088
} else {
10891089
spprintf(&new_path, 0, "%s://%s%s", ZSTR_VAL(resource->scheme),

ext/uri/php_uri.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ typedef struct php_uri {
2727
zend_string *user;
2828
zend_string *password;
2929
zend_string *host;
30-
unsigned short port;
30+
/* port is a zend_long to match the userland port getter, which
31+
* returns the port in zval. */
32+
zend_long port;
3133
zend_string *path;
3234
zend_string *query;
3335
zend_string *fragment;

ext/uri/tests/100.phpt

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var_dump(zend_test_uri_parser("https://%65xample:%65xample@%65xample.com:123/%65
1010

1111
?>
1212
--EXPECT--
13-
array(2) {
13+
array(3) {
1414
["normalized"]=>
1515
array(8) {
1616
["scheme"]=>
@@ -49,4 +49,23 @@ array(2) {
4949
["fragment"]=>
5050
string(9) "%65xample"
5151
}
52+
["struct"]=>
53+
array(8) {
54+
["scheme"]=>
55+
string(5) "https"
56+
["username"]=>
57+
string(9) "%65xample"
58+
["password"]=>
59+
string(9) "%65xample"
60+
["host"]=>
61+
string(13) "%65xample.com"
62+
["port"]=>
63+
int(123)
64+
["path"]=>
65+
string(15) "/%65xample.html"
66+
["query"]=>
67+
string(19) "%65xample=%65xample"
68+
["fragment"]=>
69+
string(9) "%65xample"
70+
}
5271
}

ext/uri/tests/102.phpt

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
--TEST--
2+
Test the handling large ports for the uri struct
3+
--EXTENSIONS--
4+
uri
5+
zend_test
6+
--FILE--
7+
<?php
8+
9+
var_dump(zend_test_uri_parser("https://example.com:42424242", "Uri\\Rfc3986\\Uri"));
10+
11+
?>
12+
--EXPECT--
13+
array(3) {
14+
["normalized"]=>
15+
array(8) {
16+
["scheme"]=>
17+
string(5) "https"
18+
["username"]=>
19+
NULL
20+
["password"]=>
21+
NULL
22+
["host"]=>
23+
string(11) "example.com"
24+
["port"]=>
25+
int(42424242)
26+
["path"]=>
27+
string(0) ""
28+
["query"]=>
29+
NULL
30+
["fragment"]=>
31+
NULL
32+
}
33+
["raw"]=>
34+
array(8) {
35+
["scheme"]=>
36+
string(5) "https"
37+
["username"]=>
38+
NULL
39+
["password"]=>
40+
NULL
41+
["host"]=>
42+
string(11) "example.com"
43+
["port"]=>
44+
int(42424242)
45+
["path"]=>
46+
string(0) ""
47+
["query"]=>
48+
NULL
49+
["fragment"]=>
50+
NULL
51+
}
52+
["struct"]=>
53+
array(8) {
54+
["scheme"]=>
55+
string(5) "https"
56+
["username"]=>
57+
NULL
58+
["password"]=>
59+
NULL
60+
["host"]=>
61+
string(11) "example.com"
62+
["port"]=>
63+
int(42424242)
64+
["path"]=>
65+
string(0) ""
66+
["query"]=>
67+
NULL
68+
["fragment"]=>
69+
NULL
70+
}
71+
}

ext/zend_test/test.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -746,6 +746,11 @@ static ZEND_FUNCTION(zend_test_uri_parser)
746746
RETURN_THROWS();
747747
}
748748

749+
php_uri *uri_struct = php_uri_parse_to_struct(parser, ZSTR_VAL(uri_string), ZSTR_LEN(uri_string), PHP_URI_COMPONENT_READ_MODE_RAW, false);
750+
if (uri_struct == NULL) {
751+
RETURN_THROWS();
752+
}
753+
749754
zval value;
750755

751756
array_init(return_value);
@@ -787,7 +792,56 @@ static ZEND_FUNCTION(zend_test_uri_parser)
787792
php_uri_get_fragment(uri, PHP_URI_COMPONENT_READ_MODE_RAW, &value);
788793
zend_hash_add(Z_ARR(raw), ZSTR_KNOWN(ZEND_STR_FRAGMENT), &value);
789794
zend_hash_str_add(Z_ARR_P(return_value), "raw", strlen("raw"), &raw);
795+
zval from_struct;
796+
zval dummy;
797+
array_init(&from_struct);
798+
if (uri_struct->scheme) {
799+
ZVAL_STR_COPY(&dummy, uri_struct->scheme);
800+
} else {
801+
ZVAL_NULL(&dummy);
802+
}
803+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_SCHEME), &dummy);
804+
if (uri_struct->user) {
805+
ZVAL_STR_COPY(&dummy, uri_struct->user);
806+
} else {
807+
ZVAL_NULL(&dummy);
808+
}
809+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_USERNAME), &dummy);
810+
if (uri_struct->password) {
811+
ZVAL_STR_COPY(&dummy, uri_struct->password);
812+
} else {
813+
ZVAL_NULL(&dummy);
814+
}
815+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_PASSWORD), &dummy);
816+
if (uri_struct->host) {
817+
ZVAL_STR_COPY(&dummy, uri_struct->host);
818+
} else {
819+
ZVAL_NULL(&dummy);
820+
}
821+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_HOST), &dummy);
822+
ZVAL_LONG(&dummy, uri_struct->port);
823+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_PORT), &dummy);
824+
if (uri_struct->path) {
825+
ZVAL_STR_COPY(&dummy, uri_struct->path);
826+
} else {
827+
ZVAL_NULL(&dummy);
828+
}
829+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_PATH), &dummy);
830+
if (uri_struct->query) {
831+
ZVAL_STR_COPY(&dummy, uri_struct->query);
832+
} else {
833+
ZVAL_NULL(&dummy);
834+
}
835+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_QUERY), &dummy);
836+
if (uri_struct->fragment) {
837+
ZVAL_STR_COPY(&dummy, uri_struct->fragment);
838+
} else {
839+
ZVAL_NULL(&dummy);
840+
}
841+
zend_hash_add(Z_ARR(from_struct), ZSTR_KNOWN(ZEND_STR_FRAGMENT), &dummy);
842+
zend_hash_str_add(Z_ARR_P(return_value), "struct", strlen("struct"), &from_struct);
790843

844+
php_uri_struct_free(uri_struct);
791845
php_uri_free(uri);
792846
}
793847

0 commit comments

Comments
 (0)