edu.umd.cs.submitServer.MultipartRequest.java Source code

Java tutorial

Introduction

Here is the source code for edu.umd.cs.submitServer.MultipartRequest.java

Source

/**
 * Marmoset: a student project snapshot, submission, testing and code review
 * system developed by the Univ. of Maryland, College Park
 * 
 * Developed as part of Jaime Spacco's Ph.D. thesis work, continuing effort led
 * by William Pugh. See http://marmoset.cs.umd.edu/
 * 
 * Copyright 2005 - 2011, Univ. of Maryland
 * 
 * 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.
 * 
 */

/*
 * Created on Jan 13, 2005
 *
 * @author jspacco
 */
package edu.umd.cs.submitServer;

import java.io.IOException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

import javax.annotation.CheckForNull;
import javax.annotation.CheckReturnValue;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.FileCleanerCleanup;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileCleaningTracker;
import org.apache.log4j.Logger;

import edu.umd.cs.marmoset.utilities.MarmosetPatterns;
import edu.umd.cs.marmoset.utilities.MarmosetUtilities;
import edu.umd.cs.marmoset.utilities.XSSScrubber;

/**
 * @author jspacco
 *
 *        
 */
@CheckReturnValue
public class MultipartRequest {
    private LinkedList<FileItem> fileItems = new LinkedList<FileItem>();
    private Map<String, Object> parameters = new HashMap<String, Object>();
    private final Logger logger;
    private final boolean strictChecking;

    public MultipartRequest(Logger logger, boolean strictChecking) {
        this.logger = logger;
        this.strictChecking = strictChecking;
    }

    public static MultipartRequest parseRequest(HttpServletRequest request, int maxSize, Logger logger,
            boolean strictChecking, ServletContext servletContext) throws IOException, ServletException {

        DiskFileItemFactory factory = getFactory(servletContext);
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setSizeMax(maxSize);
        MultipartRequest multipartRequest = new MultipartRequest(logger, strictChecking);
        try {
            // Parse the request
            List<FileItem> items = upload.parseRequest(request);

            for (FileItem item : items) {

                if (item.isFormField()) {
                    multipartRequest.setParameter(item.getFieldName(), item.getString());
                } else {
                    multipartRequest.addFileItem(item);
                }
            }
            return multipartRequest;
        } catch (FileUploadBase.SizeLimitExceededException e) {
            Debug.error("File upload is too big " + e.getActualSize() + " > " + e.getPermittedSize());
            Debug.error("upload info: " + multipartRequest);
            throw new ServletException(e);
        } catch (FileUploadException e) {
            Debug.error("FileUploadException: " + e);
            throw new ServletException(e);
        }
    }

    /**
     * @return
     */
    private static DiskFileItemFactory getFactory(ServletContext servletContext) {
        DiskFileItemFactory factory = new DiskFileItemFactory();

        FileCleaningTracker fileCleaningTracker = FileCleanerCleanup.getFileCleaningTracker(servletContext);
        factory.setFileCleaningTracker(fileCleaningTracker);
        return factory;
    }

    public void setParameter(String key, Object value) {
        parameters.put(key, value);
    }

    /**
     * Special call to get the "password" parameter. This is split into a
     * separate call to distinguish it from a call to getParameter(), which we
     * try to avoid calling since it doesn't vet the parameter before returning.
     * Presumably it's OK not to vet passwords!
     *
     * @return the value of the "password" parameter
     * @throws InvalidRequiredParameterException
     *             if parameter is not specified
     */
    public String getPasswordParameter() throws InvalidRequiredParameterException {
        return getStringParameter("password");
    }

    /**
     * Special call to get the "password" parameter, or null if the password
     * parameter is not specified. This is split into a separate call to
     * distinguish it from a call to getParameter(), which we try to avoid
     * calling since it doesn't vet the parameter before returning. Presumably
     * it's OK not to vet passwords!
     *
     * @return the value of the "password" parameter, or null if it's not
     *         specified
     */
    public String getOptionalPasswordParameter() {
        return getParameter("password");
    }

    /**
     * Get the (String) value of the given parameter. Throw an exception if it
     * wasn't specified.
     *
     * @return the value of the given parameter
     * @throws InvalidRequiredParameterException
     *             if parameter is not specified
     */
    public String getStringParameter(String name) throws InvalidRequiredParameterException {
        String param = (String) parameters.get(name);
        if (param == null)
            throw new InvalidRequiredParameterException(name + " is a required parameter and it was not present");
        if (param.equals("")) {
            throw new InvalidRequiredParameterException(name + " is a required parameter and it was empty");
        }
        return param;
    }

    /**
     * Get the (String) value of the given parameter or null if it isn't
     * specified
     *
     * @return the value of the given parameter, or null if unspecified
     */
    public @CheckForNull String getOptionalStringParameter(String name) {
        return getOptionalStringParameter(name, null);
    }

    public @CheckForNull String getOptionalStringParameter(String name, String defaultValue) {
        String param = (String) parameters.get(name);
        if (param == null || param.equals("")) {
            return defaultValue;
        }
        return param;
    }

    public int getOptionalIntParameter(String name, int defaultValue) {
        String param = (String) parameters.get(name);
        if (param == null || param.equals("")) {
            return defaultValue;
        }
        return Integer.parseInt(param);
    }

    /**
     * Return the parameter's value if matched by the provided regex pattern. If
     * the parameter is not specified or if it does not match the provided
     * regex, null is returned.
     *
     * @param name
     *            name of the parameter to retrieve
     * @param p
     *            pattern that must match a valid parameter
     * @return the parameter if it specified and valid, null otherwise
     */
    private @CheckForNull String getOptionalRegexParameter(String name, Pattern p) {
        String s = getParameter(name);
        if (s != null) {
            s = s.trim();
            if (p.matcher(s).matches()) {
                return s;
            }
            String scrubbed = XSSScrubber.scrubbedStr(s);
            logger.error(
                    "Param \"" + name + "\" value \"" + scrubbed + "\" doesn't match regex filter " + p.toString());
            if (strictChecking) {
                throw new IllegalArgumentException(name + " was malformed according to regular expression");
            } else {
                return scrubbed;
            }
        }
        return null;
    }

    /**
     * Return the parameter's value if matched by the provided regex pattern. If
     * the parameter is not specified or if it does not match the provided
     * regex, null is returned.
     *
     * @param name
     *            name of the parameter to retrieve
     * @param p
     *            pattern that must match a valid parameter
     * @return the parameter if it specified and valid, null otherwise
     */
    private String getRegexParameter(String name, Pattern p) throws InvalidRequiredParameterException {
        String s = getParameter(name);
        if (s != null) {
            if (p.matcher(s).matches()) {
                return s;
            }
            String scrubbed = XSSScrubber.scrubbedStr(s);
            logger.error(
                    "Param \"" + name + "\" value \"" + scrubbed + "\" doesn't match regex filter " + p.toString());
            if (strictChecking) {
                throw new IllegalArgumentException(name + " was malformed according to regular expression");
            } else {
                return scrubbed;
            }
        }
        throw new InvalidRequiredParameterException(name + " is a required parameter but was not specified");
    }

    /**
     * Get the string value of the given parameter, which has been passed
     * through a regular-expression filter or, if no filter was defined for that
     * parameter, has had its angle brackets escaped. Throws
     * InvalidRequiredParameterException if the parameter is not defined.
     *
     * @param name
     *            name of parameter to get
     * @return the parameter
     * @throws InvalidRequiredParameterException
     */
    public String getCheckedParameter(String name) throws InvalidRequiredParameterException {
        Pattern p = MarmosetPatterns.getPattern(name);
        if (p != null) {
            return getRegexParameter(name, p);
        } else {
            return getScrubbedParameter(name);
        }
    }

    /**
     * Get the string value of the given parameter, which has been passed
     * through a regular-expression filter or, if no filter was defined for that
     * parameter, has had its angle brackets escaped. Returns null if the
     * parameter is not defined or is malformed according to the regular
     * expression.
     *
     * @param name
     *            name of parameter to get
     * @return the filtered or scrubbed parameter, or null if it was undefined
     *         or malformed
     */
    public String getOptionalCheckedParameter(String name) {
        Pattern p = MarmosetPatterns.getPattern(name);
        if (p != null) {
            return getOptionalRegexParameter(name, p);
        } else {
            return getOptionalScrubbedParameter(name);
        }
    }

    /**
     * Get the (String) value of the given parameter, scrubbed so that angle
     * brackets are escaped to avoid an HTML script injection. Throw an
     * exception if parameter isn't specified.
     *
     * @return the value of the given parameter with angle brackets escaped
     * @throws InvalidRequiredParameterException
     *             if parameter is not specified
     */
    private String getScrubbedParameter(String name) throws InvalidRequiredParameterException {
        String param = (String) parameters.get(name);
        if (param == null || param.equals("")) {
            throw new InvalidRequiredParameterException(name + " is a required parameter and it was " + param);
        }
        return XSSScrubber.scrubbedStr(param);
    }

    /**
     * Get the (String) value of the given parameter, scrubbed so that angle
     * brackets are escaped to avoid an HTML script injection. Return null if
     * parameter isn't specified.
     *
     * @return the value of the given parameter with angle brackets escaped, or
     *         null if parameter isn't specified
     */
    private String getOptionalScrubbedParameter(String name) {
        String param = (String) parameters.get(name);
        if (param == null)
            return null;
        param = param.trim();
        if (param.equals("")) {
            return null;
        }
        return XSSScrubber.scrubbedStr(param);
    }

    public boolean getOptionalBooleanParameter(String name) {
        String param = (String) parameters.get(name);
        if (param == null)
            return false;
        return MarmosetUtilities.isTrue(param);
    }

    /**
     * @return Returns the fileItem.
     */
    public Collection<FileItem> getFileItems() {
        return fileItems;
    }

    public FileItem getFileItem() {
        if (fileItems.size() != 1)
            throw new IllegalStateException("Have " + fileItems.size() + " file uploads");
        return fileItems.element();

    }

    /**
     * @param fileItem
     *            The fileItem to set.
     */
    public void addFileItem(FileItem fileItem) {
        this.fileItems.add(fileItem);
    }

    /**
     * Finds the value mapped to by the given key. Can return null or the empty
     * string.
     *
     * @param key
     *            the key
     * @return the value mapped to by the given key. Will return null if the key
     *         is unmapped.
     */
    public String getParameter(String key) {
        return (String) parameters.get(key);
    }

    public String getParameter(String key, String defaultValue) {
        if (parameters.containsKey(key))
            return (String) parameters.get(key);
        return defaultValue;
    }

    /**
     * Returns the value mapped to by the given key as a boolean. boolean true
     * is represented by 'yes' or 'true' (case-insensitively) while false is
     * anything else. The value string cannot be null or empty.
     *
     * @param key
     *            the key
     * @return true if the key maps to a true value (where true is 'yes' or
     *         'true' case-insensitively); false otherwise
     */
    public boolean getBooleanParameter(String key) throws InvalidRequiredParameterException {
        String value = getStringParameter(key);
        value = value.toUpperCase();
        if (value.equals("YES") || value.equals("TRUE"))
            return true;
        return false;
    }

    /**
     * @param string
     *            name of the parameter
     * @return
     */
    public int getIntParameter(String key) throws InvalidRequiredParameterException {
        try {
            String value = getStringParameter(key);
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            throw new InvalidRequiredParameterException(e.getMessage());
        }
    }

    /**
     * @param string
     *            name of the parameter
     * @return
     */
    public int getIntParameter(String key, int def) {
        if (!parameters.containsKey(key)) {
            return def;
        }
        try {
            String value = (String) parameters.get(key);
            return Integer.parseInt(value);
        } catch (NumberFormatException e) {
            return def;
        }
    }

    /**
     * Return the value of the parameter parsed as an Integer, or return the
     * given default value if the parameter isn't specified or cannot be parsed.
     *
     * @param name
     *            name of parameter to get
     * @param def
     *            default to return if parameter is either unspecified or
     *            doesn't parse
     * @return Integer value of the parameter when it's specified and parseable,
     *         or the default 'def' if the parameter is unspecified or
     *         unparseable
     */
    public Integer getIntegerParameter(String name, Integer def) {
        String param = (String) parameters.get(name);
        if (param == null || param.equals("")) {
            return def;
        }
        try {
            return MarmosetUtilities.toIntegerOrNull(param);
        } catch (NumberFormatException e) {
            return def;
        }
    }

    /**
     * @param string
     * @return
     */
    public long getLongParameter(String key) throws InvalidRequiredParameterException {
        try {
            String value = getStringParameter(key);
            return Long.parseLong(value);
        } catch (NumberFormatException e) {
            throw new InvalidRequiredParameterException(e.getMessage());
        }
    }

    public double getDoubleParameter(String name) throws InvalidRequiredParameterException {
        String param = getStringParameter(name);
        if (param == null || param.equals("")) {
            throw new InvalidRequiredParameterException(name + " is a required parameter");
        }
        double d;
        try {
            d = Double.parseDouble(param);
            return d;
        } catch (IllegalArgumentException e) {
            throw new InvalidRequiredParameterException("name was of an invalid form: " + e.toString());
        }
    }

    public boolean hasKey(String key) {
        return getOptionalStringParameter(key) != null;
    }

    @Override
    public String toString() {
        return "parameters: " + parameters + "\nfileitem: " + fileItems;
    }

    public Timestamp getTimestampParameter(String name) throws InvalidRequiredParameterException {
        String param = getStringParameter(name);
        if (param == null || param.equals("")) {
            throw new InvalidRequiredParameterException(name + " is a required parameter");
        }
        Timestamp timestamp = null;
        try {
            timestamp = Timestamp.valueOf(param);
        } catch (IllegalArgumentException e) {
            throw new InvalidRequiredParameterException("name was of an invalid form: " + e.toString());
        }
        return timestamp;
    }

    public Set<String> getParameterNames() {
        return parameters.keySet();
    }
}