Skip to content

Commit df0dd8c

Browse files
committed
SCANJLIB-245 Add support for redirects
1 parent 4a07f90 commit df0dd8c

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

lib/src/main/java/org/sonarsource/scanner/lib/internal/http/ScannerHttpClient.java

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ public class ScannerHttpClient {
4343
private static final String EXCEPTION_MESSAGE_MISSING_SLASH = "URL path must start with slash: %s";
4444

4545

46-
private OkHttpClient httpClient;
46+
private OkHttpClient sharedHttpClient;
4747
private HttpConfig httpConfig;
4848

4949
public void init(HttpConfig httpConfig) {
5050
this.httpConfig = httpConfig;
51-
this.httpClient = OkHttpClientFactory.create(httpConfig);
51+
this.sharedHttpClient = OkHttpClientFactory.create(httpConfig);
5252
}
5353

5454

@@ -82,9 +82,6 @@ public void downloadFromExternalUrl(String url, Path toFile) throws IOException
8282
* @throws IllegalStateException if HTTP response code is different than 2xx
8383
*/
8484
private void downloadFile(String url, Path toFile, boolean authentication) throws IOException {
85-
if (httpClient == null) {
86-
throw new IllegalStateException("ServerConnection must be initialized");
87-
}
8885
LOG.debug("Download {} to {}", url, toFile.toAbsolutePath());
8986

9087
try (ResponseBody responseBody = callUrl(url, authentication, "application/octet-stream");
@@ -120,9 +117,6 @@ public String callWebApi(String urlPath) throws IOException {
120117
* @throws IllegalStateException if HTTP response code is different than 2xx
121118
*/
122119
private String callApi(String url) throws IOException {
123-
if (httpClient == null) {
124-
throw new IllegalStateException("ServerConnection must be initialized");
125-
}
126120
try (ResponseBody responseBody = callUrl(url, true, null)) {
127121
return responseBody.string();
128122
}
@@ -141,12 +135,21 @@ private ResponseBody callUrl(String url, boolean authentication, @Nullable Strin
141135
.get()
142136
.url(url)
143137
.addHeader("User-Agent", httpConfig.getUserAgent());
138+
OkHttpClient httpClient;
144139
if (authentication) {
145-
if (httpConfig.getToken() != null) {
146-
requestBuilder.header("Authorization", "Bearer " + httpConfig.getToken());
147-
} else if (httpConfig.getLogin() != null) {
148-
requestBuilder.header("Authorization", Credentials.basic(httpConfig.getLogin(), httpConfig.getPassword() != null ? httpConfig.getPassword() : ""));
149-
}
140+
httpClient = sharedHttpClient.newBuilder()
141+
.addNetworkInterceptor(chain -> {
142+
Request request = chain.request();
143+
if (httpConfig.getToken() != null) {
144+
request = request.newBuilder().header("Authorization", "Bearer " + httpConfig.getToken()).build();
145+
} else if (httpConfig.getLogin() != null) {
146+
request = request.newBuilder().header("Authorization", Credentials.basic(httpConfig.getLogin(), httpConfig.getPassword() != null ? httpConfig.getPassword() : "")).build();
147+
}
148+
return chain.proceed(request);
149+
})
150+
.build();
151+
} else {
152+
httpClient = sharedHttpClient;
150153
}
151154
if (acceptHeader != null) {
152155
requestBuilder.header("Accept", acceptHeader);

lib/src/test/java/org/sonarsource/scanner/lib/internal/http/ScannerHttpClientTest.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
import org.junit.jupiter.api.Test;
3030
import org.junit.jupiter.api.extension.RegisterExtension;
3131
import org.junit.jupiter.api.io.TempDir;
32+
import org.junit.jupiter.params.ParameterizedTest;
33+
import org.junit.jupiter.params.provider.ValueSource;
3234
import org.sonarsource.scanner.lib.ScannerProperties;
3335
import org.sonarsource.scanner.lib.internal.InternalProperties;
3436

@@ -51,6 +53,11 @@ class ScannerHttpClientTest {
5153
.options(wireMockConfig().dynamicPort())
5254
.build();
5355

56+
@RegisterExtension
57+
static WireMockExtension redirectProxy = WireMockExtension.newInstance()
58+
.options(wireMockConfig().dynamicPort())
59+
.build();
60+
5461
@TempDir
5562
private Path sonarUserHome;
5663

@@ -168,6 +175,28 @@ void downloadFromExternalUrl_shouldNotPassAuth(@TempDir Path tmpFolder) throws E
168175
.withoutHeader("Authorization"));
169176
}
170177

178+
@ParameterizedTest
179+
@ValueSource(ints = {301, 302, 303, 307, 308})
180+
void should_follow_redirects_and_preserve_authentication(int code) throws Exception {
181+
Map<String, String> props = new HashMap<>();
182+
props.put("sonar.login", "some_username");
183+
props.put("sonar.password", "some_password");
184+
ScannerHttpClient connection = create(redirectProxy.baseUrl(), props);
185+
186+
redirectProxy.stubFor(get("/batch/index.txt")
187+
.willReturn(aResponse()
188+
.withHeader("Location", sonarqube.baseUrl() + "/batch/index.txt")
189+
.withStatus(code)));
190+
191+
answer(HELLO_WORLD);
192+
String content = connection.callWebApi("/batch/index.txt");
193+
assertThat(content).isEqualTo(HELLO_WORLD);
194+
195+
sonarqube.verify(getRequestedFor(anyUrl())
196+
.withHeader("Authorization",
197+
equalTo("Basic " + Base64.getEncoder().encodeToString("some_username:some_password".getBytes(StandardCharsets.UTF_8)))));
198+
}
199+
171200
private ScannerHttpClient create() {
172201
return create(sonarqube.baseUrl());
173202
}

0 commit comments

Comments
 (0)