alt: do not retry when server respond with 404

This commit is contained in:
huanghongxun 2020-04-15 13:46:44 +08:00
parent 97e8ff91ea
commit f84c4310f9
3 changed files with 127 additions and 113 deletions

View File

@ -63,8 +63,20 @@ public class AdaptedDownloadProvider implements DownloadProvider {
public List<URL> injectURLWithCandidates(String baseURL) { public List<URL> injectURLWithCandidates(String baseURL) {
List<DownloadProvider> d = downloadProviderCandidates; List<DownloadProvider> d = downloadProviderCandidates;
List<URL> results = new ArrayList<>(d.size()); List<URL> results = new ArrayList<>(d.size());
for (int i = 0; i < d.size(); i++) { for (DownloadProvider downloadProvider : d) {
results.add(NetworkUtils.toURL(d.get(i).injectURL(baseURL))); results.add(NetworkUtils.toURL(downloadProvider.injectURL(baseURL)));
}
return results;
}
@Override
public List<URL> injectURLsWithCandidates(List<String> urls) {
List<DownloadProvider> d = downloadProviderCandidates;
List<URL> results = new ArrayList<>(d.size());
for (DownloadProvider downloadProvider : d) {
for (String baseURL : urls) {
results.add(NetworkUtils.toURL(downloadProvider.injectURL(baseURL)));
}
} }
return results; return results;
} }

View File

@ -88,8 +88,8 @@ public final class ForgeBMCLVersionList extends VersionList<ForgeRemoteVersion>
+ (StringUtils.isNotBlank(version.getBranch()) ? "-" + version.getBranch() : ""); + (StringUtils.isNotBlank(version.getBranch()) ? "-" + version.getBranch() : "");
String fileName1 = "forge-" + classifier + "-" + file.getCategory() + "." + file.getFormat(); String fileName1 = "forge-" + classifier + "-" + file.getCategory() + "." + file.getFormat();
String fileName2 = "forge-" + classifier + "-" + gameVersion + "-" + file.getCategory() + "." + file.getFormat(); String fileName2 = "forge-" + classifier + "-" + gameVersion + "-" + file.getCategory() + "." + file.getFormat();
urls.add("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" + classifier + "-" + gameVersion + "/" + fileName2);
urls.add("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" + classifier + "/" + fileName1); urls.add("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" + classifier + "/" + fileName1);
urls.add("https://files.minecraftforge.net/maven/net/minecraftforge/forge/" + classifier + "-" + gameVersion + "/" + fileName2);
urls.add(NetworkUtils.withQuery("https://bmclapi2.bangbang93.com/forge/download", mapOf( urls.add(NetworkUtils.withQuery("https://bmclapi2.bangbang93.com/forge/download", mapOf(
pair("mcversion", version.getGameVersion()), pair("mcversion", version.getGameVersion()),
pair("version", version.getVersion()), pair("version", version.getVersion()),

View File

@ -227,133 +227,135 @@ public class FileDownloadTask extends Task<Void> {
Exception exception = null; Exception exception = null;
URL failedURL = null; URL failedURL = null;
for (int repeat = 0; repeat < retry * urls.size(); repeat++) { int repeat = 0;
URL url = urls.get(repeat / retry); download: for (URL url : urls) {
if (isCancelled()) { for (int retryTime = 0; retryTime < retry; retryTime++) {
break; if (isCancelled()) {
} break download;
Logging.LOG.log(Level.FINER, "Downloading " + url + " to " + file);
Path temp = null;
try {
updateProgress(0);
HttpURLConnection con = NetworkUtils.createConnection(url);
if (checkETag) repository.injectConnection(con);
con = NetworkUtils.resolveConnection(con);
if (con.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
// Handle cache
try {
Path cache = repository.getCachedRemoteFile(con);
FileUtils.copyFile(cache.toFile(), file);
return;
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Unable to use cached file, redownload it", e);
repository.removeRemoteEntry(con);
// Now we must reconnect the server since 304 may result in empty content,
// if we want to redownload the file, we must reconnect the server without etag settings.
repeat--;
continue;
}
} else if (con.getResponseCode() / 100 == 4) {
} else if (con.getResponseCode() / 100 != 2) {
throw new ResponseCodeException(url, con.getResponseCode());
} }
int contentLength = con.getContentLength(); Logging.LOG.log(Level.FINER, "Downloading " + url + " to " + file);
if (contentLength < 0) Path temp = null;
throw new IOException("The content length is invalid.");
if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile())) try {
throw new IOException("Could not make directory " + file.getAbsoluteFile().getParent()); updateProgress(0);
temp = Files.createTempFile(null, null); HttpURLConnection con = NetworkUtils.createConnection(url);
rFile = new RandomAccessFile(temp.toFile(), "rw"); if (checkETag) repository.injectConnection(con);
con = NetworkUtils.resolveConnection(con);
MessageDigest digest = integrityCheck == null ? null : integrityCheck.createDigest(); if (con.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
// Handle cache
stream = con.getInputStream(); try {
int lastDownloaded = 0, downloaded = 0; Path cache = repository.getCachedRemoteFile(con);
byte[] buffer = new byte[IOUtils.DEFAULT_BUFFER_SIZE]; FileUtils.copyFile(cache.toFile(), file);
while (true) { return;
if (isCancelled()) { } catch (IOException e) {
break; Logging.LOG.log(Level.WARNING, "Unable to use cached file, redownload it", e);
repository.removeRemoteEntry(con);
// Now we must reconnect the server since 304 may result in empty content,
// if we want to redownload the file, we must reconnect the server without etag settings.
retryTime--;
continue;
}
} else if (con.getResponseCode() / 100 == 4) {
break; // we will not try this URL again
} else if (con.getResponseCode() / 100 != 2) {
throw new ResponseCodeException(url, con.getResponseCode());
} }
int read = stream.read(buffer); int contentLength = con.getContentLength();
if (read == -1) if (contentLength < 0)
break; throw new IOException("The content length is invalid.");
if (digest != null) { if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile()))
digest.update(buffer, 0, read); throw new IOException("Could not make directory " + file.getAbsoluteFile().getParent());
temp = Files.createTempFile(null, null);
rFile = new RandomAccessFile(temp.toFile(), "rw");
MessageDigest digest = integrityCheck == null ? null : integrityCheck.createDigest();
stream = con.getInputStream();
int lastDownloaded = 0, downloaded = 0;
byte[] buffer = new byte[IOUtils.DEFAULT_BUFFER_SIZE];
while (true) {
if (isCancelled()) {
break;
}
int read = stream.read(buffer);
if (read == -1)
break;
if (digest != null) {
digest.update(buffer, 0, read);
}
// Write buffer to file.
rFile.write(buffer, 0, read);
downloaded += read;
// Update progress information per second
updateProgress(downloaded, contentLength);
updateDownloadSpeed(downloaded - lastDownloaded);
lastDownloaded = downloaded;
} }
// Write buffer to file.
rFile.write(buffer, 0, read);
downloaded += read;
// Update progress information per second
updateProgress(downloaded, contentLength);
updateDownloadSpeed(downloaded - lastDownloaded); updateDownloadSpeed(downloaded - lastDownloaded);
lastDownloaded = downloaded;
}
updateDownloadSpeed(downloaded - lastDownloaded); closeFiles();
closeFiles(); if (downloaded != contentLength)
throw new IOException("Unexpected file size: " + downloaded + ", expected: " + contentLength);
if (downloaded != contentLength) // Restore temp file to original name.
throw new IOException("Unexpected file size: " + downloaded + ", expected: " + contentLength); if (isCancelled()) {
temp.toFile().delete();
// Restore temp file to original name. break download;
if (isCancelled()) {
temp.toFile().delete();
break;
}
for (IntegrityCheckHandler handler : integrityCheckHandlers) {
handler.checkIntegrity(temp, file.toPath());
}
Files.deleteIfExists(file.toPath());
if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile()))
throw new IOException("Unable to make parent directory " + file);
try {
FileUtils.moveFile(temp.toFile(), file);
} catch (Exception e) {
throw new IOException("Unable to move temp file from " + temp + " to " + file, e);
}
// Integrity check
if (integrityCheck != null) {
integrityCheck.performCheck(digest);
}
if (caching && integrityCheck != null) {
try {
repository.cacheFile(file.toPath(), integrityCheck.getAlgorithm(), integrityCheck.getChecksum());
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Failed to cache file", e);
} }
}
if (checkETag) { for (IntegrityCheckHandler handler : integrityCheckHandlers) {
repository.cacheRemoteFile(file.toPath(), con); handler.checkIntegrity(temp, file.toPath());
} }
return; Files.deleteIfExists(file.toPath());
} catch (IOException e) { if (!FileUtils.makeDirectory(file.getAbsoluteFile().getParentFile()))
if (temp != null) throw new IOException("Unable to make parent directory " + file);
temp.toFile().delete(); try {
failedURL = url; FileUtils.moveFile(temp.toFile(), file);
exception = e; } catch (Exception e) {
Logging.LOG.log(Level.WARNING, "Failed to download " + url + ", repeat times: " + (repeat + 1), e); throw new IOException("Unable to move temp file from " + temp + " to " + file, e);
} finally { }
closeFiles();
// Integrity check
if (integrityCheck != null) {
integrityCheck.performCheck(digest);
}
if (caching && integrityCheck != null) {
try {
repository.cacheFile(file.toPath(), integrityCheck.getAlgorithm(), integrityCheck.getChecksum());
} catch (IOException e) {
Logging.LOG.log(Level.WARNING, "Failed to cache file", e);
}
}
if (checkETag) {
repository.cacheRemoteFile(file.toPath(), con);
}
return;
} catch (IOException e) {
if (temp != null)
temp.toFile().delete();
failedURL = url;
exception = e;
Logging.LOG.log(Level.WARNING, "Failed to download " + url + ", repeat times: " + (++repeat), e);
} finally {
closeFiles();
}
} }
} }