Add fix for xdstp replacement for encoded authorities (#10571)

In ac35ab6 the logic in xDS Name resolver was changed to support encoded
authorities. This seems to cause an issue for xdstp replacements which
would percent encode the authority for the replacement causing double
encoding.

For example:

URI = xds:///path/to/service
Authority = path%2Fto%2Fservice
xdstp resource = xdstp:///envoy.config.listener.v3.Listener/path%252Fto%252Fservice

Here the authority is encoded due to slashes and during replacement we
percent encode it again causing %2F to change to %252F. To avoid this
issue, use the encoded authority only for the getServiceAuthority() API
and for all other use cases retain the unencoded authority.
This commit is contained in:
Anirudh Ramachandra 2023-09-22 08:25:08 -07:00 committed by GitHub
parent 88b3484a60
commit fec7c2ea4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 32 additions and 3 deletions

View File

@ -105,6 +105,9 @@ final class XdsNameResolver extends NameResolver {
@Nullable
private final String targetAuthority;
private final String serviceAuthority;
// Encoded version of the service authority as per
// https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.
private final String encodedServiceAuthority;
private final String overrideAuthority;
private final ServiceConfigParser serviceConfigParser;
private final SynchronizationContext syncContext;
@ -149,8 +152,9 @@ final class XdsNameResolver extends NameResolver {
this.targetAuthority = targetAuthority;
// The name might have multiple slashes so encode it before verifying.
String authority = GrpcUtil.AuthorityEscaper.encodeAuthority(checkNotNull(name, "name"));
serviceAuthority = GrpcUtil.checkAuthority(authority);
serviceAuthority = checkNotNull(name, "name");
this.encodedServiceAuthority =
GrpcUtil.checkAuthority(GrpcUtil.AuthorityEscaper.encodeAuthority(serviceAuthority));
this.overrideAuthority = overrideAuthority;
this.serviceConfigParser = checkNotNull(serviceConfigParser, "serviceConfigParser");
@ -169,7 +173,7 @@ final class XdsNameResolver extends NameResolver {
@Override
public String getServiceAuthority() {
return serviceAuthority;
return encodedServiceAuthority;
}
@Override

View File

@ -265,6 +265,31 @@ public class XdsNameResolverTest {
verify(mockListener, never()).onError(any(Status.class));
}
@Test
public void resolving_noTargetAuthority_xdstpWithMultipleSlashes() {
bootstrapInfo = BootstrapInfo.builder()
.servers(ImmutableList.of(ServerInfo.create(
"td.googleapis.com", InsecureChannelCredentials.create())))
.node(Node.newBuilder().build())
.clientDefaultListenerResourceNameTemplate(
"xdstp://xds.authority.com/envoy.config.listener.v3.Listener/%s?id=1")
.build();
String serviceAuthority = "path/to/service";
expectedLdsResourceName =
"xdstp://xds.authority.com/envoy.config.listener.v3.Listener/"
+ "path/to/service?id=1";
resolver = new XdsNameResolver(
null, serviceAuthority, null, serviceConfigParser, syncContext, scheduler,
xdsClientPoolFactory, mockRandom, FilterRegistry.getDefaultRegistry(), null);
// The Service Authority must be URL encoded, but unlike the LDS resource name.
assertThat(resolver.getServiceAuthority()).isEqualTo("path%2Fto%2Fservice");
resolver.start(mockListener);
verify(mockListener, never()).onError(any(Status.class));
}
@Test
public void resolving_targetAuthorityInAuthoritiesMap() {
String targetAuthority = "xds.authority.com";