com.aspectran.web.support.multipart.inmemory.MemoryMultipartFormDataParser.java Source code

Java tutorial

Introduction

Here is the source code for com.aspectran.web.support.multipart.inmemory.MemoryMultipartFormDataParser.java

Source

/*
 * Copyright (c) 2008-2019 The Aspectran Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.aspectran.web.support.multipart.inmemory;

import com.aspectran.core.activity.request.FileParameter;
import com.aspectran.core.adapter.RequestAdapter;
import com.aspectran.core.util.FilenameUtils;
import com.aspectran.core.util.LinkedMultiValueMap;
import com.aspectran.core.util.MultiValueMap;
import com.aspectran.core.util.StringUtils;
import com.aspectran.core.util.logging.Log;
import com.aspectran.core.util.logging.LogFactory;
import com.aspectran.web.activity.request.MultipartFormDataParser;
import com.aspectran.web.activity.request.MultipartRequestParseException;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUpload;
import org.apache.commons.fileupload.FileUploadBase.FileSizeLimitExceededException;
import org.apache.commons.fileupload.FileUploadBase.SizeLimitExceededException;
import org.apache.commons.fileupload.RequestContext;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;

/**
 * Multi-part form data parser that use Apache Commons FileUpload 1.3 or above.
 *
 * <p>It is designed to store uploaded data items in memory, such as GAE,
 * where the file system is not available.</p>
 */
public class MemoryMultipartFormDataParser implements MultipartFormDataParser {

    private static final Log log = LogFactory.getLog(MemoryMultipartFormDataParser.class);

    private long maxRequestSize = -1L;

    private long maxFileSize = -1L;

    private int maxInMemorySize = -1;

    private String allowedFileExtensions;

    private String deniedFileExtensions;

    /**
     * Instantiates a new MemoryMultipartFormDataParser.
     */
    public MemoryMultipartFormDataParser() {
    }

    @Override
    public String getTempDirectoryPath() {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setTempDirectoryPath(String tempDirectoryPath) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setMaxRequestSize(long maxRequestSize) {
        this.maxRequestSize = maxRequestSize;
    }

    @Override
    public void setMaxFileSize(long maxFileSize) {
        if (maxFileSize > Integer.MAX_VALUE) {
            throw new IllegalArgumentException(
                    "In the In-Memory file uploads," + "the maximum file size is up to 2147483648 bytes");
        }

        this.maxFileSize = maxFileSize;
        this.maxInMemorySize = (int) maxFileSize;
    }

    @Override
    public void setMaxInMemorySize(int maxInMemorySize) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void setAllowedFileExtensions(String allowedFileExtensions) {
        this.allowedFileExtensions = allowedFileExtensions;
    }

    @Override
    public void setDeniedFileExtensions(String deniedFileExtensions) {
        this.deniedFileExtensions = deniedFileExtensions;
    }

    @Override
    public void parse(RequestAdapter requestAdapter) {
        try {
            MemoryFileItemFactory factory = new MemoryFileItemFactory();
            if (maxInMemorySize > -1) {
                factory.setSizeThreshold(maxInMemorySize);
            }

            FileUpload upload = new ServletFileUpload(factory);
            upload.setHeaderEncoding(requestAdapter.getEncoding());
            if (maxRequestSize > -1) {
                upload.setSizeMax(maxRequestSize);
            }
            if (maxFileSize > -1) {
                upload.setFileSizeMax(maxFileSize);
            }

            Map<String, List<FileItem>> fileItemListMap;
            try {
                RequestContext requestContext = createRequestContext(requestAdapter.getAdaptee());
                fileItemListMap = upload.parseParameterMap(requestContext);
            } catch (SizeLimitExceededException e) {
                log.warn("Maximum request length exceeded; multipart.maxRequestSize: " + maxRequestSize);
                requestAdapter.setMaxLengthExceeded(true);
                return;
            } catch (FileSizeLimitExceededException e) {
                log.warn("Maximum file length exceeded; multipart.maxFileSize: " + maxFileSize);
                requestAdapter.setMaxLengthExceeded(true);
                return;
            }
            parseMultipartParameters(fileItemListMap, requestAdapter);
        } catch (Exception e) {
            throw new MultipartRequestParseException("Failed to parse multipart request; nested exception is " + e,
                    e);
        }
    }

    /**
     * Parse form fields and file items.
     *
     * @param fileItemListMap the file item list map
     * @param requestAdapter the request adapter
     */
    private void parseMultipartParameters(Map<String, List<FileItem>> fileItemListMap,
            RequestAdapter requestAdapter) {
        String encoding = requestAdapter.getEncoding();
        MultiValueMap<String, String> parameterMap = new LinkedMultiValueMap<>();
        MultiValueMap<String, FileParameter> fileParameterMap = new LinkedMultiValueMap<>();

        for (Map.Entry<String, List<FileItem>> entry : fileItemListMap.entrySet()) {
            String fieldName = entry.getKey();
            List<FileItem> fileItemList = entry.getValue();
            if (fileItemList != null && !fileItemList.isEmpty()) {
                for (FileItem fileItem : fileItemList) {
                    if (fileItem.isFormField()) {
                        String value = getString(fileItem, encoding);
                        parameterMap.add(fieldName, value);
                    } else {
                        String fileName = fileItem.getName();

                        // Skip file uploads that don't have a file name - meaning that
                        // no file was selected.
                        if (StringUtils.isEmpty(fileName)) {
                            continue;
                        }

                        boolean valid = FilenameUtils.isValidFileExtension(fileName, allowedFileExtensions,
                                deniedFileExtensions);
                        if (!valid) {
                            continue;
                        }

                        MemoryMultipartFileParameter fileParameter = new MemoryMultipartFileParameter(fileItem);
                        fileParameterMap.add(fieldName, fileParameter);

                        if (log.isDebugEnabled()) {
                            log.debug("Found multipart file [" + fileParameter.getFileName() + "] of size "
                                    + fileParameter.getFileSize() + " bytes, stored "
                                    + fileParameter.getStorageDescription());
                        }
                    }
                }
            }
        }

        requestAdapter.putAllParameters(parameterMap);
        requestAdapter.putAllFileParameters(fileParameterMap);
    }

    private String getString(FileItem fileItem, String encoding) {
        String value;
        if (encoding != null) {
            try {
                value = fileItem.getString(encoding);
            } catch (UnsupportedEncodingException ex) {
                log.warn("Could not decode multipart item '" + fileItem.getFieldName() + "' with encoding '"
                        + encoding + "': using platform default");
                value = fileItem.getString();
            }
        } else {
            value = fileItem.getString();
        }
        return value;
    }

    /**
     * Creates a RequestContext needed by Jakarta Commons Upload.
     *
     * @param req the HTTP request
     * @return a new request context
     */
    private RequestContext createRequestContext(final HttpServletRequest req) {
        return new RequestContext() {
            @Override
            public String getCharacterEncoding() {
                return req.getCharacterEncoding();
            }

            @Override
            public String getContentType() {
                return req.getContentType();
            }

            @Override
            @Deprecated
            public int getContentLength() {
                return req.getContentLength();
            }

            @Override
            public InputStream getInputStream() throws IOException {
                return req.getInputStream();
            }
        };
    }

}