diff --git a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java index 9ff046e040..2ea611f3af 100644 --- a/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java +++ b/app/common/src/main/java/stirling/software/common/model/ApplicationProperties.java @@ -35,6 +35,8 @@ import lombok.Setter; import lombok.ToString; import lombok.extern.slf4j.Slf4j; +import jakarta.annotation.PostConstruct; + import stirling.software.common.configuration.InstallationPathConfig; import stirling.software.common.configuration.YamlPropertySourceFactory; import stirling.software.common.model.exception.UnsupportedProviderException; @@ -98,6 +100,46 @@ public class ApplicationProperties { return propertySource; } + /** + * Initialize fileUploadLimit from environment variables if not set in settings.yml. + * Supports SYSTEMFILEUPLOADLIMIT (format: "100MB") and SYSTEM_MAXFILESIZE (format: "100" in MB). + */ + @PostConstruct + public void initializeFileUploadLimitFromEnv() { + // Only override if fileUploadLimit is not already set in settings.yml + if (system.getFileUploadLimit() == null || system.getFileUploadLimit().isEmpty()) { + String fileUploadLimit = null; + + // Check SYSTEMFILEUPLOADLIMIT first (format: "100MB", "1GB", etc.) + String systemFileUploadLimit = java.lang.System.getenv("SYSTEMFILEUPLOADLIMIT"); + if (systemFileUploadLimit != null && !systemFileUploadLimit.trim().isEmpty()) { + fileUploadLimit = systemFileUploadLimit.trim(); + log.info("Setting fileUploadLimit from SYSTEMFILEUPLOADLIMIT: {}", fileUploadLimit); + } else { + // Check SYSTEM_MAXFILESIZE (format: number in MB, e.g., "100") + String systemMaxFileSize = java.lang.System.getenv("SYSTEM_MAXFILESIZE"); + if (systemMaxFileSize != null && !systemMaxFileSize.trim().isEmpty()) { + try { + // Validate it's a number + long sizeInMB = Long.parseLong(systemMaxFileSize.trim()); + if (sizeInMB > 0 && sizeInMB <= 999) { + fileUploadLimit = sizeInMB + "MB"; + log.info("Setting fileUploadLimit from SYSTEM_MAXFILESIZE: {}MB", sizeInMB); + } else { + log.warn("SYSTEM_MAXFILESIZE value {} is out of valid range (1-999), ignoring", sizeInMB); + } + } catch (NumberFormatException e) { + log.warn("SYSTEM_MAXFILESIZE value '{}' is not a valid number, ignoring", systemMaxFileSize); + } + } + } + + if (fileUploadLimit != null) { + system.setFileUploadLimit(fileUploadLimit); + } + } + } + @Data public static class AutoPipeline { private String outputFolder; diff --git a/app/core/src/main/java/stirling/software/SPDF/config/MultipartConfiguration.java b/app/core/src/main/java/stirling/software/SPDF/config/MultipartConfiguration.java new file mode 100644 index 0000000000..e7e4a2b588 --- /dev/null +++ b/app/core/src/main/java/stirling/software/SPDF/config/MultipartConfiguration.java @@ -0,0 +1,76 @@ +package stirling.software.SPDF.config; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.servlet.MultipartConfigFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.DependsOn; +import org.springframework.util.unit.DataSize; + +import jakarta.servlet.MultipartConfigElement; + +import lombok.extern.slf4j.Slf4j; + +import stirling.software.SPDF.controller.web.UploadLimitService; + +/** + * Configuration for Spring multipart file upload settings. + * Synchronizes multipart limits with fileUploadLimit from settings.yml or environment variables + * (SYSTEMFILEUPLOADLIMIT or SYSTEM_MAXFILESIZE). + */ +@Configuration +@Slf4j +public class MultipartConfiguration { + + @Autowired private UploadLimitService uploadLimitService; + + /** + * Creates MultipartConfigElement that respects fileUploadLimit from settings.yml + * or environment variables (SYSTEMFILEUPLOADLIMIT or SYSTEM_MAXFILESIZE). + * Depends on ApplicationProperties being initialized so @PostConstruct has run. + */ + @Bean + @DependsOn("applicationProperties") + public MultipartConfigElement multipartConfigElement() { + MultipartConfigFactory factory = new MultipartConfigFactory(); + + // First check if SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE is explicitly set + String springMaxFileSize = java.lang.System.getenv("SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE"); + long uploadLimitBytes = 0; + + if (springMaxFileSize != null && !springMaxFileSize.trim().isEmpty()) { + // Parse the Spring property format (e.g., "2000MB") + try { + DataSize dataSize = DataSize.parse(springMaxFileSize.trim()); + uploadLimitBytes = dataSize.toBytes(); + log.info("Using SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: {}", springMaxFileSize); + } catch (Exception e) { + log.warn("Failed to parse SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE: {}", springMaxFileSize, e); + } + } + + // If not set via Spring property, use UploadLimitService which reads from + // fileUploadLimit (set from SYSTEMFILEUPLOADLIMIT/SYSTEM_MAXFILESIZE or settings.yml) + if (uploadLimitBytes == 0) { + uploadLimitBytes = uploadLimitService.getUploadLimit(); + if (uploadLimitBytes > 0) { + log.info( + "Using fileUploadLimit setting: {}", + uploadLimitService.getReadableUploadLimit()); + } + } + + // If still no limit, use default of 2000MB + if (uploadLimitBytes == 0) { + uploadLimitBytes = 2000L * 1024 * 1024; // 2000MB default + log.info("Using default multipart file upload limit: 2000MB"); + } + + // Set max file size and max request size to the same value + factory.setMaxFileSize(DataSize.ofBytes(uploadLimitBytes)); + factory.setMaxRequestSize(DataSize.ofBytes(uploadLimitBytes)); + + return factory.createMultipartConfig(); + } +} + diff --git a/app/core/src/main/resources/application.properties b/app/core/src/main/resources/application.properties index 3c13f6c969..c35a4d273b 100644 --- a/app/core/src/main/resources/application.properties +++ b/app/core/src/main/resources/application.properties @@ -26,8 +26,11 @@ spring.mvc.problemdetails.enabled=true #logging.level.org.springframework=DEBUG #logging.level.org.springframework.security=DEBUG -spring.servlet.multipart.max-file-size=2000MB -spring.servlet.multipart.max-request-size=2000MB +# Multipart file size limits +# Can be set via environment variables: SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE and SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE +# Or via SYSTEMFILEUPLOADLIMIT/SYSTEM_MAXFILESIZE which will also set fileUploadLimit in settings.yml +spring.servlet.multipart.max-file-size=${SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE:2000MB} +spring.servlet.multipart.max-request-size=${SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE:2000MB} server.servlet.session.tracking-modes=cookie server.servlet.context-path=${SYSTEM_ROOTURIPATH:/} spring.devtools.restart.enabled=true