View Javadoc

1   // ========================================================================
2   // Copyright 2000-2005 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // Licensed under the Apache License, Version 2.0 (the "License");
5   // you may not use this file except in compliance with the License.
6   // You may obtain a copy of the License at 
7   // http://www.apache.org/licenses/LICENSE-2.0
8   // Unless required by applicable law or agreed to in writing, software
9   // distributed under the License is distributed on an "AS IS" BASIS,
10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  // See the License for the specific language governing permissions and
12  // limitations under the License.
13  // ========================================================================
14  
15  package org.mortbay.jetty;
16  
17  import java.util.Enumeration;
18  import java.util.HashMap;
19  import java.util.Iterator;
20  import java.util.Map;
21  import java.util.MissingResourceException;
22  import java.util.ResourceBundle;
23  
24  import org.mortbay.io.Buffer;
25  import org.mortbay.io.BufferCache;
26  import org.mortbay.io.BufferCache.CachedBuffer;
27  import org.mortbay.log.Log;
28  import org.mortbay.util.StringUtil;
29  
30  
31  /* ------------------------------------------------------------ */
32  /** 
33   * @author Greg Wilkins
34   */
35  public class MimeTypes
36  {
37      public final static String
38        FORM_ENCODED="application/x-www-form-urlencoded",
39        MESSAGE_HTTP="message/http",
40        MULTIPART_BYTERANGES="multipart/byteranges",
41        TEXT_HTML="text/html",
42        TEXT_PLAIN="text/plain",
43        TEXT_XML="text/xml",
44        TEXT_HTML_8859_1="text/html; charset=iso-8859-1",
45        TEXT_PLAIN_8859_1="text/plain; charset=iso-8859-1",
46        TEXT_XML_8859_1="text/xml; charset=iso-8859-1",
47        TEXT_HTML_UTF_8="text/html; charset=utf-8",
48        TEXT_PLAIN_UTF_8="text/plain; charset=utf-8",
49        TEXT_XML_UTF_8="text/xml; charset=utf-8",
50      
51        // minimal changes for 6.1.12
52        TEXT_JSON="text/json",
53        TEXT_JSON_UTF_8="text/json;charset=UTF-8";
54      
55  
56      private final static int
57  	FORM_ENCODED_ORDINAL=1,
58      	MESSAGE_HTTP_ORDINAL=2,
59      	MULTIPART_BYTERANGES_ORDINAL=3,
60      	TEXT_HTML_ORDINAL=4,
61  	TEXT_PLAIN_ORDINAL=5,
62  	TEXT_XML_ORDINAL=6,
63          TEXT_HTML_8859_1_ORDINAL=7,
64          TEXT_PLAIN_8859_1_ORDINAL=8,
65          TEXT_XML_8859_1_ORDINAL=9,
66          TEXT_HTML_UTF_8_ORDINAL=10,
67          TEXT_PLAIN_UTF_8_ORDINAL=11,
68          TEXT_XML_UTF_8_ORDINAL=12,
69          TEXT_JSON_ORDINAL=13,
70          TEXT_JSON_UTF_8_ORDINAL=14;
71          
72          
73      
74      private static int __index=15;
75      
76      public final static BufferCache CACHE = new BufferCache(); 
77  
78      public final static CachedBuffer
79      	FORM_ENCODED_BUFFER=CACHE.add(FORM_ENCODED,FORM_ENCODED_ORDINAL),
80      	MESSAGE_HTTP_BUFFER=CACHE.add(MESSAGE_HTTP, MESSAGE_HTTP_ORDINAL),
81      	MULTIPART_BYTERANGES_BUFFER=CACHE.add(MULTIPART_BYTERANGES,MULTIPART_BYTERANGES_ORDINAL),
82          
83          TEXT_HTML_BUFFER=CACHE.add(TEXT_HTML,TEXT_HTML_ORDINAL),
84          TEXT_PLAIN_BUFFER=CACHE.add(TEXT_PLAIN,TEXT_PLAIN_ORDINAL),
85          TEXT_XML_BUFFER=CACHE.add(TEXT_XML,TEXT_XML_ORDINAL),
86          
87      	TEXT_HTML_8859_1_BUFFER=new CachedBuffer(TEXT_HTML_8859_1,TEXT_HTML_8859_1_ORDINAL),
88      	TEXT_PLAIN_8859_1_BUFFER=new CachedBuffer(TEXT_PLAIN_8859_1,TEXT_PLAIN_8859_1_ORDINAL),
89      	TEXT_XML_8859_1_BUFFER=new CachedBuffer(TEXT_XML_8859_1,TEXT_XML_8859_1_ORDINAL),
90          TEXT_HTML_UTF_8_BUFFER=new CachedBuffer(TEXT_HTML_UTF_8,TEXT_HTML_UTF_8_ORDINAL),
91          TEXT_PLAIN_UTF_8_BUFFER=new CachedBuffer(TEXT_PLAIN_UTF_8,TEXT_PLAIN_UTF_8_ORDINAL),
92          TEXT_XML_UTF_8_BUFFER=new CachedBuffer(TEXT_XML_UTF_8,TEXT_XML_UTF_8_ORDINAL),
93      
94          TEXT_JSON_BUFFER=CACHE.add(TEXT_JSON,TEXT_JSON_ORDINAL),
95          TEXT_JSON_UTF_8_BUFFER=CACHE.add(TEXT_JSON_UTF_8,TEXT_JSON_UTF_8_ORDINAL);
96      
97      
98      /* ------------------------------------------------------------ */
99      /* ------------------------------------------------------------ */
100     private final static Map __dftMimeMap = new HashMap();
101     private final static Map __encodings = new HashMap();
102     static
103     {
104         try
105         {
106             ResourceBundle mime = ResourceBundle.getBundle("org/mortbay/jetty/mime");
107             Enumeration i = mime.getKeys();
108             while(i.hasMoreElements())
109             {
110                 String ext = (String)i.nextElement();
111                 String m = mime.getString(ext);
112                 __dftMimeMap.put(StringUtil.asciiToLowerCase(ext),normalizeMimeType(m));
113             }
114         }
115         catch(MissingResourceException e)
116         {
117             Log.warn(e.toString());
118             Log.debug(e);
119         }
120 
121         try
122         {
123             ResourceBundle encoding = ResourceBundle.getBundle("org/mortbay/jetty/encoding");
124             Enumeration i = encoding.getKeys();
125             while(i.hasMoreElements())
126             {
127                 Buffer type = normalizeMimeType((String)i.nextElement());
128                 __encodings.put(type,encoding.getString(type.toString()));
129             }
130         }
131         catch(MissingResourceException e)
132         {
133             Log.warn(e.toString());
134             Log.debug(e);
135         }
136 
137         
138         TEXT_HTML_BUFFER.setAssociate("ISO-8859-1",TEXT_HTML_8859_1_BUFFER);
139         TEXT_HTML_BUFFER.setAssociate("ISO_8859_1",TEXT_HTML_8859_1_BUFFER);
140         TEXT_HTML_BUFFER.setAssociate("iso-8859-1",TEXT_HTML_8859_1_BUFFER);
141         TEXT_PLAIN_BUFFER.setAssociate("ISO-8859-1",TEXT_PLAIN_8859_1_BUFFER);
142         TEXT_PLAIN_BUFFER.setAssociate("ISO_8859_1",TEXT_PLAIN_8859_1_BUFFER);
143         TEXT_PLAIN_BUFFER.setAssociate("iso-8859-1",TEXT_PLAIN_8859_1_BUFFER);
144         TEXT_XML_BUFFER.setAssociate("ISO-8859-1",TEXT_XML_8859_1_BUFFER);
145         TEXT_XML_BUFFER.setAssociate("ISO_8859_1",TEXT_XML_8859_1_BUFFER);
146         TEXT_XML_BUFFER.setAssociate("iso-8859-1",TEXT_XML_8859_1_BUFFER);
147 
148         TEXT_HTML_BUFFER.setAssociate("UTF-8",TEXT_HTML_UTF_8_BUFFER);
149         TEXT_HTML_BUFFER.setAssociate("UTF8",TEXT_HTML_UTF_8_BUFFER);
150         TEXT_HTML_BUFFER.setAssociate("utf8",TEXT_HTML_UTF_8_BUFFER);
151         TEXT_HTML_BUFFER.setAssociate("utf-8",TEXT_HTML_UTF_8_BUFFER);
152         TEXT_PLAIN_BUFFER.setAssociate("UTF-8",TEXT_PLAIN_UTF_8_BUFFER);
153         TEXT_PLAIN_BUFFER.setAssociate("UTF8",TEXT_PLAIN_UTF_8_BUFFER);
154         TEXT_PLAIN_BUFFER.setAssociate("utf-8",TEXT_PLAIN_UTF_8_BUFFER);
155         TEXT_XML_BUFFER.setAssociate("UTF-8",TEXT_XML_UTF_8_BUFFER);
156         TEXT_XML_BUFFER.setAssociate("utf8",TEXT_XML_UTF_8_BUFFER);
157         TEXT_XML_BUFFER.setAssociate("UTF8",TEXT_XML_UTF_8_BUFFER);
158         TEXT_XML_BUFFER.setAssociate("utf-8",TEXT_XML_UTF_8_BUFFER);
159         
160         TEXT_JSON_BUFFER.setAssociate("UTF-8",TEXT_JSON_UTF_8_BUFFER);
161         TEXT_JSON_BUFFER.setAssociate("utf8",TEXT_JSON_UTF_8_BUFFER);
162         TEXT_JSON_BUFFER.setAssociate("UTF8",TEXT_JSON_UTF_8_BUFFER);
163         TEXT_JSON_BUFFER.setAssociate("utf-8",TEXT_JSON_UTF_8_BUFFER);
164     }
165 
166 
167     /* ------------------------------------------------------------ */
168     private Map _mimeMap;
169     
170     /* ------------------------------------------------------------ */
171     /** Constructor.
172      */
173     public MimeTypes()
174     {
175     }
176 
177     /* ------------------------------------------------------------ */
178     public synchronized Map getMimeMap()
179     {
180         return _mimeMap;
181     }
182 
183     /* ------------------------------------------------------------ */
184     /**
185      * @param mimeMap A Map of file extension to mime-type.
186      */
187     public void setMimeMap(Map mimeMap)
188     {
189         if (mimeMap==null)
190         {
191             _mimeMap=null;
192             return;
193         }
194         
195         Map m=new HashMap();
196         Iterator i=mimeMap.entrySet().iterator();
197         while (i.hasNext())
198         {
199             Map.Entry entry = (Map.Entry)i.next();
200             m.put(entry.getKey(),normalizeMimeType(entry.getValue().toString()));
201         }
202         _mimeMap=m;
203     }
204 
205     /* ------------------------------------------------------------ */
206     /** Get the MIME type by filename extension.
207      * @param filename A file name
208      * @return MIME type matching the longest dot extension of the
209      * file name.
210      */
211     public Buffer getMimeByExtension(String filename)
212     {
213         Buffer type=null;
214 
215         if (filename!=null)
216         {
217             int i=-1;
218             while(type==null)
219             {
220                 i=filename.indexOf(".",i+1);
221 
222                 if (i<0 || i>=filename.length())
223                     break;
224 
225                 String ext=StringUtil.asciiToLowerCase(filename.substring(i+1));
226                 if (_mimeMap!=null)
227                     type = (Buffer)_mimeMap.get(ext);
228                 if (type==null)
229                     type=(Buffer)__dftMimeMap.get(ext);
230             }
231         }
232 
233         if (type==null)
234         {
235             if (_mimeMap!=null)
236                 type=(Buffer)_mimeMap.get("*");
237              if (type==null)
238                  type=(Buffer)__dftMimeMap.get("*");
239         }
240 
241         return type;
242     }
243 
244     /* ------------------------------------------------------------ */
245     /** Set a mime mapping
246      * @param extension
247      * @param type
248      */
249     public void addMimeMapping(String extension,String type)
250     {
251         if (_mimeMap==null)
252             _mimeMap=new HashMap();
253         
254         _mimeMap.put(StringUtil.asciiToLowerCase(extension),normalizeMimeType(type));
255     }
256 
257     /* ------------------------------------------------------------ */
258     private static synchronized Buffer normalizeMimeType(String type)
259     {
260         Buffer b =CACHE.get(type);
261         if (b==null)
262             b=CACHE.add(type,__index++);
263         return b;
264     }
265 
266     /* ------------------------------------------------------------ */
267     public static String getCharsetFromContentType(Buffer value)
268     {
269         if (value instanceof CachedBuffer)
270         {
271             switch(((CachedBuffer)value).getOrdinal())
272             {
273                 case TEXT_HTML_8859_1_ORDINAL:
274                 case TEXT_PLAIN_8859_1_ORDINAL:
275                 case TEXT_XML_8859_1_ORDINAL:
276                     return StringUtil.__ISO_8859_1;
277                     
278                 case TEXT_HTML_UTF_8_ORDINAL:
279                 case TEXT_PLAIN_UTF_8_ORDINAL:
280                 case TEXT_XML_UTF_8_ORDINAL:
281                 case TEXT_JSON_ORDINAL:
282                 case TEXT_JSON_UTF_8_ORDINAL:
283                     return StringUtil.__UTF8;
284             }
285         }
286         
287         int i=value.getIndex();
288         int end=value.putIndex();
289         int state=0;
290         int start=0;
291         boolean quote=false;
292         for (;i<end;i++)
293         {
294             byte b = value.peek(i);
295             
296             if (quote && state!=10)
297             {
298                 if ('"'==b)
299                     quote=false;
300                 continue;
301             }
302                 
303             switch(state)
304             {
305                 case 0:
306                     if ('"'==b)
307                     {
308                         quote=true;
309                         break;
310                     }
311                     if (';'==b)
312                         state=1;
313                     break;
314 
315                 case 1: if ('c'==b) state=2; else if (' '!=b) state=0; break;
316                 case 2: if ('h'==b) state=3; else state=0;break;
317                 case 3: if ('a'==b) state=4; else state=0;break;
318                 case 4: if ('r'==b) state=5; else state=0;break;
319                 case 5: if ('s'==b) state=6; else state=0;break;
320                 case 6: if ('e'==b) state=7; else state=0;break;
321                 case 7: if ('t'==b) state=8; else state=0;break;
322 
323                 case 8: if ('='==b) state=9; else if (' '!=b) state=0; break;
324                 
325                 case 9: 
326                     if (' '==b) 
327                         break;
328                     if ('"'==b) 
329                     {
330                         quote=true;
331                         start=i+1;
332                         state=10;
333                         break;
334                     }
335                     start=i;
336                     state=10;
337                     break;
338                     
339                 case 10:
340                     if (!quote && (';'==b || ' '==b )||
341                         (quote && '"'==b ))
342                         return CACHE.lookup(value.peek(start,i-start)).toString();
343             }
344         }    
345         
346         if (state==10)
347             return CACHE.lookup(value.peek(start,i-start)).toString();
348         return null;
349         
350     }
351 
352 
353 }