Fix response code 400 when downloading mods from curse

This commit is contained in:
huanghongxun
2018-10-10 15:27:27 +08:00
parent 5eb7449b74
commit 94727353c4
8 changed files with 51 additions and 11 deletions

View File

@@ -54,6 +54,7 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem;
import org.jackhuang.hmcl.util.versioning.VersionNumber; import org.jackhuang.hmcl.util.versioning.VersionNumber;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
@@ -216,6 +217,9 @@ public final class LauncherHelper {
if (ex != null) { if (ex != null) {
String message; String message;
if (ex instanceof CurseCompletionException) { if (ex instanceof CurseCompletionException) {
if (ex.getCause() instanceof FileNotFoundException)
message = i18n("modpack.type.curse.not_found");
else
message = i18n("modpack.type.curse.error"); message = i18n("modpack.type.curse.error");
} else if (ex instanceof PermissionException) { } else if (ex instanceof PermissionException) {
message = i18n("launch.failed.executable_permission"); message = i18n("launch.failed.executable_permission");

View File

@@ -222,6 +222,7 @@ modpack.task.install.will=Install the modpack:
modpack.type.curse=Curse modpack.type.curse=Curse
modpack.type.curse.completion=Install relative files to Curse modpack modpack.type.curse.completion=Install relative files to Curse modpack
modpack.type.curse.error=Unable to complete this Curse modpack. Please retry. modpack.type.curse.error=Unable to complete this Curse modpack. Please retry.
modpack.type.curse.not_found=Some of required resources are deleted and cannot be downloaded. Please consider the latest version or other modpacks.
modpack.type.hmcl=HMCL modpack.type.hmcl=HMCL
modpack.type.multimc=MultiMC modpack.type.multimc=MultiMC
modpack.unsupported=Unsupported modpack, only HMCL, MultiMC, Curse modpacks are supported. modpack.unsupported=Unsupported modpack, only HMCL, MultiMC, Curse modpacks are supported.

View File

@@ -222,6 +222,7 @@ modpack.task.install.will=將會安裝整合包:
modpack.type.curse=Curse modpack.type.curse=Curse
modpack.type.curse.completion=下載 Curse 整合包相關檔案 modpack.type.curse.completion=下載 Curse 整合包相關檔案
modpack.type.curse.error=無法完成 Curse 整合包的下載,請多次重試或設定代理 modpack.type.curse.error=無法完成 Curse 整合包的下載,請多次重試或設定代理
modpack.type.curse.not_found=部分必需檔案已經從網路中被刪除並且再也無法下載,請嘗試該整合包的最新版本或者安裝其他整合包。
modpack.type.hmcl=HMCL modpack.type.hmcl=HMCL
modpack.type.multimc=MultiMC modpack.type.multimc=MultiMC
modpack.unsupported=不支援該整合包。僅 HMCL、MultiMC、Curse 整合包受支援。 modpack.unsupported=不支援該整合包。僅 HMCL、MultiMC、Curse 整合包受支援。

View File

@@ -222,6 +222,7 @@ modpack.task.install.will=将会安装整合包:
modpack.type.curse=Curse modpack.type.curse=Curse
modpack.type.curse.completion=下载 Curse 整合包相关文件 modpack.type.curse.completion=下载 Curse 整合包相关文件
modpack.type.curse.error=未能完成 Curse 整合包的下载,请多次重试或设置代理 modpack.type.curse.error=未能完成 Curse 整合包的下载,请多次重试或设置代理
modpack.type.curse.not_found=部分必需文件已经在网络中被删除并且再也无法下载,请尝试该整合包的最新版本或者安装其他整合包。
modpack.type.hmcl=HMCL modpack.type.hmcl=HMCL
modpack.type.multimc=MultiMC modpack.type.multimc=MultiMC
modpack.unsupported=该整合包不被支持。仅 HMCL、MultiMC、Curse 整合包受支持。 modpack.unsupported=该整合包不被支持。仅 HMCL、MultiMC、Curse 整合包受支持。

View File

@@ -35,9 +35,12 @@ public class LibraryDownloadTask extends Task {
protected final Library library; protected final Library library;
protected final String url; protected final String url;
protected boolean xz; protected boolean xz;
private final Library originalLibrary;
private boolean cached = false; private boolean cached = false;
public LibraryDownloadTask(AbstractDependencyManager dependencyManager, File file, Library library) { public LibraryDownloadTask(AbstractDependencyManager dependencyManager, File file, Library library) {
this.originalLibrary = library;
setSignificance(TaskSignificance.MODERATE); setSignificance(TaskSignificance.MODERATE);
if (library.is("net.minecraftforge", "forge")) if (library.is("net.minecraftforge", "forge"))
@@ -86,7 +89,7 @@ public class LibraryDownloadTask extends Task {
@Override @Override
public void preExecute() throws Exception { public void preExecute() throws Exception {
Optional<Path> libPath = cacheRepository.getLibrary(library.setClassifier(null)); Optional<Path> libPath = cacheRepository.getLibrary(originalLibrary);
if (libPath.isPresent()) { if (libPath.isPresent()) {
try { try {
FileUtils.copyFile(libPath.get().toFile(), jar); FileUtils.copyFile(libPath.get().toFile(), jar);

View File

@@ -27,10 +27,12 @@ import org.jackhuang.hmcl.util.io.FileUtils;
import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.io.NetworkUtils;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.util.Collection; import java.util.Collection;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level; import java.util.logging.Level;
@@ -103,6 +105,7 @@ public final class CurseCompletionTask extends Task {
AtomicBoolean flag = new AtomicBoolean(true); AtomicBoolean flag = new AtomicBoolean(true);
AtomicInteger finished = new AtomicInteger(0); AtomicInteger finished = new AtomicInteger(0);
AtomicBoolean notFound = new AtomicBoolean(false);
// Because in China, Curse is too difficult to visit, // Because in China, Curse is too difficult to visit,
// if failed, ignore it and retry next time. // if failed, ignore it and retry next time.
@@ -113,6 +116,9 @@ public final class CurseCompletionTask extends Task {
if (StringUtils.isBlank(file.getFileName())) { if (StringUtils.isBlank(file.getFileName())) {
try { try {
return file.withFileName(NetworkUtils.detectFileName(file.getUrl())); return file.withFileName(NetworkUtils.detectFileName(file.getUrl()));
} catch (FileNotFoundException e) {
notFound.set(true);
return file;
} catch (IOException ioe) { } catch (IOException ioe) {
Logging.LOG.log(Level.WARNING, "Unable to fetch the file name of URL: " + file.getUrl(), ioe); Logging.LOG.log(Level.WARNING, "Unable to fetch the file name of URL: " + file.getUrl(), ioe);
flag.set(false); flag.set(false);
@@ -132,8 +138,12 @@ public final class CurseCompletionTask extends Task {
} }
// Let this task fail if the curse manifest has not been completed. // Let this task fail if the curse manifest has not been completed.
if (!flag.get()) // But continue other downloads.
if (!flag.get() || notFound.get())
dependencies.add(Task.of(() -> { dependencies.add(Task.of(() -> {
if (notFound.get())
throw new CurseCompletionException(new FileNotFoundException());
else
throw new CurseCompletionException(); throw new CurseCompletionException();
})); }));
} }

View File

@@ -218,9 +218,9 @@ public class FileDownloadTask extends Task {
HttpURLConnection con = NetworkUtils.createConnection(url); HttpURLConnection con = NetworkUtils.createConnection(url);
if (checkETag) repository.injectConnection(con); if (checkETag) repository.injectConnection(con);
con.connect(); con = NetworkUtils.resolveConnection(con);
if (con.getResponseCode() == 304) { if (con.getResponseCode() == HttpURLConnection.HTTP_NOT_MODIFIED) {
// Handle cache // Handle cache
Path cache = repository.getCachedRemoteFile(con); Path cache = repository.getCachedRemoteFile(con);
FileUtils.copyFile(cache.toFile(), file); FileUtils.copyFile(cache.toFile(), file);

View File

@@ -19,6 +19,7 @@ package org.jackhuang.hmcl.util.io;
import java.io.*; import java.io.*;
import java.net.*; import java.net.*;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
@@ -57,13 +58,30 @@ public final class NetworkUtils {
public static HttpURLConnection createConnection(URL url) throws IOException { public static HttpURLConnection createConnection(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setUseCaches(false); connection.setUseCaches(false);
connection.setConnectTimeout(15000); connection.setConnectTimeout(15000);
connection.setReadTimeout(15000); connection.setReadTimeout(15000);
return connection; return connection;
} }
public static HttpURLConnection resolveConnection(HttpURLConnection conn) throws IOException {
conn.setUseCaches(false);
conn.setConnectTimeout(15000);
conn.setReadTimeout(15000);
conn.setInstanceFollowRedirects(false);
Map<String, List<String>> properties = conn.getRequestProperties();
int code = conn.getResponseCode();
if (code >= 300 && code <= 307 && code != 306 && code != 304) {
String newURL = conn.getHeaderField("Location").replace(" ", "%20");
conn.disconnect();
HttpURLConnection redirected = (HttpURLConnection) new URL(conn.getURL(), newURL).openConnection();
properties.forEach((key, value) -> value.forEach(element -> redirected.addRequestProperty(key, element)));
return resolveConnection(redirected);
}
return conn;
}
public static String doGet(URL url) throws IOException { public static String doGet(URL url) throws IOException {
return IOUtils.readFullyAsString(createConnection(url).getInputStream()); return IOUtils.readFullyAsString(createConnection(url).getInputStream());
} }
@@ -110,10 +128,12 @@ public final class NetworkUtils {
} }
public static String detectFileName(URL url) throws IOException { public static String detectFileName(URL url) throws IOException {
HttpURLConnection conn = createConnection(url); HttpURLConnection conn = resolveConnection(createConnection(url));
conn.connect(); int code = conn.getResponseCode();
if (conn.getResponseCode() / 100 != 2) if (code == 404)
throw new IOException("Response code " + conn.getResponseCode()); throw new FileNotFoundException();
if (code / 100 != 2)
throw new IOException(url + ": response code " + conn.getResponseCode());
return detectFileName(conn); return detectFileName(conn);
} }