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