Skip to content

Commit 5fdc022

Browse files
authored
uri: Improve exceptions for Uri\Rfc3986\Uri (php#19161)
* uri: Streamline implementation of `uriparser_parse_uri_ex()` Avoid the use of a macro and streamline the logic. * uri: Improve exceptions for `Uri\Rfc3986\Uri` * uri: Allow empty URIs for RFC3986 * NEWS * uri: Improve ext/uri/tests/004.phpt for empty URIs
1 parent 063d795 commit 5fdc022

File tree

4 files changed

+78
-41
lines changed

4 files changed

+78
-41
lines changed

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ PHP NEWS
1919
. Error handling of Uri\WhatWg\Url::withHost() is fixed when the input
2020
contains a port. Now, it triggers an exception; previously, the error
2121
was silently swallowed. (Máté Kocsis)
22+
. Support empty URIs with Uri\Rfc3986\Uri. (timwolla)
2223

2324
17 Jul 2025, PHP 8.5.0alpha2
2425

ext/uri/php_uriparser.c

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
#include "Zend/zend_exceptions.h"
2222

2323
static void uriparser_free_uri(void *uri);
24-
static void throw_invalid_uri_exception(void);
2524

2625
static void *uriparser_malloc(UriMemoryManager *memory_manager, size_t size)
2726
{
@@ -293,51 +292,59 @@ static uriparser_uris_t *uriparser_create_uris(void)
293292
return uriparser_uris;
294293
}
295294

296-
static void throw_invalid_uri_exception(void)
297-
{
298-
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified URI is malformed", 0);
299-
}
300-
301-
#define PARSE_URI(dest_uri, uri_str, uriparser_uris, silent) \
302-
do { \
303-
if (ZSTR_LEN(uri_str) == 0 || \
304-
uriParseSingleUriExMmA(dest_uri, ZSTR_VAL(uri_str), ZSTR_VAL(uri_str) + ZSTR_LEN(uri_str), NULL, mm) != URI_SUCCESS \
305-
) { \
306-
efree(uriparser_uris); \
307-
if (!silent) { \
308-
throw_invalid_uri_exception(); \
309-
} \
310-
return NULL; \
311-
} \
312-
} while (0)
313-
314295
void *uriparser_parse_uri_ex(const zend_string *uri_str, const uriparser_uris_t *uriparser_base_urls, bool silent)
315296
{
316-
uriparser_uris_t *uriparser_uris = uriparser_create_uris();
297+
UriUriA uri = {0};
317298

318-
if (uriparser_base_urls == NULL) {
319-
PARSE_URI(&uriparser_uris->uri, uri_str, uriparser_uris, silent);
320-
uriMakeOwnerMmA(&uriparser_uris->uri, mm);
321-
} else {
322-
UriUriA uri;
299+
/* Parse the URI. */
300+
if (uriParseSingleUriExMmA(&uri, ZSTR_VAL(uri_str), ZSTR_VAL(uri_str) + ZSTR_LEN(uri_str), NULL, mm) != URI_SUCCESS) {
301+
if (!silent) {
302+
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified URI is malformed", 0);
303+
}
323304

324-
PARSE_URI(&uri, uri_str, uriparser_uris, silent);
305+
goto fail;
306+
}
325307

326-
if (uriAddBaseUriExMmA(&uriparser_uris->uri, &uri, &uriparser_base_urls->uri, URI_RESOLVE_STRICTLY, mm) != URI_SUCCESS) {
327-
efree(uriparser_uris);
328-
uriFreeUriMembersMmA(&uri, mm);
308+
if (uriparser_base_urls != NULL) {
309+
UriUriA tmp = {0};
310+
311+
/* Combine the parsed URI with the base URI and store the result in 'tmp',
312+
* since the target and source URLs must be distinct. */
313+
int result = uriAddBaseUriExMmA(&tmp, &uri, &uriparser_base_urls->uri, URI_RESOLVE_STRICTLY, mm);
314+
if (result != URI_SUCCESS) {
329315
if (!silent) {
330-
throw_invalid_uri_exception();
316+
switch (result) {
317+
case URI_ERROR_ADDBASE_REL_BASE:
318+
zend_throw_exception(uri_invalid_uri_exception_ce, "The specified base URI must be absolute", 0);
319+
break;
320+
default:
321+
/* This should be unreachable in practice. */
322+
zend_throw_exception(uri_invalid_uri_exception_ce, "Failed to resolve the specified URI against the base URI", 0);
323+
break;
324+
}
331325
}
332326

333-
return NULL;
327+
goto fail;
334328
}
335329

336-
uriMakeOwnerMmA(&uriparser_uris->uri, mm);
330+
/* Store the combined URI back into 'uri'. */
337331
uriFreeUriMembersMmA(&uri, mm);
332+
uri = tmp;
338333
}
339334

335+
/* Make the resulting URI independent of the 'uri_str'. */
336+
uriMakeOwnerMmA(&uri, mm);
337+
338+
uriparser_uris_t *uriparser_uris = uriparser_create_uris();
339+
uriparser_uris->uri = uri;
340+
340341
return uriparser_uris;
342+
343+
fail:
344+
345+
uriFreeUriMembersMmA(&uri, mm);
346+
347+
return NULL;
341348
}
342349

343350
void *uriparser_parse_uri(const zend_string *uri_str, const void *base_url, zval *errors, bool silent)

ext/uri/tests/004.phpt

Lines changed: 37 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,7 @@ uri
55
--FILE--
66
<?php
77

8-
try {
9-
new Uri\Rfc3986\Uri("");
10-
} catch (Uri\InvalidUriException $e) {
11-
echo $e->getMessage() . "\n";
12-
}
13-
8+
var_dump(new Uri\Rfc3986\Uri(""));
149
var_dump(Uri\Rfc3986\Uri::parse(""));
1510

1611
try {
@@ -29,8 +24,42 @@ var_dump(Uri\WhatWg\Url::parse("http://RuPaul's Drag Race All Stars 7 Winners Ca
2924

3025
?>
3126
--EXPECTF--
32-
The specified URI is malformed
33-
NULL
27+
object(Uri\Rfc3986\Uri)#%d (%d) {
28+
["scheme"]=>
29+
NULL
30+
["username"]=>
31+
NULL
32+
["password"]=>
33+
NULL
34+
["host"]=>
35+
NULL
36+
["port"]=>
37+
NULL
38+
["path"]=>
39+
string(0) ""
40+
["query"]=>
41+
NULL
42+
["fragment"]=>
43+
NULL
44+
}
45+
object(Uri\Rfc3986\Uri)#%d (%d) {
46+
["scheme"]=>
47+
NULL
48+
["username"]=>
49+
NULL
50+
["password"]=>
51+
NULL
52+
["host"]=>
53+
NULL
54+
["port"]=>
55+
NULL
56+
["path"]=>
57+
string(0) ""
58+
["query"]=>
59+
NULL
60+
["fragment"]=>
61+
NULL
62+
}
3463
The specified URI is malformed (MissingSchemeNonRelativeUrl)
3564
NULL
3665
object(Uri\Rfc3986\Uri)#%d (%d) {

ext/uri/tests/055.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ try {
1212
}
1313
?>
1414
--EXPECT--
15-
The specified URI is malformed
15+
The specified base URI must be absolute

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy