Skip to content

Commit

Permalink
SCANJLIB-245 Add support for redirects
Browse files Browse the repository at this point in the history
  • Loading branch information
henryju committed Dec 19, 2024
1 parent 4a07f90 commit c1c8709
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ public class ScannerHttpClient {
private static final String EXCEPTION_MESSAGE_MISSING_SLASH = "URL path must start with slash: %s";


private OkHttpClient httpClient;
private OkHttpClient sharedHttpClient;
private HttpConfig httpConfig;

public void init(HttpConfig httpConfig) {
this.httpConfig = httpConfig;
this.httpClient = OkHttpClientFactory.create(httpConfig);
this.sharedHttpClient = OkHttpClientFactory.create(httpConfig);
}


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

try (ResponseBody responseBody = callUrl(url, authentication, "application/octet-stream");
Expand Down Expand Up @@ -120,9 +117,6 @@ public String callWebApi(String urlPath) throws IOException {
* @throws IllegalStateException if HTTP response code is different than 2xx
*/
private String callApi(String url) throws IOException {
if (httpClient == null) {
throw new IllegalStateException("ServerConnection must be initialized");
}
try (ResponseBody responseBody = callUrl(url, true, null)) {
return responseBody.string();
}
Expand All @@ -137,21 +131,8 @@ private String callApi(String url) throws IOException {
* @throws IllegalStateException if HTTP code is different than 2xx
*/
private ResponseBody callUrl(String url, boolean authentication, @Nullable String acceptHeader) {
var requestBuilder = new Request.Builder()
.get()
.url(url)
.addHeader("User-Agent", httpConfig.getUserAgent());
if (authentication) {
if (httpConfig.getToken() != null) {
requestBuilder.header("Authorization", "Bearer " + httpConfig.getToken());
} else if (httpConfig.getLogin() != null) {
requestBuilder.header("Authorization", Credentials.basic(httpConfig.getLogin(), httpConfig.getPassword() != null ? httpConfig.getPassword() : ""));
}
}
if (acceptHeader != null) {
requestBuilder.header("Accept", acceptHeader);
}
Request request = requestBuilder.build();
var httpClient = buildHttpClient(authentication);
var request = prepareRequest(url, acceptHeader);
Response response;
try {
response = httpClient.newCall(request).execute();
Expand All @@ -164,4 +145,37 @@ private ResponseBody callUrl(String url, boolean authentication, @Nullable Strin
}
return response.body();
}

private Request prepareRequest(String url, @org.jetbrains.annotations.Nullable String acceptHeader) {
var requestBuilder = new Request.Builder()
.get()
.url(url)
.addHeader("User-Agent", httpConfig.getUserAgent());
if (acceptHeader != null) {
requestBuilder.header("Accept", acceptHeader);
}
return requestBuilder.build();
}

private OkHttpClient buildHttpClient(boolean authentication) {
if (authentication) {
return sharedHttpClient.newBuilder()
.addNetworkInterceptor(chain -> {
Request request = chain.request();
if (httpConfig.getToken() != null) {
request = request.newBuilder()
.header("Authorization", "Bearer " + httpConfig.getToken())
.build();
} else if (httpConfig.getLogin() != null) {
request = request.newBuilder()
.header("Authorization", Credentials.basic(httpConfig.getLogin(), httpConfig.getPassword() != null ? httpConfig.getPassword() : ""))
.build();
}
return chain.proceed(request);
})
.build();
} else {
return sharedHttpClient;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.sonarsource.scanner.lib.ScannerProperties;
import org.sonarsource.scanner.lib.internal.InternalProperties;

Expand All @@ -51,6 +53,11 @@ class ScannerHttpClientTest {
.options(wireMockConfig().dynamicPort())
.build();

@RegisterExtension
static WireMockExtension redirectProxy = WireMockExtension.newInstance()
.options(wireMockConfig().dynamicPort())
.build();

@TempDir
private Path sonarUserHome;

Expand Down Expand Up @@ -168,6 +175,28 @@ void downloadFromExternalUrl_shouldNotPassAuth(@TempDir Path tmpFolder) throws E
.withoutHeader("Authorization"));
}

@ParameterizedTest
@ValueSource(ints = {301, 302, 303, 307, 308})
void should_follow_redirects_and_preserve_authentication(int code) throws Exception {
Map<String, String> props = new HashMap<>();
props.put("sonar.login", "some_username");
props.put("sonar.password", "some_password");
ScannerHttpClient connection = create(redirectProxy.baseUrl(), props);

redirectProxy.stubFor(get("/batch/index.txt")
.willReturn(aResponse()
.withHeader("Location", sonarqube.baseUrl() + "/batch/index.txt")
.withStatus(code)));

answer(HELLO_WORLD);
String content = connection.callWebApi("/batch/index.txt");
assertThat(content).isEqualTo(HELLO_WORLD);

sonarqube.verify(getRequestedFor(anyUrl())
.withHeader("Authorization",
equalTo("Basic " + Base64.getEncoder().encodeToString("some_username:some_password".getBytes(StandardCharsets.UTF_8)))));
}

private ScannerHttpClient create() {
return create(sonarqube.baseUrl());
}
Expand Down

0 comments on commit c1c8709

Please sign in to comment.