HttpUtil.java

net.minecraft.util.HttpUtil

信息

  • 全限定名:net.minecraft.util.HttpUtil
  • 类型:public class
  • 包:net.minecraft.util
  • 源码路径:src/main/java/net/minecraft/util/HttpUtil.java
  • 起始行号:L29
  • 职责:

    TODO

字段/常量

  • LOGGER
    • 类型: Logger
    • 修饰符: private static final
    • 源码定位: L30
    • 说明:

      TODO

内部类/嵌套类型

  • net.minecraft.util.HttpUtil.DownloadProgressListener
    • 类型: interface
    • 修饰符: public
    • 源码定位: L235
    • 说明:

      TODO

构造器

private HttpUtil() @ L32

  • 构造器名:HttpUtil
  • 源码定位:L32
  • 修饰符:private

参数:

说明:

TODO

方法

下面的方法块按源码顺序生成。

public static Path downloadFile(Path targetDir, URL url, Map<String,String> headers, HashFunction hashFunction, HashCode requestedHash, int maxSize, Proxy proxy, HttpUtil.DownloadProgressListener listener) @ L35

  • 方法名:downloadFile
  • 源码定位:L35
  • 返回类型:Path
  • 修饰符:public static

参数:

  • targetDir: Path
  • url: URL
  • headers: Map<String,String>
  • hashFunction: HashFunction
  • requestedHash: HashCode
  • maxSize: int
  • proxy: Proxy
  • listener: HttpUtil.DownloadProgressListener

说明:

TODO

private static void updateModificationTime(Path targetFile) @ L135

  • 方法名:updateModificationTime
  • 源码定位:L135
  • 返回类型:void
  • 修饰符:private static

参数:

  • targetFile: Path

说明:

TODO

private static HashCode hashFile(Path file, HashFunction hashFunction) @ L143

  • 方法名:hashFile
  • 源码定位:L143
  • 返回类型:HashCode
  • 修饰符:private static

参数:

  • file: Path
  • hashFunction: HashFunction

说明:

TODO

private static boolean checkExistingFile(Path file, HashFunction hashFunction, HashCode expectedHash) @ L156

  • 方法名:checkExistingFile
  • 源码定位:L156
  • 返回类型:boolean
  • 修饰符:private static

参数:

  • file: Path
  • hashFunction: HashFunction
  • expectedHash: HashCode

说明:

TODO

private static Path cachedFilePath(Path targetDir, HashCode requestedHash) @ L169

  • 方法名:cachedFilePath
  • 源码定位:L169
  • 返回类型:Path
  • 修饰符:private static

参数:

  • targetDir: Path
  • requestedHash: HashCode

说明:

TODO

private static HashCode downloadAndHash(HashFunction hashFunction, int maxSize, HttpUtil.DownloadProgressListener listener, InputStream input, Path downloadFile) @ L173

  • 方法名:downloadAndHash
  • 源码定位:L173
  • 返回类型:HashCode
  • 修饰符:private static

参数:

  • hashFunction: HashFunction
  • maxSize: int
  • listener: HttpUtil.DownloadProgressListener
  • input: InputStream
  • downloadFile: Path

说明:

TODO

public static int getAvailablePort() @ L205

  • 方法名:getAvailablePort
  • 源码定位:L205
  • 返回类型:int
  • 修饰符:public static

参数:

说明:

TODO

public static boolean isPortAvailable(int port) @ L218

  • 方法名:isPortAvailable
  • 源码定位:L218
  • 返回类型:boolean
  • 修饰符:public static

参数:

  • port: int

说明:

TODO

代码

public class HttpUtil {
    private static final Logger LOGGER = LogUtils.getLogger();
 
    private HttpUtil() {
    }
 
    public static Path downloadFile(
        Path targetDir,
        URL url,
        Map<String, String> headers,
        HashFunction hashFunction,
        @Nullable HashCode requestedHash,
        int maxSize,
        Proxy proxy,
        HttpUtil.DownloadProgressListener listener
    ) {
        HttpURLConnection connection = null;
        InputStream input = null;
        listener.requestStart();
        Path targetFile;
        if (requestedHash != null) {
            targetFile = cachedFilePath(targetDir, requestedHash);
 
            try {
                if (checkExistingFile(targetFile, hashFunction, requestedHash)) {
                    LOGGER.info("Returning cached file since actual hash matches requested");
                    listener.requestFinished(true);
                    updateModificationTime(targetFile);
                    return targetFile;
                }
            } catch (IOException var35) {
                LOGGER.warn("Failed to check cached file {}", targetFile, var35);
            }
 
            try {
                LOGGER.warn("Existing file {} not found or had mismatched hash", targetFile);
                Files.deleteIfExists(targetFile);
            } catch (IOException var34) {
                listener.requestFinished(false);
                throw new UncheckedIOException("Failed to remove existing file " + targetFile, var34);
            }
        } else {
            targetFile = null;
        }
 
        Path actualHash;
        try {
            connection = (HttpURLConnection)url.openConnection(proxy);
            connection.setInstanceFollowRedirects(true);
            headers.forEach(connection::setRequestProperty);
            input = connection.getInputStream();
            long contentLength = connection.getContentLengthLong();
            OptionalLong size = contentLength != -1L ? OptionalLong.of(contentLength) : OptionalLong.empty();
            FileUtil.createDirectoriesSafe(targetDir);
            listener.downloadStart(size);
            if (size.isPresent() && size.getAsLong() > maxSize) {
                throw new IOException("Filesize is bigger than maximum allowed (file is " + size + ", limit is " + maxSize + ")");
            }
 
            if (targetFile == null) {
                Path tmpPath = Files.createTempFile(targetDir, "download", ".tmp");
 
                try {
                    HashCode actualHashx = downloadAndHash(hashFunction, maxSize, listener, input, tmpPath);
                    Path actualPath = cachedFilePath(targetDir, actualHashx);
                    if (!checkExistingFile(actualPath, hashFunction, actualHashx)) {
                        Files.move(tmpPath, actualPath, StandardCopyOption.REPLACE_EXISTING);
                    } else {
                        updateModificationTime(actualPath);
                    }
 
                    listener.requestFinished(true);
                    return actualPath;
                } finally {
                    Files.deleteIfExists(tmpPath);
                }
            }
 
            HashCode actualHashx = downloadAndHash(hashFunction, maxSize, listener, input, targetFile);
            if (!actualHashx.equals(requestedHash)) {
                throw new IOException("Hash of downloaded file (" + actualHashx + ") did not match requested (" + requestedHash + ")");
            }
 
            listener.requestFinished(true);
            actualHash = targetFile;
        } catch (Throwable var36) {
            if (connection != null) {
                InputStream error = connection.getErrorStream();
                if (error != null) {
                    try {
                        LOGGER.error("HTTP response error: {}", IOUtils.toString(error, StandardCharsets.UTF_8));
                    } catch (Exception var32) {
                        LOGGER.error("Failed to read response from server");
                    }
                }
            }
 
            listener.requestFinished(false);
            throw new IllegalStateException("Failed to download file " + url, var36);
        } finally {
            IOUtils.closeQuietly(input);
        }
 
        return actualHash;
    }
 
    private static void updateModificationTime(Path targetFile) {
        try {
            Files.setLastModifiedTime(targetFile, FileTime.from(Instant.now()));
        } catch (IOException var2) {
            LOGGER.warn("Failed to update modification time of {}", targetFile, var2);
        }
    }
 
    private static HashCode hashFile(Path file, HashFunction hashFunction) throws IOException {
        Hasher hasher = hashFunction.newHasher();
 
        try (
            OutputStream outputStream = Funnels.asOutputStream(hasher);
            InputStream fileInput = Files.newInputStream(file);
        ) {
            fileInput.transferTo(outputStream);
        }
 
        return hasher.hash();
    }
 
    private static boolean checkExistingFile(Path file, HashFunction hashFunction, HashCode expectedHash) throws IOException {
        if (Files.exists(file)) {
            HashCode actualHash = hashFile(file, hashFunction);
            if (actualHash.equals(expectedHash)) {
                return true;
            }
 
            LOGGER.warn("Mismatched hash of file {}, expected {} but found {}", file, expectedHash, actualHash);
        }
 
        return false;
    }
 
    private static Path cachedFilePath(Path targetDir, HashCode requestedHash) {
        return targetDir.resolve(requestedHash.toString());
    }
 
    private static HashCode downloadAndHash(
        HashFunction hashFunction, int maxSize, HttpUtil.DownloadProgressListener listener, InputStream input, Path downloadFile
    ) throws IOException {
        HashCode var11;
        try (OutputStream output = Files.newOutputStream(downloadFile, StandardOpenOption.CREATE)) {
            Hasher hasher = hashFunction.newHasher();
            byte[] buffer = new byte[8196];
            long readSoFar = 0L;
 
            int read;
            while ((read = input.read(buffer)) >= 0) {
                readSoFar += read;
                listener.downloadedBytes(readSoFar);
                if (readSoFar > maxSize) {
                    throw new IOException("Filesize was bigger than maximum allowed (got >= " + readSoFar + ", limit was " + maxSize + ")");
                }
 
                if (Thread.interrupted()) {
                    LOGGER.error("INTERRUPTED");
                    throw new IOException("Download interrupted");
                }
 
                output.write(buffer, 0, read);
                hasher.putBytes(buffer, 0, read);
            }
 
            var11 = hasher.hash();
        }
 
        return var11;
    }
 
    public static int getAvailablePort() {
        try {
            int var1;
            try (ServerSocket server = new ServerSocket(0)) {
                var1 = server.getLocalPort();
            }
 
            return var1;
        } catch (IOException var5) {
            return 25564;
        }
    }
 
    public static boolean isPortAvailable(int port) {
        if (port >= 0 && port <= 65535) {
            try {
                boolean var2;
                try (ServerSocket server = new ServerSocket(port)) {
                    var2 = server.getLocalPort() == port;
                }
 
                return var2;
            } catch (IOException var6) {
                return false;
            }
        } else {
            return false;
        }
    }
 
    public interface DownloadProgressListener {
        void requestStart();
 
        void downloadStart(OptionalLong sizeBytes);
 
        void downloadedBytes(long bytesSoFar);
 
        void requestFinished(boolean success);
    }
}

引用的其他类

  • FileUtil
    • 引用位置: 方法调用
    • 关联成员: FileUtil.createDirectoriesSafe()