Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
group=io.flamingock
version=1.2.0-beta
version=1.2.0-beta.2
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -69,15 +67,9 @@ public Path downloadTo(Path workspace, URI sourceUri, String targetFileName, Str
.header("User-Agent", userAgent)
.GET()
.build();
HttpResponse<Path> response;
try {
HttpResponse<Path> 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
Expand All @@ -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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -137,6 +147,10 @@ public HttpResponse<Path> 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<Path> {

@Override
Expand Down
Loading