view src/org/eclipse/jetty/http/MimeTypes.java @ 1023:27f3dc761452

MimeTypes uses StringCache
author Franklin Schmidt <fschmidt@gmail.com>
date Tue, 01 Nov 2016 03:44:46 -0600
parents 6be43ef1eb96
children 2b769da7f67d
line wrap: on
line source

//
//  ========================================================================
//  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.StringCache;
import org.eclipse.jetty.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public final class MimeTypes
{
	private static final Logger LOG = LoggerFactory.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 StringCache CACHE = new StringCache(); 

	public final static byte[]
		FORM_ENCODED_BYTES=CACHE.add(FORM_ENCODED,FORM_ENCODED_ORDINAL),
		MESSAGE_HTTP_BYTES=CACHE.add(MESSAGE_HTTP, MESSAGE_HTTP_ORDINAL),
		MULTIPART_BYTERANGES_BYTES=CACHE.add(MULTIPART_BYTERANGES,MULTIPART_BYTERANGES_ORDINAL),
		
		TEXT_HTML_BYTES=CACHE.add(TEXT_HTML,TEXT_HTML_ORDINAL),
		TEXT_PLAIN_BYTES=CACHE.add(TEXT_PLAIN,TEXT_PLAIN_ORDINAL),
		TEXT_XML_BYTES=CACHE.add(TEXT_XML,TEXT_XML_ORDINAL),
		TEXT_JSON_BYTES=CACHE.add(TEXT_JSON,TEXT_JSON_ORDINAL),

		TEXT_HTML_8859_1_BYTES=CACHE.add(TEXT_HTML_8859_1,TEXT_HTML_8859_1_ORDINAL),
		TEXT_PLAIN_8859_1_BYTES=CACHE.add(TEXT_PLAIN_8859_1,TEXT_PLAIN_8859_1_ORDINAL),
		TEXT_XML_8859_1_BYTES=CACHE.add(TEXT_XML_8859_1,TEXT_XML_8859_1_ORDINAL),
		
		TEXT_HTML_UTF_8_BYTES=CACHE.add(TEXT_HTML_UTF_8,TEXT_HTML_UTF_8_ORDINAL),
		TEXT_PLAIN_UTF_8_BYTES=CACHE.add(TEXT_PLAIN_UTF_8,TEXT_PLAIN_UTF_8_ORDINAL),
		TEXT_XML_UTF_8_BYTES=CACHE.add(TEXT_XML_UTF_8,TEXT_XML_UTF_8_ORDINAL),
		TEXT_JSON_UTF_8_BYTES=CACHE.add(TEXT_JSON_UTF_8,TEXT_JSON_UTF_8_ORDINAL),

		TEXT_HTML__8859_1_BYTES=CACHE.add(TEXT_HTML__8859_1,TEXT_HTML_8859_1_ORDINAL),
		TEXT_PLAIN__8859_1_BYTES=CACHE.add(TEXT_PLAIN__8859_1,TEXT_PLAIN_8859_1_ORDINAL),
		TEXT_XML__8859_1_BYTES=CACHE.add(TEXT_XML__8859_1,TEXT_XML_8859_1_ORDINAL),
		
		TEXT_HTML__UTF_8_BYTES=CACHE.add(TEXT_HTML__UTF_8,TEXT_HTML_UTF_8_ORDINAL),
		TEXT_PLAIN__UTF_8_BYTES=CACHE.add(TEXT_PLAIN__UTF_8,TEXT_PLAIN_UTF_8_ORDINAL),
		TEXT_XML__UTF_8_BYTES=CACHE.add(TEXT_XML__UTF_8,TEXT_XML_UTF_8_ORDINAL),
		TEXT_JSON__UTF_8_BYTES=CACHE.add(TEXT_JSON__UTF_8,TEXT_JSON_UTF_8_ORDINAL);

	
	private final static Map<String,String> __dftMimeMap = new HashMap<String,String>();
	private final static Map<String,String> __encodings = new HashMap<String,String>();
	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(ext.toLowerCase(),normalizeMimeType(m));
				__dftMimeMap.put(ext.toLowerCase(),m);
			}
		}
		catch(MissingResourceException e)
		{
			LOG.warn(e.toString());
			LOG.debug("",e);
		}

		__encodings.put("text/html","ISO-8859-1");
		__encodings.put("text/plain","ISO-8859-1");
		__encodings.put("text/xml","UTF-8");
		__encodings.put("text/json","UTF-8");

/*
		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);
*/
	}

	// replace setAssociate()

	private static final Map<String,String> association = new HashMap<String,String>();

	private static String key(String type,String charEncoding) {
		return (type+'~'+charEncoding).toLowerCase();
	}

	private static void setAssociate(String type,String charEncoding,String result) {
		association.put( key(type,charEncoding), result );
	}

	public static String getAssociate(String type,String charEncoding) {
		return association.get( key(type,charEncoding) );
	}

	static {
		setAssociate(TEXT_HTML,"ISO-8859-1",TEXT_HTML_8859_1);
		setAssociate(TEXT_HTML,"ISO_8859_1",TEXT_HTML_8859_1);
		setAssociate(TEXT_PLAIN,"ISO-8859-1",TEXT_PLAIN_8859_1);
		setAssociate(TEXT_PLAIN,"ISO_8859_1",TEXT_PLAIN_8859_1);
		setAssociate(TEXT_XML,"ISO-8859-1",TEXT_XML_8859_1);
		setAssociate(TEXT_XML,"ISO_8859_1",TEXT_XML_8859_1);

		setAssociate(TEXT_HTML,"UTF-8",TEXT_HTML_UTF_8);
		setAssociate(TEXT_HTML,"UTF8",TEXT_HTML_UTF_8);
		setAssociate(TEXT_PLAIN,"UTF-8",TEXT_PLAIN_UTF_8);
		setAssociate(TEXT_PLAIN,"UTF8",TEXT_PLAIN_UTF_8);
		setAssociate(TEXT_XML,"UTF-8",TEXT_XML_UTF_8);
		setAssociate(TEXT_XML,"UTF8",TEXT_XML_UTF_8);
		setAssociate(TEXT_JSON,"UTF-8",TEXT_JSON_UTF_8);
		setAssociate(TEXT_JSON,"UTF8",TEXT_JSON_UTF_8);
	}


	
	/* ------------------------------------------------------------ */
	/** 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 = filename.substring(i+1).toLowerCase();
				type = __dftMimeMap.get(ext);
			}
		}

		if (type==null)
		{
			 type = __dftMimeMap.get("*");
		}

		return 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(String value)
	{
		switch(CACHE.getOrdinal(value))
		{
			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 = 0;
		int end = value.length();
		int state=0;
		int start=0;
		boolean quote=false;
		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 value.substring(start,i);
			}
		}    
		
		if (state==10)
			return value.substring(start,i);
		
		return __encodings.get(value.toLowerCase());
	}
}