diff --git a/.github/ISSUE_TEMPLATE/release-template.md b/.github/ISSUE_TEMPLATE/release-template.md index 6b95b988a65..a6751fecdbd 100644 --- a/.github/ISSUE_TEMPLATE/release-template.md +++ b/.github/ISSUE_TEMPLATE/release-template.md @@ -1,7 +1,7 @@ --- name: 'Release Process' about: 'COMMITTER ONLY: Managing the Jetty release process' -title: 'Jetty Releases 9.4.x, 10.0.y, 11.0.y' +title: 'Jetty Releases 9.4.x, 10.0.y, 11.0.y, 12.0.y' assignees: '' labels: Build @@ -31,10 +31,12 @@ This release process will produce releases: - [ ] Verify that branch `jetty-10.0.x` is merged to branch `jetty-11.0.x`. - [ ] Assign issue to "build manager", who will stage the releases. + [ ] Create and use branches `release/` to perform version specific release work from. + + [ ] Ensure `git fetch --tags` (as we potentially rewrite tag when re staging local tag can be out of sync and this command will fail and so fail the release script) + [ ] Ensure `VERSION.txt` additions for each release will be meaningful, descriptive, correct text. + [ ] Stage 9.4 release with Java 11. + [ ] Stage 10 release with Java 21. + [ ] Stage 11 release with Java 21. + + [ ] Stage 12 release with Java 22. + [ ] Push release branches `release/` to to https://github.com/eclipse/jetty.project + [ ] Push release tags `jetty-` to https://github.com/eclipse/jetty.project + [ ] Edit a draft release (for each Jetty release) in GitHub (https://github.com/eclipse/jetty.project/releases). Content is generated with the "changelog tool". diff --git a/VERSION.txt b/VERSION.txt index 17844aaeb1a..ed75934820a 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -291,11 +291,13 @@ jetty-12.0.1 - 29 August 2023 + 10411 Review deployment of Jetty Context XML files + 10416 EE9 Copies HttpFields in response -jetty-9.4.54.v20240208 - 08 February 2024 - + 1256 DoSFilter leaks USER_AUTH entries - + 11259 HTTP/2 connection not closed after idle timeout when TCP congested - (CVE-2024-22201) - + 11389 Strip default ports on ws/wss scheme uris too +jetty-11.0.21 - 14 May 2024 + + 10805 Jetty response with an invalid HTTP2 packet if the client set the + hpack table size as 0 + + 11527 Reduce ByteBuffer churning in HttpOutput + + 11634 Socks5Proxy does not support IP addresses with IP segments above 127 + + 11656 Upgrade jetty-quiche-native to version 0.21.0 + + 11782 HttpExchange retained by HttpSenderOverHTTP which caused memory leak jetty-11.0.20 - 29 January 2024 + 11081 Dropped WebSocket messages due to race condition in WebSocket frame @@ -307,6 +309,12 @@ jetty-11.0.20 - 29 January 2024 + 11273 Support BSD expr in startup script + 11349 Update quiche to 0.20.0 +jetty-9.4.54.v20240208 - 08 February 2024 + + 1256 DoSFilter leaks USER_AUTH entries + + 11259 HTTP/2 connection not closed after idle timeout when TCP congested + (CVE-2024-22201) + + 11389 Strip default ports on ws/wss scheme uris too + jetty-11.0.19 - 15 December 2023 + 9900 Improve `Request.getBeginNanoTime()` accuracy + 10812 jetty-deploy has unnecessary dependency on awaitility/hamcrest pulled diff --git a/build/scripts/release-jetty.sh b/build/scripts/release-jetty.sh index fd6029f5e6e..1453a194415 100755 --- a/build/scripts/release-jetty.sh +++ b/build/scripts/release-jetty.sh @@ -92,7 +92,7 @@ DEPLOY_OPTS="-DskipTests -Dasciidoctor.skip=false -Dmaven.build.cache.enabled=fa # DEPLOY_OPTS="$DEPLOY_OPTS -DaltDeploymentRepository=intarget::default::file://$ALT_DEPLOY_DIR/" # Uncomment for Java 1.7 -export MAVEN_OPTS="-Xmx2g" +export MAVEN_OPTS="-Xmx4g" echo "" echo "-----------------------------------------------" diff --git a/documentation/jetty-documentation/src/main/asciidoc/operations-guide/sessions/session-base.adoc b/documentation/jetty-documentation/src/main/asciidoc/operations-guide/sessions/session-base.adoc index 7e4e0f4515c..499f1e4fea6 100644 --- a/documentation/jetty-documentation/src/main/asciidoc/operations-guide/sessions/session-base.adoc +++ b/documentation/jetty-documentation/src/main/asciidoc/operations-guide/sessions/session-base.adoc @@ -31,7 +31,7 @@ This uniquely identifies the jetty server instance and is applied to the `Sessio You can either provide a value for this property, or you can allow Jetty to try and synthesize a `workerName` - the latter option is _only_ advisable in the case of a single, non-clustered deployment. There are two ways a default `workerName` can be synthesized: -* if running on Google AppEngine, the `workerName` will be formed by concatenating the values of the environment variables `JETTY_WORKER_INSTANCE` and `GAE_MODULE_INSTANCE` +* if running on Google AppEngine, the `workerName` will be formed by concatenating the values of the environment variables `JETTY_WORKER_INSTANCE` and `GAE_INSTANCE` * otherwise, the `workerName` will be formed by concatenating the environment variable `JETTY_WORKER_INSTANCE` and the literal `0`. So, if you're not running on Google AppEngine, and you haven't configured one, the workerName will always be: `node0`. diff --git a/documentation/jetty/modules/ROOT/pages/index.adoc b/documentation/jetty/modules/ROOT/pages/index.adoc index ac1c57eb289..c37fb0c4c2e 100644 --- a/documentation/jetty/modules/ROOT/pages/index.adoc +++ b/documentation/jetty/modules/ROOT/pages/index.adoc @@ -11,7 +11,7 @@ // ======================================================================== // -= Eclipse Jetty += Eclipse Jetty {page-version} This section of the site contains the documentation for {page-component-title} {page-version}. diff --git a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java index d3425e341dc..9098dc3522b 100644 --- a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java +++ b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Connection.java @@ -38,7 +38,6 @@ import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.Retainable; import org.eclipse.jetty.io.RetainableByteBuffer; -import org.eclipse.jetty.io.WriteFlusher; import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.component.LifeCycle; @@ -48,7 +47,7 @@ import org.eclipse.jetty.util.thread.strategy.AdaptiveExecutionStrategy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class HTTP2Connection extends AbstractConnection implements Parser.Listener, WriteFlusher.Listener, Connection.UpgradeTo +public class HTTP2Connection extends AbstractConnection implements Parser.Listener, Connection.UpgradeTo { private static final Logger LOG = LoggerFactory.getLogger(HTTP2Connection.class); @@ -302,12 +301,6 @@ public class HTTP2Connection extends AbstractConnection implements Parser.Listen session.onConnectionFailure(error, reason); } - @Override - public void onFlushed(long bytes) throws IOException - { - session.onFlushed(bytes); - } - protected class HTTP2Producer implements ExecutionStrategy.Producer { private final Callback fillableCallback = new FillableCallback(); diff --git a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java index 43e24fea118..981036e64a0 100644 --- a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java +++ b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/HTTP2Session.java @@ -60,7 +60,6 @@ import org.eclipse.jetty.http2.parser.Parser; import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.CyclicTimeouts; import org.eclipse.jetty.io.EndPoint; -import org.eclipse.jetty.io.WriteFlusher; import org.eclipse.jetty.util.AtomicBiInteger; import org.eclipse.jetty.util.Atomics; import org.eclipse.jetty.util.Callback; @@ -1084,11 +1083,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session streamsState.onStreamDestroyed(); } - public void onFlushed(long bytes) throws IOException - { - flusher.onFlushed(bytes); - } - private void terminate(Throwable cause) { flusher.terminate(cause); @@ -1263,8 +1257,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session public abstract boolean generate(ByteBufferPool.Accumulator accumulator) throws HpackException; - public abstract long onFlushed(long bytes) throws IOException; - boolean hasHighPriority() { return false; @@ -1355,16 +1347,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session return true; } - @Override - public long onFlushed(long bytes) - { - long flushed = Math.min(frameBytes, bytes); - if (LOG.isDebugEnabled()) - LOG.debug("Flushed {}/{} frame bytes for {}", flushed, bytes, this); - frameBytes -= flushed; - return bytes - flushed; - } - /** *

Performs actions just before writing the frame to the network.

*

Some frame, when sent over the network, causes the receiver @@ -1433,7 +1415,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session private class DataEntry extends Entry { private int frameBytes; - private int frameRemaining; private int dataBytes; private int dataRemaining; @@ -1477,7 +1458,6 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session DataFrame dataFrame = (DataFrame)frame; int frameBytes = generator.data(accumulator, dataFrame, length); this.frameBytes += frameBytes; - this.frameRemaining += frameBytes; int dataBytes = frameBytes - Frame.HEADER_LENGTH; this.dataBytes += dataBytes; @@ -1492,27 +1472,11 @@ public abstract class HTTP2Session extends ContainerLifeCycle implements Session return true; } - @Override - public long onFlushed(long bytes) throws IOException - { - long flushed = Math.min(frameRemaining, bytes); - if (LOG.isDebugEnabled()) - LOG.debug("Flushed {}/{} frame bytes for {}", flushed, bytes, this); - frameRemaining -= flushed; - // We should only forward data (not frame) bytes, - // but we trade precision for simplicity. - Object channel = stream.getAttachment(); - if (channel instanceof WriteFlusher.Listener) - ((WriteFlusher.Listener)channel).onFlushed(flushed); - return bytes - flushed; - } - @Override public void succeeded() { bytesWritten.addAndGet(frameBytes); frameBytes = 0; - frameRemaining = 0; flowControl.onDataSent(stream, dataBytes); dataBytes = 0; diff --git a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/internal/HTTP2Flusher.java b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/internal/HTTP2Flusher.java index df7df77c9f7..fd0f7c8b837 100644 --- a/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/internal/HTTP2Flusher.java +++ b/jetty-core/jetty-http2/jetty-http2-common/src/main/java/org/eclipse/jetty/http2/internal/HTTP2Flusher.java @@ -293,15 +293,6 @@ public class HTTP2Flusher extends IteratingCallback implements Dumpable return Action.SCHEDULED; } - public void onFlushed(long bytes) throws IOException - { - // A single EndPoint write may be flushed multiple times (for example with SSL). - for (HTTP2Session.Entry entry : processedEntries) - { - bytes = entry.onFlushed(bytes); - } - } - @Override public void succeeded() { diff --git a/jetty-core/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java b/jetty-core/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java index 2ebba0cd95d..24943165b43 100644 --- a/jetty-core/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java +++ b/jetty-core/jetty-io/src/main/java/org/eclipse/jetty/io/WriteFlusher.java @@ -429,8 +429,8 @@ public abstract class WriteFlusher if (written > 0) { Connection connection = _endPoint.getConnection(); - if (connection instanceof Listener) - ((Listener)connection).onFlushed(written); + if (connection instanceof Listener listener) + listener.onFlushed(written); } if (flushed) @@ -581,7 +581,10 @@ public abstract class WriteFlusher /** *

A listener of {@link WriteFlusher} events. * If implemented by a Connection class, the {@link #onFlushed(long)} event will be delivered to it.

+ * + * @deprecated functionality removed, no replacement */ + @Deprecated(since = "12.0.10", forRemoval = true) public interface Listener { /** diff --git a/jetty-core/jetty-server/src/main/config/etc/sessions/id-manager.xml b/jetty-core/jetty-server/src/main/config/etc/sessions/id-manager.xml index 0cac625436c..96536f0dada 100644 --- a/jetty-core/jetty-server/src/main/config/etc/sessions/id-manager.xml +++ b/jetty-core/jetty-server/src/main/config/etc/sessions/id-manager.xml @@ -15,7 +15,7 @@ node - + 0 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 855d0a2be91..166c70b0952 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 @@ -54,6 +54,7 @@ import org.eclipse.jetty.util.component.AttributeContainerMap; import org.eclipse.jetty.util.component.ClassLoaderDump; import org.eclipse.jetty.util.component.DumpableAttributes; import org.eclipse.jetty.util.component.DumpableCollection; +import org.eclipse.jetty.util.component.DumpableMap; import org.eclipse.jetty.util.component.Environment; import org.eclipse.jetty.util.component.Graceful; import org.eclipse.jetty.util.component.LifeCycle; @@ -137,6 +138,7 @@ public class Server extends Handler.Wrapper implements Attributes public Server(@Name("threadPool") ThreadPool pool) { this(pool, null, null); + installBean(new DumpableMap("System Properties", System.getProperties())); } public Server(@Name("threadPool") ThreadPool threadPool, @Name("scheduler") Scheduler scheduler, @Name("bufferPool") ByteBufferPool bufferPool) @@ -791,7 +793,7 @@ public class Server extends Handler.Wrapper implements Attributes */ public Resource getDefaultStyleSheet() { - return newResource("jetty-dir.css"); + return newResource("/org/eclipse/jetty/server/jetty-dir.css"); } /** @@ -801,7 +803,7 @@ public class Server extends Handler.Wrapper implements Attributes */ public Resource getDefaultFavicon() { - return newResource("favicon.ico"); + return newResource("/org/eclipse/jetty/server/favicon.ico"); } /** diff --git a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java index 0ac7056cb8f..3d479670005 100644 --- a/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java +++ b/jetty-core/jetty-server/src/main/java/org/eclipse/jetty/server/internal/HttpConnection.java @@ -52,7 +52,6 @@ import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.io.EofException; import org.eclipse.jetty.io.RetainableByteBuffer; import org.eclipse.jetty.io.RuntimeIOException; -import org.eclipse.jetty.io.WriteFlusher; import org.eclipse.jetty.io.ssl.SslConnection; import org.eclipse.jetty.server.AbstractMetaDataConnection; import org.eclipse.jetty.server.ConnectionFactory; @@ -81,7 +80,7 @@ import static org.eclipse.jetty.http.HttpStatus.INTERNAL_SERVER_ERROR_500; /** *

A {@link Connection} that handles the HTTP protocol.

*/ -public class HttpConnection extends AbstractMetaDataConnection implements Runnable, WriteFlusher.Listener, Connection.UpgradeFrom, Connection.UpgradeTo, ConnectionMetaData +public class HttpConnection extends AbstractMetaDataConnection implements Runnable, Connection.UpgradeFrom, Connection.UpgradeTo, ConnectionMetaData { private static final Logger LOG = LoggerFactory.getLogger(HttpConnection.class); private static final HttpField PREAMBLE_UPGRADE_H2C = new HttpField(HttpHeader.UPGRADE, "h2c"); @@ -336,13 +335,6 @@ public class HttpConnection extends AbstractMetaDataConnection implements Runnab BufferUtil.append(getRequestBuffer(), buffer); } - @Override - public void onFlushed(long bytes) throws IOException - { - // TODO is this callback still needed? Couldn't we wrap send callback instead? - // Either way, the dat rate calculations from HttpOutput.onFlushed should be moved to Channel. - } - void releaseRequestBuffer() { if (_retainableByteBuffer != null && !_retainableByteBuffer.hasRemaining()) diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java index 2fd15118a15..dcca3eb0375 100644 --- a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java +++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/ServerTest.java @@ -32,8 +32,10 @@ import org.eclipse.jetty.server.internal.HttpChannelState; import org.eclipse.jetty.server.internal.HttpConnection; import org.eclipse.jetty.util.Blocker; import org.eclipse.jetty.util.Callback; +import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.component.LifeCycle; import org.eclipse.jetty.util.thread.Invocable; +import org.eclipse.jetty.util.thread.QueuedThreadPool; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -143,6 +145,26 @@ public class ServerTest assertThat(response.getContent(), is("Hello")); } + @Test + public void testDump() throws Exception + { + testSimpleGET(); + ((QueuedThreadPool)(_server.getThreadPool())).tryExecute(() -> {}); + String dump = _server.dump(); + assertThat(dump, containsString("oejs.Server@")); + assertThat(dump, containsString("QueuedThreadPool")); + assertThat(dump, containsString("+= ReservedThreadExecutor@")); + assertThat(dump, containsString(".ArrayByteBufferPool@")); + assertThat(dump, containsString("+- System Properties size=")); + assertThat(dump, containsString("+> java.home: ")); + assertThat(dump, containsString("+> java.runtime.version: ")); + assertThat(dump, containsString("+= oejsh.ContextHandler@")); + assertThat(dump, containsString("+= LocalConnector@")); + assertThat(dump, containsString("key: +-")); + assertThat(dump, containsString("JVM: ")); + assertThat(dump, containsString(Jetty.VERSION)); + } + public static Stream completionScenarios() { List arguments = new ArrayList<>(); diff --git a/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/subpackage/ServerDefaultResourcesTest.java b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/subpackage/ServerDefaultResourcesTest.java new file mode 100644 index 00000000000..49ed00d8f29 --- /dev/null +++ b/jetty-core/jetty-server/src/test/java/org/eclipse/jetty/server/subpackage/ServerDefaultResourcesTest.java @@ -0,0 +1,64 @@ +// +// ======================================================================== +// Copyright (c) 1995 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.server.subpackage; + +import java.util.stream.Stream; + +import org.eclipse.jetty.server.Server; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public class ServerDefaultResourcesTest +{ + public static Stream arguments() + { + return Stream.of( + new Server(), + new Server(){} + ).map(Arguments::of); + } + + @ParameterizedTest + @MethodSource("arguments") + public void testDefaultStyleSheet(Server server) throws Exception + { + try + { + server.start(); + assertNotNull(server.getDefaultStyleSheet()); + } + finally + { + server.stop(); + } + } + + @ParameterizedTest + @MethodSource("arguments") + public void testDefaultFavicon(Server server) throws Exception + { + try + { + server.start(); + assertNotNull(server.getDefaultFavicon()); + } + finally + { + server.stop(); + } + } +} diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java index 0e4a0ae37bc..36fad2ee2e3 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java @@ -745,10 +745,10 @@ public class ContainerLifeCycle extends AbstractLifeCycle implements Container, { try { - dump(System.err, ""); - System.err.println(Dumpable.KEY); + Dumpable.dump(this, System.err); + System.err.println(); } - catch (IOException e) + catch (Throwable e) { LOG.warn("Unable to dump", e); } diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java index 7c728f5a36f..17e003b28f1 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java @@ -14,8 +14,13 @@ package org.eclipse.jetty.util.component; import java.io.IOException; +import java.io.UncheckedIOException; import java.lang.reflect.Array; import java.nio.file.Path; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; @@ -23,6 +28,7 @@ import java.util.Map; import java.util.Objects; import java.util.stream.Stream; +import org.eclipse.jetty.util.Jetty; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.annotation.ManagedObject; @@ -31,7 +37,7 @@ import org.eclipse.jetty.util.annotation.ManagedOperation; @ManagedObject("Dumpable Object") public interface Dumpable { - String KEY = "key: +- bean, += managed, +~ unmanaged, +? auto, +: iterable, +] array, +@ map, +> undefined"; + String KEY = "key: +- bean, += managed, +~ unmanaged, +? auto, +: iterable, +] array, +@ map, +> undefined\n"; @ManagedOperation(value = "Dump the nested Object state as a String", impact = "INFO") default String dump() @@ -50,24 +56,55 @@ public interface Dumpable void dump(Appendable out, String indent) throws IOException; /** - * Utility method to implement {@link #dump()} by calling {@link #dump(Appendable, String)} + * Utility method to dump to a {@link String} * * @param dumpable The dumpable to dump * @return The dumped string + * @see #dump(Appendable, String) */ static String dump(Dumpable dumpable) { StringBuilder b = new StringBuilder(); + dump(dumpable, b); + return b.toString(); + } + + /** + * Utility method to dump to an {@link Appendable} + * + * @param dumpable The dumpable to dump + * @param out The destination of the dump + */ + static void dump(Dumpable dumpable, Appendable out) + { try { - dumpable.dump(b, ""); + dumpable.dump(out, ""); + + out.append(KEY); + Runtime runtime = Runtime.getRuntime(); + Instant now = Instant.now(); + String zone = System.getProperty("user.timezone"); + out.append("JVM: %s %s %s; OS: %s %s %s; Jetty: %s; CPUs: %d; mem(free/total/max): %,d/%,d/%,d MiB\nUTC: %s; %s: %s".formatted( + System.getProperty("java.vm.vendor"), + System.getProperty("java.vm.name"), + System.getProperty("java.vm.version"), + System.getProperty("os.name"), + System.getProperty("os.arch"), + System.getProperty("os.version"), + Jetty.VERSION, + runtime.availableProcessors(), + runtime.freeMemory() / (1024 * 1024), + runtime.totalMemory() / (1024 * 1024), + runtime.maxMemory() / (1024 * 1024), + DateTimeFormatter.ISO_DATE_TIME.format(now.atOffset(ZoneOffset.UTC)), + zone, + DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(now.atZone(ZoneId.of(zone))))); } catch (IOException e) { - b.append(e.toString()); + throw new UncheckedIOException(e); } - b.append(KEY); - return b.toString(); } /** @@ -301,7 +338,7 @@ public interface Dumpable * interface to allow it to refine which of its beans can be * dumped. */ - public interface DumpableContainer extends Dumpable + interface DumpableContainer extends Dumpable { default boolean isDumpable(Object o) { diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/DumpableMap.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/DumpableMap.java new file mode 100644 index 00000000000..d56a2aa821b --- /dev/null +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/component/DumpableMap.java @@ -0,0 +1,39 @@ +// +// ======================================================================== +// Copyright (c) 1995 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.util.component; + +import java.io.IOException; +import java.util.Comparator; +import java.util.Map; + +public class DumpableMap implements Dumpable +{ + private final String _name; + private final Map _map; + + public DumpableMap(String name, Map map) + { + _name = name; + _map = map; + } + + @Override + public void dump(Appendable out, String indent) throws IOException + { + Object[] array = _map.entrySet().stream() + .sorted(Map.Entry.comparingByKey(Comparator.comparing(String::valueOf))) + .map(e -> Dumpable.named(String.valueOf(e.getKey()), e.getValue())).toArray(Object[]::new); + Dumpable.dumpObjects(out, indent, _name + " size=" + array.length, array); + } +} diff --git a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadIdPool.java b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadIdPool.java index 84f092567bf..46b0756f18a 100644 --- a/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadIdPool.java +++ b/jetty-core/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ThreadIdPool.java @@ -25,7 +25,6 @@ import org.eclipse.jetty.util.MemoryUtils; import org.eclipse.jetty.util.ProcessorUtils; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.component.Dumpable; -import org.eclipse.jetty.util.component.DumpableCollection; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -236,8 +235,12 @@ public class ThreadIdPool implements Dumpable int capacity = capacity(); List slots = new ArrayList<>(capacity); for (int i = 0; i < capacity; i++) - slots.add(_items.get(toSlot(i))); - Dumpable.dumpObjects(out, indent, this, new DumpableCollection("items", slots)); + { + E slot = _items.get(toSlot(i)); + if (slot != null) + slots.add(Dumpable.named(Integer.toString(i), slot)); + } + Dumpable.dumpObjects(out, indent, this, slots.toArray()); } @Override diff --git a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java index f790d547223..063a9e7182c 100644 --- a/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java +++ b/jetty-core/jetty-util/src/test/java/org/eclipse/jetty/util/thread/QueuedThreadPoolTest.java @@ -833,8 +833,6 @@ public class QueuedThreadPoolTest extends AbstractThreadPoolTest assertThat(count(dump, " - STARTED"), is(3)); assertThat(dump, containsString(",3<=3<=4,i=1,r=2,")); assertThat(dump, containsString("[ReservedThreadExecutor@")); - assertThat(count(dump, "> ReservedThread@"), is(1)); - assertThat(count(dump, "> null"), is(1)); assertThat(count(dump, "QueuedThreadPoolTest.lambda$testDump$"), is(0)); pool.setDetailedDump(true); diff --git a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/DebugListener.java b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/DebugListener.java index 637a0f51346..6b9b169d66a 100644 --- a/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/DebugListener.java +++ b/jetty-ee10/jetty-ee10-servlet/src/main/java/org/eclipse/jetty/ee10/servlet/DebugListener.java @@ -125,14 +125,12 @@ public class DebugListener extends AbstractLifeCycle implements ServletContextLi if (_out == null) { handler.dumpStdErr(); - System.err.println(Dumpable.KEY); } else { try { - handler.dump(_out); - _out.println(Dumpable.KEY); + Dumpable.dump(handler, _out); } catch (Exception e) { diff --git a/jetty-ee8/jetty-ee8-websocket/jetty-ee8-websocket-javax-server/pom.xml b/jetty-ee8/jetty-ee8-websocket/jetty-ee8-websocket-javax-server/pom.xml index 989b118e7da..c8cdbd7d19c 100644 --- a/jetty-ee8/jetty-ee8-websocket/jetty-ee8-websocket-javax-server/pom.xml +++ b/jetty-ee8/jetty-ee8-websocket/jetty-ee8-websocket-javax-server/pom.xml @@ -52,7 +52,7 @@ javax.websocket.server Implementation - org.eclipse.jetty.websocket.javax.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" + org.eclipse.jetty.ee8.websocket.javax.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}" osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.ee8.webapp.Configuration,osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=javax.websocket.server.ServerEndpointConfig$Configurator diff --git a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/DebugListener.java b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/DebugListener.java index 8dcbe8ff5c1..29c5e76d90d 100644 --- a/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/DebugListener.java +++ b/jetty-ee9/jetty-ee9-nested/src/main/java/org/eclipse/jetty/ee9/nested/DebugListener.java @@ -121,14 +121,12 @@ public class DebugListener extends AbstractLifeCycle implements ServletContextLi if (_out == null) { handler.dumpStdErr(); - System.err.println(Dumpable.KEY); } else { try { - handler.dump(_out); - _out.println(Dumpable.KEY); + Dumpable.dump(handler, _out); } catch (Exception e) {