Skip to content

Commit 430c847

Browse files
kixelatedclaude
andauthored
Fix AsPath for String not normalizing paths (#954)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent f90528e commit 430c847

2 files changed

Lines changed: 50 additions & 2 deletions

File tree

rs/moq-lite/src/model/origin.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1279,6 +1279,54 @@ mod tests {
12791279
assert!(limited_producer.publish_only(&["other/path".into()]).is_none());
12801280
}
12811281

1282+
// Regression test for https://github.com/moq-dev/moq/issues/910
1283+
// with_root panics when String has trailing slash (AsPath for String skips normalization)
1284+
#[tokio::test]
1285+
async fn test_with_root_trailing_slash_consumer() {
1286+
let origin = Origin::produce();
1287+
1288+
// Use an owned String so the trailing slash is NOT normalized away.
1289+
let prefix = "some_prefix/".to_string();
1290+
let mut consumer = origin.consume().with_root(prefix).unwrap();
1291+
1292+
let b = origin.create_broadcast("some_prefix/test").unwrap();
1293+
consumer.assert_next("test", &b.consume());
1294+
}
1295+
1296+
// Same issue but for the producer side of with_root
1297+
#[tokio::test]
1298+
async fn test_with_root_trailing_slash_producer() {
1299+
let origin = Origin::produce();
1300+
1301+
// Use an owned String so the trailing slash is NOT normalized away.
1302+
let prefix = "some_prefix/".to_string();
1303+
let rooted = origin.with_root(prefix).unwrap();
1304+
1305+
let b = rooted.create_broadcast("test").unwrap();
1306+
1307+
let mut consumer = rooted.consume();
1308+
consumer.assert_next("test", &b.consume());
1309+
}
1310+
1311+
// Verify unannounce also doesn't panic with trailing slash
1312+
#[tokio::test]
1313+
async fn test_with_root_trailing_slash_unannounce() {
1314+
let origin = Origin::produce();
1315+
1316+
let prefix = "some_prefix/".to_string();
1317+
let mut consumer = origin.consume().with_root(prefix).unwrap();
1318+
1319+
let b = origin.create_broadcast("some_prefix/test").unwrap();
1320+
consumer.assert_next("test", &b.consume());
1321+
1322+
// Drop the broadcast producer to trigger unannounce
1323+
drop(b);
1324+
tokio::time::sleep(tokio::time::Duration::from_millis(1)).await;
1325+
1326+
// unannounce also calls strip_prefix(&self.root).unwrap()
1327+
consumer.assert_next_none("test");
1328+
}
1329+
12821330
#[tokio::test]
12831331
async fn test_select_maintains_access_with_wider_prefix() {
12841332
let origin = Origin::produce();

rs/moq-lite/src/path.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,13 @@ impl AsPath for Path<'_> {
3535

3636
impl AsPath for String {
3737
fn as_path(&self) -> Path<'_> {
38-
Path(Cow::Borrowed(self))
38+
Path::new(self)
3939
}
4040
}
4141

4242
impl<'a> AsPath for &'a String {
4343
fn as_path(&self) -> Path<'a> {
44-
Path(Cow::Borrowed(self))
44+
Path::new(self)
4545
}
4646
}
4747

0 commit comments

Comments
 (0)