package org.apache.jetspeed.services.upload;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.turbine.util.ParameterParser;
import org.apache.turbine.util.TurbineException;
import org.apache.turbine.util.upload.FileItem;
import org.apache.turbine.services.upload.TurbineUploadService;
import org.apache.turbine.services.upload.TurbineUpload;
import org.apache.commons.fileupload.MultipartStream;
import org.apache.jetspeed.om.registry.MediaTypeEntry;
import org.apache.jetspeed.services.Registry;
import org.apache.jetspeed.capability.CapabilityMap;
import org.apache.jetspeed.capability.CapabilityMapFactory;
import org.apache.jetspeed.services.resources.JetspeedResources;
/**
* <p> This class is an implementation of {@link
* org.apache.turbine.services.upload.UploadService}.
*
* <p> Files will be stored in temporary disk storage on in memory,
* depending on request size, and will be available from the {@link
* org.apache.turbine.util.ParameterParser} as {@link
* org.apache.turbine.util.upload.FileItem}s.
*
* <p>This implementation of {@link
* org.apache.turbine.services.upload.UploadService} handles multiple
* files per single html widget, sent using multipar/mixed encoding
* type, as specified by RFC 1867. Use {@link
* org.apache.turbine.util.ParameterParser#getFileItems(String)} to
* acquire an array of {@link
* org.apache.turbine.util.upload.FileItem}s associated with given
* html widget.
*
* @author <a href="mailto:shinsuke@yahoo.co.jp">Shinsuke SUGAYA</a>
*/
public class JetspeedUploadService
extends TurbineUploadService
{
/**
* <p> Processes an <a href="http://rf.cx/rfc1867.html">RFC
* 1867</a> compliant <code>multipart/form-data</code> stream.
*
* @param req The servlet request to be parsed.
* @param params The ParameterParser instance to insert form
* fields into.
* @param path The location where the files should be stored.
* @exception TurbineException If there are problems reading/parsing
* the request or storing files.
*/
public void parseRequest( HttpServletRequest req,
ParameterParser params,
String path )
throws TurbineException
{
String contentType = req.getHeader(CONTENT_TYPE);
if(!contentType.startsWith(MULTIPART_FORM_DATA))
{
throw new TurbineException("the request doesn't contain a " +
MULTIPART_FORM_DATA + " stream");
}
int requestSize = req.getContentLength();
if(requestSize == -1)
{
throw new TurbineException("the request was rejected because " +
"it's size is unknown");
}
if(requestSize > TurbineUpload.getSizeMax())
{
throw new TurbineException("the request was rejected because " +
"it's size exceeds allowed range");
}
// get encoding info
String encoding = JetspeedResources.getString(JetspeedResources.CONTENT_ENCODING_KEY,"US-ASCII");
CapabilityMap cm = CapabilityMapFactory.getCapabilityMap(
req.getHeader("User-Agent") );
String mimeCode = cm.getPreferredType().getCode();
if ( mimeCode != null )
{
MediaTypeEntry media = (MediaTypeEntry)Registry.getEntry(Registry.MEDIA_TYPE, mimeCode);
if ( media != null && media.getCharacterSet() != null)
{
encoding = media.getCharacterSet();
}
}
try
{
byte[] boundary = contentType.substring(
contentType.indexOf("boundary=")+9).getBytes();
InputStream input = (InputStream)req.getInputStream();
MultipartStream multi = new MultipartStream(input, boundary);
multi.setHeaderEncoding(encoding);
boolean nextPart = multi.skipPreamble();
while(nextPart)
{
Map headers = parseHeaders(multi.readHeaders());
String fieldName = getFieldName(headers);
if (fieldName != null)
{
String subContentType = getHeader(headers, CONTENT_TYPE);
if (subContentType != null && subContentType
.startsWith(MULTIPART_MIXED))
{
// Multiple files.
byte[] subBoundary =
subContentType.substring(
subContentType
.indexOf("boundary=")+9).getBytes();
multi.setBoundary(subBoundary);
boolean nextSubPart = multi.skipPreamble();
while (nextSubPart)
{
headers = parseHeaders(multi.readHeaders());
if (getFileName(headers) != null)
{
FileItem item = createItem(path, headers,
requestSize);
OutputStream os = item.getOutputStream();
try
{
multi.readBodyData(os);
}
finally
{
os.close();
}
params.append(getFieldName(headers), item);
}
else
{
// Ignore anything but files inside
// multipart/mixed.
multi.discardBodyData();
}
nextSubPart = multi.readBoundary();
}
multi.setBoundary(boundary);
}
else
{
if (getFileName(headers) != null)
{
// A single file.
FileItem item = createItem(path, headers,
requestSize);
OutputStream os = item.getOutputStream();
try
{
multi.readBodyData(os);
}
finally
{
os.close();
}
params.append(getFieldName(headers), item);
}
else
{
// A form field.
FileItem item = createItem(path, headers,
requestSize);
OutputStream os = item.getOutputStream();
try
{
multi.readBodyData(os);
}
finally
{
os.close();
}
params.append(getFieldName(headers),
new String(item.get()));
}
}
}
else
{
// Skip this part.
multi.discardBodyData();
}
nextPart = multi.readBoundary();
}
}
catch(IOException e)
{
throw new TurbineException("Processing of " + MULTIPART_FORM_DATA
+ " request failed", e);
}
}
}