feat(javaTest): add dispatch audit visualizer

This commit is contained in:
zgw
2026-08-05 16:09:52 +08:00
parent f80f92dca3
commit 953f78d97e
6 changed files with 1590 additions and 2 deletions

View File

@@ -110,6 +110,22 @@ public final class HistoricalDispatchVisualizerServer {
private void route(HttpExchange exchange) throws IOException {
String path = exchange.getRequestURI().getPath();
String method = exchange.getRequestMethod();
if ("/".equals(path) || "/index.html".equals(path)) {
requireMethod(method, "GET");
writeStatic(exchange, "visualizer/index.html", "text/html; charset=utf-8");
return;
}
if ("/assets/app.css".equals(path)) {
requireMethod(method, "GET");
writeStatic(exchange, "visualizer/assets/app.css", "text/css; charset=utf-8");
return;
}
if ("/assets/app.js".equals(path)) {
requireMethod(method, "GET");
writeStatic(exchange, "visualizer/assets/app.js",
"application/javascript; charset=utf-8");
return;
}
if ("/api/health".equals(path)) {
requireMethod(method, "GET");
Map<String, Object> health = new LinkedHashMap<String, Object>();
@@ -146,6 +162,40 @@ public final class HistoricalDispatchVisualizerServer {
throw new VisualizerHttpException(404, "NOT_FOUND", "请求的审计资源不存在");
}
/**
* 从打包后的 classpath 返回审计台资源。调用方只传入固定白名单,浏览器无法借此读取本机文件。
*/
private void writeStatic(HttpExchange exchange, String resourcePath, String contentType)
throws IOException {
byte[] body;
try (InputStream inputStream = HistoricalDispatchVisualizerServer.class
.getClassLoader().getResourceAsStream(resourcePath)) {
if (inputStream == null) {
throw new VisualizerHttpException(500, "STATIC_RESOURCE_MISSING",
"审计页面资源未打包: " + resourcePath);
}
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
byte[] buffer = new byte[4096];
int read;
while ((read = inputStream.read(buffer)) >= 0) {
output.write(buffer, 0, read);
}
body = output.toByteArray();
}
}
exchange.getResponseHeaders().set("Content-Type", contentType);
exchange.getResponseHeaders().set("Cache-Control", "no-store");
exchange.getResponseHeaders().set("Content-Security-Policy",
"default-src 'self'; script-src 'self'; style-src 'self'; "
+ "img-src 'self' data:; connect-src 'self'; object-src 'none'; "
+ "base-uri 'none'; frame-ancestors 'none'");
exchange.getResponseHeaders().set("X-Content-Type-Options", "nosniff");
exchange.sendResponseHeaders(200, body.length);
try (OutputStream output = exchange.getResponseBody()) {
output.write(body);
}
}
private Map<String, Object> runSimulation(SimulationCall call) {
if (!simulationBusy.compareAndSet(false, true)) {
throw new VisualizerHttpException(409, "SIMULATION_BUSY", "已有仿真正在运行");