From e5afa24f74e5486d6b9839bb818415f0326c20c6 Mon Sep 17 00:00:00 2001 From: Aurelien Poscia Date: Mon, 21 Mar 2022 11:48:45 +0100 Subject: [PATCH] SONAR-16152 SONAR-16153 use user provided read/connect timeout for bitbucket cloud http client and stop following redirections --- .../alm/client/TimeoutConfigurationImpl.java | 8 ++- .../BitbucketCloudRestClient.java | 9 +-- ...BitbucketCloudRestClientConfiguration.java | 58 +++++++++++++++ ...ucketCloudRestClientConfigurationTest.java | 70 +++++++++++++++++++ .../server/util/OkHttpClientProvider.java | 2 + .../platformlevel/PlatformLevel4.java | 16 ++--- 6 files changed, 149 insertions(+), 14 deletions(-) create mode 100644 server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfiguration.java create mode 100644 server/sonar-alm-client/src/test/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfigurationTest.java diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/TimeoutConfigurationImpl.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/TimeoutConfigurationImpl.java index 529349922ed..d3634bd84f0 100644 --- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/TimeoutConfigurationImpl.java +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/TimeoutConfigurationImpl.java @@ -19,6 +19,7 @@ */ package org.sonar.alm.client; +import com.google.common.annotations.VisibleForTesting; import java.util.OptionalLong; import org.sonar.api.config.Configuration; import org.sonar.api.utils.log.Loggers; @@ -27,8 +28,11 @@ import org.sonar.api.utils.log.Loggers; * Implementation of {@link TimeoutConfiguration} reading values from configuration properties. */ public class TimeoutConfigurationImpl implements TimeoutConfiguration { - private static final String CONNECT_TIMEOUT_PROPERTY = "sonar.alm.timeout.connect"; - private static final String READ_TIMEOUT_PROPERTY = "sonar.alm.timeout.read"; + + @VisibleForTesting + public static final String CONNECT_TIMEOUT_PROPERTY = "sonar.alm.timeout.connect"; + @VisibleForTesting + public static final String READ_TIMEOUT_PROPERTY = "sonar.alm.timeout.read"; private static final long DEFAULT_TIMEOUT = 30_000; private final Configuration configuration; diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClient.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClient.java index f84d1e6b458..f8e8ce3b145 100644 --- a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClient.java +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClient.java @@ -61,13 +61,14 @@ public class BitbucketCloudRestClient { private final String bitbucketCloudEndpoint; private final String accessTokenEndpoint; + @Inject - public BitbucketCloudRestClient(OkHttpClient okHttpClient) { - this(okHttpClient, ENDPOINT, ACCESS_TOKEN_ENDPOINT); + public BitbucketCloudRestClient(OkHttpClient bitBucketCloudHttpClient) { + this(bitBucketCloudHttpClient, ENDPOINT, ACCESS_TOKEN_ENDPOINT); } - protected BitbucketCloudRestClient(OkHttpClient okHttpClient, String bitbucketCloudEndpoint, String accessTokenEndpoint) { - this.client = okHttpClient; + protected BitbucketCloudRestClient(OkHttpClient bitBucketCloudHttpClient, String bitbucketCloudEndpoint, String accessTokenEndpoint) { + this.client = bitBucketCloudHttpClient; this.bitbucketCloudEndpoint = bitbucketCloudEndpoint; this.accessTokenEndpoint = accessTokenEndpoint; } diff --git a/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfiguration.java b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfiguration.java new file mode 100644 index 00000000000..3a5a69ae93d --- /dev/null +++ b/server/sonar-alm-client/src/main/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfiguration.java @@ -0,0 +1,58 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.alm.client.bitbucket.bitbucketcloud; + +import okhttp3.OkHttpClient; +import org.sonar.alm.client.TimeoutConfiguration; +import org.sonar.api.ce.ComputeEngineSide; +import org.sonar.api.server.ServerSide; +import org.sonarqube.ws.client.OkHttpClientBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +@ComputeEngineSide +@ServerSide +@Configuration +@Lazy +public class BitbucketCloudRestClientConfiguration { + + private final TimeoutConfiguration timeoutConfiguration; + + @Autowired + public BitbucketCloudRestClientConfiguration(TimeoutConfiguration timeoutConfiguration) { + this.timeoutConfiguration = timeoutConfiguration; + } + + @Bean + public OkHttpClient bitbucketCloudHttpClient() { + OkHttpClientBuilder builder = new OkHttpClientBuilder(); + builder.setConnectTimeoutMs(timeoutConfiguration.getConnectTimeout()); + builder.setReadTimeoutMs(timeoutConfiguration.getReadTimeout()); + builder.setFollowRedirects(false); + return builder.build(); + } + + @Bean + public BitbucketCloudRestClient bitbucketCloudRestClient() { + return new BitbucketCloudRestClient(bitbucketCloudHttpClient()); + } +} diff --git a/server/sonar-alm-client/src/test/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfigurationTest.java b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfigurationTest.java new file mode 100644 index 00000000000..eba10a9ee31 --- /dev/null +++ b/server/sonar-alm-client/src/test/java/org/sonar/alm/client/bitbucket/bitbucketcloud/BitbucketCloudRestClientConfigurationTest.java @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2022 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.alm.client.bitbucket.bitbucketcloud; + +import java.io.IOException; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.Test; +import org.sonar.alm.client.TimeoutConfiguration; +import org.sonar.alm.client.TimeoutConfigurationImpl; +import org.sonar.api.config.internal.MapSettings; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.sonar.alm.client.TimeoutConfigurationImpl.CONNECT_TIMEOUT_PROPERTY; +import static org.sonar.alm.client.TimeoutConfigurationImpl.READ_TIMEOUT_PROPERTY; + +public class BitbucketCloudRestClientConfigurationTest { + + private static final long CONNECT_TIMEOUT_VALUE = 5435L; + private static final long READ_TIMEOUT_VALUE = 13123L; + + private final MapSettings settings = new MapSettings(); + private final TimeoutConfiguration timeoutConfiguration = new TimeoutConfigurationImpl(settings.asConfig()); + + private final BitbucketCloudRestClientConfiguration underTest = new BitbucketCloudRestClientConfiguration(timeoutConfiguration); + + public MockWebServer server = new MockWebServer(); + + @Test + public void bitBucketCloudHttpClient_returnsCorrectlyConfiguredHttpClient() throws Exception { + settings.setProperty(CONNECT_TIMEOUT_PROPERTY, CONNECT_TIMEOUT_VALUE); + settings.setProperty(READ_TIMEOUT_PROPERTY, READ_TIMEOUT_VALUE); + + OkHttpClient client = underTest.bitbucketCloudHttpClient(); + + assertThat(client.connectTimeoutMillis()).isEqualTo(CONNECT_TIMEOUT_VALUE); + assertThat(client.readTimeoutMillis()).isEqualTo(READ_TIMEOUT_VALUE); + assertThat(client.proxy()).isNull(); + assertThat(client.followRedirects()).isFalse(); + + RecordedRequest recordedRequest = call(client); + assertThat(recordedRequest.getHeader("Proxy-Authorization")).isNull(); + } + + private RecordedRequest call(OkHttpClient client) throws IOException, InterruptedException { + server.enqueue(new MockResponse().setBody("pong")); + client.newCall(new Request.Builder().url(server.url("/ping")).build()).execute(); + return server.takeRequest(); + } +} diff --git a/server/sonar-server-common/src/main/java/org/sonar/server/util/OkHttpClientProvider.java b/server/sonar-server-common/src/main/java/org/sonar/server/util/OkHttpClientProvider.java index 8c1a88e9484..3a50f78a28e 100644 --- a/server/sonar-server-common/src/main/java/org/sonar/server/util/OkHttpClientProvider.java +++ b/server/sonar-server-common/src/main/java/org/sonar/server/util/OkHttpClientProvider.java @@ -26,6 +26,7 @@ import org.sonar.api.config.Configuration; import org.sonar.api.server.ServerSide; import org.sonarqube.ws.client.OkHttpClientBuilder; import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Primary; import static java.lang.String.format; import static org.sonar.process.ProcessProperties.Property.HTTP_PROXY_PASSWORD; @@ -51,6 +52,7 @@ public class OkHttpClientProvider { /** * @return a {@link OkHttpClient} singleton */ + @Primary @Bean("OkHttpClient") public OkHttpClient provide(Configuration config, SonarRuntime runtime) { OkHttpClientBuilder builder = new OkHttpClientBuilder(); diff --git a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java index 9cc89f31eee..467040683db 100644 --- a/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java +++ b/server/sonar-webserver/src/main/java/org/sonar/server/platform/platformlevel/PlatformLevel4.java @@ -23,7 +23,7 @@ import java.util.List; import org.sonar.alm.client.TimeoutConfigurationImpl; import org.sonar.alm.client.azure.AzureDevOpsHttpClient; import org.sonar.alm.client.azure.AzureDevOpsValidator; -import org.sonar.alm.client.bitbucket.bitbucketcloud.BitbucketCloudRestClient; +import org.sonar.alm.client.bitbucket.bitbucketcloud.BitbucketCloudRestClientConfiguration; import org.sonar.alm.client.bitbucket.bitbucketcloud.BitbucketCloudValidator; import org.sonar.alm.client.bitbucketserver.BitbucketServerRestClient; import org.sonar.alm.client.bitbucketserver.BitbucketServerSettingsValidator; @@ -184,14 +184,13 @@ import org.sonar.server.projectlink.ws.ProjectLinksModule; import org.sonar.server.projecttag.ws.ProjectTagsWsModule; import org.sonar.server.property.InternalPropertiesImpl; import org.sonar.server.pushapi.ServerPushWsModule; +import org.sonar.server.pushapi.qualityprofile.DistributedRuleActivatorEventsDistributor; +import org.sonar.server.pushapi.qualityprofile.QualityProfileChangeEventServiceImpl; +import org.sonar.server.pushapi.qualityprofile.StandaloneRuleActivatorEventsDistributor; import org.sonar.server.qualitygate.ProjectsInWarningModule; import org.sonar.server.qualitygate.QualityGateModule; import org.sonar.server.qualitygate.notification.QGChangeNotificationHandler; import org.sonar.server.qualitygate.ws.QualityGateWsModule; -import org.sonar.server.qualityprofile.builtin.BuiltInQPChangeNotificationHandler; -import org.sonar.server.qualityprofile.builtin.BuiltInQPChangeNotificationTemplate; -import org.sonar.server.qualityprofile.builtin.BuiltInQProfileRepositoryImpl; -import org.sonar.server.pushapi.qualityprofile.DistributedRuleActivatorEventsDistributor; import org.sonar.server.qualityprofile.QProfileBackuperImpl; import org.sonar.server.qualityprofile.QProfileComparison; import org.sonar.server.qualityprofile.QProfileCopier; @@ -201,9 +200,10 @@ import org.sonar.server.qualityprofile.QProfileParser; import org.sonar.server.qualityprofile.QProfileResetImpl; import org.sonar.server.qualityprofile.QProfileRulesImpl; import org.sonar.server.qualityprofile.QProfileTreeImpl; -import org.sonar.server.pushapi.qualityprofile.QualityProfileChangeEventServiceImpl; +import org.sonar.server.qualityprofile.builtin.BuiltInQPChangeNotificationHandler; +import org.sonar.server.qualityprofile.builtin.BuiltInQPChangeNotificationTemplate; +import org.sonar.server.qualityprofile.builtin.BuiltInQProfileRepositoryImpl; import org.sonar.server.qualityprofile.builtin.RuleActivator; -import org.sonar.server.pushapi.qualityprofile.StandaloneRuleActivatorEventsDistributor; import org.sonar.server.qualityprofile.index.ActiveRuleIndexer; import org.sonar.server.qualityprofile.ws.QProfilesWsModule; import org.sonar.server.root.ws.RootWsModule; @@ -537,8 +537,8 @@ public class PlatformLevel4 extends PlatformLevel { GithubAppSecurityImpl.class, GithubApplicationClientImpl.class, GithubApplicationHttpClientImpl.class, + BitbucketCloudRestClientConfiguration.class, BitbucketServerRestClient.class, - BitbucketCloudRestClient.class, GitlabHttpClient.class, AzureDevOpsHttpClient.class, new AlmIntegrationsWSModule(), -- 2.39.5