diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java index 4852ae469..2d6e9be2d 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/LauncherHelper.java @@ -267,7 +267,7 @@ public final class LauncherHelper { if (ex.getCause() instanceof ResponseCodeException) { ResponseCodeException rce = (ResponseCodeException) ex.getCause(); int responseCode = rce.getResponseCode(); - URI uri = rce.getUri(); + String uri = rce.getUri(); if (responseCode == 404) message += i18n("download.code.404", uri); else @@ -298,7 +298,7 @@ public final class LauncherHelper { } else if (ex instanceof ResponseCodeException) { ResponseCodeException rce = (ResponseCodeException) ex; int responseCode = rce.getResponseCode(); - URI uri = rce.getUri(); + String uri = rce.getUri(); if (responseCode == 404) message = i18n("download.code.404", uri); else diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/game/TexturesLoader.java b/HMCL/src/main/java/org/jackhuang/hmcl/game/TexturesLoader.java index d0cfc951d..dab6a40d3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/game/TexturesLoader.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/game/TexturesLoader.java @@ -45,7 +45,6 @@ import org.jackhuang.hmcl.util.javafx.BindingMapping; import java.io.IOException; import java.io.InputStream; import java.lang.ref.WeakReference; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -110,7 +109,7 @@ public final class TexturesLoader { if (!Files.isRegularFile(file)) { // download it try { - new FileDownloadTask(URI.create(texture.getUrl()), file).run(); + new FileDownloadTask(texture.getUrl(), file).run(); LOG.info("Texture downloaded: " + texture.getUrl()); } catch (Exception e) { if (Files.isRegularFile(file)) { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java index 075a79a29..997bbe624 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/FXUtils.java @@ -836,7 +836,8 @@ public final class FXUtils { } } - public static Image loadImage(URI uri) throws Exception { + public static Image loadImage(String url) throws Exception { + URI uri = NetworkUtils.toURI(url); URLConnection connection = NetworkUtils.createConnection(uri); if (connection instanceof HttpURLConnection) { connection = NetworkUtils.resolveConnection((HttpURLConnection) connection); @@ -896,7 +897,7 @@ public final class FXUtils { } public static Task getRemoteImageTask(String url, double requestedWidth, double requestedHeight, boolean preserveRatio, boolean smooth) { - return new CacheFileTask(URI.create(url)) + return new CacheFileTask(url) .thenApplyAsync(file -> { try (var channel = FileChannel.open(file, StandardOpenOption.READ)) { var header = new byte[12]; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/HTMLRenderer.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/HTMLRenderer.java index 01a9b2942..08c33aef1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/HTMLRenderer.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/HTMLRenderer.java @@ -22,6 +22,7 @@ import javafx.scene.image.Image; import javafx.scene.image.ImageView; import javafx.scene.text.Text; import javafx.scene.text.TextFlow; +import org.jackhuang.hmcl.util.StringUtils; import org.jsoup.nodes.Node; import org.jsoup.nodes.TextNode; @@ -159,18 +160,9 @@ public final class HTMLRenderer { private void appendImage(Node node) { String src = node.absUrl("src"); - URI imageUri = null; - try { - if (!src.isEmpty()) - imageUri = URI.create(src); - } catch (Exception ignored) { - } - String alt = node.attr("alt"); - if (imageUri != null) { - URI uri = URI.create(src); - + if (StringUtils.isNotBlank(src)) { String widthAttr = node.attr("width"); String heightAttr = node.attr("height"); @@ -191,7 +183,7 @@ public final class HTMLRenderer { } try { - Image image = FXUtils.getRemoteImageTask(uri.toString(), width, height, true, true) + Image image = FXUtils.getRemoteImageTask(src, width, height, true, true) .run(); if (image == null) throw new AssertionError("Image loading task returned null"); @@ -207,7 +199,7 @@ public final class HTMLRenderer { children.add(imageView); return; } catch (Throwable e) { - LOG.warning("Failed to load image: " + uri, e); + LOG.warning("Failed to load image: " + src, e); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java index 5b2d758c5..c2e5d1547 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AccountListPage.java @@ -41,6 +41,7 @@ import org.jackhuang.hmcl.ui.construct.AdvancedListItem; import org.jackhuang.hmcl.ui.construct.ClassTitle; import org.jackhuang.hmcl.ui.decorator.DecoratorAnimatedPage; import org.jackhuang.hmcl.ui.decorator.DecoratorPage; +import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.javafx.BindingMapping; import org.jackhuang.hmcl.util.javafx.MappedObservableList; import org.jackhuang.hmcl.util.platform.NativeUtils; @@ -48,7 +49,6 @@ import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jackhuang.hmcl.util.platform.windows.Kernel32; import org.jackhuang.hmcl.util.platform.windows.WinConstants; -import java.net.URI; import java.time.ZoneId; import java.util.Arrays; import java.util.Locale; @@ -190,7 +190,7 @@ public final class AccountListPage extends DecoratorAnimatedPage implements Deco item.titleProperty().bind(title); String host = ""; try { - host = URI.create(server.getUrl()).getHost(); + host = NetworkUtils.toURI(server.getUrl()).getHost(); } catch (IllegalArgumentException e) { LOG.warning("Unparsable authlib-injector server url " + server.getUrl(), e); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java index 4b3c0b5da..84f94d540 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/account/AddAuthlibInjectorServerPane.java @@ -34,7 +34,6 @@ import org.jackhuang.hmcl.util.Lang; import javax.net.ssl.SSLException; import java.io.IOException; -import java.net.URI; import static org.jackhuang.hmcl.setting.ConfigHolder.config; import static org.jackhuang.hmcl.ui.FXUtils.onEscPressed; @@ -196,7 +195,8 @@ public final class AddAuthlibInjectorServerPane extends TransitionPane implement lblServerName.setText(serverBeingAdded.getName()); lblServerUrl.setText(serverBeingAdded.getUrl()); - lblServerWarning.setVisible("http".equals(URI.create(serverBeingAdded.getUrl()).getScheme())); + //noinspection HttpUrlsUsage + lblServerWarning.setVisible(serverBeingAdded.getUrl().startsWith("http://")); this.setContent(confirmServerPane, ContainerAnimations.SWIPE_LEFT); } else { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/URLValidator.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/URLValidator.java index 357a8b01e..2c85f73c6 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/URLValidator.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/construct/URLValidator.java @@ -21,10 +21,7 @@ import com.jfoenix.validation.base.ValidatorBase; import javafx.beans.NamedArg; import javafx.scene.control.TextInputControl; import org.jackhuang.hmcl.util.StringUtils; - -import java.io.IOException; -import java.net.URISyntaxException; -import java.net.URL; +import org.jackhuang.hmcl.util.io.NetworkUtils; import static org.jackhuang.hmcl.util.i18n.I18n.i18n; @@ -58,9 +55,9 @@ public class URLValidator extends ValidatorBase { hasErrors.set(!nullable); else { try { - new URL(textField.getText()).toURI(); + NetworkUtils.toURI(textField.getText()); hasErrors.set(false); - } catch (IOException | URISyntaxException e) { + } catch (IllegalArgumentException e) { hasErrors.set(true); } } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java index 1ff75656f..9b591d2c3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/decorator/DecoratorController.java @@ -58,7 +58,6 @@ import org.jackhuang.hmcl.ui.wizard.WizardProvider; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -214,7 +213,7 @@ public class DecoratorController { String backgroundImageUrl = config().getBackgroundImageUrl(); if (backgroundImageUrl != null) { try { - image = FXUtils.loadImage(URI.create(backgroundImageUrl)); + image = FXUtils.loadImage(backgroundImageUrl); } catch (Exception e) { LOG.warning("Couldn't load background image", e); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java index ead89c673..aee357f7b 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/DownloadPage.java @@ -55,7 +55,6 @@ import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.platform.OperatingSystem; import org.jetbrains.annotations.Nullable; -import java.net.URI; import java.nio.file.Path; import java.util.HashMap; import java.util.Locale; @@ -156,7 +155,7 @@ public class DownloadPage extends DecoratorAnimatedPage implements DecoratorPage Path dest = runDirectory.resolve(subdirectoryName).resolve(result); Controllers.taskDialog(Task.composeAsync(() -> { - var task = new FileDownloadTask(URI.create(file.getFile().getUrl()), dest); + var task = new FileDownloadTask(file.getFile().getUrl(), dest); task.setName(file.getName()); return task; }).whenComplete(Schedulers.javafx(), exception -> { diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java index 3d63f094d..a1bcd165f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/ModpackSelectionPage.java @@ -41,7 +41,6 @@ import org.jackhuang.hmcl.util.gson.JsonUtils; import java.io.File; import java.io.IOException; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.Map; @@ -124,10 +123,9 @@ public final class ModpackSelectionPage extends VBox implements WizardPage { } private void onChooseRemoteFile() { - Controllers.prompt(i18n("modpack.choose.remote.tooltip"), (urlString, resolve, reject) -> { + Controllers.prompt(i18n("modpack.choose.remote.tooltip"), (url, resolve, reject) -> { try { - URI url = URI.create(urlString); - if (urlString.endsWith("server-manifest.json")) { + if (url.endsWith("server-manifest.json")) { // if urlString ends with .json, we assume that the url is server-manifest.json Controllers.taskDialog(new GetTask(url).whenComplete(Schedulers.javafx(), (result, e) -> { ServerModpackManifest manifest = JsonUtils.fromMaybeMalformedJson(result, ServerModpackManifest.class); @@ -148,7 +146,7 @@ public final class ModpackSelectionPage extends VBox implements WizardPage { resolve.run(); Controllers.taskDialog( - new FileDownloadTask(url, modpack, null) + new FileDownloadTask(url, modpack) .whenComplete(Schedulers.javafx(), e -> { if (e == null) { resolve.run(); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java index 9ec804519..1458d835f 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/download/UpdateInstallerWizardProvider.java @@ -133,7 +133,7 @@ public final class UpdateInstallerWizardProvider implements WizardProvider { if (exception.getCause() instanceof ResponseCodeException) { ResponseCodeException rce = (ResponseCodeException) exception.getCause(); int responseCode = rce.getResponseCode(); - URI uri = rce.getUri(); + String uri = rce.getUri(); if (responseCode == 404) message += i18n("download.code.404", uri); else diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java index 2a8e5d1ab..e756141f1 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/DownloadPage.java @@ -54,7 +54,6 @@ import org.jackhuang.hmcl.util.versioning.GameVersionNumber; import org.jetbrains.annotations.Nullable; import java.io.File; -import java.net.URI; import java.util.*; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -180,7 +179,7 @@ public class DownloadPage extends Control implements DecoratorPage { Controllers.taskDialog( Task.composeAsync(() -> { - var task = new FileDownloadTask(URI.create(file.getFile().getUrl()), dest.toPath(), file.getFile().getIntegrityCheck()); + var task = new FileDownloadTask(file.getFile().getUrl(), dest.toPath(), file.getFile().getIntegrityCheck()); task.setName(file.getName()); return task; }), diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java index 07c2587eb..8b02ca9f8 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/ModUpdatesPage.java @@ -45,7 +45,6 @@ import org.jackhuang.hmcl.util.Pair; import org.jackhuang.hmcl.util.TaskCancellationAction; import org.jackhuang.hmcl.util.io.CSVTable; -import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; import java.time.LocalDateTime; @@ -294,7 +293,7 @@ public class ModUpdatesPage extends BorderPane implements DecoratorPage { fileName += ModManager.DISABLED_EXTENSION; var task = new FileDownloadTask( - URI.create(remote.getFile().getUrl()), + remote.getFile().getUrl(), modManager.getModsDirectory().resolve(fileName)); task.setName(remote.getName()); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java index 522afbf7e..e284cd930 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/VersionSettingsPage.java @@ -32,9 +32,6 @@ import javafx.scene.control.Toggle; import javafx.scene.layout.*; import javafx.scene.text.Text; import javafx.stage.FileChooser; -import org.jackhuang.hmcl.game.GameDirectoryType; -import org.jackhuang.hmcl.game.HMCLGameRepository; -import org.jackhuang.hmcl.game.ProcessPriority; import org.jackhuang.hmcl.game.*; import org.jackhuang.hmcl.java.JavaManager; import org.jackhuang.hmcl.setting.*; diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java index 750b4aa1a..efc7de9fb 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/ui/versions/Versions.java @@ -40,12 +40,12 @@ import org.jackhuang.hmcl.ui.download.ModpackInstallWizardProvider; import org.jackhuang.hmcl.ui.export.ExportWizardProvider; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.TaskCancellationAction; +import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jackhuang.hmcl.util.platform.OperatingSystem; import java.io.File; import java.io.IOException; import java.net.URI; -import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; import java.util.concurrent.CancellationException; @@ -75,9 +75,9 @@ public final class Versions { Path modpack; URI downloadURL; try { + downloadURL = NetworkUtils.toURI(file.getFile().getUrl()); modpack = Files.createTempFile("modpack", ".zip"); - downloadURL = new URI(file.getFile().getUrl()); - } catch (IOException | URISyntaxException e) { + } catch (IOException | IllegalArgumentException e) { Controllers.dialog( i18n("install.failed.downloading.detail", file.getFile().getUrl()) + "\n" + StringUtils.getStackTrace(e), i18n("download.failed.no_code"), MessageDialogPane.MessageType.ERROR); diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java index 2b6a91a3c..653e398f3 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/HMCLDownloadTask.java @@ -23,7 +23,6 @@ import org.tukaani.xz.XZInputStream; import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.jar.JarOutputStream; @@ -33,7 +32,7 @@ final class HMCLDownloadTask extends FileDownloadTask { private final RemoteVersion.Type archiveFormat; public HMCLDownloadTask(RemoteVersion version, Path target) { - super(URI.create(version.getUrl()), target, version.getIntegrityCheck()); + super(version.getUrl(), target, version.getIntegrityCheck()); archiveFormat = version.getType(); } diff --git a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java index 5c4d8d056..627877d12 100644 --- a/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java +++ b/HMCL/src/main/java/org/jackhuang/hmcl/upgrade/RemoteVersion.java @@ -26,14 +26,13 @@ import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.IOException; -import java.net.URI; import java.util.Optional; public class RemoteVersion { public static RemoteVersion fetch(UpdateChannel channel, String url) throws IOException { try { - JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(URI.create(url)), JsonObject.class); + JsonObject response = JsonUtils.fromNonNullJson(NetworkUtils.doGet(url), JsonObject.class); String version = Optional.ofNullable(response.get("version")).map(JsonElement::getAsString).orElseThrow(() -> new IOException("version is missing")); String jarUrl = Optional.ofNullable(response.get("jar")).map(JsonElement::getAsString).orElse(null); String jarHash = Optional.ofNullable(response.get("jarsha1")).map(JsonElement::getAsString).orElse(null); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServer.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServer.java index ebe8fb6f5..947724848 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServer.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/authlibinjector/AuthlibInjectorServer.java @@ -29,6 +29,7 @@ import java.net.URISyntaxException; import java.util.LinkedHashMap; import java.util.Map; import java.util.Optional; +import java.util.regex.Pattern; import org.jackhuang.hmcl.auth.yggdrasil.YggdrasilService; import org.jackhuang.hmcl.util.io.HttpRequest; @@ -58,10 +59,10 @@ public class AuthlibInjectorServer implements Observable { public static AuthlibInjectorServer locateServer(String url) throws IOException { try { url = addHttpsIfMissing(url); - HttpURLConnection conn = NetworkUtils.createHttpConnection(URI.create(url)); + HttpURLConnection conn = NetworkUtils.createHttpConnection(url); String ali = conn.getHeaderField("x-authlib-injector-api-location"); if (ali != null) { - URI absoluteAli = conn.getURL().toURI().resolve(ali); + URI absoluteAli = conn.getURL().toURI().resolve(NetworkUtils.toURI(ali)); if (!urlEqualsIgnoreSlash(url, absoluteAli.toString())) { conn.disconnect(); url = absoluteAli.toString(); @@ -85,15 +86,15 @@ public class AuthlibInjectorServer implements Observable { } private static String addHttpsIfMissing(String url) throws IOException { - URI uri = URI.create(url); - - if (uri.getScheme() == null) { - return "https://" + url; - } else if (!NetworkUtils.isHttpUri(uri)) { - throw new IOException("Yggdrasil server should be an HTTP or HTTPS URI, but got: " + url); - } else { + if (Pattern.compile("^(?[a-zA-Z][a-zA-Z0-9+.-]*)://").matcher(url).find()) return url; - } + + if (url.startsWith("//")) + return "https:" + url; + else if (url.startsWith("/")) + return "https:/" + url; + else + return "https://" + url; } private static boolean urlEqualsIgnoreSlash(String a, String b) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java index ea95e9766..b2b4b5148 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/microsoft/MicrosoftService.java @@ -34,7 +34,6 @@ import org.jackhuang.hmcl.util.javafx.ObservableOptionalCache; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; -import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; import java.nio.file.Path; @@ -165,7 +164,7 @@ public class MicrosoftService { .accept("application/json").createConnection(); if (request.getResponseCode() != 200) { - throw new ResponseCodeException(URI.create("https://api.minecraftservices.com/entitlements/mcstore"), request.getResponseCode()); + throw new ResponseCodeException("https://api.minecraftservices.com/entitlements/mcstore", request.getResponseCode()); } // Get Minecraft Account UUID @@ -248,7 +247,7 @@ public class MicrosoftService { if (responseCode == HTTP_NOT_FOUND) { throw new NoMinecraftJavaEditionProfileException(); } else if (responseCode != 200) { - throw new ResponseCodeException(URI.create("https://api.minecraftservices.com/minecraft/profile"), responseCode); + throw new ResponseCodeException("https://api.minecraftservices.com/minecraft/profile", responseCode); } String result = NetworkUtils.readFullyAsString(conn); @@ -258,12 +257,12 @@ public class MicrosoftService { public Optional getCompleteGameProfile(UUID uuid) throws AuthenticationException { Objects.requireNonNull(uuid); - return Optional.ofNullable(GSON.fromJson(request(URI.create("https://sessionserver.mojang.com/session/minecraft/profile/" + UUIDTypeAdapter.fromUUID(uuid)), null), CompleteGameProfile.class)); + return Optional.ofNullable(GSON.fromJson(request("https://sessionserver.mojang.com/session/minecraft/profile/" + UUIDTypeAdapter.fromUUID(uuid), null), CompleteGameProfile.class)); } public void uploadSkin(String accessToken, boolean isSlim, Path file) throws AuthenticationException, UnsupportedOperationException { try { - HttpURLConnection con = NetworkUtils.createHttpConnection(URI.create("https://api.minecraftservices.com/minecraft/profile/skins")); + HttpURLConnection con = NetworkUtils.createHttpConnection("https://api.minecraftservices.com/minecraft/profile/skins"); con.setRequestMethod("POST"); con.setRequestProperty("Authorization", "Bearer " + accessToken); con.setDoOutput(true); @@ -288,12 +287,12 @@ public class MicrosoftService { } } - private static String request(URI url, Object payload) throws AuthenticationException { + private static String request(String url, Object payload) throws AuthenticationException { try { if (payload == null) return NetworkUtils.doGet(url); else - return NetworkUtils.doPost(url, payload instanceof String ? (String) payload : GSON.toJson(payload), "application/json"); + return NetworkUtils.doPost(NetworkUtils.toURI(url), payload instanceof String ? (String) payload : GSON.toJson(payload), "application/json"); } catch (IOException e) { throw new ServerDisconnectException(e); } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/offline/Skin.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/offline/Skin.java index ec477a3c2..e30d6293d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/offline/Skin.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/auth/offline/Skin.java @@ -27,13 +27,13 @@ import org.jackhuang.hmcl.util.Lang; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.JsonUtils; import org.jackhuang.hmcl.util.io.FileUtils; +import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jetbrains.annotations.Nullable; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; -import java.net.URI; import java.net.URLConnection; import java.nio.file.Files; import java.nio.file.Path; @@ -166,7 +166,7 @@ public class Skin { String realCslApi = type == Type.LITTLE_SKIN ? "https://littleskin.cn/csl" : StringUtils.removeSuffix(Lang.requireNonNullElse(cslApi, ""), "/"); - return Task.composeAsync(() -> new GetTask(URI.create(String.format("%s/%s.json", realCslApi, username)))) + return Task.composeAsync(() -> new GetTask(String.format("%s/%s.json", realCslApi, username))) .thenComposeAsync(json -> { SkinJson result = JsonUtils.GSON.fromJson(json, SkinJson.class); @@ -176,8 +176,8 @@ public class Skin { return Task.allOf( Task.supplyAsync(result::getModel), - result.getHash() == null ? Task.supplyAsync(() -> null) : new FetchBytesTask(URI.create(String.format("%s/textures/%s", realCslApi, result.getHash())), 3), - result.getCapeHash() == null ? Task.supplyAsync(() -> null) : new FetchBytesTask(URI.create(String.format("%s/textures/%s", realCslApi, result.getCapeHash())), 3) + result.getHash() == null ? Task.supplyAsync(() -> null) : new FetchBytesTask(String.format("%s/textures/%s", realCslApi, result.getHash())), + result.getCapeHash() == null ? Task.supplyAsync(() -> null) : new FetchBytesTask(String.format("%s/textures/%s", realCslApi, result.getCapeHash())) ); }).thenApplyAsync(result -> { if (result == null) { @@ -229,8 +229,8 @@ public class Skin { private static class FetchBytesTask extends FetchTask { - public FetchBytesTask(URI uri, int retry) { - super(List.of(uri), retry); + public FetchBytesTask(String uri) { + super(List.of(NetworkUtils.toURI(uri))); } @Override diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java index 28a12539c..4be18b881 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/DownloadProvider.java @@ -17,6 +17,8 @@ */ package org.jackhuang.hmcl.download; +import org.jackhuang.hmcl.util.io.NetworkUtils; + import java.net.URI; import java.util.List; import java.util.stream.Collectors; @@ -33,7 +35,7 @@ public interface DownloadProvider { String getAssetBaseURL(); default List getAssetObjectCandidates(String assetObjectLocation) { - return List.of(URI.create(getAssetBaseURL() + assetObjectLocation)); + return List.of(NetworkUtils.toURI(getAssetBaseURL() + assetObjectLocation)); } /** @@ -57,7 +59,7 @@ public interface DownloadProvider { * @return the URL that is equivalent to [baseURL], but belongs to your own service provider. */ default List injectURLWithCandidates(String baseURL) { - return List.of(URI.create(injectURL(baseURL))); + return List.of(NetworkUtils.toURI(injectURL(baseURL))); } default List injectURLsWithCandidates(List urls) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java index b5f19dda6..a5c89f387 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/fabric/FabricAPIInstallTask.java @@ -23,7 +23,6 @@ import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; import java.io.IOException; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -59,7 +58,7 @@ public final class FabricAPIInstallTask extends Task { @Override public void execute() throws IOException { dependencies.add(new FileDownloadTask( - URI.create(remote.getVersion().getFile().getUrl()), + remote.getVersion().getFile().getUrl(), dependencyManager.getGameRepository().getRunDirectory(version.getId()).toPath().resolve("mods").resolve("fabric-api-" + remote.getVersion().getVersion() + ".jar"), remote.getVersion().getFile().getIntegrityCheck()) ); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java index 447599099..1c1782dfe 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/forge/ForgeBMCLVersionList.java @@ -29,7 +29,6 @@ import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.net.URI; import java.time.Instant; import java.time.format.DateTimeParseException; import java.util.ArrayList; @@ -86,7 +85,7 @@ public final class ForgeBMCLVersionList extends VersionList public Task refreshAsync(String gameVersion) { String lookupVersion = toLookupVersion(gameVersion); - return new GetTask(URI.create(apiRoot + "/forge/minecraft/" + lookupVersion)).thenGetJsonAsync(listTypeOf(ForgeVersion.class)) + return new GetTask(apiRoot + "/forge/minecraft/" + lookupVersion).thenGetJsonAsync(listTypeOf(ForgeVersion.class)) .thenAcceptAsync(forgeVersions -> { lock.writeLock().lock(); try { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java index 30ff1bdb1..561e8eb94 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/game/GameVersionList.java @@ -25,7 +25,6 @@ import org.jackhuang.hmcl.util.gson.JsonUtils; import java.io.InputStreamReader; import java.io.Reader; -import java.net.URI; import java.util.Collection; import java.util.Collections; @@ -54,7 +53,7 @@ public final class GameVersionList extends VersionList { @Override public Task refreshAsync() { - return new GetTask(URI.create(downloadProvider.getVersionListURL())).thenGetJsonAsync(GameRemoteVersions.class) + return new GetTask(downloadProvider.getVersionListURL()).thenGetJsonAsync(GameRemoteVersions.class) .thenAcceptAsync(root -> { GameRemoteVersions unlistedVersions = null; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java index 2310a238a..42b9dd117 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/liteloader/LiteLoaderVersionList.java @@ -28,7 +28,6 @@ import org.jsoup.nodes.Document; import java.io.IOException; import java.io.UncheckedIOException; -import java.net.URI; import java.util.Collections; import java.util.Map; import java.util.Objects; @@ -53,7 +52,7 @@ public final class LiteLoaderVersionList extends VersionList refreshAsync(String gameVersion) { - return new GetTask(URI.create(downloadProvider.injectURL(LITELOADER_LIST))) + return new GetTask(downloadProvider.injectURL(LITELOADER_LIST)) .thenGetJsonAsync(LiteLoaderVersionsRoot.class) .thenAcceptAsync(root -> { LiteLoaderGameVersions versions = root.getVersions().get(gameVersion); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeBMCLVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeBMCLVersionList.java index 6db11dcb1..940d1062d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeBMCLVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeBMCLVersionList.java @@ -25,7 +25,6 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.gson.Validation; -import java.net.URI; import java.util.Collections; import java.util.Optional; @@ -66,7 +65,7 @@ public final class NeoForgeBMCLVersionList extends VersionList refreshAsync(String gameVersion) { - return new GetTask(URI.create(apiRoot + "/neoforge/list/" + gameVersion)).thenGetJsonAsync(listTypeOf(NeoForgeVersion.class)) + return new GetTask(apiRoot + "/neoforge/list/" + gameVersion).thenGetJsonAsync(listTypeOf(NeoForgeVersion.class)) .thenAcceptAsync(neoForgeVersions -> { lock.writeLock().lock(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOfficialVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOfficialVersionList.java index 3a20320a6..5de46f86b 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOfficialVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/neoforge/NeoForgeOfficialVersionList.java @@ -5,7 +5,6 @@ import org.jackhuang.hmcl.download.VersionList; import org.jackhuang.hmcl.task.GetTask; import org.jackhuang.hmcl.task.Task; -import java.net.URI; import java.util.Collections; import java.util.List; import java.util.Optional; @@ -39,8 +38,8 @@ public final class NeoForgeOfficialVersionList extends VersionList refreshAsync() { return Task.allOf( - new GetTask(URI.create(downloadProvider.injectURL(OLD_URL))).thenGetJsonAsync(OfficialAPIResult.class), - new GetTask(URI.create(downloadProvider.injectURL(META_URL))).thenGetJsonAsync(OfficialAPIResult.class) + new GetTask(downloadProvider.injectURL(OLD_URL)).thenGetJsonAsync(OfficialAPIResult.class), + new GetTask(downloadProvider.injectURL(META_URL)).thenGetJsonAsync(OfficialAPIResult.class) ).thenAcceptAsync(results -> { lock.writeLock().lock(); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java index 48e0f31a2..7d8dd0f1d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/optifine/OptiFineBMCLVersionList.java @@ -24,7 +24,6 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.versioning.VersionNumber; -import java.net.URI; import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -73,7 +72,7 @@ public final class OptiFineBMCLVersionList extends VersionList refreshAsync() { - return new GetTask(URI.create(apiRoot + "/optifine/versionlist")).thenGetJsonAsync(listTypeOf(OptiFineVersion.class)).thenAcceptAsync(root -> { + return new GetTask(apiRoot + "/optifine/versionlist").thenGetJsonAsync(listTypeOf(OptiFineVersion.class)).thenAcceptAsync(root -> { lock.writeLock().lock(); try { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java index 89fdfb85c..f849023f6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/download/quilt/QuiltAPIInstallTask.java @@ -23,7 +23,6 @@ import org.jackhuang.hmcl.task.FileDownloadTask; import org.jackhuang.hmcl.task.Task; import java.io.IOException; -import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -59,7 +58,7 @@ public final class QuiltAPIInstallTask extends Task { @Override public void execute() throws IOException { dependencies.add(new FileDownloadTask( - URI.create(remote.getVersion().getFile().getUrl()), + remote.getVersion().getFile().getUrl(), dependencyManager.getGameRepository().getRunDirectory(version.getId()).toPath().resolve("mods").resolve("quilt-api-" + remote.getVersion().getVersion() + ".jar"), remote.getVersion().getFile().getIntegrityCheck()) ); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/RemoteMod.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/RemoteMod.java index 20ad0b805..9542cbecd 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/RemoteMod.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/RemoteMod.java @@ -28,9 +28,7 @@ import java.util.List; import java.util.Map; import java.util.stream.Stream; -import static org.jackhuang.hmcl.util.io.NetworkUtils.encodeLocation; - -public class RemoteMod { +public final class RemoteMod { public static final RemoteMod BROKEN = new RemoteMod("", "", "RemoteMod.BROKEN", "", Collections.emptyList(), "", "", new RemoteMod.IMod() { @Override @@ -313,7 +311,7 @@ public class RemoteMod { } public String getUrl() { - return encodeLocation(url); + return url; } public String getFilename() { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseManifestFile.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseManifestFile.java index bb1013372..848ee314a 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseManifestFile.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/curse/CurseManifestFile.java @@ -21,10 +21,8 @@ import com.google.gson.JsonParseException; import com.google.gson.annotations.SerializedName; import org.jackhuang.hmcl.util.Immutable; import org.jackhuang.hmcl.util.gson.Validation; -import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jetbrains.annotations.Nullable; -import java.net.URI; import java.util.Objects; /** @@ -84,15 +82,13 @@ public final class CurseManifestFile implements Validation { } @Nullable - public URI getUrl() { + public String getUrl() { if (url == null) { - if (fileName != null) { - return URI.create(NetworkUtils.encodeLocation(String.format("https://edge.forgecdn.net/files/%d/%d/%s", fileID / 1000, fileID % 1000, fileName))); - } else { - return null; - } + return fileName != null + ? String.format("https://edge.forgecdn.net/files/%d/%d/%s", fileID / 1000, fileID % 1000, fileName) + : null; } else { - return URI.create(NetworkUtils.encodeLocation(url)); + return url; } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java index c3057cc5e..dc2e2c4dc 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackCompletionTask.java @@ -35,7 +35,6 @@ import org.jetbrains.annotations.Nullable; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -101,7 +100,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask { throw new CustomException(); } })).thenComposeAsync(wrap(unused1 -> { - return executor.one(new GetTask(URI.create(manifest.getFileApi() + "/manifest.json"))); + return executor.one(new GetTask(manifest.getFileApi() + "/manifest.json")); })).thenComposeAsync(wrap(remoteManifestJson -> { McbbsModpackManifest remoteManifest; // We needs to update modpack from online server. @@ -201,10 +200,10 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask { McbbsModpackManifest.CurseFile file = (McbbsModpackManifest.CurseFile) rawFile; if (StringUtils.isBlank(file.getFileName())) { try { - return file.withFileName(NetworkUtils.detectFileName(file.getUrl())); + return file.withFileName(NetworkUtils.detectFileName(NetworkUtils.toURI(file.getUrl()))); } catch (IOException e) { try { - String result = NetworkUtils.doGet(URI.create(String.format("https://cursemeta.dries007.net/%d/%d.json", file.getProjectID(), file.getFileID()))); + String result = NetworkUtils.doGet(String.format("https://cursemeta.dries007.net/%d/%d.json", file.getProjectID(), file.getFileID())); CurseMetaMod mod = JsonUtils.fromNonNullJson(result, CurseMetaMod.class); return file.withFileName(mod.getFileNameOnDisk()).withURL(mod.getDownloadURL()); } catch (FileNotFoundException fof) { @@ -213,7 +212,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask { return file; } catch (IOException | JsonParseException e2) { try { - String result = NetworkUtils.doGet(URI.create(String.format("https://addons-ecs.forgesvc.net/api/v2/addon/%d/file/%d", file.getProjectID(), file.getFileID()))); + String result = NetworkUtils.doGet(String.format("https://addons-ecs.forgesvc.net/api/v2/addon/%d/file/%d", file.getProjectID(), file.getFileID())); CurseMetaMod mod = JsonUtils.fromNonNullJson(result, CurseMetaMod.class); return file.withFileName(mod.getFileName()).withURL(mod.getDownloadURL()); } catch (FileNotFoundException fof) { @@ -297,7 +296,7 @@ public class McbbsModpackCompletionTask extends CompletableFutureTask { if (file instanceof McbbsModpackManifest.AddonFile) { McbbsModpackManifest.AddonFile addonFile = (McbbsModpackManifest.AddonFile) file; return new FileDownloadTask( - URI.create(remoteManifest.getFileApi() + "/overrides/" + NetworkUtils.encodeLocation(addonFile.getPath())), + remoteManifest.getFileApi() + "/overrides/" + addonFile.getPath(), modManager.getSimpleModPath(addonFile.getPath()), addonFile.getHash() != null ? new FileDownloadTask.IntegrityCheck("SHA-1", addonFile.getHash()) : null); } else if (file instanceof McbbsModpackManifest.CurseFile) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java index 7deffb716..b5d5f84a8 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/mcbbs/McbbsModpackManifest.java @@ -27,11 +27,9 @@ import org.jackhuang.hmcl.mod.ModpackManifest; import org.jackhuang.hmcl.mod.ModpackProvider; import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.gson.*; -import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jetbrains.annotations.Nullable; import java.io.IOException; -import java.net.URI; import java.nio.charset.Charset; import java.util.Collections; import java.util.List; @@ -329,9 +327,10 @@ public class McbbsModpackManifest implements ModpackManifest, Validation { return fileName; } - public URI getUrl() { - return url == null ? URI.create("https://www.curseforge.com/minecraft/mc-mods/" + projectID + "/download/" + fileID + "/file") - : URI.create(NetworkUtils.encodeLocation(url)); + public String getUrl() { + return url == null + ? "https://www.curseforge.com/minecraft/mc-mods/" + projectID + "/download/" + fileID + "/file" + : url; } public CurseFile withFileName(String fileName) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCComponents.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCComponents.java index 39fca4719..c9452d01f 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCComponents.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/multimc/MultiMCComponents.java @@ -1,6 +1,7 @@ package org.jackhuang.hmcl.mod.multimc; import org.jackhuang.hmcl.download.LibraryAnalyzer; +import org.jackhuang.hmcl.util.io.NetworkUtils; import java.net.URI; import java.util.*; @@ -46,6 +47,6 @@ public final class MultiMCComponents { } public static URI getMetaURL(String componentID, String version) { - return URI.create(String.format("https://meta.multimc.org/v1/%s/%s.json", componentID, version)); + return NetworkUtils.toURI(String.format("https://meta.multimc.org/v1/%s/%s.json", componentID, version)); } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java index c07a14317..5edc37760 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/mod/server/ServerModpackCompletionTask.java @@ -28,11 +28,9 @@ import org.jackhuang.hmcl.task.Task; import org.jackhuang.hmcl.util.DigestUtils; import org.jackhuang.hmcl.util.StringUtils; import org.jackhuang.hmcl.util.gson.JsonUtils; -import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.File; import java.io.IOException; -import java.net.URI; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; @@ -84,7 +82,7 @@ public class ServerModpackCompletionTask extends Task { @Override public void preExecute() throws Exception { if (manifest == null || StringUtils.isBlank(manifest.getManifest().getFileApi())) return; - dependent = new GetTask(URI.create(manifest.getManifest().getFileApi() + "/server-manifest.json")); + dependent = new GetTask(manifest.getManifest().getFileApi() + "/server-manifest.json"); } @Override @@ -152,7 +150,7 @@ public class ServerModpackCompletionTask extends Task { if (download) { total++; dependencies.add(new FileDownloadTask( - URI.create(remoteManifest.getFileApi() + "/overrides/" + NetworkUtils.encodeLocation(file.getPath())), + remoteManifest.getFileApi() + "/overrides/" + file.getPath(), actualPath, new FileDownloadTask.IntegrityCheck("SHA-1", file.getHash())) .withCounter("hmcl.modpack.download")); diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CacheFileTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CacheFileTask.java index e594f29d4..63201df78 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CacheFileTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/CacheFileTask.java @@ -17,6 +17,7 @@ */ package org.jackhuang.hmcl.task; +import org.jackhuang.hmcl.util.io.NetworkUtils; import org.jetbrains.annotations.NotNull; import java.io.IOException; @@ -36,12 +37,12 @@ import static org.jackhuang.hmcl.util.logging.Logger.LOG; */ public final class CacheFileTask extends FetchTask { - public CacheFileTask(@NotNull URI uri) { - super(List.of(uri), DEFAULT_RETRY); + public CacheFileTask(@NotNull String uri) { + super(List.of(NetworkUtils.toURI(uri))); } - public CacheFileTask(@NotNull URI uri, int retry) { - super(List.of(uri), retry); + public CacheFileTask(@NotNull URI uri) { + super(List.of(uri)); } @Override diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FetchTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FetchTask.java index 1444370cf..9bfbc12cd 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FetchTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FetchTask.java @@ -49,14 +49,13 @@ public abstract class FetchTask extends Task { protected static final int DEFAULT_RETRY = 3; protected final List uris; - protected final int retry; + protected int retry = DEFAULT_RETRY; protected CacheRepository repository = CacheRepository.getInstance(); - public FetchTask(@NotNull List<@NotNull URI> uris, int retry) { + public FetchTask(@NotNull List<@NotNull URI> uris) { Objects.requireNonNull(uris); this.uris = List.copyOf(uris); - this.retry = retry; if (this.uris.isEmpty()) throw new IllegalArgumentException("At least one URL is required"); @@ -64,6 +63,13 @@ public abstract class FetchTask extends Task { setExecutor(download()); } + public void setRetry(int retry) { + if (retry <= 0) + throw new IllegalArgumentException("Retry count must be greater than 0"); + + this.retry = retry; + } + public void setCacheRepository(CacheRepository repository) { this.repository = repository; } @@ -167,7 +173,7 @@ public abstract class FetchTask extends Task { if (responseCode == HttpURLConnection.HTTP_NOT_MODIFIED) { // Handle cache try { - Path cache = repository.getCachedRemoteFile(conn.getURL().toURI()); + Path cache = repository.getCachedRemoteFile(NetworkUtils.toURI(conn.getURL())); useCachedResult(cache); LOG.info("Using cached file for " + NetworkUtils.dropQuery(uri)); return; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java index 12ab51bae..7caf9e8c6 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/FileDownloadTask.java @@ -22,6 +22,7 @@ import org.jackhuang.hmcl.util.Hex; import org.jackhuang.hmcl.util.io.ChecksumMismatchException; import org.jackhuang.hmcl.util.io.CompressingUtils; import org.jackhuang.hmcl.util.io.FileUtils; +import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.IOException; import java.io.OutputStream; @@ -82,6 +83,23 @@ public class FileDownloadTask extends FetchTask { private Path candidate; private final ArrayList integrityCheckHandlers = new ArrayList<>(); + /** + * @param uri the URI of remote file. + * @param path the location that download to. + */ + public FileDownloadTask(String uri, Path path) { + this(List.of(NetworkUtils.toURI(uri)), path, null); + } + + /** + * @param uri the URI of remote file. + * @param path the location that download to. + * @param integrityCheck the integrity check to perform, null if no integrity check is to be performed + */ + public FileDownloadTask(String uri, Path path, IntegrityCheck integrityCheck) { + this(List.of(NetworkUtils.toURI(uri)), path, integrityCheck); + } + /** * @param uri the URI of remote file. * @param path the location that download to. @@ -99,16 +117,6 @@ public class FileDownloadTask extends FetchTask { this(List.of(uri), path, integrityCheck); } - /** - * @param uri the URI of remote file. - * @param path the location that download to. - * @param integrityCheck the integrity check to perform, null if no integrity check is to be performed - * @param retry the times for retrying if downloading fails. - */ - public FileDownloadTask(URI uri, Path path, IntegrityCheck integrityCheck, int retry) { - this(List.of(uri), path, integrityCheck, retry); - } - /** * Constructor. * @@ -127,19 +135,7 @@ public class FileDownloadTask extends FetchTask { * @param integrityCheck the integrity check to perform, null if no integrity check is to be performed */ public FileDownloadTask(List uris, Path path, IntegrityCheck integrityCheck) { - this(uris, path, integrityCheck, DEFAULT_RETRY); - } - - /** - * Constructor. - * - * @param uris uris of remote file, will be attempted in order. - * @param path the location that download to. - * @param integrityCheck the integrity check to perform, null if no integrity check is to be performed - * @param retry the times for retrying if downloading fails. - */ - public FileDownloadTask(List uris, Path path, IntegrityCheck integrityCheck, int retry) { - super(uris, retry); + super(uris); this.file = path; this.integrityCheck = integrityCheck; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java index dba5d75f7..ff20730db 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/task/GetTask.java @@ -19,12 +19,12 @@ package org.jackhuang.hmcl.task; import com.google.gson.reflect.TypeToken; import org.jackhuang.hmcl.util.gson.JsonUtils; +import org.jackhuang.hmcl.util.io.NetworkUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URI; import java.net.URLConnection; -import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; import java.util.List; @@ -36,29 +36,18 @@ import static java.nio.charset.StandardCharsets.UTF_8; */ public final class GetTask extends FetchTask { - private final Charset charset; + public GetTask(String uri) { + this(NetworkUtils.toURI(uri)); + } public GetTask(URI url) { - this(url, UTF_8); - } - - public GetTask(URI url, Charset charset) { - this(url, charset, DEFAULT_RETRY); - } - - public GetTask(URI url, Charset charset, int retry) { - this(List.of(url), charset, retry); + this(List.of(url)); + setName(url.toString()); } public GetTask(List url) { - this(url, UTF_8, DEFAULT_RETRY); - } - - public GetTask(List urls, Charset charset, int retry) { - super(urls, retry); - this.charset = charset; - - setName(urls.get(0).toString()); + super(url); + setName(url.get(0).toString()); } @Override @@ -85,7 +74,7 @@ public final class GetTask extends FetchTask { public void close() throws IOException { if (!isSuccess()) return; - String result = baos.toString(charset); + String result = baos.toString(UTF_8); setResult(result); if (checkETag) { diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/CacheRepository.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/CacheRepository.java index f2f36b977..ff5612f94 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/CacheRepository.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/CacheRepository.java @@ -29,7 +29,6 @@ import org.jetbrains.annotations.Nullable; import java.io.*; import java.net.HttpURLConnection; import java.net.URI; -import java.net.URISyntaxException; import java.net.URLConnection; import java.nio.channels.Channels; import java.nio.channels.FileChannel; @@ -185,8 +184,8 @@ public class CacheRepository { URI uri; try { - uri = NetworkUtils.dropQuery(conn.getURL().toURI()); - } catch (URISyntaxException e) { + uri = NetworkUtils.dropQuery(NetworkUtils.toURI(conn.getURL())); + } catch (IllegalArgumentException e) { return; } ETagItem eTagItem; @@ -229,16 +228,16 @@ public class CacheRepository { if (StringUtils.isBlank(eTag)) return null; URI uri; try { - uri = NetworkUtils.dropQuery(connection.getURL().toURI()); - } catch (URISyntaxException e) { + uri = NetworkUtils.dropQuery(NetworkUtils.toURI(connection.getURL())); + } catch (IllegalArgumentException e) { throw new IOException(e); } String lastModified = connection.getHeaderField("Last-Modified"); CacheResult cacheResult = cacheSupplier.get(); - ETagItem eTagItem = new ETagItem(uri, eTag, cacheResult.hash, Files.getLastModifiedTime(cacheResult.cachedFile).toMillis(), lastModified); + ETagItem eTagItem = new ETagItem(uri.toString(), eTag, cacheResult.hash, Files.getLastModifiedTime(cacheResult.cachedFile).toMillis(), lastModified); lock.writeLock().lock(); try { - index.compute(eTagItem.url, updateEntity(eTagItem, true)); + index.compute(uri, updateEntity(eTagItem, true)); saveETagIndex(); } finally { lock.writeLock().unlock(); @@ -282,7 +281,7 @@ public class CacheRepository { for (Collection eTagItems : indexes) { if (eTagItems != null) { for (ETagItem eTag : eTagItems) { - eTags.compute(eTag.url, updateEntity(eTag, false)); + eTags.compute(NetworkUtils.toURI(eTag.url), updateEntity(eTag, false)); } } } @@ -331,7 +330,7 @@ public class CacheRepository { } private static final class ETagItem { - private final URI url; + private final String url; private final String eTag; private final String hash; @SerializedName("local") @@ -346,7 +345,7 @@ public class CacheRepository { this(null, null, null, 0, null); } - public ETagItem(URI url, String eTag, String hash, long localLastModified, String remoteLastModified) { + public ETagItem(String url, String eTag, String hash, long localLastModified, String remoteLastModified) { this.url = url; this.eTag = eTag; this.hash = hash; diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java index 3f8535858..c701ffd2d 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/HttpRequest.java @@ -29,7 +29,6 @@ import java.io.IOException; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; -import java.net.URI; import java.net.URL; import java.util.HashMap; import java.util.HashSet; @@ -120,7 +119,7 @@ public abstract class HttpRequest { } public HttpURLConnection createConnection() throws IOException { - HttpURLConnection con = createHttpConnection(URI.create(url)); + HttpURLConnection con = createHttpConnection(url); con.setRequestMethod(method); for (Map.Entry entry : headers.entrySet()) { con.setRequestProperty(entry.getKey(), entry.getValue()); @@ -188,9 +187,9 @@ public abstract class HttpRequest { if (con.getResponseCode() / 100 != 2) { if (!ignoreHttpCode && !toleratedHttpCodes.contains(con.getResponseCode())) { try { - throw new ResponseCodeException(NetworkUtils.toURI(url), con.getResponseCode(), NetworkUtils.readFullyAsString(con)); + throw new ResponseCodeException(url.toString(), con.getResponseCode(), NetworkUtils.readFullyAsString(con)); } catch (IOException e) { - throw new ResponseCodeException(NetworkUtils.toURI(url), con.getResponseCode(), e); + throw new ResponseCodeException(url.toString(), con.getResponseCode(), e); } } } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/NetworkUtils.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/NetworkUtils.java index 5fe499a4b..50effea53 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/NetworkUtils.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/NetworkUtils.java @@ -18,6 +18,7 @@ package org.jackhuang.hmcl.util.io; import org.jackhuang.hmcl.util.Pair; +import org.jetbrains.annotations.NotNull; import java.io.*; import java.net.*; @@ -122,10 +123,18 @@ public final class NetworkUtils { return connection; } + public static HttpURLConnection createHttpConnection(String url) throws IOException { + return (HttpURLConnection) createConnection(toURI(url)); + } + public static HttpURLConnection createHttpConnection(URI url) throws IOException { return (HttpURLConnection) createConnection(url); } + private static void encodeCodePoint(StringBuilder builder, int codePoint) { + builder.append(encodeURL(Character.toString(codePoint))); + } + /** * @param location the url to be URL encoded * @return encoded URL @@ -133,29 +142,59 @@ public final class NetworkUtils { * "https://github.com/curl/curl/blob/3f7b1bb89f92c13e69ee51b710ac54f775aab320/lib/transfer.c#L1427-L1461">Curl */ public static String encodeLocation(String location) { - StringBuilder sb = new StringBuilder(); + int i = 0; boolean left = true; - for (char ch : location.toCharArray()) { - switch (ch) { - case ' ': - if (left) - sb.append("%20"); - else - sb.append('+'); - break; - case '?': - left = false; - // fallthrough - default: - if (ch >= 0x80) - sb.append(encodeURL(Character.toString(ch))); - else - sb.append(ch); - break; + while (i < location.length()) { + char ch = location.charAt(i); + if (ch == ' ' || ch >= 0x80) + break; + else if (ch == '?') + left = false; + i++; + } + + if (i == location.length()) { + // No need to encode + return location; + } + + var builder = new StringBuilder(location.length() + 10); + builder.append(location, 0, i); + + for (; i < location.length(); i++) { + char ch = location.charAt(i); + if (Character.isSurrogate(ch)) { + if (Character.isHighSurrogate(ch) && i < location.length() - 1) { + char ch2 = location.charAt(i + 1); + if (Character.isLowSurrogate(ch2)) { + int codePoint = Character.toCodePoint(ch, ch2); + encodeCodePoint(builder, codePoint); + i++; + continue; + } + } + + // Invalid surrogate pair, encode as '?' + builder.append("%3F"); + continue; + } + + if (ch == ' ') { + if (left) + builder.append("%20"); + else + builder.append('+'); + } else if (ch == '?') { + left = false; + builder.append('?'); + } else if (ch >= 0x80) { + encodeCodePoint(builder, ch); + } else { + builder.append(ch); } } - return sb.toString(); + return builder.toString(); } /** @@ -200,6 +239,10 @@ public final class NetworkUtils { return conn; } + public static String doGet(String uri) throws IOException { + return doGet(toURI(uri)); + } + public static String doGet(URI uri) throws IOException { return readFullyAsString(resolveConnection(createHttpConnection(uri))); } @@ -319,14 +362,6 @@ public final class NetworkUtils { } } - public static URI toURI(URL url) { - try { - return url.toURI(); - } catch (URISyntaxException e) { - throw new IllegalArgumentException(e); - } - } - // ==== Shortcut methods for encoding/decoding URLs in UTF-8 ==== public static String encodeURL(String toEncode) { return URLEncoder.encode(toEncode, UTF_8); @@ -335,6 +370,20 @@ public final class NetworkUtils { public static String decodeURL(String toDecode) { return URLDecoder.decode(toDecode, UTF_8); } + + /// @throws IllegalArgumentException if the string is not a valid URI + public static @NotNull URI toURI(@NotNull String uri) { + try { + return new URI(encodeLocation(uri)); + } catch (URISyntaxException e) { + // Possibly an Internationalized Domain Name (IDN) + return URI.create(uri); + } + } + + public static @NotNull URI toURI(@NotNull URL url) { + return toURI(url.toExternalForm()); + } // ==== } diff --git a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java index 5206c8cb8..67ed53dfe 100644 --- a/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java +++ b/HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/ResponseCodeException.java @@ -22,32 +22,44 @@ import java.net.URI; public final class ResponseCodeException extends IOException { - private final URI uri; + private final String uri; private final int responseCode; private final String data; public ResponseCodeException(URI uri, int responseCode) { + this(uri.toString(), responseCode); + } + + public ResponseCodeException(URI uri, int responseCode, Throwable cause) { + this(uri.toString(), responseCode, cause); + } + + public ResponseCodeException(URI uri, int responseCode, String data) { + this(uri.toString(), responseCode, data); + } + + public ResponseCodeException(String uri, int responseCode) { super("Unable to request url " + uri + ", response code: " + responseCode); this.uri = uri; this.responseCode = responseCode; this.data = null; } - public ResponseCodeException(URI uri, int responseCode, Throwable cause) { + public ResponseCodeException(String uri, int responseCode, Throwable cause) { super("Unable to request url " + uri + ", response code: " + responseCode, cause); this.uri = uri; this.responseCode = responseCode; this.data = null; } - public ResponseCodeException(URI uri, int responseCode, String data) { + public ResponseCodeException(String uri, int responseCode, String data) { super("Unable to request url " + uri + ", response code: " + responseCode + ", data: " + data); this.uri = uri; this.responseCode = responseCode; this.data = data; } - public URI getUri() { + public String getUri() { return uri; } diff --git a/HMCLCore/src/test/java/org/jackhuang/hmcl/util/io/NetworkUtilsTest.java b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/io/NetworkUtilsTest.java index 0423ff59c..7d22b499b 100644 --- a/HMCLCore/src/test/java/org/jackhuang/hmcl/util/io/NetworkUtilsTest.java +++ b/HMCLCore/src/test/java/org/jackhuang/hmcl/util/io/NetworkUtilsTest.java @@ -21,18 +21,39 @@ import org.junit.jupiter.api.Test; import static java.nio.charset.StandardCharsets.US_ASCII; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.jackhuang.hmcl.util.io.NetworkUtils.encodeLocation; +import static org.jackhuang.hmcl.util.io.NetworkUtils.getCharsetFromContentType; import static org.junit.jupiter.api.Assertions.assertEquals; /** * @author Glavo */ public class NetworkUtilsTest { + + @Test + public void testEncodeLocation() { + assertEquals("https://github.com", encodeLocation("https://github.com")); + assertEquals("https://github.com/HMCL-dev/HMCL/commits?author=Glavo", encodeLocation("https://github.com/HMCL-dev/HMCL/commits?author=Glavo")); + assertEquals("https://www.example.com/file%20with%20space", encodeLocation("https://www.example.com/file with space")); + assertEquals("https://www.example.com/file%20with%20space", encodeLocation("https://www.example.com/file%20with%20space")); + assertEquals("https://www.example.com/%E6%B5%8B%E8%AF%95", encodeLocation("https://www.example.com/测试")); + assertEquals("https://www.example.com/%F0%9F%98%87", encodeLocation("https://www.example.com/\uD83D\uDE07")); + assertEquals("https://www.example.com/test?a=10+20", encodeLocation("https://www.example.com/test?a=10 20")); + assertEquals("https://www.example.com/%E6%B5%8B%E8%AF%95?a=10+20", encodeLocation("https://www.example.com/测试?a=10 20")); + + // Invalid surrogate pair + assertEquals("https://www.example.com/%3F", encodeLocation("https://www.example.com/\uD83D")); + assertEquals("https://www.example.com/%3F", encodeLocation("https://www.example.com/\uDE07")); + assertEquals("https://www.example.com/%3Ftest", encodeLocation("https://www.example.com/\uD83Dtest")); + assertEquals("https://www.example.com/%3Ftest", encodeLocation("https://www.example.com/\uDE07test")); + } + @Test public void testGetEncodingFromUrl() { - assertEquals(UTF_8, NetworkUtils.getCharsetFromContentType(null)); - assertEquals(UTF_8, NetworkUtils.getCharsetFromContentType("")); - assertEquals(UTF_8, NetworkUtils.getCharsetFromContentType("text/html")); - assertEquals(UTF_8, NetworkUtils.getCharsetFromContentType("text/html; charset=utf-8")); - assertEquals(US_ASCII, NetworkUtils.getCharsetFromContentType("text/html; charset=ascii")); + assertEquals(UTF_8, getCharsetFromContentType(null)); + assertEquals(UTF_8, getCharsetFromContentType("")); + assertEquals(UTF_8, getCharsetFromContentType("text/html")); + assertEquals(UTF_8, getCharsetFromContentType("text/html; charset=utf-8")); + assertEquals(US_ASCII, getCharsetFromContentType("text/html; charset=ascii")); } }