|
|
|
@ -16,12 +16,20 @@
|
|
|
|
|
|
|
|
|
|
package org.springframework.boot.web.server;
|
|
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.Collections;
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
|
import java.util.Locale;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Map.Entry;
|
|
|
|
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
|
|
|
|
|
|
|
|
import org.springframework.aot.hint.RuntimeHints;
|
|
|
|
|
import org.springframework.aot.hint.RuntimeHintsRegistrar;
|
|
|
|
|
import org.springframework.core.io.ClassPathResource;
|
|
|
|
|
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
|
|
|
|
import org.springframework.util.Assert;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -29,196 +37,15 @@ import org.springframework.util.Assert;
|
|
|
|
|
* {@literal <mime-mapping>} element traditionally found in web.xml.
|
|
|
|
|
*
|
|
|
|
|
* @author Phillip Webb
|
|
|
|
|
* @author Guirong Hu
|
|
|
|
|
* @since 2.0.0
|
|
|
|
|
*/
|
|
|
|
|
public final class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
public sealed class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Default mime mapping commonly used.
|
|
|
|
|
*/
|
|
|
|
|
public static final MimeMappings DEFAULT;
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
MimeMappings mappings = new MimeMappings();
|
|
|
|
|
mappings.add("abs", "audio/x-mpeg");
|
|
|
|
|
mappings.add("ai", "application/postscript");
|
|
|
|
|
mappings.add("aif", "audio/x-aiff");
|
|
|
|
|
mappings.add("aifc", "audio/x-aiff");
|
|
|
|
|
mappings.add("aiff", "audio/x-aiff");
|
|
|
|
|
mappings.add("aim", "application/x-aim");
|
|
|
|
|
mappings.add("art", "image/x-jg");
|
|
|
|
|
mappings.add("asf", "video/x-ms-asf");
|
|
|
|
|
mappings.add("asx", "video/x-ms-asf");
|
|
|
|
|
mappings.add("au", "audio/basic");
|
|
|
|
|
mappings.add("avi", "video/x-msvideo");
|
|
|
|
|
mappings.add("avx", "video/x-rad-screenplay");
|
|
|
|
|
mappings.add("bcpio", "application/x-bcpio");
|
|
|
|
|
mappings.add("bin", "application/octet-stream");
|
|
|
|
|
mappings.add("bmp", "image/bmp");
|
|
|
|
|
mappings.add("body", "text/html");
|
|
|
|
|
mappings.add("cdf", "application/x-cdf");
|
|
|
|
|
mappings.add("cer", "application/pkix-cert");
|
|
|
|
|
mappings.add("class", "application/java");
|
|
|
|
|
mappings.add("cpio", "application/x-cpio");
|
|
|
|
|
mappings.add("csh", "application/x-csh");
|
|
|
|
|
mappings.add("css", "text/css");
|
|
|
|
|
mappings.add("dib", "image/bmp");
|
|
|
|
|
mappings.add("doc", "application/msword");
|
|
|
|
|
mappings.add("dtd", "application/xml-dtd");
|
|
|
|
|
mappings.add("dv", "video/x-dv");
|
|
|
|
|
mappings.add("dvi", "application/x-dvi");
|
|
|
|
|
mappings.add("eot", "application/vnd.ms-fontobject");
|
|
|
|
|
mappings.add("eps", "application/postscript");
|
|
|
|
|
mappings.add("etx", "text/x-setext");
|
|
|
|
|
mappings.add("exe", "application/octet-stream");
|
|
|
|
|
mappings.add("gif", "image/gif");
|
|
|
|
|
mappings.add("gtar", "application/x-gtar");
|
|
|
|
|
mappings.add("gz", "application/x-gzip");
|
|
|
|
|
mappings.add("hdf", "application/x-hdf");
|
|
|
|
|
mappings.add("hqx", "application/mac-binhex40");
|
|
|
|
|
mappings.add("htc", "text/x-component");
|
|
|
|
|
mappings.add("htm", "text/html");
|
|
|
|
|
mappings.add("html", "text/html");
|
|
|
|
|
mappings.add("ief", "image/ief");
|
|
|
|
|
mappings.add("jad", "text/vnd.sun.j2me.app-descriptor");
|
|
|
|
|
mappings.add("jar", "application/java-archive");
|
|
|
|
|
mappings.add("java", "text/x-java-source");
|
|
|
|
|
mappings.add("jnlp", "application/x-java-jnlp-file");
|
|
|
|
|
mappings.add("jpe", "image/jpeg");
|
|
|
|
|
mappings.add("jpeg", "image/jpeg");
|
|
|
|
|
mappings.add("jpg", "image/jpeg");
|
|
|
|
|
mappings.add("js", "application/javascript");
|
|
|
|
|
mappings.add("jsf", "text/plain");
|
|
|
|
|
mappings.add("json", "application/json");
|
|
|
|
|
mappings.add("jspf", "text/plain");
|
|
|
|
|
mappings.add("kar", "audio/midi");
|
|
|
|
|
mappings.add("latex", "application/x-latex");
|
|
|
|
|
mappings.add("m3u", "audio/x-mpegurl");
|
|
|
|
|
mappings.add("mac", "image/x-macpaint");
|
|
|
|
|
mappings.add("man", "text/troff");
|
|
|
|
|
mappings.add("mathml", "application/mathml+xml");
|
|
|
|
|
mappings.add("me", "text/troff");
|
|
|
|
|
mappings.add("mid", "audio/midi");
|
|
|
|
|
mappings.add("midi", "audio/midi");
|
|
|
|
|
mappings.add("mif", "application/x-mif");
|
|
|
|
|
mappings.add("mov", "video/quicktime");
|
|
|
|
|
mappings.add("movie", "video/x-sgi-movie");
|
|
|
|
|
mappings.add("mp1", "audio/mpeg");
|
|
|
|
|
mappings.add("mp2", "audio/mpeg");
|
|
|
|
|
mappings.add("mp3", "audio/mpeg");
|
|
|
|
|
mappings.add("mp4", "video/mp4");
|
|
|
|
|
mappings.add("mpa", "audio/mpeg");
|
|
|
|
|
mappings.add("mpe", "video/mpeg");
|
|
|
|
|
mappings.add("mpeg", "video/mpeg");
|
|
|
|
|
mappings.add("mpega", "audio/x-mpeg");
|
|
|
|
|
mappings.add("mpg", "video/mpeg");
|
|
|
|
|
mappings.add("mpv2", "video/mpeg2");
|
|
|
|
|
mappings.add("ms", "application/x-wais-source");
|
|
|
|
|
mappings.add("nc", "application/x-netcdf");
|
|
|
|
|
mappings.add("oda", "application/oda");
|
|
|
|
|
mappings.add("odb", "application/vnd.oasis.opendocument.database");
|
|
|
|
|
mappings.add("odc", "application/vnd.oasis.opendocument.chart");
|
|
|
|
|
mappings.add("odf", "application/vnd.oasis.opendocument.formula");
|
|
|
|
|
mappings.add("odg", "application/vnd.oasis.opendocument.graphics");
|
|
|
|
|
mappings.add("odi", "application/vnd.oasis.opendocument.image");
|
|
|
|
|
mappings.add("odm", "application/vnd.oasis.opendocument.text-master");
|
|
|
|
|
mappings.add("odp", "application/vnd.oasis.opendocument.presentation");
|
|
|
|
|
mappings.add("ods", "application/vnd.oasis.opendocument.spreadsheet");
|
|
|
|
|
mappings.add("odt", "application/vnd.oasis.opendocument.text");
|
|
|
|
|
mappings.add("otg", "application/vnd.oasis.opendocument.graphics-template");
|
|
|
|
|
mappings.add("oth", "application/vnd.oasis.opendocument.text-web");
|
|
|
|
|
mappings.add("otp", "application/vnd.oasis.opendocument.presentation-template");
|
|
|
|
|
mappings.add("ots", "application/vnd.oasis.opendocument.spreadsheet-template");
|
|
|
|
|
mappings.add("ott", "application/vnd.oasis.opendocument.text-template");
|
|
|
|
|
mappings.add("ogx", "application/ogg");
|
|
|
|
|
mappings.add("ogv", "video/ogg");
|
|
|
|
|
mappings.add("oga", "audio/ogg");
|
|
|
|
|
mappings.add("ogg", "audio/ogg");
|
|
|
|
|
mappings.add("otf", "application/x-font-opentype");
|
|
|
|
|
mappings.add("spx", "audio/ogg");
|
|
|
|
|
mappings.add("flac", "audio/flac");
|
|
|
|
|
mappings.add("anx", "application/annodex");
|
|
|
|
|
mappings.add("axa", "audio/annodex");
|
|
|
|
|
mappings.add("axv", "video/annodex");
|
|
|
|
|
mappings.add("xspf", "application/xspf+xml");
|
|
|
|
|
mappings.add("pbm", "image/x-portable-bitmap");
|
|
|
|
|
mappings.add("pct", "image/pict");
|
|
|
|
|
mappings.add("pdf", "application/pdf");
|
|
|
|
|
mappings.add("pgm", "image/x-portable-graymap");
|
|
|
|
|
mappings.add("pic", "image/pict");
|
|
|
|
|
mappings.add("pict", "image/pict");
|
|
|
|
|
mappings.add("pls", "audio/x-scpls");
|
|
|
|
|
mappings.add("png", "image/png");
|
|
|
|
|
mappings.add("pnm", "image/x-portable-anymap");
|
|
|
|
|
mappings.add("pnt", "image/x-macpaint");
|
|
|
|
|
mappings.add("ppm", "image/x-portable-pixmap");
|
|
|
|
|
mappings.add("ppt", "application/vnd.ms-powerpoint");
|
|
|
|
|
mappings.add("pps", "application/vnd.ms-powerpoint");
|
|
|
|
|
mappings.add("ps", "application/postscript");
|
|
|
|
|
mappings.add("psd", "image/vnd.adobe.photoshop");
|
|
|
|
|
mappings.add("qt", "video/quicktime");
|
|
|
|
|
mappings.add("qti", "image/x-quicktime");
|
|
|
|
|
mappings.add("qtif", "image/x-quicktime");
|
|
|
|
|
mappings.add("ras", "image/x-cmu-raster");
|
|
|
|
|
mappings.add("rdf", "application/rdf+xml");
|
|
|
|
|
mappings.add("rgb", "image/x-rgb");
|
|
|
|
|
mappings.add("rm", "application/vnd.rn-realmedia");
|
|
|
|
|
mappings.add("roff", "text/troff");
|
|
|
|
|
mappings.add("rtf", "application/rtf");
|
|
|
|
|
mappings.add("rtx", "text/richtext");
|
|
|
|
|
mappings.add("sfnt", "application/font-sfnt");
|
|
|
|
|
mappings.add("sh", "application/x-sh");
|
|
|
|
|
mappings.add("shar", "application/x-shar");
|
|
|
|
|
mappings.add("sit", "application/x-stuffit");
|
|
|
|
|
mappings.add("snd", "audio/basic");
|
|
|
|
|
mappings.add("src", "application/x-wais-source");
|
|
|
|
|
mappings.add("sv4cpio", "application/x-sv4cpio");
|
|
|
|
|
mappings.add("sv4crc", "application/x-sv4crc");
|
|
|
|
|
mappings.add("svg", "image/svg+xml");
|
|
|
|
|
mappings.add("svgz", "image/svg+xml");
|
|
|
|
|
mappings.add("swf", "application/x-shockwave-flash");
|
|
|
|
|
mappings.add("t", "text/troff");
|
|
|
|
|
mappings.add("tar", "application/x-tar");
|
|
|
|
|
mappings.add("tcl", "application/x-tcl");
|
|
|
|
|
mappings.add("tex", "application/x-tex");
|
|
|
|
|
mappings.add("texi", "application/x-texinfo");
|
|
|
|
|
mappings.add("texinfo", "application/x-texinfo");
|
|
|
|
|
mappings.add("tif", "image/tiff");
|
|
|
|
|
mappings.add("tiff", "image/tiff");
|
|
|
|
|
mappings.add("tr", "text/troff");
|
|
|
|
|
mappings.add("tsv", "text/tab-separated-values");
|
|
|
|
|
mappings.add("ttf", "application/x-font-ttf");
|
|
|
|
|
mappings.add("txt", "text/plain");
|
|
|
|
|
mappings.add("ulw", "audio/basic");
|
|
|
|
|
mappings.add("ustar", "application/x-ustar");
|
|
|
|
|
mappings.add("vxml", "application/voicexml+xml");
|
|
|
|
|
mappings.add("xbm", "image/x-xbitmap");
|
|
|
|
|
mappings.add("xht", "application/xhtml+xml");
|
|
|
|
|
mappings.add("xhtml", "application/xhtml+xml");
|
|
|
|
|
mappings.add("xls", "application/vnd.ms-excel");
|
|
|
|
|
mappings.add("xml", "application/xml");
|
|
|
|
|
mappings.add("xpm", "image/x-xpixmap");
|
|
|
|
|
mappings.add("xsl", "application/xml");
|
|
|
|
|
mappings.add("xslt", "application/xslt+xml");
|
|
|
|
|
mappings.add("xul", "application/vnd.mozilla.xul+xml");
|
|
|
|
|
mappings.add("xwd", "image/x-xwindowdump");
|
|
|
|
|
mappings.add("vsd", "application/vnd.visio");
|
|
|
|
|
mappings.add("wasm", "application/wasm");
|
|
|
|
|
mappings.add("wav", "audio/x-wav");
|
|
|
|
|
mappings.add("wbmp", "image/vnd.wap.wbmp");
|
|
|
|
|
mappings.add("wml", "text/vnd.wap.wml");
|
|
|
|
|
mappings.add("wmlc", "application/vnd.wap.wmlc");
|
|
|
|
|
mappings.add("wmls", "text/vnd.wap.wmlsc");
|
|
|
|
|
mappings.add("wmlscriptc", "application/vnd.wap.wmlscriptc");
|
|
|
|
|
mappings.add("wmv", "video/x-ms-wmv");
|
|
|
|
|
mappings.add("woff", "application/font-woff");
|
|
|
|
|
mappings.add("woff2", "application/font-woff2");
|
|
|
|
|
mappings.add("wrl", "model/vrml");
|
|
|
|
|
mappings.add("wspolicy", "application/wspolicy+xml");
|
|
|
|
|
mappings.add("z", "application/x-compress");
|
|
|
|
|
mappings.add("zip", "application/zip");
|
|
|
|
|
DEFAULT = unmodifiableMappings(mappings);
|
|
|
|
|
}
|
|
|
|
|
public static final MimeMappings DEFAULT = new DefaultMimeMappings();
|
|
|
|
|
|
|
|
|
|
private final Map<String, Mapping> map;
|
|
|
|
|
|
|
|
|
@ -253,24 +80,11 @@ public final class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
* @param mappings source mappings
|
|
|
|
|
* @param mutable if the new object should be mutable.
|
|
|
|
|
*/
|
|
|
|
|
private MimeMappings(MimeMappings mappings, boolean mutable) {
|
|
|
|
|
MimeMappings(MimeMappings mappings, boolean mutable) {
|
|
|
|
|
Assert.notNull(mappings, "Mappings must not be null");
|
|
|
|
|
this.map = (mutable ? new LinkedHashMap<>(mappings.map) : Collections.unmodifiableMap(mappings.map));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Iterator<Mapping> iterator() {
|
|
|
|
|
return getAll().iterator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns all defined mappings.
|
|
|
|
|
* @return the mappings.
|
|
|
|
|
*/
|
|
|
|
|
public Collection<Mapping> getAll() {
|
|
|
|
|
return this.map.values();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Add a new mime mapping.
|
|
|
|
|
* @param extension the file extension (excluding '.')
|
|
|
|
@ -278,7 +92,20 @@ public final class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
* @return any previous mapping or {@code null}
|
|
|
|
|
*/
|
|
|
|
|
public String add(String extension, String mimeType) {
|
|
|
|
|
Mapping previous = this.map.put(extension, new Mapping(extension, mimeType));
|
|
|
|
|
Assert.notNull(extension, "Extension must not be null");
|
|
|
|
|
Assert.notNull(mimeType, "MimeType must not be null");
|
|
|
|
|
Mapping previous = this.map.put(extension.toLowerCase(Locale.ENGLISH), new Mapping(extension, mimeType));
|
|
|
|
|
return (previous != null) ? previous.getMimeType() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove an existing mapping.
|
|
|
|
|
* @param extension the file extension (excluding '.')
|
|
|
|
|
* @return the removed mime mapping or {@code null} if no item was removed
|
|
|
|
|
*/
|
|
|
|
|
public String remove(String extension) {
|
|
|
|
|
Assert.notNull(extension, "Extension must not be null");
|
|
|
|
|
Mapping previous = this.map.remove(extension.toLowerCase(Locale.ENGLISH));
|
|
|
|
|
return (previous != null) ? previous.getMimeType() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -288,18 +115,22 @@ public final class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
* @return a mime mapping or {@code null}
|
|
|
|
|
*/
|
|
|
|
|
public String get(String extension) {
|
|
|
|
|
Mapping mapping = this.map.get(extension);
|
|
|
|
|
Assert.notNull(extension, "Extension must not be null");
|
|
|
|
|
Mapping mapping = this.map.get(extension.toLowerCase(Locale.ENGLISH));
|
|
|
|
|
return (mapping != null) ? mapping.getMimeType() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Remove an existing mapping.
|
|
|
|
|
* @param extension the file extension (excluding '.')
|
|
|
|
|
* @return the removed mime mapping or {@code null} if no item was removed
|
|
|
|
|
* Returns all defined mappings.
|
|
|
|
|
* @return the mappings.
|
|
|
|
|
*/
|
|
|
|
|
public String remove(String extension) {
|
|
|
|
|
Mapping previous = this.map.remove(extension);
|
|
|
|
|
return (previous != null) ? previous.getMimeType() : null;
|
|
|
|
|
public Collection<Mapping> getAll() {
|
|
|
|
|
return this.map.values();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public final Iterator<Mapping> iterator() {
|
|
|
|
|
return getAll().iterator();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
@ -311,14 +142,18 @@ public final class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (obj instanceof MimeMappings other) {
|
|
|
|
|
return this.map.equals(other.map);
|
|
|
|
|
return getMap().equals(other.map);
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int hashCode() {
|
|
|
|
|
return this.map.hashCode();
|
|
|
|
|
return getMap().hashCode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Map<String, Mapping> getMap() {
|
|
|
|
|
return this.map;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@ -328,9 +163,22 @@ public final class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
* @return an unmodifiable view of the specified mappings.
|
|
|
|
|
*/
|
|
|
|
|
public static MimeMappings unmodifiableMappings(MimeMappings mappings) {
|
|
|
|
|
Assert.notNull(mappings, "Mappings must not be null");
|
|
|
|
|
return new MimeMappings(mappings, false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Crate a new lazy copy of the given mappings will only copy entries if the mappings
|
|
|
|
|
* are mutated.
|
|
|
|
|
* @param mappings the source mappings
|
|
|
|
|
* @return a new mappings instance
|
|
|
|
|
* @since 3.0.0
|
|
|
|
|
*/
|
|
|
|
|
public static MimeMappings lazyCopy(MimeMappings mappings) {
|
|
|
|
|
Assert.notNull(mappings, "Mappings must not be null");
|
|
|
|
|
return new LazyMimeMappingsCopy(mappings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* A single mime mapping.
|
|
|
|
|
*/
|
|
|
|
@ -381,4 +229,175 @@ public final class MimeMappings implements Iterable<MimeMappings.Mapping> {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* {@link MimeMappings} implementation used for {@link MimeMappings#DEFAULT}. Provides
|
|
|
|
|
* in-memory access for common mappings and lazily loads the complete set when
|
|
|
|
|
* necessary.
|
|
|
|
|
*/
|
|
|
|
|
static final class DefaultMimeMappings extends MimeMappings {
|
|
|
|
|
|
|
|
|
|
static final String MIME_MAPPINGS_PROPERTIES = "mime-mappings.properties";
|
|
|
|
|
|
|
|
|
|
private static final MimeMappings COMMON;
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
MimeMappings mappings = new MimeMappings();
|
|
|
|
|
mappings.add("avi", "video/x-msvideo");
|
|
|
|
|
mappings.add("bin", "application/octet-stream");
|
|
|
|
|
mappings.add("body", "text/html");
|
|
|
|
|
mappings.add("class", "application/java");
|
|
|
|
|
mappings.add("css", "text/css");
|
|
|
|
|
mappings.add("dtd", "application/xml-dtd");
|
|
|
|
|
mappings.add("gif", "image/gif");
|
|
|
|
|
mappings.add("gtar", "application/x-gtar");
|
|
|
|
|
mappings.add("gz", "application/x-gzip");
|
|
|
|
|
mappings.add("htm", "text/html");
|
|
|
|
|
mappings.add("html", "text/html");
|
|
|
|
|
mappings.add("jar", "application/java-archive");
|
|
|
|
|
mappings.add("java", "text/x-java-source");
|
|
|
|
|
mappings.add("jnlp", "application/x-java-jnlp-file");
|
|
|
|
|
mappings.add("jpe", "image/jpeg");
|
|
|
|
|
mappings.add("jpeg", "image/jpeg");
|
|
|
|
|
mappings.add("jpg", "image/jpeg");
|
|
|
|
|
mappings.add("js", "application/javascript");
|
|
|
|
|
mappings.add("json", "application/json");
|
|
|
|
|
mappings.add("otf", "application/x-font-opentype");
|
|
|
|
|
mappings.add("pdf", "application/pdf");
|
|
|
|
|
mappings.add("png", "image/png");
|
|
|
|
|
mappings.add("ps", "application/postscript");
|
|
|
|
|
mappings.add("tar", "application/x-tar");
|
|
|
|
|
mappings.add("tif", "image/tiff");
|
|
|
|
|
mappings.add("tiff", "image/tiff");
|
|
|
|
|
mappings.add("ttf", "application/x-font-ttf");
|
|
|
|
|
mappings.add("txt", "text/plain");
|
|
|
|
|
mappings.add("xht", "application/xhtml+xml");
|
|
|
|
|
mappings.add("xhtml", "application/xhtml+xml");
|
|
|
|
|
mappings.add("xls", "application/vnd.ms-excel");
|
|
|
|
|
mappings.add("xml", "application/xml");
|
|
|
|
|
mappings.add("xsl", "application/xml");
|
|
|
|
|
mappings.add("xslt", "application/xslt+xml");
|
|
|
|
|
mappings.add("wasm", "application/wasm");
|
|
|
|
|
mappings.add("zip", "application/zip");
|
|
|
|
|
COMMON = unmodifiableMappings(mappings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private volatile Map<String, Mapping> loaded;
|
|
|
|
|
|
|
|
|
|
DefaultMimeMappings() {
|
|
|
|
|
super(new MimeMappings(), false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Collection<Mapping> getAll() {
|
|
|
|
|
return load().values();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String get(String extension) {
|
|
|
|
|
Assert.notNull(extension, "Extension must not be null");
|
|
|
|
|
extension = extension.toLowerCase(Locale.ENGLISH);
|
|
|
|
|
Map<String, Mapping> loaded = this.loaded;
|
|
|
|
|
if (loaded != null) {
|
|
|
|
|
return get(loaded, extension);
|
|
|
|
|
}
|
|
|
|
|
String commonMimeType = COMMON.get(extension);
|
|
|
|
|
if (commonMimeType != null) {
|
|
|
|
|
return commonMimeType;
|
|
|
|
|
}
|
|
|
|
|
loaded = load();
|
|
|
|
|
return get(loaded, extension);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private String get(Map<String, Mapping> mappings, String extension) {
|
|
|
|
|
Mapping mapping = mappings.get(extension);
|
|
|
|
|
return (mapping != null) ? mapping.getMimeType() : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
Map<String, Mapping> getMap() {
|
|
|
|
|
return load();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private Map<String, Mapping> load() {
|
|
|
|
|
Map<String, Mapping> loaded = this.loaded;
|
|
|
|
|
if (loaded != null) {
|
|
|
|
|
return loaded;
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
loaded = new LinkedHashMap<>();
|
|
|
|
|
for (Entry<?, ?> entry : PropertiesLoaderUtils
|
|
|
|
|
.loadProperties(new ClassPathResource(MIME_MAPPINGS_PROPERTIES, getClass())).entrySet()) {
|
|
|
|
|
loaded.put((String) entry.getKey(),
|
|
|
|
|
new Mapping((String) entry.getKey(), (String) entry.getValue()));
|
|
|
|
|
}
|
|
|
|
|
loaded = Collections.unmodifiableMap(loaded);
|
|
|
|
|
this.loaded = loaded;
|
|
|
|
|
return loaded;
|
|
|
|
|
}
|
|
|
|
|
catch (IOException ex) {
|
|
|
|
|
throw new IllegalArgumentException("Unable to load the default MIME types", ex);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* {@link MimeMappings} implementation used to create a lazy copy only when the
|
|
|
|
|
* mappings are mutated.
|
|
|
|
|
*/
|
|
|
|
|
static final class LazyMimeMappingsCopy extends MimeMappings {
|
|
|
|
|
|
|
|
|
|
private final MimeMappings source;
|
|
|
|
|
|
|
|
|
|
private AtomicBoolean copied = new AtomicBoolean();
|
|
|
|
|
|
|
|
|
|
LazyMimeMappingsCopy(MimeMappings source) {
|
|
|
|
|
this.source = source;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String add(String extension, String mimeType) {
|
|
|
|
|
copyIfNecessary();
|
|
|
|
|
return super.add(extension, mimeType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String remove(String extension) {
|
|
|
|
|
copyIfNecessary();
|
|
|
|
|
return super.remove(extension);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void copyIfNecessary() {
|
|
|
|
|
if (this.copied.compareAndSet(false, true)) {
|
|
|
|
|
this.source.forEach((mapping) -> add(mapping.getExtension(), mapping.getMimeType()));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String get(String extension) {
|
|
|
|
|
return !this.copied.get() ? this.source.get(extension) : super.get(extension);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public Collection<Mapping> getAll() {
|
|
|
|
|
return !this.copied.get() ? this.source.getAll() : super.getAll();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
Map<String, Mapping> getMap() {
|
|
|
|
|
return !this.copied.get() ? this.source.getMap() : super.getMap();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static class MimeMappingsRuntimeHints implements RuntimeHintsRegistrar {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
|
|
|
|
|
hints.resources().registerPattern(
|
|
|
|
|
"org/springframework/boot/web/server/" + DefaultMimeMappings.MIME_MAPPINGS_PROPERTIES);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|