From ca3055423a571e7999df3210647d8a2c23d3b28d Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Thu, 24 Nov 2022 16:57:29 +1100 Subject: [PATCH] Mutable server MimeTypes (#8933) Make the MimeTypes available from the server mutable. Context MimeTypes are now wrappers over the server MimeTypes, so configuration at the server level is inherited by all contexts. --- .../org/eclipse/jetty/http/MimeTypes.java | 75 +++++++++++++++++++ .../org/eclipse/jetty/http/MimeTypesTest.java | 58 ++++++++++++++ .../java/org/eclipse/jetty/server/Server.java | 8 +- .../jetty/server/handler/ContextHandler.java | 14 +++- .../server/handler/ContextHandlerTest.java | 2 - 5 files changed, 153 insertions(+), 4 deletions(-) diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java index e90a59a2a54..c0e4008e524 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/MimeTypes.java @@ -273,6 +273,7 @@ public class MimeTypes { public Mutable() { + this(DEFAULTS); } public Mutable(MimeTypes defaults) @@ -305,6 +306,80 @@ public class MimeTypes } } + public static class Wrapper extends Mutable + { + private MimeTypes _wrapped; + + public Wrapper() + { + super(null); + } + + public MimeTypes getWrapped() + { + return _wrapped; + } + + public void setWrapped(MimeTypes wrapped) + { + _wrapped = wrapped; + } + + @Override + public String getMimeForExtension(String extension) + { + String mime = super.getMimeForExtension(extension); + return mime == null && _wrapped != null ? _wrapped.getMimeForExtension(extension) : mime; + } + + @Override + public String getCharsetInferredFromContentType(String contentType) + { + String charset = super.getCharsetInferredFromContentType(contentType); + return charset == null && _wrapped != null ? _wrapped.getCharsetInferredFromContentType(contentType) : charset; + } + + @Override + public String getCharsetAssumedFromContentType(String contentType) + { + String charset = super.getCharsetAssumedFromContentType(contentType); + return charset == null && _wrapped != null ? _wrapped.getCharsetAssumedFromContentType(contentType) : charset; + } + + @Override + public Map getMimeMap() + { + Map map = super.getMimeMap(); + if (_wrapped == null || map.isEmpty()) + return map; + map = new HashMap<>(map); + map.putAll(_wrapped.getMimeMap()); + return Collections.unmodifiableMap(map); + } + + @Override + public Map getInferredMap() + { + Map map = super.getInferredMap(); + if (_wrapped == null || map.isEmpty()) + return map; + map = new HashMap<>(map); + map.putAll(_wrapped.getInferredMap()); + return Collections.unmodifiableMap(map); + } + + @Override + public Map getAssumedMap() + { + Map map = super.getAssumedMap(); + if (_wrapped == null || map.isEmpty()) + return map; + map = new HashMap<>(map); + map.putAll(_wrapped.getAssumedMap()); + return Collections.unmodifiableMap(map); + } + } + public static final MimeTypes DEFAULTS = new MimeTypes(null) { { diff --git a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java index 5d9704423d3..d0064d4092a 100644 --- a/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java +++ b/jetty-core/jetty-http/src/test/java/org/eclipse/jetty/http/MimeTypesTest.java @@ -126,4 +126,62 @@ public class MimeTypesTest assertThat("MimeTypes.getContentTypeWithoutCharset(\"" + contentTypeWithCharset + "\")", MimeTypes.getContentTypeWithoutCharset(contentTypeWithCharset), is(expectedContentType)); } + + @Test + public void testWrapper() + { + MimeTypes.Wrapper wrapper = new MimeTypes.Wrapper(); + assertThat(wrapper.getMimeMap().size(), is(0)); + assertThat(wrapper.getInferredMap().size(), is(0)); + assertThat(wrapper.getAssumedMap().size(), is(0)); + + wrapper.addMimeMapping("txt", "text/plain"); + wrapper.addInferred("text/plain", "usascii"); + wrapper.addAssumed("json", "utf-8"); + + assertThat(wrapper.getMimeMap().size(), is(1)); + assertThat(wrapper.getInferredMap().size(), is(1)); + assertThat(wrapper.getAssumedMap().size(), is(1)); + assertThat(wrapper.getMimeByExtension("fee.txt"), is("text/plain")); + assertThat(wrapper.getCharsetInferredFromContentType("text/plain"), is("usascii")); + assertThat(wrapper.getCharsetAssumedFromContentType("json"), is("utf-8")); + + MimeTypes.Mutable wrapped = new MimeTypes.Mutable(null); + wrapper.setWrapped(wrapped); + + assertThat(wrapper.getMimeMap().size(), is(1)); + assertThat(wrapper.getInferredMap().size(), is(1)); + assertThat(wrapper.getAssumedMap().size(), is(1)); + assertThat(wrapper.getMimeByExtension("fee.txt"), is("text/plain")); + assertThat(wrapper.getCharsetInferredFromContentType("text/plain"), is("usascii")); + assertThat(wrapper.getCharsetAssumedFromContentType("json"), is("utf-8")); + + wrapped.addMimeMapping("txt", "overridden"); + wrapped.addInferred("text/plain", "overridden"); + wrapped.addAssumed("json", "overridden"); + + assertThat(wrapper.getMimeMap().size(), is(1)); + assertThat(wrapper.getInferredMap().size(), is(1)); + assertThat(wrapper.getAssumedMap().size(), is(1)); + assertThat(wrapper.getMimeByExtension("fee.txt"), is("text/plain")); + assertThat(wrapper.getCharsetInferredFromContentType("text/plain"), is("usascii")); + assertThat(wrapper.getCharsetAssumedFromContentType("json"), is("utf-8")); + + wrapped.addMimeMapping("xml", "text/xml"); + wrapped.addInferred("text/xml", "iso-8859-1"); + wrapped.addAssumed("text/xxx", "assumed"); + assertThat(wrapped.getMimeMap().size(), is(2)); + assertThat(wrapped.getInferredMap().size(), is(2)); + assertThat(wrapped.getAssumedMap().size(), is(2)); + + assertThat(wrapper.getMimeMap().size(), is(2)); + assertThat(wrapper.getInferredMap().size(), is(2)); + assertThat(wrapper.getAssumedMap().size(), is(2)); + assertThat(wrapper.getMimeByExtension("fee.txt"), is("text/plain")); + assertThat(wrapper.getCharsetInferredFromContentType("text/plain"), is("usascii")); + assertThat(wrapper.getCharsetAssumedFromContentType("json"), is("utf-8")); + assertThat(wrapper.getMimeByExtension("fee.xml"), is("text/xml")); + assertThat(wrapper.getCharsetInferredFromContentType("text/xml"), is("iso-8859-1")); + assertThat(wrapper.getCharsetAssumedFromContentType("text/xxx"), is("assumed")); + } } diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index c8a5560dff3..540f9d73ab7 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -70,6 +70,7 @@ public class Server extends Handler.Wrapper implements Attributes private final List _connectors = new CopyOnWriteArrayList<>(); private final Context _serverContext = new ServerContext(); private final AutoLock _dateLock = new AutoLock(); + private final MimeTypes.Mutable _mimeTypes = new MimeTypes.Mutable(); private String _serverInfo = __serverInfo; private boolean _stopAtShutdown; private boolean _dumpAfterStart; @@ -141,6 +142,11 @@ public class Server extends Handler.Wrapper implements Attributes return _serverContext; } + public MimeTypes.Mutable getMimeTypes() + { + return _mimeTypes; + } + @Override public InvocationType getInvocationType() { @@ -729,7 +735,7 @@ public class Server extends Handler.Wrapper implements Attributes @Override public MimeTypes getMimeTypes() { - return MimeTypes.DEFAULTS; + return _mimeTypes; } @Override diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 2534e3f467e..aa49712aedf 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -96,7 +96,7 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace */ private final Context _context; private final Attributes _persistentAttributes = new Mapped(); - private final MimeTypes.Mutable _mimeTypes = new MimeTypes.Mutable(); + private final MimeTypes.Wrapper _mimeTypes = new MimeTypes.Wrapper(); private final List _contextListeners = new CopyOnWriteArrayList<>(); private final List _vhosts = new ArrayList<>(); @@ -160,11 +160,23 @@ public class ContextHandler extends Handler.Wrapper implements Attributes, Grace addAliasCheck(new SymlinkAllowedResourceAliasChecker(this)); } + @Override + public void setServer(Server server) + { + super.setServer(server); + _mimeTypes.setWrapped(server.getMimeTypes()); + } + protected Context newContext() { return new Context(); } + /** + * @return A mutable MimeTypes that wraps the {@link Server#getMimeTypes()} + * once {@link ContextHandler#setServer(Server)} has been called. + * @see MimeTypes.Wrapper + */ public MimeTypes.Mutable getMimeTypes() { return _mimeTypes; diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java index 74b8b61ef25..a2ce90bf0c0 100644 --- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java +++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/handler/ContextHandlerTest.java @@ -179,8 +179,6 @@ public class ContextHandlerTest assertThat(stream.getResponse().getStatus(), equalTo(200)); assertThat(stream.getResponseHeaders().get(HttpHeader.CONTENT_TYPE), equalTo(MimeTypes.Type.TEXT_PLAIN_UTF_8.asString())); assertThat(BufferUtil.toString(stream.getResponseContent()), equalTo(helloHandler.getMessage())); - - } private void assertInContext(Request request)