]> WPIA git - gigi.git/blobdiff - lib/jetty/org/eclipse/jetty/http/MimeTypes.java
Importing upstream Jetty jetty-9.2.1.v20140609
[gigi.git] / lib / jetty / org / eclipse / jetty / http / MimeTypes.java
diff --git a/lib/jetty/org/eclipse/jetty/http/MimeTypes.java b/lib/jetty/org/eclipse/jetty/http/MimeTypes.java
new file mode 100644 (file)
index 0000000..9cac4ab
--- /dev/null
@@ -0,0 +1,485 @@
+//
+//  ========================================================================
+//  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.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import org.eclipse.jetty.util.ArrayTrie;
+import org.eclipse.jetty.util.BufferUtil;
+import org.eclipse.jetty.util.StringUtil;
+import org.eclipse.jetty.util.Trie;
+import org.eclipse.jetty.util.log.Log;
+import org.eclipse.jetty.util.log.Logger;
+
+
+/* ------------------------------------------------------------ */
+/**
+ * 
+ */
+public class MimeTypes
+{
+    public enum Type
+    {
+        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",StandardCharsets.UTF_8),
+        APPLICATION_JSON("application/json",StandardCharsets.UTF_8),
+
+        TEXT_HTML_8859_1("text/html; charset=ISO-8859-1",TEXT_HTML),
+        TEXT_HTML_UTF_8("text/html; charset=UTF-8",TEXT_HTML),
+        
+        TEXT_PLAIN_8859_1("text/plain; charset=ISO-8859-1",TEXT_PLAIN),
+        TEXT_PLAIN_UTF_8("text/plain; charset=UTF-8",TEXT_PLAIN),
+        
+        TEXT_XML_8859_1("text/xml; charset=ISO-8859-1",TEXT_XML),
+        TEXT_XML_UTF_8("text/xml; charset=UTF-8",TEXT_XML),
+        
+        TEXT_JSON_8859_1("text/json; charset=ISO-8859-1",TEXT_JSON),
+        TEXT_JSON_UTF_8("text/json; charset=UTF-8",TEXT_JSON),
+        
+        APPLICATION_JSON_8859_1("text/json; charset=ISO-8859-1",APPLICATION_JSON),
+        APPLICATION_JSON_UTF_8("text/json; charset=UTF-8",APPLICATION_JSON);
+
+
+        /* ------------------------------------------------------------ */
+        private final String _string;
+        private final Type _base;
+        private final ByteBuffer _buffer;
+        private final Charset _charset;
+        private final boolean _assumedCharset;
+        private final HttpField _field;
+
+        /* ------------------------------------------------------------ */
+        Type(String s)
+        {
+            _string=s;
+            _buffer=BufferUtil.toBuffer(s);
+            _base=this;
+            _charset=null;
+            _assumedCharset=false;
+            _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string);
+        } 
+
+        /* ------------------------------------------------------------ */
+        Type(String s,Type base)
+        {
+            _string=s;
+            _buffer=BufferUtil.toBuffer(s);
+            _base=base;
+            int i=s.indexOf("; charset=");
+            _charset=Charset.forName(s.substring(i+10));
+            _assumedCharset=false;
+            _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string);
+        }
+
+        /* ------------------------------------------------------------ */
+        Type(String s,Charset cs)
+        {
+            _string=s;
+            _base=this;
+            _buffer=BufferUtil.toBuffer(s);
+            _charset=cs;
+            _assumedCharset=true;
+            _field=new HttpGenerator.CachedHttpField(HttpHeader.CONTENT_TYPE,_string);
+        }
+
+        /* ------------------------------------------------------------ */
+        public ByteBuffer asBuffer()
+        {
+            return _buffer.asReadOnlyBuffer();
+        }
+        
+        /* ------------------------------------------------------------ */
+        public Charset getCharset()
+        {
+            return _charset;
+        }
+        
+        /* ------------------------------------------------------------ */
+        public boolean is(String s)
+        {
+            return _string.equalsIgnoreCase(s);    
+        }
+
+        /* ------------------------------------------------------------ */
+        public String asString()
+        {
+            return _string;
+        }
+        
+        /* ------------------------------------------------------------ */
+        @Override
+        public String toString()
+        {
+            return _string;
+        }
+
+        /* ------------------------------------------------------------ */
+        public boolean isCharsetAssumed()
+        {
+            return _assumedCharset;
+        }
+
+        /* ------------------------------------------------------------ */
+        public HttpField getContentTypeField()
+        {
+            return _field;
+        }
+
+        /* ------------------------------------------------------------ */
+        public Type getBaseType()
+        {
+            return _base;
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    private static final Logger LOG = Log.getLogger(MimeTypes.class);
+    public  final static Trie<MimeTypes.Type> CACHE= new ArrayTrie<>(512);
+    private final static Trie<ByteBuffer> TYPES= new ArrayTrie<ByteBuffer>(512);
+    private final static Map<String,String> __dftMimeMap = new HashMap<String,String>();
+    private final static Map<String,String> __encodings = new HashMap<String,String>();
+
+    static
+    {
+        for (MimeTypes.Type type : MimeTypes.Type.values())
+        {
+            CACHE.put(type.toString(),type);
+            TYPES.put(type.toString(),type.asBuffer());
+
+            int charset=type.toString().indexOf(";charset=");
+            if (charset>0)
+            {
+                CACHE.put(type.toString().replace(";charset=","; charset="),type);
+                TYPES.put(type.toString().replace(";charset=","; charset="),type.asBuffer());
+            }
+        }
+
+        try
+        {
+            ResourceBundle mime = ResourceBundle.getBundle("org/eclipse/jetty/http/mime");
+            Enumeration<String> i = mime.getKeys();
+            while(i.hasMoreElements())
+            {
+                String ext = 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<String> i = encoding.getKeys();
+            while(i.hasMoreElements())
+            {
+                String type = i.nextElement();
+                __encodings.put(type,encoding.getString(type));
+            }
+        }
+        catch(MissingResourceException e)
+        {
+            LOG.warn(e.toString());
+            LOG.debug(e);
+        }
+    }
+
+
+    /* ------------------------------------------------------------ */
+    private final Map<String,String> _mimeMap=new HashMap<String,String>();
+
+    /* ------------------------------------------------------------ */
+    /** Constructor.
+     */
+    public MimeTypes()
+    {
+    }
+
+    /* ------------------------------------------------------------ */
+    public synchronized Map<String,String> getMimeMap()
+    {
+        return _mimeMap;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @param mimeMap A Map of file extension to mime-type.
+     */
+    public void setMimeMap(Map<String,String> mimeMap)
+    {
+        _mimeMap.clear();
+        if (mimeMap!=null)
+        {
+            for (Entry<String, String> ext : mimeMap.entrySet())
+                _mimeMap.put(StringUtil.asciiToLowerCase(ext.getKey()),normalizeMimeType(ext.getValue()));
+        }
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** 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 String getMimeByExtension(String filename)
+    {
+        String 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=_mimeMap.get(ext);
+                if (type==null)
+                    type=__dftMimeMap.get(ext);
+            }
+        }
+
+        if (type==null)
+        {
+            if (_mimeMap!=null)
+                type=_mimeMap.get("*");
+            if (type==null)
+                type=__dftMimeMap.get("*");
+        }
+
+        return type;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set a mime mapping
+     * @param extension
+     * @param type
+     */
+    public void addMimeMapping(String extension,String type)
+    {
+        _mimeMap.put(StringUtil.asciiToLowerCase(extension),normalizeMimeType(type));
+    }
+
+    /* ------------------------------------------------------------ */
+    public static Set<String> getKnownMimeTypes()
+    {
+        return new HashSet<>(__dftMimeMap.values());
+    }
+    
+    /* ------------------------------------------------------------ */
+    private static String normalizeMimeType(String type)
+    {
+        MimeTypes.Type t =CACHE.get(type);
+        if (t!=null)
+            return t.asString();
+
+        return StringUtil.asciiToLowerCase(type);
+    }
+
+    /* ------------------------------------------------------------ */
+    public static String getCharsetFromContentType(String value)
+    {
+        if (value==null)
+            return null;
+        int end=value.length();
+        int state=0;
+        int start=0;
+        boolean quote=false;
+        int i=0;
+        for (;i<end;i++)
+        {
+            char b = value.charAt(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 StringUtil.normalizeCharset(value,start,i-start);
+            }
+        }
+
+        if (state==10)
+            return StringUtil.normalizeCharset(value,start,i-start);
+
+        return null;
+    }
+
+    public static String inferCharsetFromContentType(String value)
+    {
+        return __encodings.get(value);
+    }
+    
+    public static String getContentTypeWithoutCharset(String value)
+    {
+        int end=value.length();
+        int state=0;
+        int start=0;
+        boolean quote=false;
+        int i=0;
+        StringBuilder builder=null;
+        for (;i<end;i++)
+        {
+            char b = value.charAt(i);
+
+            if ('"'==b)
+            {
+                if (quote)
+                {
+                    quote=false;
+                }
+                else
+                {
+                    quote=true;
+                }
+                
+                switch(state)
+                {
+                    case 11:
+                        builder.append(b);break;
+                    case 10:
+                        break;
+                    case 9:
+                        builder=new StringBuilder();
+                        builder.append(value,0,start+1);
+                        state=10;
+                        break;
+                    default:
+                        start=i;
+                        state=0;           
+                }
+                continue;
+            }
+            
+            if (quote)
+            {
+                if (builder!=null && state!=10)
+                    builder.append(b);
+                continue;
+            }
+
+            switch(state)
+            {
+                case 0:
+                    if (';'==b)
+                        state=1;
+                    else if (' '!=b)
+                        start=i;
+                    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;
+                    builder=new StringBuilder();
+                    builder.append(value,0,start+1);
+                    state=10;
+                    break;
+
+                case 10:
+                    if (';'==b)
+                    {
+                        builder.append(b);
+                        state=11;
+                    }
+                    break;
+                case 11:
+                    if (' '!=b)
+                        builder.append(b);
+            }
+        }
+        if (builder==null)
+            return value;
+        return builder.toString();
+
+    }
+}