Skip to content

Commit fcfc7d0

Browse files
committed
Apply lexbor fix for empty hosts
Applying the lexbor/lexbor@cf07699 fix for lexbor.
1 parent a311f05 commit fcfc7d0

5 files changed

Lines changed: 272 additions & 5 deletions

File tree

‎ext/lexbor/lexbor/url/url.c‎

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1115,11 +1115,13 @@ lxb_url_host_copy(const lxb_url_host_t *src, lxb_url_host_t *dst,
11151115

11161116
dst->type = src->type;
11171117

1118-
if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) {
1119-
if (src->type == LXB_URL_HOST_TYPE__UNDEF) {
1120-
return LXB_STATUS_OK;
1121-
}
1118+
if (src->type == LXB_URL_HOST_TYPE__UNDEF
1119+
|| src->type == LXB_URL_HOST_TYPE_EMPTY)
1120+
{
1121+
return LXB_STATUS_OK;
1122+
}
11221123

1124+
if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) {
11231125
return lxb_url_str_copy(&src->u.domain,
11241126
&dst->u.domain, dst_mraw);
11251127
}
@@ -1152,6 +1154,24 @@ lxb_url_host_set_empty(lxb_url_host_t *host, lexbor_mraw_t *mraw)
11521154
host->type = LXB_URL_HOST_TYPE_EMPTY;
11531155
}
11541156

1157+
lxb_inline bool
1158+
lxb_url_host_is_empty(const lxb_url_host_t *host)
1159+
{
1160+
if (host->type == LXB_URL_HOST_TYPE_EMPTY) {
1161+
return true;
1162+
}
1163+
1164+
if (host->type == LXB_URL_HOST_TYPE_DOMAIN) {
1165+
return host->u.domain.length == 0;
1166+
}
1167+
1168+
if (host->type == LXB_URL_HOST_TYPE_OPAQUE) {
1169+
return host->u.opaque.length == 0;
1170+
}
1171+
1172+
return false;
1173+
}
1174+
11551175
static bool
11561176
lxb_url_host_eq(lxb_url_host_t *host, const lxb_char_t *data, size_t length)
11571177
{
@@ -1251,7 +1271,7 @@ lxb_url_normalized_windows_drive_letter(const lxb_char_t *data,
12511271
static bool
12521272
lxb_url_cannot_have_user_pass_port(lxb_url_t *url)
12531273
{
1254-
return url->host.type == LXB_URL_HOST_TYPE_EMPTY
1274+
return lxb_url_host_is_empty(&url->host)
12551275
|| url->host.type == LXB_URL_HOST_TYPE__UNDEF
12561276
|| url->scheme.type == LXB_URL_SCHEMEL_TYPE_FILE;
12571277
}
@@ -3978,6 +3998,11 @@ lxb_url_opaque_host_parse(lxb_url_parser_t *parser, const lxb_char_t *data,
39783998
lxb_status_t status;
39793999
const lxb_char_t *p;
39804000

4001+
if (data == end) {
4002+
lxb_url_host_set_empty(host, mraw);
4003+
return LXB_STATUS_OK;
4004+
}
4005+
39814006
p = data;
39824007

39834008
while (p < end) {
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
From cf07699ca0f5fa4e1f7fd05c2135fd38e6d196c2 Mon Sep 17 00:00:00 2001
2+
From: Alexander Borisov <lex.borisov@gmail.com>
3+
Date: Fri, 26 Jun 2026 18:55:56 +0300
4+
Subject: [PATCH] URL: fixed setters for empty hosts.
5+
MIME-Version: 1.0
6+
Content-Type: text/plain; charset=UTF-8
7+
Content-Transfer-Encoding: 8bit
8+
9+
Empty non-special hosts were represented as empty opaque hosts, so
10+
lxb_url_cannot_have_user_pass_port() allowed username, password, and port
11+
setters to modify scheme://.
12+
13+
For fixed this store empty opaque-host input as LXB_URL_HOST_TYPE_EMPTY.
14+
15+
Per report from Máté Kocsis (@kocsismate).
16+
17+
This relates to #387 issue on GitHub.
18+
---
19+
source/lexbor/url/url.c | 35 ++++++++++++++++++---
20+
test/files/lexbor/url/changes.ton | 52 +++++++++++++++++++++++++++++--
21+
test/files/lexbor/url/url.ton | 8 ++++-
22+
3 files changed, 86 insertions(+), 9 deletions(-)
23+
24+
diff --git a/source/lexbor/url/url.c b/source/lexbor/url/url.c
25+
index ced4462b..e1da2c38 100644
26+
--- a/source/lexbor/url/url.c
27+
+++ b/source/lexbor/url/url.c
28+
@@ -1116,11 +1116,13 @@ lxb_url_host_copy(const lxb_url_host_t *src, lxb_url_host_t *dst,
29+
30+
dst->type = src->type;
31+
32+
- if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) {
33+
- if (src->type == LXB_URL_HOST_TYPE__UNDEF) {
34+
- return LXB_STATUS_OK;
35+
- }
36+
+ if (src->type == LXB_URL_HOST_TYPE__UNDEF
37+
+ || src->type == LXB_URL_HOST_TYPE_EMPTY)
38+
+ {
39+
+ return LXB_STATUS_OK;
40+
+ }
41+
42+
+ if (src->type <= LXB_URL_HOST_TYPE_OPAQUE) {
43+
return lxb_url_str_copy(&src->u.domain,
44+
&dst->u.domain, dst_mraw);
45+
}
46+
@@ -1153,6 +1155,24 @@ lxb_url_host_set_empty(lxb_url_host_t *host, lexbor_mraw_t *mraw)
47+
host->type = LXB_URL_HOST_TYPE_EMPTY;
48+
}
49+
50+
+lxb_inline bool
51+
+lxb_url_host_is_empty(const lxb_url_host_t *host)
52+
+{
53+
+ if (host->type == LXB_URL_HOST_TYPE_EMPTY) {
54+
+ return true;
55+
+ }
56+
+
57+
+ if (host->type == LXB_URL_HOST_TYPE_DOMAIN) {
58+
+ return host->u.domain.length == 0;
59+
+ }
60+
+
61+
+ if (host->type == LXB_URL_HOST_TYPE_OPAQUE) {
62+
+ return host->u.opaque.length == 0;
63+
+ }
64+
+
65+
+ return false;
66+
+}
67+
+
68+
static bool
69+
lxb_url_host_eq(lxb_url_host_t *host, const lxb_char_t *data, size_t length)
70+
{
71+
@@ -1252,7 +1272,7 @@ lxb_url_normalized_windows_drive_letter(const lxb_char_t *data,
72+
static bool
73+
lxb_url_cannot_have_user_pass_port(lxb_url_t *url)
74+
{
75+
- return url->host.type == LXB_URL_HOST_TYPE_EMPTY
76+
+ return lxb_url_host_is_empty(&url->host)
77+
|| url->host.type == LXB_URL_HOST_TYPE__UNDEF
78+
|| url->scheme.type == LXB_URL_SCHEMEL_TYPE_FILE;
79+
}
80+
@@ -3979,6 +3999,11 @@ lxb_url_opaque_host_parse(lxb_url_parser_t *parser, const lxb_char_t *data,
81+
lxb_status_t status;
82+
const lxb_char_t *p;
83+
84+
+ if (data == end) {
85+
+ lxb_url_host_set_empty(host, mraw);
86+
+ return LXB_STATUS_OK;
87+
+ }
88+
+
89+
p = data;
90+
91+
while (p < end) {
92+
diff --git a/test/files/lexbor/url/changes.ton b/test/files/lexbor/url/changes.ton
93+
index 07bc9449..1a0b6e35 100644
94+
--- a/test/files/lexbor/url/changes.ton
95+
+++ b/test/files/lexbor/url/changes.ton
96+
@@ -1,5 +1,5 @@
97+
[
98+
- /* Test count: 1 */
99+
+ /* Test count: 47 */
100+
/* 1 */
101+
{
102+
"url": "https://user:pass@lexbor.com/docs/html/path?x=y&a=b#best-fragment",
103+
@@ -982,9 +982,53 @@
104+
"failed": false
105+
},
106+
/* 45 */
107+
+ {
108+
+ "url": "scheme://",
109+
+ "done": "scheme://",
110+
+ "change": {
111+
+ "href": null,
112+
+ "protocol": null,
113+
+ "username": "user",
114+
+ "password": "pass",
115+
+ "host": null,
116+
+ "hostname": null,
117+
+ "port": "433",
118+
+ "pathname": null,
119+
+ "search": null,
120+
+ "hash": null
121+
+ },
122+
+ "scheme": "scheme",
123+
+ "host": "",
124+
+ "path": "",
125+
+ "failed": false
126+
+ },
127+
+ /* 46 */
128+
+ {
129+
+ "url": "scheme://host",
130+
+ "done": "scheme://host:433",
131+
+ "change": {
132+
+ "href": null,
133+
+ "protocol": null,
134+
+ "username": null,
135+
+ "password": null,
136+
+ "host": null,
137+
+ "hostname": null,
138+
+ "port": "433",
139+
+ "pathname": null,
140+
+ "search": null,
141+
+ "hash": null
142+
+ },
143+
+ "scheme": "scheme",
144+
+ "host": "host",
145+
+ "port": 433,
146+
+ "has_port": true,
147+
+ "path": "",
148+
+ "failed": false
149+
+ },
150+
+ /* 47 */
151+
{
152+
"url": "https://example.com:432",
153+
- "done": "https://example.com:432",
154+
+ "done": "https://example.com:432/",
155+
"change": {
156+
"href": null,
157+
"protocol": null,
158+
@@ -999,7 +1043,9 @@
159+
},
160+
"scheme": "https",
161+
"host": "example.com",
162+
- "port": "432",
163+
+ "port": 432,
164+
+ "has_port": true,
165+
+ "path": "/",
166+
"failed": true
167+
}
168+
]
169+
diff --git a/test/files/lexbor/url/url.ton b/test/files/lexbor/url/url.ton
170+
index 2baa4bc2..85794c5b 100644
171+
--- a/test/files/lexbor/url/url.ton
172+
+++ b/test/files/lexbor/url/url.ton
173+
@@ -1,5 +1,5 @@
174+
[
175+
- /* Test count: 7 */
176+
+ /* Test count: 8 */
177+
/* 1 */
178+
{
179+
"url": "https://user:pass@lexbor.com:450/docs/lexbor/?search=lxb_status_t#version",
180+
@@ -74,5 +74,11 @@
181+
"path": "",
182+
"failed": false,
183+
"encoding": "utf-8"
184+
+ },
185+
+ /* 8 */
186+
+ {
187+
+ "url": "scheme://:433",
188+
+ "failed": true,
189+
+ "encoding": "utf-8"
190+
}
191+
]
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Test Uri\WhatWg\Url component modification - password - empty host
3+
--FILE--
4+
<?php
5+
6+
$url1 = new Uri\WhatWg\Url("scheme://");
7+
$url2 = $url1->withPassword("password");
8+
9+
var_dump($url1->getPassword());
10+
var_dump($url2->getPassword());
11+
var_dump($url2->toAsciiString());
12+
13+
?>
14+
--EXPECT--
15+
NULL
16+
NULL
17+
string(9) "scheme://"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Test Uri\WhatWg\Url component modification - port - empty host
3+
--FILE--
4+
<?php
5+
6+
$url1 = new Uri\WhatWg\Url("scheme://");
7+
$url2 = $url1->withPort(433);
8+
9+
var_dump($url1->getPort());
10+
var_dump($url2->getPort());
11+
var_dump($url2->toAsciiString());
12+
13+
?>
14+
--EXPECT--
15+
NULL
16+
NULL
17+
string(9) "scheme://"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Test Uri\WhatWg\Url component modification - username - empty host
3+
--FILE--
4+
<?php
5+
6+
$url1 = new Uri\WhatWg\Url("scheme://");
7+
$url2 = $url1->withUsername("user");
8+
9+
var_dump($url1->getUsername());
10+
var_dump($url2->getUsername());
11+
var_dump($url2->toAsciiString());
12+
13+
?>
14+
--EXPECT--
15+
NULL
16+
NULL
17+
string(9) "scheme://"

0 commit comments

Comments
 (0)