Skip to content

Commit 21b3acf

Browse files
committed
fix(storage): conditionally override authority and add BetaApi annotation
1 parent aee5030 commit 21b3acf

4 files changed

Lines changed: 136 additions & 15 deletions

File tree

‎java-storage/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcStorageOptions.java‎

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -363,17 +363,7 @@ private Tuple<StorageSettings, Opts<UserProject>> resolveSettingsAndOpts() throw
363363
channelProviderBuilder.setAttemptDirectPathXds();
364364
}
365365

366-
if (attemptDirectPathXdsOverInterconnect) {
367-
com.google.api.core.ApiFunction<ManagedChannelBuilder, ManagedChannelBuilder>
368-
existingConfigurator = channelProviderBuilder.getChannelConfigurator();
369-
channelProviderBuilder.setChannelConfigurator(
370-
channelBuilder -> {
371-
if (existingConfigurator != null) {
372-
channelBuilder = existingConfigurator.apply(channelBuilder);
373-
}
374-
return channelBuilder.overrideAuthority(DEFAULT_HOST_NO_SCHEME);
375-
});
376-
}
366+
377367

378368
if (scheme.equals("http")) {
379369
channelProviderBuilder.setChannelConfigurator(ManagedChannelBuilder::usePlaintext);
@@ -604,6 +594,7 @@ public GrpcStorageOptions.Builder setAttemptDirectPath(boolean attemptDirectPath
604594
*
605595
* @since 2.72.0
606596
*/
597+
@BetaApi
607598
public GrpcStorageOptions.Builder setAttemptDirectPathXdsOverInterconnect(
608599
boolean attemptDirectPathXdsOverInterconnect) {
609600
this.attemptDirectPathXdsOverInterconnect = attemptDirectPathXdsOverInterconnect;

‎java-storage/google-cloud-storage/src/test/java/com/google/cloud/storage/StorageOptionsBuilderTest.java‎

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,38 @@ public void grpc_attemptDirectPathXdsOverInterconnect() throws Exception {
9292
(com.google.api.gax.grpc.InstantiatingGrpcChannelProvider) tcp;
9393

9494
assertThat(provider.isAttemptDirectPathXdsOverInterconnect()).isTrue();
95+
com.google.api.core.ApiFunction<io.grpc.ManagedChannelBuilder, io.grpc.ManagedChannelBuilder>
96+
configurator = provider.toBuilder().getChannelConfigurator();
97+
if (configurator != null) {
98+
io.grpc.ManagedChannelBuilder<?> fakeBuilder =
99+
io.grpc.ManagedChannelBuilder.forAddress("foo", 80);
100+
io.grpc.ManagedChannelBuilder<?> appliedBuilder = configurator.apply(fakeBuilder);
101+
String authority = extractAuthorityFromChannelBuilder(appliedBuilder);
102+
assertThat(authority).isNull();
103+
}
104+
}
105+
106+
@Test
107+
public void grpc_fallbackFromDirectPathXdsOverInterconnect_doesNotOverrideAuthority()
108+
throws Exception {
109+
GrpcStorageOptions options =
110+
GrpcStorageOptions.grpc()
111+
.setHost("https://storage.my-universe.com")
112+
.setAttemptDirectPathXdsOverInterconnect(true)
113+
.setCredentials(com.google.cloud.NoCredentials.getInstance())
114+
.build();
115+
com.google.api.gax.grpc.InstantiatingGrpcChannelProvider provider =
116+
(com.google.api.gax.grpc.InstantiatingGrpcChannelProvider)
117+
options.getStorageSettings().getTransportChannelProvider();
118+
com.google.api.core.ApiFunction<io.grpc.ManagedChannelBuilder, io.grpc.ManagedChannelBuilder>
119+
configurator = provider.toBuilder().getChannelConfigurator();
120+
if (configurator != null) {
121+
io.grpc.ManagedChannelBuilder<?> fakeBuilder =
122+
io.grpc.ManagedChannelBuilder.forAddress("foo", 80);
123+
io.grpc.ManagedChannelBuilder<?> appliedBuilder = configurator.apply(fakeBuilder);
124+
String authority = extractAuthorityFromChannelBuilder(appliedBuilder);
125+
assertThat(authority).isNull();
126+
}
95127
}
96128

97129
@Test
@@ -115,4 +147,43 @@ public ResultRetryAlgorithm<?> getNonidempotentHandler() {
115147
return null;
116148
}
117149
}
150+
151+
private static String extractAuthorityFromChannelBuilder(
152+
io.grpc.ManagedChannelBuilder<?> channelBuilder) {
153+
try {
154+
Object current = channelBuilder;
155+
while (current != null) {
156+
Class<?> clazz = current.getClass();
157+
java.lang.reflect.Field field = null;
158+
while (clazz != null) {
159+
try {
160+
field = clazz.getDeclaredField("authority");
161+
break;
162+
} catch (NoSuchFieldException e) {
163+
try {
164+
field = clazz.getDeclaredField("overrideAuthority");
165+
break;
166+
} catch (Exception ignored) {
167+
}
168+
clazz = clazz.getSuperclass();
169+
}
170+
}
171+
if (field != null) {
172+
field.setAccessible(true);
173+
return (String) field.get(current);
174+
}
175+
try {
176+
java.lang.reflect.Field delegate = current.getClass().getDeclaredField("delegate");
177+
delegate.setAccessible(true);
178+
current = delegate.get(current);
179+
} catch (Exception e) {
180+
break;
181+
}
182+
}
183+
return null;
184+
} catch (Exception e) {
185+
throw new RuntimeException(e);
186+
}
187+
}
118188
}
189+

‎sdk-platform-java/gax-java/gax-grpc/src/main/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProvider.java‎

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -771,6 +771,9 @@ public ManagedChannelBuilder<?> createChannelBuilder() throws IOException {
771771
target += "?force-xds";
772772
}
773773
builder = Grpc.newChannelBuilder(target, channelCreds);
774+
if (isAttemptDirectPathXdsOverInterconnect() && serviceAddress.equals("storage-direct.googleapis.com")) {
775+
builder.overrideAuthority("storage.googleapis.com");
776+
}
774777
resolvedTarget = target;
775778
} else {
776779
builder = Grpc.newChannelBuilderForAddress(serviceAddress, port, channelCreds);
@@ -787,6 +790,18 @@ public ManagedChannelBuilder<?> createChannelBuilder() throws IOException {
787790
Level.WARNING,
788791
"DirectPath was requested but is not available. Falling back to CloudPath.");
789792
}
793+
String fallbackEndpoint = endpoint;
794+
String fallbackMtlsEndpoint = mtlsEndpoint;
795+
if (serviceAddress.equals("storage-direct.googleapis.com")) {
796+
serviceAddress = "storage.googleapis.com";
797+
fallbackEndpoint = serviceAddress + ":" + port;
798+
if (fallbackMtlsEndpoint != null
799+
&& fallbackMtlsEndpoint.contains("storage-direct.googleapis.com")) {
800+
fallbackMtlsEndpoint =
801+
fallbackMtlsEndpoint.replace(
802+
"storage-direct.googleapis.com", "storage.googleapis.com");
803+
}
804+
}
790805
ChannelCredentials channelCredentials;
791806
try {
792807
// Try and create credentials via DCA. See https://google.aip.dev/auth/4114.
@@ -796,8 +811,8 @@ public ManagedChannelBuilder<?> createChannelBuilder() throws IOException {
796811
}
797812
if (channelCredentials != null) {
798813
// Create the channel using channel credentials created via DCA.
799-
builder = Grpc.newChannelBuilder(endpoint, channelCredentials);
800-
resolvedTarget = endpoint;
814+
builder = Grpc.newChannelBuilder(fallbackEndpoint, channelCredentials);
815+
resolvedTarget = fallbackEndpoint;
801816
} else {
802817
// Could not create channel credentials via DCA. In accordance with
803818
// https://google.aip.dev/auth/4115, if credentials not available through
@@ -815,11 +830,12 @@ public ManagedChannelBuilder<?> createChannelBuilder() throws IOException {
815830
}
816831
// Connect to the MTLS endpoint when using S2A because S2A is used to perform an MTLS
817832
// handshake.
818-
builder = Grpc.newChannelBuilder(mtlsEndpoint, channelCredentials);
819-
resolvedTarget = mtlsEndpoint;
833+
builder = Grpc.newChannelBuilder(fallbackMtlsEndpoint, channelCredentials);
834+
resolvedTarget = fallbackMtlsEndpoint;
820835
} else {
821836
// Use default if we cannot initialize channel credentials via DCA or S2A.
822837
builder = ManagedChannelBuilder.forAddress(serviceAddress, port);
838+
builder.overrideAuthority(serviceAddress);
823839
resolvedTarget = serviceAddress + ":" + port;
824840
}
825841
}

‎sdk-platform-java/gax-java/gax-grpc/src/test/java/com/google/api/gax/grpc/InstantiatingGrpcChannelProviderTest.java‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1786,6 +1786,8 @@ void canUseDirectPath_interconnectEnabledButDirectPathDisabled_fallsBackToCloudP
17861786
assertThat(logHandler.getAllMessages())
17871787
.contains("DirectPath was requested but is not available. Falling back to CloudPath.");
17881788
InstantiatingGrpcChannelProvider.LOG.removeHandler(logHandler);
1789+
String authority = extractAuthorityFromChannelBuilder(provider.createChannelBuilder());
1790+
Truth.assertThat(authority).isNotEqualTo("storage.googleapis.com");
17891791
}
17901792

17911793
@Test
@@ -1818,6 +1820,8 @@ void canUseDirectPath_interconnectAndDirectPathEnabledButNonGduUniverse_fallsBac
18181820
assertThat(logHandler.getAllMessages())
18191821
.contains("DirectPath was requested but is not available. Falling back to CloudPath.");
18201822
InstantiatingGrpcChannelProvider.LOG.removeHandler(logHandler);
1823+
String authority = extractAuthorityFromChannelBuilder(provider.createChannelBuilder());
1824+
Truth.assertThat(authority).isNotEqualTo("storage.googleapis.com");
18211825
}
18221826

18231827
private static class FakeLogHandler extends Handler {
@@ -1839,4 +1843,43 @@ List<String> getAllMessages() {
18391843
return records.stream().map(LogRecord::getMessage).collect(Collectors.toList());
18401844
}
18411845
}
1846+
1847+
1848+
private static String extractAuthorityFromChannelBuilder(
1849+
ManagedChannelBuilder<?> channelBuilder) {
1850+
try {
1851+
Object current = channelBuilder;
1852+
while (current != null) {
1853+
Class<?> clazz = current.getClass();
1854+
java.lang.reflect.Field field = null;
1855+
while (clazz != null) {
1856+
try {
1857+
field = clazz.getDeclaredField("authority");
1858+
break;
1859+
} catch (NoSuchFieldException e) {
1860+
try {
1861+
field = clazz.getDeclaredField("overrideAuthority");
1862+
break;
1863+
} catch (Exception ignored) {
1864+
}
1865+
clazz = clazz.getSuperclass();
1866+
}
1867+
}
1868+
if (field != null) {
1869+
field.setAccessible(true);
1870+
return (String) field.get(current);
1871+
}
1872+
try {
1873+
java.lang.reflect.Field delegate = current.getClass().getDeclaredField("delegate");
1874+
delegate.setAccessible(true);
1875+
current = delegate.get(current);
1876+
} catch (Exception e) {
1877+
break;
1878+
}
1879+
}
1880+
return null;
1881+
} catch (Exception e) {
1882+
throw new RuntimeException(e);
1883+
}
1884+
}
18421885
}

0 commit comments

Comments
 (0)