Skip to content

UriComponentsBuilder silently drops some Registry-based Naming Authorities #27774

Closed
@fedorka

Description

@fedorka

In spring-web 5.3.13, UriComponentsBuilder.fromUri / UriComponentsBuilder.uri silently drops some RFC 2396 3.2.1 Registry-based Naming Authorities even when they are accepted as RFC 3986 3.2 authorities.

    // I tested java 17.0.1-zulu and 8.0.312-zulu - with the same results.

    @Test
    public void testUriComponentBuilder() throws URISyntaxException {
        // Generic scheme to avoid any assumptions around HTTP
        String scheme = "scheme";

        // Matches
        // - RFC 2396 3.2.1. "reg_name" Registry-based Naming Authority
        // - RFC 3986 3.2.2 "host" Host
        // NOT an RFC 2396 3.2.2. "server" Server-based Naming Authority
        String authority = "rfc_2396_authority";


        String uriString = scheme + ":" + "//" + authority ;

        URI testUri = new URI(uriString);

        UriComponents uriComponentsFromUriString = UriComponentsBuilder.fromUriString(uriString).build(true);
        UriComponents uriComponentsFromUri = UriComponentsBuilder.fromUri(testUri).build(true);

        // Demonstrate that the URI is well formed according to RFC 2396 and parses as expected
        assertAll("testUriFromString should have a RFC 2396 Registry-based Naming Authority (3.2.1.)",
                () -> assertEquals(authority, testUriFromString.getAuthority()),
                () -> assertNull(testUriFromString.getUserInfo()),
                () -> assertNull(testUriFromString.getHost()),
                () -> assertEquals(-1, testUriFromString.getPort())
        );

        // Demonstrate that the URI is parseable under RFC 3986 from string form
        assertAll("uriComponentsFromUriString should be populated ",
                () -> assertEquals(authority, uriComponentsFromUriString.getHost())
        );

        // Demonstrate that the parsed URI is equivalent (according to java.net.URI)
        assertEquals(testUriFromString, uriComponentsFromUriString.toUri());

        // Unexpectedly fails as getHost() return a null even though testUri has an RFC 3986 host
        assertAll("uriComponentsFromUri should have populated host ",
                () -> assertEquals(authority, uriComponentsFromUri.getHost())
        );

    }

When java.net.URI encounters an RFC 2396 3.2.1 authority (identified as any correct authority not parseable under RFC 2396 3.2.2), it returns null values for the server-based naming authority components, causing UriComponentBuilder to assume they are unset and silently dropping the data. However, this data is available via URI.getAuthority().

I would expect that UriComponentBuilder would attempt to reparse the authority from Uri.getAuthority under the RFC 3986 3.2 specification.

The fact that these classes are written against different versions of the spec is obviously a complicating factor. The most straightforward option is to reparse the URI from scratch under the RFC 3986 spec, though I think that it would be preferable to only parse the authority component to limit the blast radius of this change. I am happy to contribute a PR, but would appreciate thumbs up on the approach before investing the time as this would substantially change existing behavior if UriComponentBuilder.uri is being used after the authority components have been set via another method.

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions