Search code examples
javaspringspring-bootspring-boot-starter-parent

What is the alternate to org.springframework.web.multipart.MultipartResolver;


I am upgrading spring-boot-starter-parent from version 2.5.3 to 3.0.0

I was using the org.springframework.web.multipart.commons.CommonsMultipartResolver; (extending it) for my file upload needs

  • setting sizes of max uploads.
  • Getting file params
  • validating attachments etc

However in the new version CommonsMultipartResolver is no longer supported. I need help to figure out what I can use as an alternate.

Example of code:

public class MyMultipartResolver extends CommonsMultipartResolver {

    private boolean resolveLazily = false;
    private String supportedMimeTypes;

    @Autowired
    private SessionService sessionService;

    @Autowired
    private UserFileUploadEventService userFileUploadEventService;

    @Value("${file.supportedMimeTypes}")
    public void setSupportedMimeTypes(String value) {
        supportedMimeTypes = value;
    }
    
    @Value("${upload.document.max.file.size}")
    private int maxFileSize;

    @Value("${scep.executable.path}")
    private String scepExePath;

    @Value("${upload.document.directory}")
    private String uploadedDocumentPath;

    public TamsMultipartResolver() {
        super();
    }

    @Override
    public void setResolveLazily(boolean resolveLazily) {
        this.resolveLazily = resolveLazily;
    }

    
    @Override
    public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
        Assert.notNull(request, "Request must not be null");
        if (this.resolveLazily) {
            return new DefaultMultipartHttpServletRequest(request) {
                @Override
                protected void initializeMultipart() {
                    MultipartParsingResult parsingResult = parseRequest(request);
                    validateAttachment(parsingResult.getMultipartFiles().getFirst("file"));
                    setMultipartFiles(parsingResult.getMultipartFiles());
                    setMultipartParameters(getSanitizedMultipartparameters(parsingResult));
                }
            };
        } else {
            MultipartParsingResult parsingResult = parseRequest(request);
            validateAttachment(parsingResult.getMultipartFiles().getFirst("file"));
            return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(), getSanitizedMultipartparameters(parsingResult),
                    parsingResult.getMultipartParameterContentTypes());
        }
    }

    private Map<String, String[]> getSanitizedMultipartparameters(MultipartParsingResult parsingResult) {
        Map<String, String[]> mpParams = parsingResult.getMultipartParameters();
        if (mpParams != null) {
            HashMap<String, String[]> encodedParams = new HashMap<String, String[]>();
            for (String key : mpParams.keySet()) {
                encodedParams.put(key, AntiSamyHelper.sanitizeXSS(mpParams.get(key)));
            }
            return encodedParams;
        }
        return mpParams;
    }

    public void validateAttachment(MultipartFile file) throws BadRequestException {
        final int fileSize = new Long(file.getSize()).intValue();
        final String simpleFileName = file.getOriginalFilename();
        if (simpleFileName.length() > 0) {
            if (isFrequecyAttack()) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_FREQUENCY_VIOLATION);
            }
            if (!isValidMimeType(file)) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_INVALID_FILE_TYPE);
            }
            if (fileSize > maxFileSize) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_INVALID_FILE_SIZE);
            }
            if (containsThreat(file)) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_MALICIOUS_FILE_DETECTED);
            }
        } else {
            throw new BadRequestException(RestConstants.FILE_UPLOAD_INVALID_FILE_TYPE);
        }
    }

Solution

  • I was able to use the library mentioned here: github.com/spring-projects/spring-framework/issues/29562

    Here is the equivalent code from the question:

    public class MyMultipartResolver extends StandardServletMultipartResolver {

    private boolean resolveLazily = false;
    private String supportedMimeTypes;
    
    @Autowired
    private SessionService sessionService;
    
    @Autowired
    private UserFileUploadEventService userFileUploadEventService;
    
    @Value("${file.supportedMimeTypes}")
    public void setSupportedMimeTypes(String value) {
        supportedMimeTypes = value;
    }
    
    @Value("${upload.document.max.file.size}")
    private int maxFileSize;
    
    @Value("${scep.executable.path}")
    private String scepExePath;
    
    @Value("${upload.document.directory}")
    private String uploadedDocumentPath;
    
    public TamsMultipartResolver() {
        super();
    }
    
    @Override
    public void setResolveLazily(boolean resolveLazily) {
        this.resolveLazily = resolveLazily;
    }
    
    /*
     * (non-Javadoc)
     * @see org.springframework.web.multipart.commons.CommonsMultipartResolver#resolveMultipart(javax.servlet.http.HttpServletRequest)
     */
    @Override
    public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
        Assert.notNull(request, "Request must not be null");
        if (this.resolveLazily) {
            return new DefaultMultipartHttpServletRequest(request) {
                @Override
                protected void initializeMultipart() {
                    MultipartHttpServletRequest parsingResult = resolveMultipart(request);
    
                    validateAttachment(Objects.requireNonNull(parsingResult.getFile("file")));
                    setMultipartFiles(parsingResult.getMultiFileMap());
                    setMultipartParameters(getSanitizedMultipartparameters(parsingResult.getParameterMap()));
                }
            };
        } else {
            MultipartHttpServletRequest parsingResult = resolveMultipart(request);
            validateAttachment(Objects.requireNonNull(parsingResult.getFile("file")));
    
            /*Map<String, String> newMap = parsingResult.getFileMap().entrySet()
                    .stream()
                    .collect(HashMap::new, (map, entry) -> {
                        map.put(entry.getKey(), entry.getValue().getContentType());
                    }, HashMap::putAll);*/
    
            Map<String, String> mpParamContentTypes = new HashMap<>();
            for (Map.Entry<String, MultipartFile> entry : parsingResult.getFileMap().entrySet()) {
                String key = entry.getKey();
                MultipartFile value = entry.getValue();
                String contentType = value.getContentType();
                mpParamContentTypes.put(key, contentType);
            }
    
            return new DefaultMultipartHttpServletRequest(request, parsingResult.getMultiFileMap(), getSanitizedMultipartparameters(parsingResult.getParameterMap()),
                    mpParamContentTypes);
        }
    }
    
    private Map<String, String[]> getSanitizedMultipartparameters(Map<String, String[]> mpParams) {
        if (mpParams != null) {
            HashMap<String, String[]> encodedParams = new HashMap<String, String[]>();
            for (String key : mpParams.keySet()) {
                encodedParams.put(key, AntiSamyHelper.sanitizeXSS(mpParams.get(key)));
            }
            return encodedParams;
        }
        return null;
    }
    
    public void validateAttachment(MultipartFile file) throws BadRequestException {
        final int fileSize = new Long(file.getSize()).intValue();
        final String simpleFileName = file.getOriginalFilename();
        if (simpleFileName.length() > 0) {
            if (isFrequecyAttack()) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_FREQUENCY_VIOLATION);
            }
            if (!isValidMimeType(file)) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_INVALID_FILE_TYPE);
            }
            if (fileSize > maxFileSize) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_INVALID_FILE_SIZE);
            }
            if (containsThreat(file)) {
                throw new BadRequestException(RestConstants.FILE_UPLOAD_MALICIOUS_FILE_DETECTED);
            }
        } else {
            throw new BadRequestException(RestConstants.FILE_UPLOAD_INVALID_FILE_TYPE);
        }
    }