Skip to content

Commit

Permalink
Merge branch 'fix3400/log-export-oom' of https://github.com/burningtn…
Browse files Browse the repository at this point in the history
…t/HMCL into prs
  • Loading branch information
burningtnt committed Nov 17, 2024
2 parents 639d5b1 + d48a246 commit 65ec005
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 13 deletions.
17 changes: 13 additions & 4 deletions HMCL/src/main/java/org/jackhuang/hmcl/game/LogExporter.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
import org.jackhuang.hmcl.util.io.Zipper;
import org.jackhuang.hmcl.util.platform.OperatingSystem;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.*;
import java.lang.management.ManagementFactory;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
Expand Down Expand Up @@ -94,8 +94,17 @@ private static void processLogs(Path directory, String fileExtension, String log
FileTime time = Files.readAttributes(file, BasicFileAttributes.class).lastModifiedTime();
if (time.toMillis() >= processStartTime) {
try {
String crashLog = Logger.filterForbiddenToken(FileUtils.readText(file, OperatingSystem.NATIVE_CHARSET));
zipper.putTextFile(crashLog, file.getFileName().toString());
if (Files.size(file) >= 1024 * 1024 * 5) {
try (
Reader reader = Files.newBufferedReader(file, OperatingSystem.NATIVE_CHARSET);
Writer writer = new BufferedWriter(new OutputStreamWriter(zipper.putStream(file.getFileName().toString()), StandardCharsets.UTF_8))
) {
Logger.filterForbiddenToken(reader, writer);
}
} else {
String crashLog = Logger.filterForbiddenToken(FileUtils.readText(file, OperatingSystem.NATIVE_CHARSET));
zipper.putTextFile(crashLog, file.getFileName().toString());
}
} catch (IOException e) {
LOG.warning("Failed to read log file: " + file, e);
}
Expand Down
44 changes: 40 additions & 4 deletions HMCLCore/src/main/java/org/jackhuang/hmcl/util/io/Zipper.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@
package org.jackhuang.hmcl.util.io;

import org.jackhuang.hmcl.util.function.ExceptionalPredicate;
import org.jetbrains.annotations.NotNull;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
Expand Down Expand Up @@ -149,6 +147,44 @@ public void putFile(Path file, String path) throws IOException {
}
}

public OutputStream putStream(String path) throws IOException {
zos.putNextEntry(new ZipEntry(normalize(path)));

return new OutputStream() {
private volatile boolean closed;

private void ensureOpen() throws IOException {
if (closed) {
throw new IOException("Stream closed");
}
}

@Override
public void write(byte @NotNull [] b) throws IOException {
ensureOpen();
zos.write(b);
}

@Override
public void write(byte @NotNull [] b, int off, int len) throws IOException {
ensureOpen();
zos.write(b, off, len);
}

@Override
public void close() throws IOException {
closed = true;
zos.closeEntry();
}

@Override
public void write(int b) throws IOException {
ensureOpen();
zos.write(b);
}
};
}

public void putStream(InputStream in, String path) throws IOException {
zos.putNextEntry(new ZipEntry(normalize(path)));
IOUtils.copyTo(in, zos, buffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
import org.tukaani.xz.XZOutputStream;

import java.io.*;
import java.nio.file.*;
import java.nio.file.DirectoryStream;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
Expand All @@ -25,7 +28,7 @@
public final class Logger {
public static final Logger LOG = new Logger();

private static volatile String[] accessTokens = new String[0];
static volatile String[] accessTokens = new String[0];

public static synchronized void registerAccessToken(String token) {
final String[] oldAccessTokens = accessTokens;
Expand All @@ -37,11 +40,12 @@ public static synchronized void registerAccessToken(String token) {
}

public static String filterForbiddenToken(String message) {
for (String token : accessTokens)
message = message.replace(token, "<access token>");
return message;
return TokenFence.filter(accessTokens, message);
}

public static void filterForbiddenToken(Reader reader, Writer out) throws IOException {
TokenFence.filter(accessTokens, reader, out);
}

static final String CLASS_NAME = Logger.class.getName();

Expand Down
124 changes: 124 additions & 0 deletions HMCLCore/src/main/java/org/jackhuang/hmcl/util/logging/TokenFence.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
package org.jackhuang.hmcl.util.logging;

import java.io.IOException;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;

final class TokenFence {
private TokenFence() {
}

public static String filter(String[] accessTokens, String message) {
for (String token : accessTokens)
message = message.replace(token, "<access token>");
return message;
}

public static void filter(String[] accessTokens, Reader reader, Writer out) throws IOException {
char[] buffer = new char[Math.max(1024, accessTokens[0].length() + 16)];
if (accessTokens.length == 1) {
filter(accessTokens[0], reader, out, buffer);
} else {
Path t1 = Files.createTempFile("hmcl-token-fence-", ".txt"), t2 = Files.createTempFile("hmcl-token-fence-", ".txt");
try (Writer o1 = Files.newBufferedWriter(t1, StandardCharsets.UTF_8)) {
filter(accessTokens[0], reader, o1, buffer);
}

for (int i = 1; i < accessTokens.length - 1; i++) {
String token = accessTokens[i];
if (token.length() > buffer.length) {
buffer = new char[token.length() + 16];
}

try (Reader i1 = Files.newBufferedReader(t1, StandardCharsets.UTF_8); Writer i2 = Files.newBufferedWriter(t2, StandardCharsets.UTF_8)) {
filter(token, i1, i2, buffer);
}

Path t3 = t2;
t2 = t1;
t1 = t3;
}

try (Reader r1 = Files.newBufferedReader(t1, StandardCharsets.UTF_8)) {
filter(accessTokens[accessTokens.length - 1], r1, out, buffer);
}
}

for (String token : accessTokens) {
if (token.length() > buffer.length) {
buffer = new char[token.length() + 16];
}
filter(token, reader, out, buffer);
}
}

private static void filter(String token, Reader reader, Writer out, char[] buffer) throws IOException {
char first = token.charAt(0);
int start = 0, length;
while ((length = reader.read(buffer, start, buffer.length - start)) != -1 || start != 0) {
if (start != 0) {
length = (length == -1 ? 0 : length) + start;
}
if (length < token.length()) {
out.write(buffer, 0, length);
return;
}

int fi = findToken(buffer, length, token);
if (fi == -1) {
int fi2 = indexOf(buffer, length - token.length() + 1, length, first);
if (fi2 == -1) {
out.write(buffer, 0, length);
start = 0;
} else {
out.write(buffer, 0, fi2);
System.arraycopy(buffer, fi2, buffer, 0, length - fi2);
start = length - fi2;
}
} else {
out.write(buffer, 0, fi);
out.write("<access token>");
start = length - fi - token.length();
System.arraycopy(buffer, fi + token.length(), buffer, 0, start);
}
}
}

private static int findToken(char[] buffer, int length, String token) {
char first = token.charAt(0);
int start = 0;
while (true) {
int fi = indexOf(buffer, start, length - token.length() + 1, first);
if (fi == -1) {
return -1;
}
if (isToken(buffer, fi, token)) {
return fi;
}
start = fi + 1;
}
}

private static int indexOf(char[] buffer, int start, int length, char target) {
for (int i = start; i < length; i++) {
if (buffer[i] == target) {
return i;
}
}

return -1;
}

private static boolean isToken(char[] buffer, int start, String token) {
for (int i = 1; i < token.length(); i++) {
if (buffer[start + i] != token.charAt(i)) {
return false;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2020 huangyuhui <[email protected]> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.util.logger;

import org.jackhuang.hmcl.util.logging.Logger;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class LoggerTest {
@Test
public void checkTokenFence() throws IOException {
for (String s : new String[]{
"a_token", "the_token", "another_token"
}) {
Logger.registerAccessToken(s);
}

test("a_token001122334455the_token667788another_token");

{
char[] data = new char[1050];
"the_token".getChars(0, "the_token".length(), data, 1020);
"another_token".getChars(0, "another_token".length(), data, 1035);
test(data);
}
}

private void test(char[] data) throws IOException {
test(new String(data));
}

private void test(String data) throws IOException {
try (StringWriter writer = new StringWriter()) {
Logger.filterForbiddenToken(new StringReader(data), writer);

assertEquals(Logger.filterForbiddenToken(data), writer.toString());
}
}
}

0 comments on commit 65ec005

Please sign in to comment.