Fix fragment parsing for relative URI in RfcUriParser

When parsing a relative URI such as `path2#foo`, RfcUriParser's
SCHEME_OR_PATH state advanced to FRAGMENT without moving the component
index past the `#` character, so the captured fragment included the
entire input (`path2#foo`) instead of just `foo`. As a result,
`toUriString()` produced `path2#path2#foo`.

Update the SCHEME_OR_PATH `#` transition to advance the component
index to `i + 1`, matching the sibling `?` -> QUERY transition in the
same state and every other `-> FRAGMENT` transition in the parser.
URIs with a `/` in the path are unaffected because they leave
SCHEME_OR_PATH for PATH on the first slash; the WhatWG parser already
handled this case correctly.

Closes gh-36762

Signed-off-by: daguimu <daguimu.geek@gmail.com>
This commit is contained in:
daguimu
2026-05-07 20:30:39 +08:00
committed by rstoyanchev
parent 175c1f9437
commit c2191e3ce2
2 changed files with 22 additions and 1 deletions
@@ -178,7 +178,7 @@ abstract class RfcUriParser {
parser.capturePath().advanceTo(QUERY, i + 1);
break;
case '#':
parser.capturePath().advanceTo(FRAGMENT);
parser.capturePath().advanceTo(FRAGMENT, i + 1);
break;
}
}
@@ -270,6 +270,27 @@ class UriComponentsBuilderTests {
UriComponentsBuilder.fromUriString("http://[1abc:2abc:3abc::5ABC:6abc:8080/resource", parserType));
}
@ParameterizedTest // gh-36759
@EnumSource
void fromUriStringRelativeUriWithFragment(ParserType parserType) {
UriComponents result = UriComponentsBuilder.fromUriString("path2#foo", parserType).build();
assertThat(result.getScheme()).isNull();
assertThat(result.getHost()).isNull();
assertThat(result.getPath()).isEqualTo("path2");
assertThat(result.getFragment()).isEqualTo("foo");
assertThat(result.toUriString()).isEqualTo("path2#foo");
}
@ParameterizedTest // gh-36759
@EnumSource
void fromUriStringRelativeUriWithEmptyFragment(ParserType parserType) {
UriComponents result = UriComponentsBuilder.fromUriString("path2#", parserType).build();
assertThat(result.getScheme()).isNull();
assertThat(result.getHost()).isNull();
assertThat(result.getPath()).isEqualTo("path2");
assertThat(result.getFragment()).isNull();
}
@ParameterizedTest // see SPR-11970
@EnumSource
void fromUriStringNoPathWithReservedCharInQuery(ParserType parserType) {