| // |
| // ======================================================================== |
| // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. |
| // ------------------------------------------------------------------------ |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // and Apache License v2.0 which accompanies this distribution. |
| // |
| // The Eclipse Public License is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // The Apache License v2.0 is available at |
| // http://www.opensource.org/licenses/apache2.0.php |
| // |
| // You may elect to redistribute this code under either of these licenses. |
| // ======================================================================== |
| // |
| |
| package org.eclipse.jetty.http; |
| |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| |
| import org.eclipse.jetty.io.Buffer; |
| import org.eclipse.jetty.io.BufferCache; |
| import org.eclipse.jetty.io.BufferCache.CachedBuffer; |
| import org.eclipse.jetty.util.StringUtil; |
| import org.eclipse.jetty.util.log.Log; |
| import org.eclipse.jetty.util.log.Logger; |
| |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * |
| */ |
| public class MimeTypes |
| { |
| private static final Logger LOG = Log.getLogger(MimeTypes.class); |
| |
| public final static String |
| FORM_ENCODED="application/x-www-form-urlencoded", |
| MESSAGE_HTTP="message/http", |
| MULTIPART_BYTERANGES="multipart/byteranges", |
| |
| TEXT_HTML="text/html", |
| TEXT_PLAIN="text/plain", |
| TEXT_XML="text/xml", |
| TEXT_JSON="text/json", |
| |
| TEXT_HTML_8859_1="text/html;charset=ISO-8859-1", |
| TEXT_PLAIN_8859_1="text/plain;charset=ISO-8859-1", |
| TEXT_XML_8859_1="text/xml;charset=ISO-8859-1", |
| |
| TEXT_HTML_UTF_8="text/html;charset=UTF-8", |
| TEXT_PLAIN_UTF_8="text/plain;charset=UTF-8", |
| TEXT_XML_UTF_8="text/xml;charset=UTF-8", |
| TEXT_JSON_UTF_8="text/json;charset=UTF-8"; |
| |
| private final static String |
| TEXT_HTML__8859_1="text/html; charset=ISO-8859-1", |
| TEXT_PLAIN__8859_1="text/plain; charset=ISO-8859-1", |
| TEXT_XML__8859_1="text/xml; charset=ISO-8859-1", |
| TEXT_HTML__UTF_8="text/html; charset=UTF-8", |
| TEXT_PLAIN__UTF_8="text/plain; charset=UTF-8", |
| TEXT_XML__UTF_8="text/xml; charset=UTF-8", |
| TEXT_JSON__UTF_8="text/json; charset=UTF-8"; |
| |
| private final static int |
| FORM_ENCODED_ORDINAL=1, |
| MESSAGE_HTTP_ORDINAL=2, |
| MULTIPART_BYTERANGES_ORDINAL=3, |
| |
| TEXT_HTML_ORDINAL=4, |
| TEXT_PLAIN_ORDINAL=5, |
| TEXT_XML_ORDINAL=6, |
| TEXT_JSON_ORDINAL=7, |
| |
| TEXT_HTML_8859_1_ORDINAL=8, |
| TEXT_PLAIN_8859_1_ORDINAL=9, |
| TEXT_XML_8859_1_ORDINAL=10, |
| |
| TEXT_HTML_UTF_8_ORDINAL=11, |
| TEXT_PLAIN_UTF_8_ORDINAL=12, |
| TEXT_XML_UTF_8_ORDINAL=13, |
| TEXT_JSON_UTF_8_ORDINAL=14; |
| |
| private static int __index=15; |
| |
| public final static BufferCache CACHE = new BufferCache(); |
| |
| public final static CachedBuffer |
| FORM_ENCODED_BUFFER=CACHE.add(FORM_ENCODED,FORM_ENCODED_ORDINAL), |
| MESSAGE_HTTP_BUFFER=CACHE.add(MESSAGE_HTTP, MESSAGE_HTTP_ORDINAL), |
| MULTIPART_BYTERANGES_BUFFER=CACHE.add(MULTIPART_BYTERANGES,MULTIPART_BYTERANGES_ORDINAL), |
| |
| TEXT_HTML_BUFFER=CACHE.add(TEXT_HTML,TEXT_HTML_ORDINAL), |
| TEXT_PLAIN_BUFFER=CACHE.add(TEXT_PLAIN,TEXT_PLAIN_ORDINAL), |
| TEXT_XML_BUFFER=CACHE.add(TEXT_XML,TEXT_XML_ORDINAL), |
| TEXT_JSON_BUFFER=CACHE.add(TEXT_JSON,TEXT_JSON_ORDINAL), |
| |
| TEXT_HTML_8859_1_BUFFER=CACHE.add(TEXT_HTML_8859_1,TEXT_HTML_8859_1_ORDINAL), |
| TEXT_PLAIN_8859_1_BUFFER=CACHE.add(TEXT_PLAIN_8859_1,TEXT_PLAIN_8859_1_ORDINAL), |
| TEXT_XML_8859_1_BUFFER=CACHE.add(TEXT_XML_8859_1,TEXT_XML_8859_1_ORDINAL), |
| |
| TEXT_HTML_UTF_8_BUFFER=CACHE.add(TEXT_HTML_UTF_8,TEXT_HTML_UTF_8_ORDINAL), |
| TEXT_PLAIN_UTF_8_BUFFER=CACHE.add(TEXT_PLAIN_UTF_8,TEXT_PLAIN_UTF_8_ORDINAL), |
| TEXT_XML_UTF_8_BUFFER=CACHE.add(TEXT_XML_UTF_8,TEXT_XML_UTF_8_ORDINAL), |
| TEXT_JSON_UTF_8_BUFFER=CACHE.add(TEXT_JSON_UTF_8,TEXT_JSON_UTF_8_ORDINAL), |
| |
| TEXT_HTML__8859_1_BUFFER=CACHE.add(TEXT_HTML__8859_1,TEXT_HTML_8859_1_ORDINAL), |
| TEXT_PLAIN__8859_1_BUFFER=CACHE.add(TEXT_PLAIN__8859_1,TEXT_PLAIN_8859_1_ORDINAL), |
| TEXT_XML__8859_1_BUFFER=CACHE.add(TEXT_XML__8859_1,TEXT_XML_8859_1_ORDINAL), |
| |
| TEXT_HTML__UTF_8_BUFFER=CACHE.add(TEXT_HTML__UTF_8,TEXT_HTML_UTF_8_ORDINAL), |
| TEXT_PLAIN__UTF_8_BUFFER=CACHE.add(TEXT_PLAIN__UTF_8,TEXT_PLAIN_UTF_8_ORDINAL), |
| TEXT_XML__UTF_8_BUFFER=CACHE.add(TEXT_XML__UTF_8,TEXT_XML_UTF_8_ORDINAL), |
| TEXT_JSON__UTF_8_BUFFER=CACHE.add(TEXT_JSON__UTF_8,TEXT_JSON_UTF_8_ORDINAL); |
| |
| |
| /* ------------------------------------------------------------ */ |
| /* ------------------------------------------------------------ */ |
| private final static Map __dftMimeMap = new HashMap(); |
| private final static Map __encodings = new HashMap(); |
| static |
| { |
| try |
| { |
| ResourceBundle mime = ResourceBundle.getBundle("org/eclipse/jetty/http/mime"); |
| Enumeration i = mime.getKeys(); |
| while(i.hasMoreElements()) |
| { |
| String ext = (String)i.nextElement(); |
| String m = mime.getString(ext); |
| __dftMimeMap.put(StringUtil.asciiToLowerCase(ext),normalizeMimeType(m)); |
| } |
| } |
| catch(MissingResourceException e) |
| { |
| LOG.warn(e.toString()); |
| LOG.debug(e); |
| } |
| |
| try |
| { |
| ResourceBundle encoding = ResourceBundle.getBundle("org/eclipse/jetty/http/encoding"); |
| Enumeration i = encoding.getKeys(); |
| while(i.hasMoreElements()) |
| { |
| Buffer type = normalizeMimeType((String)i.nextElement()); |
| __encodings.put(type,encoding.getString(type.toString())); |
| } |
| } |
| catch(MissingResourceException e) |
| { |
| LOG.warn(e.toString()); |
| LOG.debug(e); |
| } |
| |
| |
| TEXT_HTML_BUFFER.setAssociate("ISO-8859-1",TEXT_HTML_8859_1_BUFFER); |
| TEXT_HTML_BUFFER.setAssociate("ISO_8859_1",TEXT_HTML_8859_1_BUFFER); |
| TEXT_HTML_BUFFER.setAssociate("iso-8859-1",TEXT_HTML_8859_1_BUFFER); |
| TEXT_PLAIN_BUFFER.setAssociate("ISO-8859-1",TEXT_PLAIN_8859_1_BUFFER); |
| TEXT_PLAIN_BUFFER.setAssociate("ISO_8859_1",TEXT_PLAIN_8859_1_BUFFER); |
| TEXT_PLAIN_BUFFER.setAssociate("iso-8859-1",TEXT_PLAIN_8859_1_BUFFER); |
| TEXT_XML_BUFFER.setAssociate("ISO-8859-1",TEXT_XML_8859_1_BUFFER); |
| TEXT_XML_BUFFER.setAssociate("ISO_8859_1",TEXT_XML_8859_1_BUFFER); |
| TEXT_XML_BUFFER.setAssociate("iso-8859-1",TEXT_XML_8859_1_BUFFER); |
| |
| TEXT_HTML_BUFFER.setAssociate("UTF-8",TEXT_HTML_UTF_8_BUFFER); |
| TEXT_HTML_BUFFER.setAssociate("UTF8",TEXT_HTML_UTF_8_BUFFER); |
| TEXT_HTML_BUFFER.setAssociate("utf8",TEXT_HTML_UTF_8_BUFFER); |
| TEXT_HTML_BUFFER.setAssociate("utf-8",TEXT_HTML_UTF_8_BUFFER); |
| TEXT_PLAIN_BUFFER.setAssociate("UTF-8",TEXT_PLAIN_UTF_8_BUFFER); |
| TEXT_PLAIN_BUFFER.setAssociate("UTF8",TEXT_PLAIN_UTF_8_BUFFER); |
| TEXT_PLAIN_BUFFER.setAssociate("utf8",TEXT_PLAIN_UTF_8_BUFFER); |
| TEXT_PLAIN_BUFFER.setAssociate("utf-8",TEXT_PLAIN_UTF_8_BUFFER); |
| TEXT_XML_BUFFER.setAssociate("UTF-8",TEXT_XML_UTF_8_BUFFER); |
| TEXT_XML_BUFFER.setAssociate("UTF8",TEXT_XML_UTF_8_BUFFER); |
| TEXT_XML_BUFFER.setAssociate("utf8",TEXT_XML_UTF_8_BUFFER); |
| TEXT_XML_BUFFER.setAssociate("utf-8",TEXT_XML_UTF_8_BUFFER); |
| TEXT_JSON_BUFFER.setAssociate("UTF-8",TEXT_JSON_UTF_8_BUFFER); |
| TEXT_JSON_BUFFER.setAssociate("UTF8",TEXT_JSON_UTF_8_BUFFER); |
| TEXT_JSON_BUFFER.setAssociate("utf8",TEXT_JSON_UTF_8_BUFFER); |
| TEXT_JSON_BUFFER.setAssociate("utf-8",TEXT_JSON_UTF_8_BUFFER); |
| } |
| |
| |
| /* ------------------------------------------------------------ */ |
| private Map _mimeMap; |
| |
| /* ------------------------------------------------------------ */ |
| /** Constructor. |
| */ |
| public MimeTypes() |
| { |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public synchronized Map getMimeMap() |
| { |
| return _mimeMap; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** |
| * @param mimeMap A Map of file extension to mime-type. |
| */ |
| public void setMimeMap(Map mimeMap) |
| { |
| if (mimeMap==null) |
| { |
| _mimeMap=null; |
| return; |
| } |
| |
| Map m=new HashMap(); |
| Iterator i=mimeMap.entrySet().iterator(); |
| while (i.hasNext()) |
| { |
| Map.Entry entry = (Map.Entry)i.next(); |
| m.put(entry.getKey(),normalizeMimeType(entry.getValue().toString())); |
| } |
| _mimeMap=m; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** Get the MIME type by filename extension. |
| * @param filename A file name |
| * @return MIME type matching the longest dot extension of the |
| * file name. |
| */ |
| public Buffer getMimeByExtension(String filename) |
| { |
| Buffer type=null; |
| |
| if (filename!=null) |
| { |
| int i=-1; |
| while(type==null) |
| { |
| i=filename.indexOf(".",i+1); |
| |
| if (i<0 || i>=filename.length()) |
| break; |
| |
| String ext=StringUtil.asciiToLowerCase(filename.substring(i+1)); |
| if (_mimeMap!=null) |
| type = (Buffer)_mimeMap.get(ext); |
| if (type==null) |
| type=(Buffer)__dftMimeMap.get(ext); |
| } |
| } |
| |
| if (type==null) |
| { |
| if (_mimeMap!=null) |
| type=(Buffer)_mimeMap.get("*"); |
| if (type==null) |
| type=(Buffer)__dftMimeMap.get("*"); |
| } |
| |
| return type; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| /** Set a mime mapping |
| * @param extension |
| * @param type |
| */ |
| public void addMimeMapping(String extension,String type) |
| { |
| if (_mimeMap==null) |
| _mimeMap=new HashMap(); |
| |
| _mimeMap.put(StringUtil.asciiToLowerCase(extension),normalizeMimeType(type)); |
| } |
| |
| /* ------------------------------------------------------------ */ |
| private static synchronized Buffer normalizeMimeType(String type) |
| { |
| Buffer b =CACHE.get(type); |
| if (b==null) |
| b=CACHE.add(type,__index++); |
| return b; |
| } |
| |
| /* ------------------------------------------------------------ */ |
| public static String getCharsetFromContentType(Buffer value) |
| { |
| if (value instanceof CachedBuffer) |
| { |
| switch(((CachedBuffer)value).getOrdinal()) |
| { |
| case TEXT_HTML_8859_1_ORDINAL: |
| case TEXT_PLAIN_8859_1_ORDINAL: |
| case TEXT_XML_8859_1_ORDINAL: |
| return StringUtil.__ISO_8859_1; |
| |
| case TEXT_HTML_UTF_8_ORDINAL: |
| case TEXT_PLAIN_UTF_8_ORDINAL: |
| case TEXT_XML_UTF_8_ORDINAL: |
| case TEXT_JSON_UTF_8_ORDINAL: |
| return StringUtil.__UTF8; |
| } |
| } |
| |
| int i=value.getIndex(); |
| int end=value.putIndex(); |
| int state=0; |
| int start=0; |
| boolean quote=false; |
| for (;i<end;i++) |
| { |
| byte b = value.peek(i); |
| |
| if (quote && state!=10) |
| { |
| if ('"'==b) |
| quote=false; |
| continue; |
| } |
| |
| switch(state) |
| { |
| case 0: |
| if ('"'==b) |
| { |
| quote=true; |
| break; |
| } |
| if (';'==b) |
| state=1; |
| break; |
| |
| case 1: if ('c'==b) state=2; else if (' '!=b) state=0; break; |
| case 2: if ('h'==b) state=3; else state=0;break; |
| case 3: if ('a'==b) state=4; else state=0;break; |
| case 4: if ('r'==b) state=5; else state=0;break; |
| case 5: if ('s'==b) state=6; else state=0;break; |
| case 6: if ('e'==b) state=7; else state=0;break; |
| case 7: if ('t'==b) state=8; else state=0;break; |
| |
| case 8: if ('='==b) state=9; else if (' '!=b) state=0; break; |
| |
| case 9: |
| if (' '==b) |
| break; |
| if ('"'==b) |
| { |
| quote=true; |
| start=i+1; |
| state=10; |
| break; |
| } |
| start=i; |
| state=10; |
| break; |
| |
| case 10: |
| if (!quote && (';'==b || ' '==b )|| |
| (quote && '"'==b )) |
| return CACHE.lookup(value.peek(start,i-start)).toString(StringUtil.__UTF8); |
| } |
| } |
| |
| if (state==10) |
| return CACHE.lookup(value.peek(start,i-start)).toString(StringUtil.__UTF8); |
| |
| return (String)__encodings.get(value); |
| } |
| } |