dims 02/02/27 12:21:23 Modified: src/webapp/WEB-INF web.xml Added: src/java/org/apache/cocoon/components/request MultipartRequestFactoryImpl.java src/java/org/apache/cocoon/components/request/multipart FilePart.java FilePartArray.java FilePartFile.java MultipartException.java MultipartParser.java MultipartRequestWrapper.java TokenStream.java Log: "Replacement for maybeupload" from "Jeroen ter Voorde" <[EMAIL PROTECTED]> Revision Changes Path 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/MultipartRequestFactoryImpl.java Index: MultipartRequestFactoryImpl.java =================================================================== /* * * ============================================================================ * The Apache Software License, Version 1.1 * ============================================================================ * * Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. * * Redistribution and use in source and binary forms, with or without modifica- * tion, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * 3. The end-user documentation included with the redistribution, if any, must * include the following acknowledgment: "This product includes software * developed by the Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, if * and wherever such third-party acknowledgments normally appear. * * 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be * used to endorse or promote products derived from this software without * prior written permission. For written permission, please contact * [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", nor may * "Apache" appear in their name, without prior written permission of the * Apache Software Foundation. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * This software consists of voluntary contributions made by many individuals * on behalf of the Apache Software Foundation and was originally created by * Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache * Software Foundation, please see <http://www.apache.org/>. * */ package org.apache.cocoon.components.request; import org.apache.cocoon.components.request.multipart.MultipartRequestWrapper; import javax.servlet.http.HttpServletRequest; import java.io.File; import java.util.Vector; /** * * Extends the {@link RequestFactory} class * * @author <a href="mailto:[EMAIL PROTECTED]">Davanum Srinivas</a> * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: MultipartRequestFactoryImpl.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ public final class MultipartRequestFactoryImpl extends RequestFactory { /** * Return a wrapped request object * * @param request * @param saveUploadedFilesToDisk * @param uploadDirectory * @param allowOverwrite * @param silentlyRename * @param maxUploadSize * * @return */ public HttpServletRequest getServletRequest(HttpServletRequest request, boolean saveUploadedFilesToDisk, File uploadDirectory, boolean allowOverwrite, boolean silentlyRename, int maxUploadSize) { HttpServletRequest req = request; String contentType = req.getContentType(); if (contentType == null) { contentType = "application/x-www-form-urlencoded"; } if (contentType.startsWith("multipart/form-data")) { try { req = new MultipartRequestWrapper(request, saveUploadedFilesToDisk, uploadDirectory, allowOverwrite, silentlyRename, maxUploadSize); } catch (Exception e) { req = request; } } return req; } /** * Implementation of the get method * * @param request * @param name * * @return */ public Object get(HttpServletRequest request, String name) { // FIXME We should get rid of this instanceof test if (request instanceof MultipartRequestWrapper) { return ((MultipartRequestWrapper) request).get(name); } else { String[] values = request.getParameterValues(name); if (values == null) { return null; } if (values.length == 1) { return values[0]; } if (values.length > 1) { Vector vect = new Vector(values.length); for (int i = 0; i < values.length; i++) { vect.add(values[i]); } return vect; } } return null; } } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/multipart/FilePart.java Index: FilePart.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.request.multipart; import java.io.InputStream; import java.util.Map; /** * This (abstract) class represents a file part parsed from a http post stream. * It is subclassed by FilePartFile (which is a file allready written to disk) and * FilePartArray (which is a file in memory) * * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: FilePart.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ public abstract class FilePart { /** Field headers */ private Map headers; /** * Returns the part headers * * @return */ public Map getHeaders() { return headers; } /** * Returns the filename * * @return */ public abstract String getFileName(); /** * Returns the filepath * * @return */ public String getFilePath() { return (String) headers.get("filename"); } /** * Returns the mime type (or null if unknown) * * @return */ public String getMimeType() { return (String) headers.get("content-type"); } /** * Returns an InputStream containing the file data * * @return * * @throws Exception */ public abstract InputStream getInputStream() throws Exception; } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/multipart/FilePartArray.java Index: FilePartArray.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.request.multipart; import java.io.File; import java.io.InputStream; import java.util.Map; /** * This class represents a file part parsed from a http post stream. * * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: FilePartArray.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ public class FilePartArray extends FilePart { /** Field in */ private InputStream in = null; /** Field headers */ private Map headers; /** * Constructor FilePartArray * * @param headers * @param in */ protected FilePartArray(Map headers, InputStream in) { this.headers = headers; this.in = in; } /** * Returns the filename * * @return */ public String getFileName() { File f = new File((String) headers.get("filename")); return f.getName(); } /** * Returns a (ByteArray)InputStream containing the file data * * @return * * @throws Exception */ public InputStream getInputStream() throws Exception { return in; } } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/multipart/FilePartFile.java Index: FilePartFile.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.request.multipart; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.util.Map; /** * This class represents a file part parsed from a http post stream. * * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: FilePartFile.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ public class FilePartFile extends FilePart { /** Field file */ private File file = null; /** Field headers */ private Map headers; /** * Constructor FilePartFile * * @param headers * @param file */ protected FilePartFile(Map headers, File file) { this.headers = headers; this.file = file; } /** * Returns the filename * * @return */ public String getFileName() { return file.getName(); } /** * Returns the file * * @return */ public File getFile() { return file; } /** * Returns a (ByteArray)InputStream containing the file data * * @return * * @throws Exception */ public InputStream getInputStream() throws Exception { return new FileInputStream(file); } } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/multipart/MultipartException.java Index: MultipartException.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.request.multipart; /** * Exception thrown when on a parse error such as * a malformed stream. * * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: MultipartException.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ public class MultipartException extends Exception { /** * Constructor MultipartException */ public MultipartException() { super(); } /** * Constructor MultipartException * * @param text */ public MultipartException(String text) { super(text); } } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/multipart/MultipartParser.java Index: MultipartParser.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.request.multipart; import javax.servlet.http.HttpServletRequest; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PushbackInputStream; import java.util.Hashtable; import java.util.StringTokenizer; import java.util.Vector; /** * This class is used to implement a multipart request wrapper. * It will parse the http post stream and and fill it's hashtable with values. * * The hashtable will contain: * Vector: inline part values * FilePart: file part * * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: MultipartParser.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ public class MultipartParser extends Hashtable { /** Field FILE_BUFFER_SIZE */ private final static int FILE_BUFFER_SIZE = 4096; /** Field INLINE_BUFFER_SIZE */ private final static int INLINE_BUFFER_SIZE = 256; /** Field MAX_BOUNDARY_SIZE */ private static final int MAX_BOUNDARY_SIZE = 128; /** Field saveUploadedFilesToDisk */ private boolean saveUploadedFilesToDisk; /** Field uploadDirectory */ private File uploadDirectory = null; /** Field allowOverwrite */ private boolean allowOverwrite; /** Field silentlyRename */ private boolean silentlyRename; /** Field maxUploadSize */ private int maxUploadSize; /** * Constructor, parses given request * * @param request The servlet request. * @param saveUploadFilesToDisk Write fileparts to the uploadDirectory. If true the corresponding object * in the hashtable will contain a FilePartFile, if false a FilePartArray * @param File uploadDirectory The directory to write to if saveUploadedFilesToDisk is true. * @param saveUploadedFilesToDisk * @param uploadDirectory * @param allowOverwrite Allow existing files to be overwritten. * @param silentlyRename If file exists rename file (using filename+number). * @param maxUploadSize The maximum content length accepted. * * @throws IOException * @throws MultipartException */ public MultipartParser( HttpServletRequest request, boolean saveUploadedFilesToDisk, File uploadDirectory, boolean allowOverwrite, boolean silentlyRename, int maxUploadSize) throws IOException, MultipartException { this.saveUploadedFilesToDisk = saveUploadedFilesToDisk; this.uploadDirectory = uploadDirectory; this.allowOverwrite = allowOverwrite; this.silentlyRename = silentlyRename; this.maxUploadSize = maxUploadSize; if (request.getContentLength() > maxUploadSize) { throw new IOException("Content length exceeds maximum upload size"); } parseMultiPart( new TokenStream( new PushbackInputStream( new BufferedInputStream(request.getInputStream()), MAX_BOUNDARY_SIZE)), getBoundary(request.getContentType())); } /** * Parse a multipart block * * @param ts * @param boundary * * @throws IOException * @throws MultipartException */ private void parseMultiPart(TokenStream ts, String boundary) throws IOException, MultipartException { ts.setBoundary(boundary.getBytes()); ts.read(); // read first boundary away ts.setBoundary(("\r\n" + boundary).getBytes()); while (ts.getState() == TokenStream.STATE_NEXTPART) { ts.nextPart(); parsePart(ts); } if (ts.getState() != TokenStream.STATE_ENDMULTIPART) { // sanity check throw new MultipartException("Malformed stream"); } } /** * Parse a single part * * @param ts * * @throws IOException * @throws MultipartException */ private void parsePart(TokenStream ts) throws IOException, MultipartException { Hashtable headers = new Hashtable(); headers = readHeaders(ts); try { if (headers.containsKey("filename")) { parseFilePart(ts, headers); } else if (((String) headers.get("content-disposition")) .toLowerCase().equals("form-data")) { parseInlinePart(ts, headers); } // FIXME: multipart/mixed parts are untested. else if (((String) headers.get("content-disposition")).toLowerCase() .indexOf("multipart") > -1) { parseMultiPart(new TokenStream(ts, MAX_BOUNDARY_SIZE), "--" + (String) headers.get("boundary")); ts.read(); // read past boundary } else { throw new MultipartException("Unknown part type"); } } catch (IOException e) { throw new MultipartException("Malformed stream: " + e.getMessage()); } catch (NullPointerException e) { throw new MultipartException("Malformed header"); } } /** * Parse a file part * * @param in * @param headers * * @throws IOException * @throws MultipartException */ private void parseFilePart(TokenStream in, Hashtable headers) throws IOException, MultipartException { byte[] buf = new byte[FILE_BUFFER_SIZE]; OutputStream out = null; File file = null; if (!saveUploadedFilesToDisk) { out = new ByteArrayOutputStream(); } else { String filePath = uploadDirectory.getPath() + File.separator; String fileName = new File((String) headers.get("filename")).getName(); file = new File(filePath + fileName); if (file.exists()) { if (!allowOverwrite) { if (silentlyRename) { int c = 0; do { file = new File(filePath + c++ + "_" + fileName); } while (file.exists()); } else { throw new MultipartException("Duplicate file " + file.getName() + "."); } } } out = new FileOutputStream(file); } int read = 0; while (in.getState() == TokenStream.STATE_READING) { // read data read = in.read(buf); out.write(buf, 0, read); } out.close(); if (file == null) { byte[] bytes = ((ByteArrayOutputStream) out).toByteArray(); put(headers.get("name"), new FilePartArray(headers, new ByteArrayInputStream(bytes))); } else { put(headers.get("name"), new FilePartFile(headers, file)); } } /** * Parse an inline part * * @param in * @param headers * * @throws IOException */ private void parseInlinePart(TokenStream in, Hashtable headers) throws IOException { byte[] buf = new byte[INLINE_BUFFER_SIZE]; ByteArrayOutputStream out = new ByteArrayOutputStream(); StringBuffer value = new StringBuffer(); while (in.getState() == TokenStream.STATE_READING) { int read = in.read(buf); value.append(new String(buf, 0, read)); } String field = (String) headers.get("name"); Vector v = (Vector) get(field); if (v == null) { v = new Vector(); put(field, v); } v.add(value.toString()); } /** * Read part headers * * @param in * * @return * * @throws IOException */ private Hashtable readHeaders(TokenStream in) throws IOException { Hashtable headers = new Hashtable(); String hdrline = readln(in); while (!"".equals(hdrline)) { StringTokenizer tokenizer = new StringTokenizer(hdrline); headers.put(tokenizer.nextToken(" :").toLowerCase(), tokenizer.nextToken(" :;")); while (tokenizer.hasMoreTokens()) { headers.put(tokenizer.nextToken(" ;=\""), tokenizer.nextToken("=\"")); } hdrline = readln(in); } return headers; } /** * Get boundary from contentheader * * @param hdr * * @return */ private String getBoundary(String hdr) { int start = hdr.toLowerCase().indexOf("boundary="); if (start > -1) { return "--" + hdr.substring(start + 9); } else { return null; } } /** * Read string until newline or end of stream * * @param in * * @return * * @throws IOException */ private String readln(TokenStream in) throws IOException { StringBuffer out = new StringBuffer(); int b = in.read(); while ((b != -1) && (b != '\r')) { out.append((char) b); b = in.read(); } if (b == '\r') { in.read(); // read '\n' } return out.toString(); } } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/multipart/MultipartRequestWrapper.java Index: MultipartRequestWrapper.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.request.multipart; import javax.servlet.RequestDispatcher; import javax.servlet.ServletInputStream; import javax.servlet.ServletRequest; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.security.Principal; import java.util.Enumeration; import java.util.Locale; import java.util.Map; import java.util.Vector; /** * Servlet request wrapper for multipart parser. * * @author Jeroen ter Voorde * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: MultipartRequestWrapper.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ public class MultipartRequestWrapper implements ServletRequest, HttpServletRequest { /** Field CONTENTHEADER */ private final String CONTENTHEADER = "multipart/form-data"; /** Field request */ private HttpServletRequest request = null; /** Field values */ private MultipartParser values = null; /** * Constructor MultipartRequestWrapper * * @param request * @param saveUploadedFilesToDisk * @param uploadDirectory * @param allowOverwrite * @param silentlyRename * @param maxUploadSize * * @throws IOException * @throws MultipartException */ public MultipartRequestWrapper( HttpServletRequest request, boolean saveUploadedFilesToDisk, File uploadDirectory, boolean allowOverwrite, boolean silentlyRename, int maxUploadSize) throws IOException, MultipartException { this.request = request; String contentType = request.getContentType(); if ((contentType != null) && (contentType.toLowerCase().indexOf(CONTENTHEADER) > -1)) { values = new MultipartParser(request, saveUploadedFilesToDisk, uploadDirectory, allowOverwrite, silentlyRename, maxUploadSize); } } /** * Method get * * @param name * * @return */ public Object get(String name) { Object result = null; if (values != null) { result = values.get(name); if (result instanceof Vector) { if (((Vector) result).size() == 1) { return ((Vector) result).elementAt(0); } else { return result; } } } else { String[] array = request.getParameterValues(name); Vector vec = new Vector(); if (array != null) { for (int i = 0; i < array.length; i++) { vec.addElement(array[i]); } if (vec.size() == 1) { result = vec.elementAt(0); } else { result = vec; } } } return result; } /** * Method getParameterNames * * @return */ public Enumeration getParameterNames() { if (values != null) { return values.keys(); } else { return request.getParameterNames(); } } /** * Method getParameter * * @param name * * @return */ public String getParameter(String name) { Object value = get(name); String result = null; if (value != null) { if (value instanceof Vector) { value = ((Vector) value).elementAt(0); } result = value.toString(); } return result; } /** * Method getParameterValues * * @param name * * @return */ public String[] getParameterValues(String name) { if (values != null) { Object value = get(name); if (value != null) { if (value instanceof Vector) { return (String[]) ((Vector) value).toArray(); } else { return new String[]{value.toString()}; } } return null; } else { return request.getParameterValues(name); } } /** * Method getRequest * * @return */ public HttpServletRequest getRequest() { return request; } /** * Method getAttribute * * @param name * * @return */ public Object getAttribute(String name) { return request.getAttribute(name); } /** * Method getAttributeNames * * @return */ public Enumeration getAttributeNames() { return request.getAttributeNames(); } /** * Method getCharacterEncoding * * @return */ public String getCharacterEncoding() { return request.getCharacterEncoding(); } /** * Method getContentLength * * @return */ public int getContentLength() { return request.getContentLength(); } /** * Method getContentType * * @return */ public String getContentType() { return request.getContentType(); } /** * Method getInputStream * * @return * * @throws IOException */ public ServletInputStream getInputStream() throws IOException { return request.getInputStream(); } /** * Method getProtocol * * @return */ public String getProtocol() { return request.getProtocol(); } /** * Method getScheme * * @return */ public String getScheme() { return request.getScheme(); } /** * Method getServerName * * @return */ public String getServerName() { return request.getServerName(); } /** * Method getServerPort * * @return */ public int getServerPort() { return request.getServerPort(); } /** * Method getReader * * @return * * @throws IOException */ public BufferedReader getReader() throws IOException { return request.getReader(); } /** * Method getRemoteAddr * * @return */ public String getRemoteAddr() { return request.getRemoteAddr(); } /** * Method getRemoteHost * * @return */ public String getRemoteHost() { return request.getRemoteHost(); } /** * Method setAttribute * * @param name * @param o */ public void setAttribute(String name, Object o) { request.setAttribute(name, o); } /** * Method removeAttribute * * @param name */ public void removeAttribute(String name) { request.removeAttribute(name); } /** * Method getLocale * * @return */ public Locale getLocale() { return request.getLocale(); } /** * Method getLocales * * @return */ public Enumeration getLocales() { return request.getLocales(); } /** * Method isSecure * * @return */ public boolean isSecure() { return request.isSecure(); } /** * Method getRequestDispatcher * * @param path * * @return */ public RequestDispatcher getRequestDispatcher(String path) { return request.getRequestDispatcher(path); } /** * Method getRealPath * * @param path * * @return */ public String getRealPath(String path) { return request.getRealPath(path); } /** * Method getAuthType * * @return */ public String getAuthType() { return request.getAuthType(); } /** * Method getCookies * * @return */ public Cookie[] getCookies() { return request.getCookies(); } /** * Method getDateHeader * * @param name * * @return */ public long getDateHeader(String name) { return request.getDateHeader(name); } /** * Method getHeader * * @param name * * @return */ public String getHeader(String name) { return request.getHeader(name); } /** * Method getHeaders * * @param name * * @return */ public Enumeration getHeaders(String name) { return request.getHeaders(name); } /** * Method getHeaderNames * * @return */ public Enumeration getHeaderNames() { return request.getHeaderNames(); } /** * Method getIntHeader * * @param name * * @return */ public int getIntHeader(String name) { return request.getIntHeader(name); } /** * Method getMethod * * @return */ public String getMethod() { return request.getMethod(); } /** * Method getPathInfo * * @return */ public String getPathInfo() { return request.getPathInfo(); } /** * Method getPathTranslated * * @return */ public String getPathTranslated() { return request.getPathTranslated(); } /** * Method getContextPath * * @return */ public String getContextPath() { return request.getContextPath(); } /** * Method getQueryString * * @return */ public String getQueryString() { return request.getQueryString(); } /** * Method getRemoteUser * * @return */ public String getRemoteUser() { return request.getRemoteUser(); } /** * Method isUserInRole * * @param role * * @return */ public boolean isUserInRole(String role) { return request.isUserInRole(role); } /** * Method getUserPrincipal * * @return */ public Principal getUserPrincipal() { return request.getUserPrincipal(); } /** * Method getRequestedSessionId * * @return */ public String getRequestedSessionId() { return request.getRequestedSessionId(); } /** * Method getRequestURI * * @return */ public String getRequestURI() { return request.getRequestURI(); } /** * Method getServletPath * * @return */ public String getServletPath() { return request.getServletPath(); } /** * Method getSession * * @param create * * @return */ public HttpSession getSession(boolean create) { return request.getSession(create); } /** * Method getSession * * @return */ public HttpSession getSession() { return request.getSession(); } /** * Method isRequestedSessionIdValid * * @return */ public boolean isRequestedSessionIdValid() { return request.isRequestedSessionIdValid(); } /** * Method isRequestedSessionIdFromCookie * * @return */ public boolean isRequestedSessionIdFromCookie() { return request.isRequestedSessionIdFromCookie(); } /** * Method isRequestedSessionIdFromURL * * @return */ public boolean isRequestedSessionIdFromURL() { return request.isRequestedSessionIdFromURL(); } /** * Method isRequestedSessionIdFromUrl * * @return */ public boolean isRequestedSessionIdFromUrl() { return request.isRequestedSessionIdFromURL(); } /** * Method getParameterMap * * @return */ public Map getParameterMap() { // FIXME: return null; } /** * Method setCharacterEncoding * * @param s */ public void setCharacterEncoding(String s) { // FIXME: } /** * Method getRequestURL * * @return */ public StringBuffer getRequestURL() { // FIXME: return null; } } 1.1 xml-cocoon2/src/java/org/apache/cocoon/components/request/multipart/TokenStream.java Index: TokenStream.java =================================================================== /* ============================================================================ The Apache Software License, Version 1.1 ============================================================================ Copyright (C) 1999-2002 The Apache Software Foundation. All rights reserved. Redistribution and use in source and binary forms, with or without modifica- tion, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. The end-user documentation included with the redistribution, if any, must include the following acknowledgment: "This product includes software developed by the Apache Software Foundation (http://www.apache.org/)." Alternately, this acknowledgment may appear in the software itself, if and wherever such third-party acknowledgments normally appear. 4. The names "Apache Cocoon" and "Apache Software Foundation" must not be used to endorse or promote products derived from this software without prior written permission. For written permission, please contact [EMAIL PROTECTED] 5. Products derived from this software may not be called "Apache", nor may "Apache" appear in their name, without prior written permission of the Apache Software Foundation. THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU- DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. This software consists of voluntary contributions made by many individuals on behalf of the Apache Software Foundation and was originally created by Stefano Mazzocchi <[EMAIL PROTECTED]>. For more information on the Apache Software Foundation, please see <http://www.apache.org/>. */ package org.apache.cocoon.components.request.multipart; import java.io.IOException; import java.io.PushbackInputStream; /** * Utility class for MultipartParser. Divides the inputstream into parts * separated by a given boundary. * * A newline is espected after each boundary and is parsed away. * @author <a href="mailto:[EMAIL PROTECTED]">Jeroen ter Voorde</a> * @version CVS $Id: TokenStream.java,v 1.1 2002/02/27 20:21:22 dims Exp $ */ class TokenStream extends PushbackInputStream { /** * Initial state, no boundary has been set. */ public static final int STATE_NOBOUNDARY = -1; /** * Fully read a part, now at the beginning of a new part */ public static final int STATE_NEXTPART = -2; /** * Read last boundary, end of multipart block */ public static final int STATE_ENDMULTIPART = -3; /** * End of stream, this should not happen */ public static final int STATE_ENDOFSTREAM = -4; /** * Currently reading a part */ public static final int STATE_READING = -5; /** Field in */ private PushbackInputStream in = null; /** Field boundary */ private byte[] boundary = null; /** Field state */ private int state = STATE_NOBOUNDARY; /** * Creates a new pushback token stream from in. * * @param in The input stream * @param pushbackSize Size (in bytes) of the pushback buffer */ public TokenStream(PushbackInputStream in, int pushbackSize) { super(in, pushbackSize); this.in = in; } /** * Creates a new pushback token stream from in with pushback buffer size 1. * * @param in The input stream */ public TokenStream(PushbackInputStream in) { this(in, 1); } /** * Sets the boundary to scan for * * @param boundary A byte array containg the boundary * * @throws MultipartException */ public void setBoundary(byte[] boundary) throws MultipartException { this.boundary = boundary; if (state == STATE_NOBOUNDARY) { state = STATE_READING; } } /** * Start reading the next part in the stream. This method may only be called * if state is STATE_NEXTPART. It will throw a MultipartException if not. * * @throws MultipartException */ public void nextPart() throws MultipartException { if (state != STATE_NEXTPART) { throw new MultipartException("Illegal state"); } state = STATE_READING; } /** * Return the stream state * * @return */ public int getState() { return state; } /** * Fill the ouput buffer until either it's full, the boundary has been reached or * the end of the inputstream has been reached. * When a boundary is reached it is entirely read away including trailing \r's and \n's. * It will not be written to the output buffer. * The stream state is updated after each call. * * @param out The output buffer * * @return * * @throws IOException */ private int readToBoundary(byte[] out) throws IOException { if (state != STATE_READING) { return 0; } int boundaryIndex = 0; int read = 0; int written = 0; int b = in.read(); while (true) { while ((byte) b != boundary[0]) { if (b == -1) { state = STATE_ENDOFSTREAM; return written; } out[written++] = (byte) b; if (written == out.length) { return written; } b = in.read(); } boundaryIndex = 0; // we know the first byte matched // check for boundary while ((boundaryIndex < boundary.length) && ((byte) b == boundary[boundaryIndex])) { b = in.read(); boundaryIndex++; } if (boundaryIndex == boundary.length) { // matched boundary if (b != -1) { if (b == '\r') { // newline, another part follows state = STATE_NEXTPART; in.read(); } else if (b == '-') { // hyphen, end of multipart state = STATE_ENDMULTIPART; in.read(); // read next hyphen in.read(); // read \r in.read(); // read \n } else { // something else, error throw new IOException( "Unexpected character after boundary"); } } else { // nothing after boundary, this shouldn't happen either state = STATE_ENDOFSTREAM; } return written; } else { // did not match boundary // bytes skipped, write first skipped byte, push back the rest if (b != -1) { // b may be -1 in.unread(b); // the non-matching byte } in.unread(boundary, 1, boundaryIndex - 1); // unread skipped boundary data out[written++] = boundary[0]; if (written == out.length) { return written; } } b = in.read(); } } /** * @see java.io.InputStream#read(byte[]) * * @param out * * @return * * @throws IOException */ public int read(byte[] out) throws IOException { if (state != STATE_READING) { return 0; } return readToBoundary(out); } /** * @see java.io.InputStream#read(byte[],int,int) * * @param out * @param off * @param len * * @return * * @throws IOException */ public int read(byte[] out, int off, int len) throws IOException { if ((off < 0) || (off >= out.length)) { throw new IOException("Buffer offset outside buffer"); } if (off + len >= out.length) { throw new IOException("Buffer end outside buffer"); } if (len < 0) { throw new IOException("Length must be a positive integer"); } byte[] buf = new byte[len]; int read = read(buf); if (read > 0) { System.arraycopy(buf, 0, out, off, read); } return read; } /** * @see java.io.InputStream#read() * * @return * * @throws IOException */ public int read() throws IOException { byte[] buf = new byte[1]; int read = read(buf); if (read == 0) { return -1; } else { return (int) buf[0]; } } } 1.5 +4 -2 xml-cocoon2/src/webapp/WEB-INF/web.xml Index: web.xml =================================================================== RCS file: /home/cvs/xml-cocoon2/src/webapp/WEB-INF/web.xml,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- web.xml 24 Feb 2002 11:10:58 -0000 1.4 +++ web.xml 27 Feb 2002 20:21:23 -0000 1.5 @@ -194,11 +194,13 @@ --> <!-- - This parameter allows you to select the request factory. + This parameter allows you to select the request factory. Possible choices are as follows: + - org.apache.cocoon.components.request.MultipartRequestFactoryImpl + - org.apache.cocoon.components.request.MaybeUploadRequestFactoryImpl --> <init-param> <param-name>request-factory</param-name> - <param-value>org.apache.cocoon.components.request.MaybeUploadRequestFactoryImpl</param-value> + <param-value>org.apache.cocoon.components.request.MultipartRequestFactoryImpl</param-value> </init-param> <!--
---------------------------------------------------------------------- In case of troubles, e-mail: [EMAIL PROTECTED] To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]