diff --git a/gradle.properties b/gradle.properties index 1b0cb24..f183279 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ group=io.flamingock -version=1.2.0-beta +version=1.2.0-beta.2 diff --git a/src/main/java/io/flamingock/cli/executor/util/http/HttpFileDownloader.java b/src/main/java/io/flamingock/cli/executor/util/http/HttpFileDownloader.java index bcff9b3..44db993 100644 --- a/src/main/java/io/flamingock/cli/executor/util/http/HttpFileDownloader.java +++ b/src/main/java/io/flamingock/cli/executor/util/http/HttpFileDownloader.java @@ -37,10 +37,8 @@ public class HttpFileDownloader { private final Duration requestTimeout; public HttpFileDownloader() { - this(DEFAULT_CONNECT_TIMEOUT, DEFAULT_REQUEST_TIMEOUT, (request, target, resolvedConnectTimeout) -> HttpClient.newBuilder() - .connectTimeout(resolvedConnectTimeout) - .build() - .send(request, HttpResponse.BodyHandlers.ofFile(target))); + this(DEFAULT_CONNECT_TIMEOUT, DEFAULT_REQUEST_TIMEOUT, (request, target, resolvedConnectTimeout) -> + createHttpClient(resolvedConnectTimeout).send(request, HttpResponse.BodyHandlers.ofFile(target))); } HttpFileDownloader(Duration connectTimeout, Duration requestTimeout, DownloadExecutor downloadExecutor) { @@ -69,15 +67,9 @@ public Path downloadTo(Path workspace, URI sourceUri, String targetFileName, Str .header("User-Agent", userAgent) .GET() .build(); + HttpResponse response; try { - HttpResponse response = downloadExecutor.download(request, targetFile, connectTimeout); - if (response.statusCode() < 200 || response.statusCode() >= 300) { - deletePartialFile(targetFile); - throw new IOException("Download failed while fetching " + downloadLabel - + " with HTTP " + response.statusCode() + " from " + sourceUri - + ". Check your network connection and retry."); - } - return targetFile; + response = downloadExecutor.download(request, targetFile, connectTimeout); } catch (IOException e) { deletePartialFile(targetFile); throw new IOException("Download failed while fetching " + downloadLabel @@ -88,6 +80,21 @@ public Path downloadTo(Path workspace, URI sourceUri, String targetFileName, Str throw new IOException("Download interrupted while fetching " + downloadLabel + ". Retry the command once the interruption is cleared.", e); } + + if (response.statusCode() < 200 || response.statusCode() >= 300) { + deletePartialFile(targetFile); + throw new IOException("Download failed while fetching " + downloadLabel + + " with HTTP " + response.statusCode() + " from " + sourceUri + + ". Check your network connection and retry."); + } + return targetFile; + } + + static HttpClient createHttpClient(Duration connectTimeout) { + return HttpClient.newBuilder() + .connectTimeout(connectTimeout) + .followRedirects(HttpClient.Redirect.NORMAL) + .build(); } private void deletePartialFile(Path targetFile) throws IOException { diff --git a/src/test/java/io/flamingock/cli/executor/util/http/HttpFileDownloaderTest.java b/src/test/java/io/flamingock/cli/executor/util/http/HttpFileDownloaderTest.java index b8b87ca..059a877 100644 --- a/src/test/java/io/flamingock/cli/executor/util/http/HttpFileDownloaderTest.java +++ b/src/test/java/io/flamingock/cli/executor/util/http/HttpFileDownloaderTest.java @@ -21,6 +21,7 @@ import javax.net.ssl.SSLSession; import java.io.IOException; import java.net.URI; +import java.net.http.HttpClient; import java.net.http.HttpHeaders; import java.net.http.HttpRequest; import java.net.http.HttpResponse; @@ -68,9 +69,18 @@ void downloadTo_deletesPartialArchiveWhenServerReturnsFailure() { assertTrue(exception.getMessage().contains(DOWNLOAD_LABEL)); assertTrue(exception.getMessage().contains("HTTP 503")); + assertEquals(1, countOccurrences(exception.getMessage(), "Download failed while fetching")); assertFalse(Files.exists(workspace.resolve(TARGET_FILE_NAME))); } + @Test + void createHttpClient_followsStandardRedirects() { + HttpClient client = HttpFileDownloader.createHttpClient(Duration.ofSeconds(10)); + + assertEquals(HttpClient.Redirect.NORMAL, client.followRedirects()); + assertEquals(Duration.ofSeconds(10), client.connectTimeout().orElseThrow()); + } + @Test void downloadTo_setsReasonableTimeoutsAndUserAgent() throws Exception { RecordingDownloadExecutor executor = new RecordingDownloadExecutor(200); @@ -137,6 +147,10 @@ public HttpResponse download(HttpRequest request, Path target, Duration co } } + private static int countOccurrences(String text, String token) { + return text.split(java.util.regex.Pattern.quote(token), -1).length - 1; + } + private record HttpResponseStub(int statusCode, Path body, HttpRequest request) implements HttpResponse { @Override