/*
* MultiPartRequest.java
*
* This work is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License,
* or (at your option) any later version.
*
* This work is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA
*
* Copyright (c) 2004 Per Cederberg. All rights reserved.
*/
package org.liquidsite.core.web;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.fileupload.DiskFileUpload;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.liquidsite.util.log.Log;
/**
* An HTTP multi-part request and response.
*
* @author Per Cederberg, <per at percederberg dot net>
* @version 1.0
*/
public class MultiPartRequest extends Request {
/**
* The class logger.
*/
private static final Log LOG = new Log(MultiPartRequest.class);
/**
* The temporary upload directory.
*/
private String uploadDir = "";
/**
* The maximum upload size.
*/
private int uploadSize = 0;
/**
* The normal query or post parameters.
*/
private HashMap parameters = new HashMap();
/**
* The file parameters.
*/
private HashMap files = new HashMap();
/**
* Creates a new multi-part request.
*
* @param context the servlet context
* @param request the HTTP request
* @param response the HTTP response
* @param tempDir the temporary upload directory
* @param maxSize the maximum upload size (in bytes)
*
* @throws ServletException if the request couldn't be parsed
* correctly
*/
public MultiPartRequest(ServletContext context,
HttpServletRequest request,
HttpServletResponse response,
String tempDir,
int maxSize)
throws ServletException {
super(context, request, response);
this.uploadDir = tempDir;
this.uploadSize = maxSize;
try {
parse(request);
} catch (FileUploadException e) {
LOG.error(e.getMessage());
throw new ServletException(
"Couldn't handle multipart request: " + e.getMessage());
}
}
/**
* Parses the incoming multi-part HTTP request.
*
* @param request the HTTP request
*
* @throws FileUploadException if the request couldn't be parsed
* correctly
*/
private void parse(HttpServletRequest request)
throws FileUploadException {
DiskFileUpload parser = new DiskFileUpload();
List list;
FileItem item;
String value;
// Create multi-part parser
parser.setRepositoryPath(uploadDir);
parser.setSizeMax(uploadSize);
parser.setSizeThreshold(4096);
// Parse request
list = parser.parseRequest(request);
for (int i = 0; i < list.size(); i++) {
item = (FileItem) list.get(i);
if (item.isFormField()) {
try {
value = item.getString("UTF-8");
} catch (UnsupportedEncodingException ignore) {
value = item.getString();
}
parameters.put(item.getFieldName(), value);
} else {
files.put(item.getFieldName(), new MultiPartFile(item));
}
}
}
/**
* Returns a map with all the request parameter names and values.
*
* @return the map with request parameter names and values
*/
public Map getAllParameters() {
return parameters;
}
/**
* Returns the value of a request parameter. If the specified
* parameter does not exits, a default value will be returned.
*
* @param name the request parameter name
* @param defVal the default parameter value
*
* @return the request parameter value, or
* the default value if no such parameter was found
*/
public String getParameter(String name, String defVal) {
String value = (String) parameters.get(name);
return (value == null) ? defVal : value;
}
/**
* Returns the specified file request parameter.
*
* @param name the request parameter name
*
* @return the request file parameter, or
* null if no such file parameter was found
*/
public FileParameter getFileParameter(String name) {
return (FileParameter) files.get(name);
}
/**
* Disposes of all resources used by this request object. This
* method shouldn't be called until a response has been written.
*/
public void dispose() {
Iterator iter = files.values().iterator();
super.dispose();
while (iter.hasNext()) {
((MultiPartFile) iter.next()).dispose();
}
parameters.clear();
files.clear();
parameters = null;
files = null;
}
/**
* Returns the upload directory.
*
* @return the upload directory
*/
protected String getUploadDir() {
return uploadDir;
}
/**
* A request file parameter.
*
* @author Per Cederberg, <per at percederberg dot net>
* @version 1.0
*/
private class MultiPartFile implements FileParameter {
/**
* The file item.
*/
private FileItem item;
/**
* Creates a new request file parameter.
*
* @param item the file item
*/
MultiPartFile(FileItem item) {
this.item = item;
}
/**
* Returns the base file name including the extension. The
* file name returned is guaranteed to not contain any file
* path or directory name.
*
* @return the base file name (with extension)
*/
public String getName() {
String name = item.getName();
if (name.lastIndexOf("/") >= 0) {
name = name.substring(name.lastIndexOf("/") + 1);
}
if (name.lastIndexOf("\\") >= 0) {
name = name.substring(name.lastIndexOf("\\") + 1);
}
return name;
}
/**
* Returns the full file name including path and extension.
* The file name returned should be exactly the one sent by
* the browser.
*
* @return the full file path
*/
public String getPath() {
return item.getName();
}
/**
* Returns the file size.
*
* @return the file size
*/
public long getSize() {
return item.getSize();
}
/**
* Writes this file to a temporary file in the upload
* directory. After calling this method, only the dispose()
* method can be called.
*
* @return the file created
*
* @throws IOException if the file parameter couldn't be
* written
*/
public File write() throws IOException {
String name = getName();
File file;
file = new File(getUploadDir(), name);
for (int i = 1; file.exists(); i++) {
file = new File(getUploadDir(), i + "." + name);
}
write(file);
return file;
}
/**
* Writes this file to the specified destination file. After
* calling this method, only the dispose() method can be
* called.
*
* @param dest the destination file
*
* @throws IOException if the file parameter couldn't be
* written to the specified file
*/
public void write(File dest) throws IOException {
String error;
try {
item.write(dest);
} catch (Exception e) {
error = "couldn't move request file to " + dest +
": " + e.getMessage();
throw new IOException(error);
}
}
/**
* Disposes of all resources used by this object. This method
* shouldn't be called until the file parameter should no
* longer be used.
*/
void dispose() {
item.delete();
}
}
}