xds/federation: fix percent encoding on server side

Overlooked in #8857 on server side. Since `XdsNameResolver.percentEncodePath()` will be also used for server side, I moved the method to `XdsClient`.
This commit is contained in:
ZHANG Dapeng 2022-02-07 13:29:09 -08:00 committed by GitHub
parent 7a9ceacafc
commit a1c41e3d30
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 37 additions and 40 deletions

View File

@ -24,6 +24,7 @@ import com.google.common.base.Joiner;
import com.google.common.base.MoreObjects;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableList;
import com.google.common.net.UrlEscapers;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.protobuf.Any;
import io.grpc.Status;
@ -106,6 +107,15 @@ abstract class XdsClient {
return resourceName.replace(rawQuery, canonifiedQuery);
}
static String percentEncodePath(String input) {
Iterable<String> pathSegs = Splitter.on('/').split(input);
List<String> encodedSegs = new ArrayList<>();
for (String pathSeg : pathSegs) {
encodedSegs.add(UrlEscapers.urlPathSegmentEscaper().escape(pathSeg));
}
return Joiner.on('/').join(encodedSegs);
}
@AutoValue
abstract static class LdsUpdate implements ResourceUpdate {
// Http level api listener configuration.

View File

@ -22,12 +22,10 @@ import static io.grpc.xds.Bootstrapper.XDSTP_SCHEME;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import com.google.common.net.UrlEscapers;
import com.google.gson.Gson;
import com.google.protobuf.util.Durations;
import io.grpc.Attributes;
@ -193,7 +191,7 @@ final class XdsNameResolver extends NameResolver {
}
String replacement = serviceAuthority;
if (listenerNameTemplate.startsWith(XDSTP_SCHEME)) {
replacement = percentEncodePath(replacement);
replacement = XdsClient.percentEncodePath(replacement);
}
String ldsResourceName = expandPercentS(listenerNameTemplate, replacement);
if (!XdsClient.isResourceNameValid(ldsResourceName, ResourceType.LDS.typeUrl())
@ -208,16 +206,6 @@ final class XdsNameResolver extends NameResolver {
resolveState.start();
}
@VisibleForTesting
static String percentEncodePath(String input) {
Iterable<String> pathSegs = Splitter.on('/').split(input);
List<String> encodedSegs = new ArrayList<>();
for (String pathSeg : pathSegs) {
encodedSegs.add(UrlEscapers.urlPathSegmentEscaper().escape(pathSeg));
}
return Joiner.on('/').join(encodedSegs);
}
private static String expandPercentS(String template, String replacement) {
return template.replace("%s", replacement);
}

View File

@ -24,7 +24,6 @@ import com.google.auto.value.AutoValue;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.net.UrlEscapers;
import com.google.common.util.concurrent.SettableFuture;
import io.grpc.Attributes;
import io.grpc.InternalServerInterceptors;
@ -196,7 +195,7 @@ final class XdsServerWrapper extends Server {
}
String replacement = listenerAddress;
if (listenerTemplate.startsWith(XDSTP_SCHEME)) {
replacement = UrlEscapers.urlFragmentEscaper().escape(replacement);
replacement = XdsClient.percentEncodePath(replacement);
}
discoveryState = new DiscoveryState(listenerTemplate.replaceAll("%s", replacement));
}

View File

@ -2619,6 +2619,31 @@ public class ClientXdsClientDataTest {
.isEqualTo(expectedCanonifiedName);
}
/**
* Tests compliance with RFC 3986 section 3.3
* https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
*/
@Test
public void percentEncodePath() {
String unreserved = "aAzZ09-._~";
assertThat(XdsClient.percentEncodePath(unreserved)).isEqualTo(unreserved);
String subDelims = "!$&'(*+,;/=";
assertThat(XdsClient.percentEncodePath(subDelims)).isEqualTo(subDelims);
String colonAndAt = ":@";
assertThat(XdsClient.percentEncodePath(colonAndAt)).isEqualTo(colonAndAt);
String needBeEncoded = "?#[]";
assertThat(XdsClient.percentEncodePath(needBeEncoded)).isEqualTo("%3F%23%5B%5D");
String ipv4 = "0.0.0.0:8080";
assertThat(XdsClient.percentEncodePath(ipv4)).isEqualTo(ipv4);
String ipv6 = "[::1]:8080";
assertThat(XdsClient.percentEncodePath(ipv6)).isEqualTo("%5B::1%5D:8080");
}
private static Filter buildHttpConnectionManagerFilter(HttpFilter... httpFilters) {
return Filter.newBuilder()
.setName("envoy.http_connection_manager")

View File

@ -1955,31 +1955,6 @@ public class XdsNameResolverTest {
.isFalse();
}
/**
* Tests compliance with RFC 3986 section 3.3
* https://datatracker.ietf.org/doc/html/rfc3986#section-3.3
*/
@Test
public void percentEncodePath() {
String unreserved = "aAzZ09-._~";
assertThat(XdsNameResolver.percentEncodePath(unreserved)).isEqualTo(unreserved);
String subDelims = "!$&'(*+,;/=";
assertThat(XdsNameResolver.percentEncodePath(subDelims)).isEqualTo(subDelims);
String colonAndAt = ":@";
assertThat(XdsNameResolver.percentEncodePath(colonAndAt)).isEqualTo(colonAndAt);
String needBeEncoded = "?#[]";
assertThat(XdsNameResolver.percentEncodePath(needBeEncoded)).isEqualTo("%3F%23%5B%5D");
String ipv4 = "0.0.0.0:8080";
assertThat(XdsNameResolver.percentEncodePath(ipv4)).isEqualTo(ipv4);
String ipv6 = "[::1]:8080";
assertThat(XdsNameResolver.percentEncodePath(ipv6)).isEqualTo("%5B::1%5D:8080");
}
private final class FakeXdsClientPoolFactory implements XdsClientPoolFactory {
Map<String, ?> bootstrap;