diff --git a/engines/base/src/main/java/org/alfresco/transform/base/transform/ProcessHandler.java b/engines/base/src/main/java/org/alfresco/transform/base/transform/ProcessHandler.java index 80e063a1..fe070c25 100644 --- a/engines/base/src/main/java/org/alfresco/transform/base/transform/ProcessHandler.java +++ b/engines/base/src/main/java/org/alfresco/transform/base/transform/ProcessHandler.java @@ -42,6 +42,7 @@ import java.util.stream.Collectors; import jakarta.jms.Destination; import jakarta.servlet.http.HttpServletRequest; +import org.springframework.http.HttpStatus; import org.springframework.web.multipart.MultipartFile; import org.alfresco.transform.base.CustomTransformer; @@ -51,6 +52,7 @@ import org.alfresco.transform.base.probes.ProbeTransform; import org.alfresco.transform.base.registry.CustomTransformers; import org.alfresco.transform.client.model.TransformRequest; import org.alfresco.transform.common.TransformerDebug; +import org.alfresco.transform.common.TransformerMessages; import org.alfresco.transform.exceptions.TransformException; import org.alfresco.transform.registry.TransformServiceRegistry; @@ -163,12 +165,27 @@ abstract class ProcessHandler extends FragmentHandler @Override public void onSuccessfulTransform() { + validateOutputLength(); sendTransformResponse(transformManager); LogEntry.setTargetSize(transformManager.getOutputLength()); LogEntry.setStatusCodeAndMessage(OK, "Success"); } + /** + * Checks whether the output file has zero length, although the input file has a non-zero length. This scenario happens when the source file is corrupted. + */ + private void validateOutputLength() + { + long sourceLen = getSourceSize(); + long targetLen = transformManager.getOutputLength(); + if (sourceLen > 0 && targetLen <= 0) + { + transformerDebug.logFailure(reference, TransformerMessages.CORRUPTED_FILE_ERROR); + throw new TransformException(HttpStatus.UNPROCESSABLE_ENTITY, TransformerMessages.CORRUPTED_FILE_ERROR); + } + } + protected void sendTransformResponse(TransformManagerImpl transformManager) {} diff --git a/engines/tika/src/test/java/org/alfresco/transform/tika/TikaTransformationIT.java b/engines/tika/src/test/java/org/alfresco/transform/tika/TikaTransformationIT.java index a3d1fd04..e55eb947 100644 --- a/engines/tika/src/test/java/org/alfresco/transform/tika/TikaTransformationIT.java +++ b/engines/tika/src/test/java/org/alfresco/transform/tika/TikaTransformationIT.java @@ -2,7 +2,7 @@ * #%L * Alfresco Transform Core * %% - * Copyright (C) 2005 - 2021 Alfresco Software Limited + * Copyright (C) 2005 - 2025 Alfresco Software Limited * %% * This file is part of the Alfresco software. * - @@ -29,6 +29,7 @@ package org.alfresco.transform.tika; import static java.text.MessageFormat.format; import static java.util.function.Function.identity; +import static org.assertj.core.api.Assertions.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.fail; import static org.springframework.http.HttpStatus.OK; @@ -41,9 +42,12 @@ import org.apache.commons.lang3.tuple.Triple; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.core.io.Resource; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.client.HttpClientErrorException; import org.alfresco.transform.base.clients.HttpClient; +import org.alfresco.transform.common.TransformerMessages; /** * @author Cezar Leahu @@ -164,4 +168,52 @@ public class TikaTransformationIT allTargets("quick.tar.gz", "application/x-gzip")) .flatMap(identity()); } + + /** + * Tests that while transforming a corrupted file to txt format, exception is thrown. + * + * @param entry + * values to execute same test with different parameters. + */ + @ParameterizedTest + @MethodSource("engineTransformationsCorruptedToText") + public void testTransformationCorruptedToText(Triple entry) + { + final String sourceFile = entry.getLeft(); + final String sourceMimetype = entry.getRight(); + final String targetExtension = entry.getMiddle(); + String targetMimetype = extensionMimetype.get(targetExtension); + + final String description = format("Transform ({0}, {1} -> {2}, {3})", + sourceFile, sourceMimetype, targetMimetype, targetExtension); + + HttpClientErrorException expectedException = catchThrowableOfType(HttpClientErrorException.class, () -> { + HttpClient.sendTRequest(ENGINE_URL, sourceFile, null, + targetMimetype, targetExtension, ImmutableMap.of( + "targetEncoding", "UTF-8", + "sourceMimetype", sourceMimetype)); + fail("Corrupted file should have thrown an exception"); + }); + + assertThat(expectedException).as(description) + .hasMessageContaining(TransformerMessages.CORRUPTED_FILE_ERROR) + .extracting(HttpClientErrorException::getStatusCode) + .isEqualTo(HttpStatus.UNPROCESSABLE_ENTITY); + } + + private static Stream> engineTransformationsCorruptedToText() + { + return Stream + .of( + textTargets("quick_corrupted.doc", "application/msword"), + textTargets("quick_corrupted.ppt", "application/vnd.ms-powerpoint"), + textTargets("quick_corrupted.pptx", "application/vnd.openxmlformats-officedocument.presentationml.presentation")) + .flatMap(identity()); + } + + private static Stream> textTargets(final String sourceFile, + final String sourceMimetype) + { + return Stream.of(Triple.of(sourceFile, "txt", sourceMimetype)); + } } diff --git a/engines/tika/src/test/resources/quick_corrupted.doc b/engines/tika/src/test/resources/quick_corrupted.doc new file mode 100644 index 00000000..f5aa7c58 Binary files /dev/null and b/engines/tika/src/test/resources/quick_corrupted.doc differ diff --git a/engines/tika/src/test/resources/quick_corrupted.ppt b/engines/tika/src/test/resources/quick_corrupted.ppt new file mode 100644 index 00000000..68f6e924 Binary files /dev/null and b/engines/tika/src/test/resources/quick_corrupted.ppt differ diff --git a/engines/tika/src/test/resources/quick_corrupted.pptx b/engines/tika/src/test/resources/quick_corrupted.pptx new file mode 100644 index 00000000..54920d11 Binary files /dev/null and b/engines/tika/src/test/resources/quick_corrupted.pptx differ diff --git a/model/src/main/java/org/alfresco/transform/common/TransformerMessages.java b/model/src/main/java/org/alfresco/transform/common/TransformerMessages.java new file mode 100644 index 00000000..5907d52a --- /dev/null +++ b/model/src/main/java/org/alfresco/transform/common/TransformerMessages.java @@ -0,0 +1,37 @@ +/* + * #%L + * Alfresco Transform Model + * %% + * Copyright (C) 2025 Alfresco Software Limited + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ +package org.alfresco.transform.common; + +/** + * Holds definition of constants related to the Transformation messages. + */ +public class TransformerMessages +{ + // Exceptions + public static final String CORRUPTED_FILE_ERROR = "The file after transformation is empty. This could be caused by a corrupted source file."; + + /** + * Creates new instance of the class. + */ + private TransformerMessages() + {} +}