zip and response issues (#5786)

This commit is contained in:
Anthony Stirling
2026-02-24 20:08:18 +00:00
committed by GitHub
parent 1f9b90ad57
commit abbd332909
4 changed files with 21 additions and 17 deletions

View File

@@ -100,6 +100,11 @@ public class FileToPdf {
while (entry != null) {
Path filePath =
tempUnzippedDir.getPath().resolve(sanitizeZipFilename(entry.getName()));
Path normalizedTargetDir = tempUnzippedDir.getPath().toAbsolutePath().normalize();
Path normalizedFilePath = filePath.toAbsolutePath().normalize();
if (!normalizedFilePath.startsWith(normalizedTargetDir)) {
throw new IOException("Zip entry path escapes target directory: " + entry.getName());
}
if (!entry.isDirectory()) {
Files.createDirectories(filePath.getParent());
if (entry.getName().toLowerCase(Locale.ROOT).endsWith(".html")

View File

@@ -166,7 +166,7 @@ public class ConvertWebsiteToPDF {
private String fetchRemoteHtml(String url) throws IOException, InterruptedException {
HttpClient client =
HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NORMAL)
.followRedirects(HttpClient.Redirect.NEVER)
.connectTimeout(Duration.ofSeconds(10))
.build();
@@ -180,7 +180,7 @@ public class ConvertWebsiteToPDF {
HttpResponse<String> response =
client.send(request, HttpResponse.BodyHandlers.ofString(StandardCharsets.UTF_8));
if (response.statusCode() >= 400 || response.body() == null) {
if (response.statusCode() >= 300 || response.body() == null) {
throw ExceptionUtils.createIOException(
"error.httpRequestFailed",
"Failed to retrieve remote HTML. Status: {0}",

View File

@@ -29,6 +29,8 @@ import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.databind.ObjectMapper;
import stirling.software.common.util.ExceptionUtils;
import stirling.software.common.util.ExceptionUtils.*;
import stirling.software.common.util.RegexPatternUtils;
@@ -866,21 +868,18 @@ public class GlobalExceptionHandler {
response.setContentType("application/problem+json");
response.setCharacterEncoding("UTF-8");
String errorJson =
String.format(
"""
{
"type": "about:blank",
"title": "Not Acceptable",
"status": 406,
"detail": "The requested resource could not be returned in an acceptable format. Error responses are returned as JSON.",
"instance": "%s",
"timestamp": "%s",
"hints": ["Error responses are always returned as application/json or application/problem+json", "Set Accept header to include application/json for proper error handling"]
}
""",
request.getRequestURI(), Instant.now().toString());
// Use ObjectMapper to properly escape JSON values and prevent XSS
ObjectMapper mapper = new ObjectMapper();
java.util.Map<String, Object> errorMap = new java.util.LinkedHashMap<>();
errorMap.put("type", "about:blank");
errorMap.put("title", "Not Acceptable");
errorMap.put("status", 406);
errorMap.put("detail", "The requested resource could not be returned in an acceptable format. Error responses are returned as JSON.");
errorMap.put("instance", request.getRequestURI());
errorMap.put("timestamp", Instant.now().toString());
errorMap.put("hints", java.util.Arrays.asList("Error responses are always returned as application/json or application/problem+json", "Set Accept header to include application/json for proper error handling"));
String errorJson = mapper.writeValueAsString(errorMap);
response.getWriter().write(errorJson);
response.getWriter().flush();
}

View File

@@ -298,7 +298,7 @@ public class ConvertWebsiteToPdfTest {
HttpResponse<String> response = Mockito.mock();
httpClientStatic.when(HttpClient::newBuilder).thenReturn(builder);
when(builder.followRedirects(HttpClient.Redirect.NORMAL)).thenReturn(builder);
when(builder.followRedirects(HttpClient.Redirect.NEVER)).thenReturn(builder);
when(builder.connectTimeout(any(Duration.class))).thenReturn(builder);
when(builder.build()).thenReturn(client);