From 878b7ee06d4d3768ad5586a9170a3e319c3c226b Mon Sep 17 00:00:00 2001 From: hns Date: Fri, 29 Jul 2005 11:45:42 +0000 Subject: [PATCH] * Switch to Jakarta Commons FileUpload for handling file uploads. * Introduce uploadSoftfail setting in apps.properties that allows file upload errors to be cought by checking req.data.helma_upload_error --- src/helma/servlet/AbstractServletClient.java | 118 ++++-- src/helma/util/FileUpload.java | 151 ------- src/helma/util/mime/LanguageTag.java | 161 -------- src/helma/util/mime/MimeHeaderHolder.java | 51 --- src/helma/util/mime/MimeHeaders.java | 147 ------- src/helma/util/mime/MimeHeadersFactory.java | 25 -- src/helma/util/mime/MimeParser.java | 228 ----------- src/helma/util/mime/MimeParserException.java | 14 - src/helma/util/mime/MimeParserFactory.java | 24 -- src/helma/util/mime/MimeType.java | 373 ------------------ .../util/mime/MimeTypeFormatException.java | 14 - src/helma/util/mime/MultipartInputStream.java | 214 ---------- src/helma/util/mime/Utils.java | 143 ------- 13 files changed, 77 insertions(+), 1586 deletions(-) delete mode 100644 src/helma/util/FileUpload.java delete mode 100644 src/helma/util/mime/LanguageTag.java delete mode 100644 src/helma/util/mime/MimeHeaderHolder.java delete mode 100644 src/helma/util/mime/MimeHeaders.java delete mode 100644 src/helma/util/mime/MimeHeadersFactory.java delete mode 100644 src/helma/util/mime/MimeParser.java delete mode 100644 src/helma/util/mime/MimeParserException.java delete mode 100644 src/helma/util/mime/MimeParserFactory.java delete mode 100644 src/helma/util/mime/MimeType.java delete mode 100644 src/helma/util/mime/MimeTypeFormatException.java delete mode 100644 src/helma/util/mime/MultipartInputStream.java delete mode 100644 src/helma/util/mime/Utils.java diff --git a/src/helma/servlet/AbstractServletClient.java b/src/helma/servlet/AbstractServletClient.java index 16c16101..d726f065 100644 --- a/src/helma/servlet/AbstractServletClient.java +++ b/src/helma/servlet/AbstractServletClient.java @@ -27,6 +27,11 @@ import java.util.*; import javax.servlet.*; import javax.servlet.http.*; +import org.apache.commons.fileupload.FileUpload; +import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload.DiskFileUpload; +import org.apache.commons.fileupload.FileUploadBase; + /** * This is an abstract Hop servlet adapter. This class communicates with hop applications * via RMI. Subclasses are either one servlet per app, or one servlet that handles multiple apps @@ -43,7 +48,7 @@ public abstract class AbstractServletClient extends HttpServlet { String hopUrl; // limit to HTTP uploads in kB - int uploadLimit = 4096; + int uploadLimit = 1024; // cookie domain to use String cookieDomain; @@ -61,6 +66,10 @@ public abstract class AbstractServletClient extends HttpServlet { // enable debug output boolean debug; + // soft fail on file upload errors by setting flag "helma_upload_error" in RequestTrans + // if fals, an error response is written to the client immediately without entering helma + boolean uploadSoftfail = false; + /** * Init this servlet. * @@ -76,10 +85,13 @@ public abstract class AbstractServletClient extends HttpServlet { try { uploadLimit = (upstr == null) ? 1024 : Integer.parseInt(upstr); } catch (NumberFormatException x) { - System.err.println("Bad format for uploadLimit: " + upstr); + System.err.println("Bad number format for uploadLimit: " + upstr); uploadLimit = 1024; } + // soft fail mode for upload errors + uploadSoftfail = ("true".equalsIgnoreCase(init.getInitParameter("uploadSoftfail"))); + // get cookie domain cookieDomain = init.getInitParameter("cookieDomain"); if (cookieDomain != null) { @@ -150,36 +162,55 @@ public abstract class AbstractServletClient extends HttpServlet { } } - // check for MIME file uploads - String contentType = request.getContentType(); - - if ((contentType != null) && - (contentType.indexOf("multipart/form-data") == 0)) { + if (FileUpload.isMultipartContent(request)) { // File Upload try { - FileUpload upload = getUpload(request, encoding); + DiskFileUpload upload = new DiskFileUpload(); - if (upload != null) { - Hashtable parts = upload.getParts(); + upload.setSizeMax(uploadLimit * 1024); + upload.setHeaderEncoding(encoding); - for (Enumeration e = parts.keys(); e.hasMoreElements();) { - String nextKey = (String) e.nextElement(); - Object nextPart = parts.get(nextKey); + List uploads = upload.parseRequest(request); + Iterator it = uploads.iterator(); - if (nextPart instanceof List) { - reqtrans.set(nextKey, ((List) nextPart).get(0)); - reqtrans.set(nextKey+"_array", ((List) nextPart).toArray()); - } else { - reqtrans.set(nextKey, nextPart); - } + while (it.hasNext()) { + FileItem item = (FileItem) it.next(); + // TODO: set fieldname_array if multiple values for one fieldname + String name = item.getFieldName(); + Object value = null; + // check if this is an ordinary HTML form element or a file upload + if (item.isFormField()) { + value = item.getString(encoding); + } else { + value = new MimePart(item.getName(), + item.get(), + item.getContentType()); + } + // if multiple values exist for this name, append to _array + if (reqtrans.get(name) != null) { + appendFormValue(reqtrans, name, value); + } else { + reqtrans.set(name, value); } } - } catch (Exception upx) { - sendError(response, HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, - "Sorry, upload size exceeds limit of " + uploadLimit + - "kB."); - return; + } catch (Exception upx) { + System.err.println("Error in file upload: " + upx); + if (uploadSoftfail) { + String msg = upx.getMessage(); + if (msg == null || msg.length() == 0) { + msg = upx.toString(); + } + reqtrans.set("helma_upload_error", msg); + } else if (upx instanceof FileUploadBase.SizeLimitExceededException) { + sendError(response, HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE, + "File upload size exceeds limit of " + uploadLimit + "kB"); + return; + } else { + sendError(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + "Error in file upload: " + upx); + return; + } } } @@ -487,24 +518,29 @@ public abstract class AbstractServletClient extends HttpServlet { } } - FileUpload getUpload(HttpServletRequest request, String encoding) throws Exception { - int contentLength = request.getContentLength(); - BufferedInputStream in = new BufferedInputStream(request.getInputStream()); - - if (contentLength > (uploadLimit * 1024)) { - throw new RuntimeException("Upload exceeds limit of " + uploadLimit + " kb."); + /** + * Used to build the form value array when a multipart (file upload) form has + * multiple values for one form element name. + * + * @param reqtrans + * @param name + * @param value + */ + private void appendFormValue(RequestTrans reqtrans, String name, Object value) { + String arrayName = name + "_array"; + try { + Object[] values = (Object[]) reqtrans.get(arrayName); + if (values == null) { + reqtrans.set(arrayName, new Object[] {reqtrans.get(name), value}); + } else { + Object[] newValues = new Object[values.length + 1]; + System.arraycopy(values, 0, newValues, 0, values.length); + newValues[values.length] = value; + reqtrans.set(arrayName, newValues); + } + } catch (ClassCastException x) { + // name_array is defined as something else in the form - don't overwrite it } - - String contentType = request.getContentType(); - FileUpload upload = new FileUpload(uploadLimit); - - upload.load(in, contentType, contentLength, encoding); - - return upload; - } - - Object getUploadPart(FileUpload upload, String name) { - return upload.getParts().get(name); } /** diff --git a/src/helma/util/FileUpload.java b/src/helma/util/FileUpload.java deleted file mode 100644 index 88f6b14c..00000000 --- a/src/helma/util/FileUpload.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Helma License Notice - * - * The contents of this file are subject to the Helma License - * Version 2.0 (the "License"). You may not use this file except in - * compliance with the License. A copy of the License is available at - * http://adele.helma.org/download/helma/license.txt - * - * Copyright 1998-2003 Helma Software. All Rights Reserved. - * - * $RCSfile$ - * $Author$ - * $Revision$ - * $Date$ - */ - -package helma.util; - -import helma.util.mime.*; -import java.io.*; -import java.util.*; - -/** - * Utility class for MIME file uploads via HTTP POST. - */ -public class FileUpload { - public Hashtable parts; - int maxKbytes; - - /** - * Creates a new FileUpload object. - */ - public FileUpload() { - maxKbytes = 4096; - } - - /** - * Creates a new FileUpload object. - * - * @param max ... - */ - public FileUpload(int max) { - maxKbytes = max; - } - - /** - * - * - * @return ... - */ - public Hashtable getParts() { - return parts; - } - - /** - * - * - * @param is ... - * @param contentType ... - * @param contentLength ... - * - * @throws Exception ... - * @throws MimeParserException ... - * @throws IOException ... - */ - public void load(InputStream is, String contentType, int contentLength, String encoding) - throws Exception { - parts = new Hashtable(); - - String boundary = MimePart.getSubHeader(contentType, "boundary"); - - if (boundary == null) { - throw new MimeParserException("Error parsing MIME input stream."); - } - - if ((maxKbytes > -1) && (contentLength > (maxKbytes * 1024))) { - throw new IOException("Size of upload exceeds limit of " + maxKbytes + - " kB."); - } - - byte[] b = new byte[contentLength]; - MultipartInputStream in = new MultipartInputStream(new BufferedInputStream(is), - boundary.getBytes()); - - while (in.nextInputStream()) { - MimeParser parser = new MimeParser(in, new MimeHeadersFactory()); - MimeHeaders headers = (MimeHeaders) parser.parse(); - - InputStream bodystream = parser.getInputStream(); - int read; - int count = 0; - - while ((read = bodystream.read(b, count, 4096)) > -1) { - count += read; - - if (count == b.length) { - byte[] newb = new byte[count + 4096]; - - System.arraycopy(b, 0, newb, 0, count); - b = newb; - } - } - - byte[] newb = new byte[count]; - - System.arraycopy(b, 0, newb, 0, count); - - String type = headers.getValue("Content-Type"); - String disposition = headers.getValue("Content-Disposition"); - String name = MimePart.getSubHeader(disposition, "name"); - String filename = MimePart.getSubHeader(disposition, "filename"); - - if (filename != null) { - int sep = filename.lastIndexOf("\\"); - - if (sep > -1) { - filename = filename.substring(sep + 1); - } - - sep = filename.lastIndexOf("/"); - - if (sep > -1) { - filename = filename.substring(sep + 1); - } - } - - Object existingValue = parts.get(name); - Object newValue = null; - - if (filename != null) { - newValue = new MimePart(filename, newb, type); - } else { - newValue = new String(newb, encoding); - } - - if (existingValue == null) { - // no previous value, just add new object - parts.put(name, newValue); - } else if (existingValue instanceof ArrayList) { - // already multiple values, add to list - ((ArrayList) existingValue).add(newValue); - } else { - // already one value, convert to list - ArrayList list = new ArrayList(); - list.add(existingValue); - list.add(newValue); - parts.put(name, list); - } - } - } -} diff --git a/src/helma/util/mime/LanguageTag.java b/src/helma/util/mime/LanguageTag.java deleted file mode 100644 index c695c977..00000000 --- a/src/helma/util/mime/LanguageTag.java +++ /dev/null @@ -1,161 +0,0 @@ -// LanguageTag.java -// $Id$ -// (c) COPYRIGHT MIT, INRIA and Keio, 1999 -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.*; -import java.io.*; - -/** - * This class is used to represent parsed Language tags, - * It creates a representation from a string based representation - * of the Language tag, as defined in RFC 1766 - * NOTE, we don't check that languages are defined according to ISO 639 - */ - -public class LanguageTag implements Serializable, Cloneable { - public static int NO_MATCH = -1; - public static int MATCH_LANGUAGE = 1; - public static int MATCH_SPECIFIC_LANGUAGE = 2; - // subtag is not dialect as subtype can be - // dialect or country identification or script variation, etc... - public static int MATCH_SUBTAG = 3; - public static int MATCH_SPECIFIC_SUBTAG = 4; - - /** - * String representation of the language - * - * @serial - */ - protected String language = null ; - /** - * String representation of subtag - * - * @serial - */ - protected String subtag = null ; - - /** - * external form of this language tag - * - * @serial - */ - protected String external = null ; - - /** - * How good the given LanguageTag matches the receiver of the method ? - * This method returns a matching level among: - *
- *
NO_MATCH
Language not matching,
- *
MATCH_LANGUAGE
Languages match roughly (with *),
- *
MATCH_SPECIFIC_LANGUAGE
Languages match exactly,
- *
MATCH_SUBTAG
Languages match, subtags matches roughly
- *
MATCH_SPECIFIC_SUBAG
Languages match, subtag matches exactly
- *
- * The matches are ranked from worst match to best match, a simple - * Max ( match[i], matched) will give the best match. - * @param other The other LanguageTag to match against ourself. - */ - - public int match (LanguageTag other) { - int match = NO_MATCH; - // match types: - if ( language.equals("*") || other.language.equals("*") ) { - match = MATCH_LANGUAGE; - } else if ( ! language.equalsIgnoreCase(other.language) ) { - return NO_MATCH ; - } else { - match = MATCH_SPECIFIC_LANGUAGE; - } - // match subtypes: - if ((subtag == null) || (other.subtag == null)) - return match; - if ( subtag.equals("*") || other.subtag.equals("*") ) { - match = MATCH_SUBTAG ; - } else if ( ! subtag.equalsIgnoreCase(other.subtag) ) { - return NO_MATCH; - } else { - match = MATCH_SPECIFIC_SUBTAG; - } - return match; - } - - /** - * A printable representation of this LanguageTag. - * The printed representation is guaranteed to be parseable by the - * String constructor. - */ - - public String toString () { - if ( external == null ) { - if (subtag != null) { - external = language + "-" + subtag; - } else { - external = language; - } - } - return external ; - } - - /** - * Get the language - * @return The language, encoded as a String. - */ - - public String getLanguage() { - return language; - } - - /** - * Get the subtag - * @return The subtag, encoded as a string - */ - - public String getSubtag() { - return language; - } - - /** - * Construct a Language tag from a spec - * @param spec A string representing a LangateTag - */ - public LanguageTag(String spec) { - int strl = spec.length() ; - int start = 0, look = -1 ; - // skip leading/trailing blanks: - while ((start < strl) && (spec.charAt (start)) <= ' ') - start++ ; - while ((strl > start) && (spec.charAt (strl-1) <= ' ')) - strl-- ; - // get the type: - StringBuffer sb = new StringBuffer () ; - while ((start < strl) && ((look = spec.charAt(start)) != '-') - && ((look = spec.charAt(start)) != ';')) { - sb.append ((char) look) ; - start++ ; - } - this.language = sb.toString() ; - if ( look == '-' ) { - start++ ; - sb.setLength(0) ; - while ((start < strl) - && ((look = spec.charAt(start)) > ' ') && (look != ';')) { - sb.append ((char) look) ; - start++ ; - } - this.subtag = sb.toString() ; - } - } - - /** - * construct directly a language tag - * it NEEDS both language and subtype parameters - */ - - public LanguageTag(String language, String subtag) { - this.language = language; - this.subtag = subtag; - } -} diff --git a/src/helma/util/mime/MimeHeaderHolder.java b/src/helma/util/mime/MimeHeaderHolder.java deleted file mode 100644 index 886563dd..00000000 --- a/src/helma/util/mime/MimeHeaderHolder.java +++ /dev/null @@ -1,51 +0,0 @@ -// MimeHeaderHolder.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.io.*; - -public interface MimeHeaderHolder { - - /** - * A new header has been parsed. - * @param name The name of the encountered header. - * @param buf The byte buffer containing the value. - * @param off Offset of the header value in the above buffer. - * @param len Length of the value in the above header. - * @exception MimeParserException if the parsing failed - */ - - public void notifyHeader(String name, byte buf[], int off, int len) - throws MimeParserException; - - /** - * The parsing is now about to start, take any appropriate action. - * This hook can return a true boolean value to enforce - * the MIME parser into transparent mode (eg the parser will not - * try to parse any headers. - *

This hack is primarily defined for HTTP/0.9 support, it might - * also be usefull for other hacks. - * @param parser The Mime parser. - * @return A boolean true if the MimeParser shouldn't - * continue the parsing, false otherwise. - * @exception MimeParserException if the parsing failed - * @exception IOException if an IO error occurs. - */ - - public boolean notifyBeginParsing(MimeParser parser) - throws MimeParserException, IOException; - - /** - * All the headers have been parsed, take any appropriate actions. - * @param parser The Mime parser. - * @exception MimeParserException if the parsing failed - * @exception IOException if an IO error occurs. - */ - - public void notifyEndParsing(MimeParser parser) - throws MimeParserException, IOException; - -} diff --git a/src/helma/util/mime/MimeHeaders.java b/src/helma/util/mime/MimeHeaders.java deleted file mode 100644 index ff682b2e..00000000 --- a/src/helma/util/mime/MimeHeaders.java +++ /dev/null @@ -1,147 +0,0 @@ -// MimeHeaders.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.io.*; -import java.util.*; - -/** - * The most stupid MIME header holder. - * This class uses a hashtable mapping header names (as String), to header - * values (as String). Header names are lowered before entering the hashtable. - */ - -public class MimeHeaders implements MimeHeaderHolder { - Hashtable headers = null; - MimeParser parser = null; - - /** - * A new header has been parsed. - * @param name The name of the encountered header. - * @param buf The byte buffer containing the value. - * @param off Offset of the header value in the above buffer. - * @param len Length of the value in the above header. - * @exception MimeParserException if the parsing failed - */ - - public void notifyHeader(String name, byte buf[], int off, int len) - throws MimeParserException - { - String lname = name.toLowerCase(); - String oldval = null; - if ( headers == null ) { - headers = new Hashtable(5); - } else { - oldval = (String) headers.get(lname); - } - String newval = ((oldval != null) - ? oldval + "," + new String(buf, 0, off, len) - : new String(buf, 0, off, len)); - headers.put(lname, newval); - } - - /** - * The parsing is now about to start, take any appropriate action. - * This hook can return a true boolean value to enforce - * the MIME parser into transparent mode (eg the parser will not - * try to parse any headers. - *

This hack is primarily defined for HTTP/0.9 support, it might - * also be usefull for other hacks. - * @param parser The Mime parser. - * @return A boolean true if the MimeParser shouldn't - * continue the parsing, false otherwise. - * @exception IOException if an IO error occurs. - */ - - public boolean notifyBeginParsing(MimeParser parser) - throws IOException - { - return false; - } - - /** - * All the headers have been parsed, take any appropriate actions. - * @param parser The Mime parser. - * @exception IOException if an IO error occurs. - */ - - public void notifyEndParsing(MimeParser parser) - throws IOException - { - return; - } - - /** - * Set a header value. - * @param name The header name. - * @param value The header value. - */ - - public void setValue(String name, String value) { - if ( headers == null ) - headers = new Hashtable(5); - headers.put(name.toLowerCase(), value); - } - - /** - * Retreive a header value. - * @param name The name of the header. - * @return The value for this header, or null if - * undefined. - */ - - public String getValue(String name) { - return ((headers != null) - ? (String) headers.get(name.toLowerCase()) - : null); - } - - /** - * Enumerate the headers defined by the holder. - * @return A enumeration of header names, or null if no - * header is defined. - */ - - public Enumeration enumerateHeaders() { - if ( headers == null ) - return null; - return headers.keys(); - } - - /** - * Get the entity stream attached to these headers, if any. - * @return An InputStream instance, or null if no - * entity available. - */ - - public InputStream getInputStream() { - return ((parser != null) ? parser.getInputStream() : null); - } - - /** - * Dump all headers to the given stream. - * @param out The stream to dump to. - */ - - public void dump(PrintStream out) { - Enumeration names = enumerateHeaders(); - if ( names != null ) { - while (names.hasMoreElements()) { - String name = (String) names.nextElement(); - out.println(name+": "+headers.get(name)); - } - } - } - - public MimeHeaders(MimeParser parser) { - this.parser = parser; - } - - public MimeHeaders() { - } - - -} diff --git a/src/helma/util/mime/MimeHeadersFactory.java b/src/helma/util/mime/MimeHeadersFactory.java deleted file mode 100644 index a91ab8cd..00000000 --- a/src/helma/util/mime/MimeHeadersFactory.java +++ /dev/null @@ -1,25 +0,0 @@ -// MimeHeadersFactory.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -/** - * A Mime header factory, that will build instances of the MimeHeaders class - * to hold MIME headers. - */ - -public class MimeHeadersFactory implements MimeParserFactory { - - /** - * Create a new header holder to hold the parser's result. - * @param parser The parser that has something to parse. - * @return A MimeParserHandler compliant object. - */ - - public MimeHeaderHolder createHeaderHolder(MimeParser parser) { - return new MimeHeaders(parser); - } - -} diff --git a/src/helma/util/mime/MimeParser.java b/src/helma/util/mime/MimeParser.java deleted file mode 100644 index 3d5f5277..00000000 --- a/src/helma/util/mime/MimeParser.java +++ /dev/null @@ -1,228 +0,0 @@ -// MimeParser.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.*; -import java.io.* ; - -/** - * The MimeParser class parses an input MIME stream. - */ - -public class MimeParser { - protected int ch = -1 ; - protected InputStream input = null ; - protected byte buffer[] = new byte[128] ; - protected int bsize = 0 ; - - /** - * The factory used to create new MIME header holders. - */ - protected MimeParserFactory factory = null ; - - protected void expect (int car) - throws MimeParserException, IOException - { - if ( car != ch ) { - String sc = (new Character((char) car)).toString() ; - String se = (new Character((char) ch)).toString() ; - throw new MimeParserException ("expecting " - + sc + "("+car+")" - + " got " - + se + "("+ch+")\n" - + "context: " - + new String (buffer, 0, 0, bsize) - + "\n") ; - } - ch = input.read() ; - } - - protected void skipSpaces () - throws MimeParserException, IOException - { - while ( (ch == ' ') || (ch == '\t') ) - ch = input.read() ; - } - - protected final void append (int c) { - if ( bsize+1 >= buffer.length ) { - byte nb[] = new byte[buffer.length*2] ; - System.arraycopy (buffer, 0, nb, 0, buffer.length) ; - buffer = nb ; - } - buffer[bsize++] = (byte) c ; - } - - /* - * Get the header name: - */ - - protected String parse822HeaderName () - throws MimeParserException, IOException - { - bsize = 0 ; - while ( (ch >= 32) && (ch != ':') ) { - append ((char) ch) ; - ch = input.read() ; - } - expect (':') ; - if ( bsize <= 0 ) - throw new MimeParserException ("expected a header name.") ; - return new String (buffer, 0, 0, bsize) ; - } - - /* - * Get the header body, still trying to be 822 compliant *and* HTTP - * robust, which is unfortunatelly a contrdiction. - */ - - protected void parse822HeaderBody () - throws MimeParserException, IOException - { - bsize = 0 ; - skipSpaces () ; - loop: - while ( true ) { - switch (ch) { - case -1: - break loop ; - case '\r': - if ( (ch = input.read()) != '\n' ) { - append ('\r') ; - continue ; - } - // no break intentional - case '\n': - // do as if '\r' had been received. This defeats 822, but - // makes HTTP more "robust". I wish HTTP were a binary - // protocol. - switch (ch = input.read()) { - case ' ': case '\t': - do { - ch = input.read () ; - } while ((ch == ' ') || (ch == '\t')) ; - append(ch); - break ; - default: - break loop ; - } - break ; - default: - append ((char) ch) ; - break ; - } - ch = input.read() ; - } - return ; - } - - /* - * Parse the given input stream for an HTTP 1.1 token. - */ - - protected String parseToken (boolean lower) - throws MimeParserException, IOException - { - bsize = 0 ; - while ( true ) { - switch ( ch ) { - // CTLs - case -1: - case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: - case 8: case 9: case 10: case 11: case 12: case 13: case 14: - case 15: case 16: case 17: case 18: case 19: case 20: case 21: - case 22: case 23: case 24: case 25: case 26: case 27: case 28: - case 29: case 30: case 31: - // tspecials - case '(': case ')': case '<': case '>': case '@': - case ',': case ';': case ':': case '\\': case '\"': - case '/': case '[': case ']': case '?': case '=': - case '{': case '}': case ' ': - return new String (buffer, 0, 0, bsize) ; - default: - append ((char) (lower - ? Character.toLowerCase((char) ch) - : ch)) ; - } - ch = input.read() ; - } - } - - protected void parse822Headers(MimeHeaderHolder msg) - throws MimeParserException, IOException - { - while ( true ) { - if ( ch == '\r' ) { - if ( (ch = input.read()) == '\n' ) - return ; - } else if ( ch == '\n' ) { - return ; - } - String name = parse822HeaderName () ; - skipSpaces() ; - parse822HeaderBody () ; - msg.notifyHeader(name, buffer, 0, bsize); - } - } - - public MimeHeaderHolder parse() - throws MimeParserException, IOException - { - MimeHeaderHolder msg = factory.createHeaderHolder(this); - ch = input.read() ; - cached = true ; - if ( ! msg.notifyBeginParsing(this) ) { - if ( ! cached ) - ch = input.read(); - parse822Headers (msg) ; - } - msg.notifyEndParsing(this); - return msg; - } - - boolean cached = false ; - - public int read() - throws IOException - { - if ( cached ) - cached = false; - else - ch = input.read(); - return ch; - } - - public void unread(int ch) { - if ( cached ) - throw new RuntimeException("cannot unread more then once !"); - this.ch = ch; - cached = true; - } - - /** - * Get the message body, as an input stream. - * @return The input stream used by the parser to get data, after - * a call to parse, this input stream contains exactly - * the body of the message. - */ - - public InputStream getInputStream () { - return input ; - } - - /** - * Create an instance of the MIMEParser class. - * @param input The input stream to be parsed as a MIME stream. - * @param factory The factory used to create MIME header holders. - */ - - public MimeParser (InputStream input, MimeParserFactory factory) { - this.input = input ; - this.factory = factory; - } - - -} diff --git a/src/helma/util/mime/MimeParserException.java b/src/helma/util/mime/MimeParserException.java deleted file mode 100644 index f4b05a98..00000000 --- a/src/helma/util/mime/MimeParserException.java +++ /dev/null @@ -1,14 +0,0 @@ -// MimeParserException.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -public class MimeParserException extends Exception { - - public MimeParserException(String msg) { - super(msg); - } - -} diff --git a/src/helma/util/mime/MimeParserFactory.java b/src/helma/util/mime/MimeParserFactory.java deleted file mode 100644 index 41e94044..00000000 --- a/src/helma/util/mime/MimeParserFactory.java +++ /dev/null @@ -1,24 +0,0 @@ -// MimeParserFactory.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -/** - * This class is used by the MimeParser, to create new MIME message holders. - * Each MIME parse instances is custmozied wit hits own factory, which it - * will use to create MIME header holders. - */ - -public interface MimeParserFactory { - - /** - * Create a new header holder to hold the parser's result. - * @param parser The parser that has something to parse. - * @return A MimeParserHandler compliant object. - */ - - abstract public MimeHeaderHolder createHeaderHolder(MimeParser parser); - -} diff --git a/src/helma/util/mime/MimeType.java b/src/helma/util/mime/MimeType.java deleted file mode 100644 index ce821316..00000000 --- a/src/helma/util/mime/MimeType.java +++ /dev/null @@ -1,373 +0,0 @@ -// MimeType.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.*; -import java.io.*; - -/** - * This class is used to represent parsed MIME types. - * It creates this representation from a string based representation of - * the MIME type, as defined in the RFC 1345. - */ - -public class MimeType implements Serializable, Cloneable { - /** - * List of well known MIME types: - */ - public static MimeType TEXT_HTML = null ; - public static MimeType APPLICATION_POSTSCRIPT = null ; - public static MimeType TEXT_PLAIN = null ; - public static MimeType APPLICATION_X_WWW_FORM_URLENCODED = null ; - public static MimeType MULTIPART_FORM_DATA = null ; - public static MimeType APPLICATION_X_JAVA_AGENT = null ; - public static MimeType MESSAGE_HTTP = null ; - public static MimeType TEXT_CSS = null ; - public static MimeType TEXT = null ; - - static { - try { - TEXT_HTML - = new MimeType("text/html"); - APPLICATION_POSTSCRIPT - = new MimeType ("application/postscript") ; - TEXT_PLAIN - = new MimeType("text/plain") ; - APPLICATION_X_WWW_FORM_URLENCODED - = new MimeType("application/x-www-form-urlencoded") ; - MULTIPART_FORM_DATA - = new MimeType("multipart/form-data") ; - APPLICATION_X_JAVA_AGENT - = new MimeType("application/x-java-agent") ; - MESSAGE_HTTP - = new MimeType("message/http"); - TEXT_CSS - = new MimeType("text/css"); - TEXT - = new MimeType("text/*"); - } catch (MimeTypeFormatException e) { - System.out.println ("httpd.MimeType: invalid static init.") ; - System.exit (1) ; - } - } - - public final static int NO_MATCH = -1 ; - public final static int MATCH_TYPE = 1 ; - public final static int MATCH_SPECIFIC_TYPE = 2 ; - public final static int MATCH_SUBTYPE = 3 ; - public final static int MATCH_SPECIFIC_SUBTYPE = 4 ; - - /** - * String representation of type - * - * @serial - */ - protected String type = null ; - /** - * String representation of subtype - * - * @serial - */ - protected String subtype = null ; - /** - * parameter names - * - * @serial - */ - protected String pnames[] = null; - /** - * parameter values - * - * @serial - */ - protected String pvalues[] = null; - /** - * external form of this mime type - * - * @serial - */ - protected String external = null ; - - /** - * How good the given MimeType matches the receiver of the method ? - * This method returns a matching level among: - *

- *
NO_MATCH
Types not matching,
- *
MATCH_TYPE
Types match,
- *
MATCH_SPECIFIC_TYPE
Types match exactly,
- *
MATCH_SUBTYPE
Types match, subtypes matches too
- *
MATCH_SPECIFIC_SUBTYPE
Types match, subtypes matches exactly
- *
- * The matches are ranked from worst match to best match, a simple - * Max ( match[i], matched) will give the best match. - * @param other The other MimeType to match against ourself. - */ - - public int match (MimeType other) { - int match = NO_MATCH; - // match types: - if ( type.equals("*") || other.type.equals("*") ) { - return MATCH_TYPE; - } else if ( ! type.equals (other.type) ) { - return NO_MATCH ; - } else { - match = MATCH_SPECIFIC_TYPE; - } - // match subtypes: - if ( subtype.equals("*") || other.subtype.equals("*") ) { - match = MATCH_SUBTYPE ; - } else if ( ! subtype.equals (other.subtype) ) { - return NO_MATCH; - } else { - match = MATCH_SPECIFIC_SUBTYPE; - } - return match; - } - - /** - * A printable representation of this MimeType. - * The printed representation is guaranteed to be parseable by the - * String constructor. - */ - - public String toString () { - if ( external == null ) { - StringBuffer sb = new StringBuffer (type) ; - sb.append((char) '/') ; - sb.append (subtype) ; - if ( pnames != null ) { - for (int i = 0 ; i < pnames.length; i++) { - sb.append(';'); - sb.append(pnames[i]); - if ( pvalues[i] != null ) { - sb.append('='); - sb.append(pvalues[i]); - } - } - } - external = sb.toString() ; - } - return external ; - } - - - /** - * Does this MIME type has some value for the given parameter ? - * @param name The parameter to check. - * @return True if this parameter has a value, false - * otherwise. - */ - public boolean hasParameter (String name) { - if ( pnames != null ) { - for (int i = 0 ; i < pnames.length ; i++) { - if ( pnames[i].equals(name) ) - return true ; - } - } - return false ; - } - - /** - * Get the major type of this mime type. - * @return The major type, encoded as a String. - */ - - public String getType() { - return type; - } - - /** - * Get the minor type (subtype) of this mime type. - * @return The minor or subtype encoded as a String. - */ - public String getSubtype() { - return subtype; - } - - - /** - * Get a mime type parameter value. - * @param name The parameter whose value is to be returned. - * @return The parameter value, or null if not found. - */ - public String getParameterValue (String name) { - if ( pnames != null ) { - for (int i = 0 ; i < pnames.length ; i++) { - if ( pnames[i].equals(name) ) - return pvalues[i]; - } - } - return null ; - } - - /** - * adds some parameters to a MimeType - * @param param a String array of parameter names - * @param values the corresponding String array of values - */ - public void addParameters(String[] param, String[] values) { - // sanity check - if ((param == null) || (values == null) || - (values.length != param.length)) - return; - if (pnames == null) { - pnames = param; - pvalues = values; - } else { - String[] nparam = new String[pnames.length+param.length]; - String[] nvalues = new String[pvalues.length+values.length]; - System.arraycopy(pnames, 0, nparam, 0, pnames.length); - System.arraycopy(param, 0, nparam, pnames.length, param.length); - System.arraycopy(pvalues, 0, nvalues, 0, pvalues.length); - System.arraycopy(values,0, nvalues, pvalues.length, values.length); - pnames = nparam; - pvalues = nvalues; - } - external = null; - } - - /** - * get a clone of this object - * @return another cloned instance of MimeType - */ - public MimeType getClone() { - try { - return (MimeType) clone(); - } catch (CloneNotSupportedException ex) { - // should never happen as we are Cloneable! - } - // never reached - return null; - } - - /** - * adds a parameterto a MimeType - * @param param the parameter name, as a String - * @param value the parameter value, as a Sting - */ - public void addParameter(String param, String value) { - String[] p = new String[1]; - String[] v = new String[1]; - p[0] = param; - v[0] = value; - addParameters(p, v); - } - - /** - * Construct MimeType object for the given string. - * The string should be the representation of the type. This methods - * tries to be compliant with HTTP1.1, p 15, although it is not - * (because of quoted-text not being accepted). - * FIXME - * @param spec A string representing a MimeType - * @exception MimeTypeFormatException if the string couldn't be parsed. - */ - public MimeType (String spec) - throws MimeTypeFormatException - { - int strl = spec.length() ; - int start = 0, look = -1 ; - // skip leading/trailing blanks: - while ((start < strl) && (spec.charAt (start)) <= ' ') - start++ ; - while ((strl > start) && (spec.charAt (strl-1) <= ' ')) - strl-- ; - // get the type: - StringBuffer sb = new StringBuffer () ; - while ((start < strl) && ((look = spec.charAt(start)) != '/')) { - sb.append ((char) look) ; - start++ ; - } - if ( look != '/' ) - throw new MimeTypeFormatException (spec) ; - this.type = sb.toString() ; - // get the subtype: - start++ ; - sb.setLength(0) ; - while ((start < strl) - && ((look = spec.charAt(start)) > ' ') && (look != ';')) { - sb.append ((char) look) ; - start++ ; - } - this.subtype = sb.toString() ; - // get parameters, if any: - while ((start < strl) && ((look = spec.charAt(start)) <= ' ')) - start++ ; - if ( start < strl ) { - if (spec.charAt(start) != ';') - throw new MimeTypeFormatException (spec) ; - start++ ; - Vector vp = new Vector(4) ; - Vector vv = new Vector(4) ; - while ( start < strl ) { - while ((start < strl) && (spec.charAt(start) <= ' ')) start++ ; - // get parameter name: - sb.setLength (0) ; - while ((start < strl) - && ((look=spec.charAt(start)) > ' ') && (look != '=')) { - sb.append (Character.toLowerCase((char) look)) ; - start++ ; - } - String name = sb.toString() ; - // get the value: - while ((start < strl) && (spec.charAt(start) <= ' ')) start++ ; - if (spec.charAt(start) != '=') - throw new MimeTypeFormatException (spec) ; - start++ ; - while ((start < strl) && - ((spec.charAt(start) == '"') || - (spec.charAt(start) <= ' '))) start++ ; - sb.setLength(0) ; - while ((start < strl) - && ((look=spec.charAt(start)) > ' ') - && (look != ';') - && (look != '"')) { - sb.append ((char) look) ; - start++ ; - } - while ((start < strl) && (spec.charAt(start) != ';')) start++ ; - start++ ; - String value = sb.toString() ; - vp.addElement(name); - vv.addElement(value); - } - this.pnames = new String[vp.size()]; - vp.copyInto(pnames); - this.pvalues = new String[vv.size()]; - vv.copyInto(pvalues); - } - } - - public MimeType (String type, String subtype - , String pnames[], String pvalues[]) { - this.type = type ; - this.subtype = subtype ; - this.pnames = pnames; - this.pvalues = pvalues; - } - - public MimeType (String type, String subtype) { - this.type = type; - this.subtype = subtype; - } - - public static void main (String args[]) { - if ( args.length == 1) { - MimeType type = null ; - try { - type = new MimeType (args[0]) ; - } catch (MimeTypeFormatException e) { - } - if ( type != null ) - System.out.println (type) ; - else - System.out.println ("Invalid mime type specification.") ; - } else { - System.out.println ("Usage: java MimeType ") ; - } - } - -} diff --git a/src/helma/util/mime/MimeTypeFormatException.java b/src/helma/util/mime/MimeTypeFormatException.java deleted file mode 100644 index 227a4bbe..00000000 --- a/src/helma/util/mime/MimeTypeFormatException.java +++ /dev/null @@ -1,14 +0,0 @@ -// MimeType.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -public class MimeTypeFormatException extends Exception { - - public MimeTypeFormatException(String msg) { - super(msg); - } - -} diff --git a/src/helma/util/mime/MultipartInputStream.java b/src/helma/util/mime/MultipartInputStream.java deleted file mode 100644 index 5bb0b3ce..00000000 --- a/src/helma/util/mime/MultipartInputStream.java +++ /dev/null @@ -1,214 +0,0 @@ -// MultipartInputStream.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1996. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.io.* ; - -/** - * A class to handle multipart MIME input streams. See RC 1521. - * This class handles multipart input streams, as defined by the RFC 1521. - * It prvides a sequential interface to all MIME parts, and for each part - * it delivers a suitable InputStream for getting its body. - */ - -public class MultipartInputStream extends InputStream { - InputStream in = null; - byte boundary[] = null ; - byte buffer[] = null ; - boolean partEnd = false ; - boolean fileEnd = false ; - - // Read boundary bytes of input in buffer - // Return true if enough bytes available, false otherwise. - - private final boolean readBoundaryBytes() - throws IOException - { - int pos = 0; - while ( pos < buffer.length ) { - int got = in.read(buffer, pos, buffer.length-pos); - if ( got < 0 ) - return false; - pos += got; - } - return true; - } - - // Skip to next input boundary, set stream at begining of content: - // Returns true if boundary was found, false otherwise. - - protected boolean skipToBoundary() - throws IOException - { - int ch = in.read() ; - skip: - while ( ch != -1 ) { - if ( ch != '-' ) { - ch = in.read() ; - continue ; - } - if ((ch = in.read()) != '-') - continue ; - in.mark(boundary.length) ; - if ( ! readBoundaryBytes() ) { - in.reset(); - ch = in.read(); - continue skip; - } - for (int i = 0 ; i < boundary.length ; i++) { - if ( buffer[i] != boundary[i] ) { - in.reset() ; - ch = in.read() ; - continue skip ; - } - } - // FIXME: should we check for a properly syntaxed part, which - // means that we should expect '\r\n'. For now, we just skip - // as much as we can. - if ( (ch = in.read()) == '\r' ) { - ch = in.read() ; - } - in.mark(3); - if( in.read() == '-' ) { // check fileEnd! - if( in.read() == '\r' && in.read() == '\n' ) { - fileEnd = true ; - return false ; - } - } - in.reset(); - return true ; - } - fileEnd = true ; - return false ; - } - - /** - * Read one byte of data from the current part. - * @return A byte of data, or -1 if end of file. - * @exception IOException If some IO error occured. - */ - - public int read() - throws IOException - { - int ch ; - if ( partEnd ) - return -1 ; - switch (ch = in.read()) { - case '\r': - // check for a boundary - in.mark(boundary.length+3) ; - int c1 = in.read() ; - int c2 = in.read() ; - int c3 = in.read() ; - if ((c1 == '\n') && (c2 == '-') && (c3 == '-')) { - if ( ! readBoundaryBytes() ) { - in.reset(); - return ch; - } - for (int i = 0 ; i < boundary.length ; i++) { - if ( buffer[i] != boundary[i] ) { - in.reset() ; - return ch ; - } - } - partEnd = true ; - if ( (ch = in.read()) == '\r' ) { - in.read() ; - } else if (ch == '-') { - // FIXME, check the second hyphen - if (in.read() == '-') - fileEnd = true ; - } else { - fileEnd = (ch == -1); - } - return -1 ; - } else { - in.reset () ; - return ch ; - } - // not reached - case -1: - fileEnd = true ; - return -1 ; - default: - return ch ; - } - } - - /** - * Read n bytes of data from the current part. - * @return the number of bytes data, read or -1 - * if end of file. - * @exception IOException If some IO error occured. - */ - public int read (byte b[], int off, int len) - throws IOException - { - int got = 0 ; - int ch ; - - while ( got < len ) { - if ((ch = read()) == -1) - return (got == 0) ? -1 : got ; - b[off+(got++)] = (byte) (ch & 0xFF) ; - } - return got ; - } - - public long skip (long n) - throws IOException - { - while ((--n >= 0) && (read() != -1)) - ; - return n ; - } - - public int available () - throws IOException - { - return in.available(); - } - - /** - * Switch to the next available part of data. - * One can interrupt the current part, and use this method to switch - * to next part before current part was totally read. - * @return A boolean true if there next partis ready, - * or false if this was the last part. - */ - - public boolean nextInputStream() - throws IOException - { - if ( fileEnd ) { - return false ; - } - if ( ! partEnd ) { - return skipToBoundary() ; - } else { - partEnd = false ; - return true ; - } - } - - /** - * Construct a new multipart input stream. - * @param in The initial (multipart) input stream. - * @param boundary The input stream MIME boundary. - */ - - public MultipartInputStream (InputStream in, byte boundary[]) { - this.in = (in.markSupported() - ? in - : new BufferedInputStream(in, boundary.length+4)); - this.boundary = boundary ; - this.buffer = new byte[boundary.length] ; - this.partEnd = false ; - this.fileEnd = false ; - } - -} diff --git a/src/helma/util/mime/Utils.java b/src/helma/util/mime/Utils.java deleted file mode 100644 index 0a2844aa..00000000 --- a/src/helma/util/mime/Utils.java +++ /dev/null @@ -1,143 +0,0 @@ -// Utils.java -// $Id$ -// (c) COPYRIGHT MIT and INRIA, 1998. -// Please first read the full copyright statement in file COPYRIGHT.html - -package helma.util.mime; - -import java.util.Hashtable; - -/** - * @version $Revision$ - * @author Benoit Mahe (bmahe@w3.org) - */ -public class Utils { - - private static Hashtable extension_map = new Hashtable(); - - private static void setSuffix(String ext, String ct) { - extension_map.put(ext, ct); - } - - static { - setSuffix("", "content/unknown"); - setSuffix(".uu", "application/octet-stream"); - setSuffix(".saveme", "application/octet-stream"); - setSuffix(".dump", "application/octet-stream"); - setSuffix(".hqx", "application/octet-stream"); - setSuffix(".arc", "application/octet-stream"); - setSuffix(".o", "application/octet-stream"); - setSuffix(".a", "application/octet-stream"); - setSuffix(".bin", "application/octet-stream"); - setSuffix(".exe", "application/octet-stream"); - setSuffix(".z", "application/octet-stream"); - setSuffix(".gz", "application/octet-stream"); - setSuffix(".oda", "application/oda"); - setSuffix(".pdf", "application/pdf"); - setSuffix(".eps", "application/postscript"); - setSuffix(".ai", "application/postscript"); - setSuffix(".ps", "application/postscript"); - setSuffix(".rtf", "application/rtf"); - setSuffix(".dvi", "application/x-dvi"); - setSuffix(".hdf", "application/x-hdf"); - setSuffix(".latex", "application/x-latex"); - setSuffix(".cdf", "application/x-netcdf"); - setSuffix(".nc", "application/x-netcdf"); - setSuffix(".tex", "application/x-tex"); - setSuffix(".texinfo", "application/x-texinfo"); - setSuffix(".texi", "application/x-texinfo"); - setSuffix(".t", "application/x-troff"); - setSuffix(".tr", "application/x-troff"); - setSuffix(".roff", "application/x-troff"); - setSuffix(".man", "application/x-troff-man"); - setSuffix(".me", "application/x-troff-me"); - setSuffix(".ms", "application/x-troff-ms"); - setSuffix(".src", "application/x-wais-source"); - setSuffix(".wsrc", "application/x-wais-source"); - setSuffix(".zip", "application/zip"); - setSuffix(".bcpio", "application/x-bcpio"); - setSuffix(".cpio", "application/x-cpio"); - setSuffix(".gtar", "application/x-gtar"); - setSuffix(".shar", "application/x-shar"); - setSuffix(".sh", "application/x-shar"); - setSuffix(".sv4cpio", "application/x-sv4cpio"); - setSuffix(".sv4crc", "application/x-sv4crc"); - setSuffix(".tar", "application/x-tar"); - setSuffix(".ustar", "application/x-ustar"); - setSuffix(".snd", "audio/basic"); - setSuffix(".au", "audio/basic"); - setSuffix(".aifc", "audio/x-aiff"); - setSuffix(".aif", "audio/x-aiff"); - setSuffix(".aiff", "audio/x-aiff"); - setSuffix(".wav", "audio/x-wav"); - setSuffix(".gif", "image/gif"); - setSuffix(".ief", "image/ief"); - setSuffix(".jfif", "image/jpeg"); - setSuffix(".jfif-tbnl", "image/jpeg"); - setSuffix(".jpe", "image/jpeg"); - setSuffix(".jpg", "image/jpeg"); - setSuffix(".jpeg", "image/jpeg"); - setSuffix(".tif", "image/tiff"); - setSuffix(".tiff", "image/tiff"); - setSuffix(".ras", "image/x-cmu-rast"); - setSuffix(".pnm", "image/x-portable-anymap"); - setSuffix(".pbm", "image/x-portable-bitmap"); - setSuffix(".pgm", "image/x-portable-graymap"); - setSuffix(".ppm", "image/x-portable-pixmap"); - setSuffix(".rgb", "image/x-rgb"); - setSuffix(".xbm", "image/x-xbitmap"); - setSuffix(".xpm", "image/x-xpixmap"); - setSuffix(".xwd", "image/x-xwindowdump"); - setSuffix(".htm", "text/html"); - setSuffix(".html", "text/html"); - setSuffix(".text", "text/plain"); - setSuffix(".c", "text/plain"); - setSuffix(".cc", "text/plain"); - setSuffix(".c++", "text/plain"); - setSuffix(".h", "text/plain"); - setSuffix(".pl", "text/plain"); - setSuffix(".txt", "text/plain"); - setSuffix(".java", "text/plain"); - setSuffix(".rtx", "application/rtf"); - setSuffix(".tsv", "texyt/tab-separated-values"); - setSuffix(".etx", "text/x-setext"); - setSuffix(".mpg", "video/mpeg"); - setSuffix(".mpe", "video/mpeg"); - setSuffix(".mpeg", "video/mpeg"); - setSuffix(".mov", "video/quicktime"); - setSuffix(".qt", "video/quicktime"); - setSuffix(".avi", "application/x-troff-msvideo"); - setSuffix(".movie", "video/x-sgi-movie"); - setSuffix(".mv", "video/x-sgi-movie"); - setSuffix(".mime", "message/rfc822"); - } - - /** - * A useful utility routine that tries to guess the content-type - * of an object based upon its extension. - */ - public static String guessContentTypeFromName(String fname) { - String ext = ""; - int i = fname.lastIndexOf('#'); - - if (i != -1) - fname = fname.substring(0, i - 1); - i = fname.lastIndexOf('.'); - i = Math.max(i, fname.lastIndexOf('/')); - i = Math.max(i, fname.lastIndexOf('?')); - - if (i != -1 && fname.charAt(i) == '.') { - ext = fname.substring(i).toLowerCase(); - } - return (String) extension_map.get(ext); - } - - public static MimeType getMimeType(String filename) { - try { - return new MimeType(guessContentTypeFromName(filename)); - } catch (MimeTypeFormatException ex) { - return null; - } - } - -}