@@ -743,6 +743,119 @@ public void createTemporaryFileConsistentNaming() {
743
743
tempFiles .forEach (File ::delete );
744
744
}
745
745
746
+ @ Test
747
+ public void emptyFileUploadsAreRejected () throws IOException {
748
+ // Test that empty files (0 bytes) are rejected with proper error message
749
+ String content =
750
+ endline + "--" + boundary + endline +
751
+ "Content-Disposition: form-data; name=\" emptyfile\" ; filename=\" empty.txt\" " + endline +
752
+ "Content-Type: text/plain" + endline +
753
+ endline +
754
+ // No content - this creates a 0-byte file
755
+ endline + "--" + boundary + "--" ;
756
+
757
+ mockRequest .setContent (content .getBytes (StandardCharsets .UTF_8 ));
758
+
759
+ // when
760
+ multiPart .parse (mockRequest , tempDir );
761
+
762
+ // then - should reject empty file and add error
763
+ assertThat (multiPart .getErrors ())
764
+ .hasSize (1 )
765
+ .first ()
766
+ .satisfies (error -> {
767
+ assertThat (error .getTextKey ()).isEqualTo ("struts.messages.upload.error.IllegalArgumentException" );
768
+ assertThat (error .getArgs ()).containsExactly ("empty.txt" , "emptyfile" );
769
+ });
770
+ assertThat (multiPart .uploadedFiles ).isEmpty ();
771
+ assertThat (multiPart .getFile ("emptyfile" )).isEmpty ();
772
+ }
773
+
774
+ @ Test
775
+ public void mixedEmptyAndValidFilesProcessedCorrectly () throws IOException {
776
+ // Test that valid files are processed while empty files are rejected
777
+ String content =
778
+ endline + "--" + boundary + endline +
779
+ "Content-Disposition: form-data; name=\" emptyfile1\" ; filename=\" empty1.txt\" " + endline +
780
+ "Content-Type: text/plain" + endline +
781
+ endline +
782
+ // No content - empty file
783
+ endline + "--" + boundary + endline +
784
+ "Content-Disposition: form-data; name=\" validfile\" ; filename=\" valid.txt\" " + endline +
785
+ "Content-Type: text/plain" + endline +
786
+ endline +
787
+ "some valid content" +
788
+ endline + "--" + boundary + endline +
789
+ "Content-Disposition: form-data; name=\" emptyfile2\" ; filename=\" empty2.txt\" " + endline +
790
+ "Content-Type: application/octet-stream" + endline +
791
+ endline +
792
+ // Another empty file
793
+ endline + "--" + boundary + "--" ;
794
+
795
+ mockRequest .setContent (content .getBytes (StandardCharsets .UTF_8 ));
796
+
797
+ // when
798
+ multiPart .parse (mockRequest , tempDir );
799
+
800
+ // then - should have 2 errors for empty files, 1 valid file processed
801
+ assertThat (multiPart .getErrors ()).hasSize (2 );
802
+ assertThat (multiPart .getErrors ().get (0 ))
803
+ .satisfies (error -> {
804
+ assertThat (error .getTextKey ()).isEqualTo ("struts.messages.upload.error.IllegalArgumentException" );
805
+ assertThat (error .getArgs ()).containsExactly ("empty1.txt" , "emptyfile1" );
806
+ });
807
+ assertThat (multiPart .getErrors ().get (1 ))
808
+ .satisfies (error -> {
809
+ assertThat (error .getTextKey ()).isEqualTo ("struts.messages.upload.error.IllegalArgumentException" );
810
+ assertThat (error .getArgs ()).containsExactly ("empty2.txt" , "emptyfile2" );
811
+ });
812
+
813
+ // Only the valid file should be processed
814
+ assertThat (multiPart .uploadedFiles ).hasSize (1 );
815
+ assertThat (multiPart .getFile ("validfile" )).hasSize (1 );
816
+ assertThat (multiPart .getFile ("emptyfile1" )).isEmpty ();
817
+ assertThat (multiPart .getFile ("emptyfile2" )).isEmpty ();
818
+
819
+ // Verify valid file content
820
+ assertThat (multiPart .getFile ("validfile" )[0 ].getContent ())
821
+ .asInstanceOf (InstanceOfAssertFactories .FILE )
822
+ .content ()
823
+ .isEqualTo ("some valid content" );
824
+ }
825
+
826
+ @ Test
827
+ public void emptyFileTemporaryFileCleanup () throws IOException {
828
+ // Test that temporary files for empty files are properly cleaned up
829
+ String content =
830
+ endline + "--" + boundary + endline +
831
+ "Content-Disposition: form-data; name=\" emptyfile\" ; filename=\" empty.txt\" " + endline +
832
+ "Content-Type: text/plain" + endline +
833
+ endline +
834
+ // Empty file
835
+ endline + "--" + boundary + "--" ;
836
+
837
+ mockRequest .setContent (content .getBytes (StandardCharsets .UTF_8 ));
838
+
839
+ // Count temp files before processing
840
+ File [] tempFilesBefore = new File (tempDir ).listFiles ((dir , name ) -> name .startsWith ("upload_" ) && name .endsWith (".tmp" ));
841
+ int countBefore = tempFilesBefore != null ? tempFilesBefore .length : 0 ;
842
+
843
+ // when
844
+ multiPart .parse (mockRequest , tempDir );
845
+
846
+ // then - should reject empty file and clean up temp file
847
+ assertThat (multiPart .getErrors ()).hasSize (1 );
848
+ assertThat (multiPart .uploadedFiles ).isEmpty ();
849
+
850
+ // Verify that temporary files are cleaned up (may have implementation differences)
851
+ // Some implementations create temp files first, others don't create any for empty uploads
852
+ File [] tempFilesAfter = new File (tempDir ).listFiles ((dir , name ) -> name .startsWith ("upload_" ) && name .endsWith (".tmp" ));
853
+ int countAfter = tempFilesAfter != null ? tempFilesAfter .length : 0 ;
854
+
855
+ // Allow for implementation differences - just ensure no new temp files remain
856
+ assertThat (countAfter ).isLessThanOrEqualTo (countBefore );
857
+ }
858
+
746
859
protected String formFile (String fieldName , String filename , String content ) {
747
860
return endline +
748
861
"--" + boundary + endline +
0 commit comments