diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/CachingHttpContentFactory.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/CachingHttpContentFactory.java index 0a1bf048d9c..cce551591d8 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/CachingHttpContentFactory.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/CachingHttpContentFactory.java @@ -381,7 +381,7 @@ public class CachingHttpContentFactory implements HttpContent.Factory @Override public ByteBuffer getByteBuffer() { - return _buffer; + return _buffer == null ? null : _buffer.asReadOnlyBuffer(); } @Override diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/FileMappingHttpContentFactory.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/FileMappingHttpContentFactory.java index dc515e1f924..c3155f86a77 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/FileMappingHttpContentFactory.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/FileMappingHttpContentFactory.java @@ -86,13 +86,13 @@ public class FileMappingHttpContentFactory implements HttpContent.Factory { ByteBuffer buffer = _buffer; if (buffer != null) - return (buffer == SENTINEL_BUFFER) ? super.getByteBuffer() : buffer; + return (buffer == SENTINEL_BUFFER) ? super.getByteBuffer() : buffer.asReadOnlyBuffer(); try (AutoLock lock = _lock.lock()) { if (_buffer == null) _buffer = getMappedByteBuffer(); - return (_buffer == SENTINEL_BUFFER) ? super.getByteBuffer() : _buffer; + return (_buffer == SENTINEL_BUFFER) ? super.getByteBuffer() : _buffer.asReadOnlyBuffer(); } } diff --git a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/HttpContent.java b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/HttpContent.java index 7fa9d54b2c7..96cdf3584f9 100644 --- a/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/HttpContent.java +++ b/jetty-core/jetty-http/src/main/java/org/eclipse/jetty/http/content/HttpContent.java @@ -63,6 +63,12 @@ public interface HttpContent Resource getResource(); + /** + *

Get this HTTP content as a {@link ByteBuffer} if possible.

+ *

Each invocation returns a new {@link ByteBuffer} instance that is + * read-only and contains valid data between the pos and the limit.

+ * @return a {@link ByteBuffer} instance or null. + */ ByteBuffer getByteBuffer(); default long getBytesOccupied() diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java index 3c5dc4f07c4..d633b9a446c 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/ResourceService.java @@ -641,7 +641,7 @@ public class ResourceService { try { - ByteBuffer buffer = content.getByteBuffer(); + ByteBuffer buffer = content.getByteBuffer(); // this buffer is going to be consumed by response.write() if (buffer != null) response.write(true, buffer, callback); else diff --git a/jetty-ee10/jetty-ee10-webapp/src/test/java/org/eclipse/jetty/ee10/webapp/WebAppDefaultServletCacheTest.java b/jetty-ee10/jetty-ee10-webapp/src/test/java/org/eclipse/jetty/ee10/webapp/WebAppDefaultServletCacheTest.java new file mode 100644 index 00000000000..8055e338e08 --- /dev/null +++ b/jetty-ee10/jetty-ee10-webapp/src/test/java/org/eclipse/jetty/ee10/webapp/WebAppDefaultServletCacheTest.java @@ -0,0 +1,88 @@ +// +// ======================================================================== +// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// ======================================================================== +// + +package org.eclipse.jetty.ee10.webapp; + +import java.net.URI; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import org.eclipse.jetty.http.HttpTester; +import org.eclipse.jetty.server.LocalConnector; +import org.eclipse.jetty.server.Server; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class WebAppDefaultServletCacheTest +{ + private LocalConnector connector; + private Server server; + private Path resourcePath; + + @BeforeEach + protected void setUp() throws Exception + { + server = new Server(); + connector = new LocalConnector(server); + server.addConnector(connector); + + URI uri = getClass().getResource("/org/acme").toURI(); + resourcePath = Paths.get(uri); + server.addHandler(new WebAppContext(uri.toString(), "/")); + + server.start(); + } + + @AfterEach + protected void tearDown() throws Exception + { + server.stop(); + } + + @Test + public void testCacheRefreshing() throws Exception + { + String fileName = "jetty-pic.png"; + long fileSize = Files.size(resourcePath.resolve(fileName)); + + HttpTester.Response response1 = sendRequest(fileName); + assertEquals(response1.getLongField("Content-Length"), fileSize); + assertEquals(200, response1.getStatus()); + + HttpTester.Response response2 = sendRequest(fileName, "If-Modified-Since: " + response1.get("Last-Modified")); + assertEquals(response2.getLongField("Content-Length"), 0L); + assertEquals(304, response2.getStatus()); + + HttpTester.Response response3 = sendRequest(fileName, "Cache-Control: no-cache", "Pragma: no-cache"); + assertEquals(response3.getLongField("Content-Length"), fileSize); + assertEquals(200, response3.getStatus()); + } + + private HttpTester.Response sendRequest(String file, String... extraHeaders) throws Exception + { + StringBuilder rawRequest = new StringBuilder(); + rawRequest.append("GET /").append(file).append(" HTTP/1.1\r\n"); + rawRequest.append("Host: local\r\n"); + for (String extraHeader : extraHeaders) + { + rawRequest.append(extraHeader).append("\r\n"); + } + rawRequest.append("\r\n"); + String rawResponse = connector.getResponse(rawRequest.toString()); + return HttpTester.parseResponse(rawResponse); + } +} diff --git a/jetty-ee10/jetty-ee10-webapp/src/test/resources/org/acme/jetty-pic.png b/jetty-ee10/jetty-ee10-webapp/src/test/resources/org/acme/jetty-pic.png new file mode 100644 index 00000000000..2df513a88d6 Binary files /dev/null and b/jetty-ee10/jetty-ee10-webapp/src/test/resources/org/acme/jetty-pic.png differ