Merge remote-tracking branch 'origin/jetty-10.0.x' into jetty-10.0.x-7635-QpackDecoderMaxBlockedStreams

This commit is contained in:
Lachlan Roberts 2022-05-16 09:59:00 +10:00
commit 15e32ca3ea
29 changed files with 721 additions and 257 deletions

View File

@ -17,26 +17,19 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-SymbolicName>org.eclipse.jetty.demos.demo-mock-resources</Bundle-SymbolicName>
<Bundle-Description>Mock resources used for testing</Bundle-Description>
<Export-Package>
com.acme;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
<Import-Package>
javax.sql, javax.transaction;version="1.1", javax.mail;version="1.4.1"
</Import-Package>
<_nouses>true</_nouses>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-SymbolicName>org.eclipse.jetty.demos.demo-mock-resources</Bundle-SymbolicName>
<Bundle-Description>Mock resources used for testing</Bundle-Description>
<Export-Package>
com.acme;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
<Import-Package>
javax.sql, javax.transaction;version="1.1", javax.mail;version="1.4.1"
</Import-Package>
<_nouses>true</_nouses>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -17,19 +17,12 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Import-Package>${osgi.slf4j.import.packages},org.eclipse.jetty.alpn;resolution:=optional,*</Import-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client)";resolution:=optional;cardinality:=multiple</Require-Capability>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Import-Package>${osgi.slf4j.import.packages},org.eclipse.jetty.alpn;resolution:=optional,*</Import-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional, osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.io.ssl.ALPNProcessor$Client)";resolution:=optional;cardinality:=multiple</Require-Capability>
</instructions>
</configuration>
</plugin>
<!-- always include the sources to be able to prepare the eclipse-jetty-SDK feature
with a snapshot. -->

View File

@ -50,20 +50,13 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Export-Package>
org.eclipse.jetty.gcloud.session.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Export-Package>
org.eclipse.jetty.gcloud.session.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -158,13 +158,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ
{
if (LOG.isDebugEnabled())
LOG.debug("onRequest", x);
onBadMessage(x);
return null;
return () -> onBadMessage(x);
}
catch (Throwable x)
{
onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
return null;
return () -> onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
}
}
@ -190,13 +188,11 @@ public class HttpChannelOverHTTP2 extends HttpChannel implements Closeable, Writ
}
catch (BadMessageException x)
{
onBadMessage(x);
return null;
return () -> onBadMessage(x);
}
catch (Throwable x)
{
onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
return null;
return () -> onBadMessage(new BadMessageException(HttpStatus.INTERNAL_SERVER_ERROR_500, null, x));
}
}

View File

@ -0,0 +1,149 @@
//
// ========================================================================
// 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.http2.server;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HostPortHttpField;
import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.http.HttpMethod;
import org.eclipse.jetty.http.HttpScheme;
import org.eclipse.jetty.http.HttpVersion;
import org.eclipse.jetty.http.MetaData;
import org.eclipse.jetty.http2.frames.HeadersFrame;
import org.eclipse.jetty.http2.frames.PrefaceFrame;
import org.eclipse.jetty.http2.frames.SettingsFrame;
import org.eclipse.jetty.http2.generator.Generator;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.HttpConfiguration;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.component.LifeCycle;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class BadURITest
{
private Server server;
private ServerConnector connector;
protected void startServer(Handler handler) throws Exception
{
server = new Server();
connector = new ServerConnector(server, 1, 1, new HTTP2CServerConnectionFactory(new HttpConfiguration()));
server.addConnector(connector);
server.setHandler(handler);
server.start();
}
@AfterEach
public void dispose()
{
LifeCycle.stop(server);
}
@Test
public void testBadURI() throws Exception
{
CountDownLatch handlerLatch = new CountDownLatch(1);
startServer(new AbstractHandler()
{
@Override
public void handle(String target, Request jettyRequest, HttpServletRequest request, HttpServletResponse response)
{
jettyRequest.setHandled(true);
handlerLatch.countDown();
}
});
// Remove existing ErrorHandlers.
for (ErrorHandler errorHandler : server.getBeans(ErrorHandler.class))
{
server.removeBean(errorHandler);
}
server.addBean(new ErrorHandler()
{
@Override
public ByteBuffer badMessageError(int status, String reason, HttpFields.Mutable fields)
{
// Return a very large buffer that will cause HTTP/2 flow control exhaustion and/or TCP congestion.
return ByteBuffer.allocateDirect(128 * 1024 * 1024);
}
});
ByteBufferPool byteBufferPool = connector.getByteBufferPool();
Generator generator = new Generator(byteBufferPool);
// Craft a request with a bad URI, it will not hit the Handler.
MetaData.Request metaData1 = new MetaData.Request(
HttpMethod.GET.asString(),
HttpScheme.HTTP.asString(),
new HostPortHttpField("localhost:" + connector.getLocalPort()),
// Use an ambiguous path parameter so that the URI is invalid.
"/foo/..;/bar",
HttpVersion.HTTP_2,
HttpFields.EMPTY,
-1
);
ByteBufferPool.Lease lease = new ByteBufferPool.Lease(byteBufferPool);
generator.control(lease, new PrefaceFrame());
generator.control(lease, new SettingsFrame(new HashMap<>(), false));
generator.control(lease, new HeadersFrame(1, metaData1, null, true));
try (Socket client = new Socket("localhost", connector.getLocalPort()))
{
OutputStream output = client.getOutputStream();
for (ByteBuffer buffer : lease.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
// Wait for the first request be processed on the server.
Thread.sleep(1000);
// Send a second request and verify that it hits the Handler.
lease.recycle();
MetaData.Request metaData2 = new MetaData.Request(
HttpMethod.GET.asString(),
HttpScheme.HTTP.asString(),
new HostPortHttpField("localhost:" + connector.getLocalPort()),
"/valid",
HttpVersion.HTTP_2,
HttpFields.EMPTY,
-1
);
generator.control(lease, new HeadersFrame(3, metaData2, null, true));
for (ByteBuffer buffer : lease.getByteBuffers())
{
output.write(BufferUtil.toArray(buffer));
}
assertTrue(handlerLatch.await(5, TimeUnit.SECONDS));
}
}
}

View File

@ -170,7 +170,8 @@ public class QpackDecoder implements Dumpable
if (LOG.isDebugEnabled())
LOG.debug("Decoded: streamId={}, metadata={}", streamId, metaData);
_metaDataNotifications.add(new MetaDataNotification(streamId, metaData, handler));
_instructions.add(new SectionAcknowledgmentInstruction(streamId));
if (requiredInsertCount > 0)
_instructions.add(new SectionAcknowledgmentInstruction(streamId));
}
else
{
@ -247,7 +248,8 @@ public class QpackDecoder implements Dumpable
while (iterator.hasNext())
{
EncodedFieldSection encodedFieldSection = iterator.next();
if (encodedFieldSection.getRequiredInsertCount() <= insertCount)
int requiredInsertCount = encodedFieldSection.getRequiredInsertCount();
if (requiredInsertCount <= insertCount)
{
iterator.remove();
long streamId = encodedFieldSection.getStreamId();
@ -258,7 +260,8 @@ public class QpackDecoder implements Dumpable
LOG.debug("Decoded: streamId={}, metadata={}", streamId, metaData);
_metaDataNotifications.add(new MetaDataNotification(streamId, metaData, encodedFieldSection.getHandler()));
_instructions.add(new SectionAcknowledgmentInstruction(streamId));
if (requiredInsertCount > 0)
_instructions.add(new SectionAcknowledgmentInstruction(streamId));
}
}
}

View File

@ -0,0 +1,83 @@
//
// ========================================================================
// 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.http3.qpack;
import java.nio.ByteBuffer;
import org.eclipse.jetty.http3.qpack.QpackException.SessionException;
import org.eclipse.jetty.http3.qpack.internal.instruction.SectionAcknowledgmentInstruction;
import org.eclipse.jetty.util.BufferUtil;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.eclipse.jetty.http3.qpack.QpackTestUtil.encode;
import static org.eclipse.jetty.http3.qpack.QpackTestUtil.toBuffer;
import static org.eclipse.jetty.http3.qpack.QpackTestUtil.toMetaData;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
public class SectionAcknowledgmentTest
{
private static final int MAX_BLOCKED_STREAMS = 5;
private static final int MAX_HEADER_SIZE = 1024;
private QpackEncoder _encoder;
private QpackDecoder _decoder;
private TestDecoderHandler _decoderHandler;
private TestEncoderHandler _encoderHandler;
@BeforeEach
public void before()
{
_encoderHandler = new TestEncoderHandler();
_decoderHandler = new TestDecoderHandler();
_encoder = new QpackEncoder(_encoderHandler, MAX_BLOCKED_STREAMS);
_decoder = new QpackDecoder(_decoderHandler, MAX_HEADER_SIZE);
}
@Test
public void testSectionAcknowledgmentForZeroRequiredInsertCountOnDecoder() throws Exception
{
// Encode a header with only a value contained in the static table.
ByteBuffer buffer = encode(_encoder, 0, toMetaData("GET", "/", "http"));
// No instruction since no addition to table.
Instruction instruction = _encoderHandler.getInstruction();
assertNull(instruction);
// Decoding should generate no instruction.
_decoder.decode(0, buffer, _decoderHandler);
instruction = _decoderHandler.getInstruction();
assertNull(instruction);
}
@Test
public void testSectionAcknowledgmentForZeroRequiredInsertCountOnEncoder() throws Exception
{
// Encode a header with only a value contained in the static table.
ByteBuffer buffer = encode(_encoder, 0, toMetaData("GET", "/", "http"));
assertThat(BufferUtil.remaining(buffer), greaterThan(0L));
// Parsing a section ack instruction on the encoder when we are not expecting it should result in QPACK_DECODER_STREAM_ERROR.
SectionAcknowledgmentInstruction instruction = new SectionAcknowledgmentInstruction(0);
ByteBuffer instructionBuffer = toBuffer(instruction);
SessionException error = assertThrows(SessionException.class, () -> _encoder.parseInstructions(instructionBuffer));
assertThat(error.getErrorCode(), equalTo(QpackException.QPACK_ENCODER_STREAM_ERROR));
assertThat(error.getMessage(), containsString("No StreamInfo for 0"));
}
}

View File

@ -21,19 +21,12 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory</Provide-Capability>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory</Provide-Capability>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -21,19 +21,12 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory</Provide-Capability>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"</Require-Capability>
<Provide-Capability>osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory</Provide-Capability>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -216,7 +216,7 @@
<dependency>
<groupId>org.apache.aries.spifly</groupId>
<artifactId>org.apache.aries.spifly.dynamic.bundle</artifactId>
<version>1.3.4</version>
<version>1.3.5</version>
<scope>test</scope>
<exclusions>
<exclusion>

View File

@ -45,7 +45,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
@ -89,11 +88,7 @@ public class TestJettyOSGiBootHTTP2Conscrypt
res.add(CoreOptions.systemProperty("jetty.alpn.protocols").value("h2,http/1.1"));
res.add(CoreOptions.systemProperty("jetty.sslContext.provider").value("Conscrypt"));
res.add(wrappedBundle(mavenBundle().groupId("org.conscrypt").artifactId("conscrypt-openjdk-uber").versionAsInProject())
.imports("javax.net.ssl,*")
.exports("org.conscrypt;version=" + System.getProperty("conscrypt-version"))
.instructions("Bundle-NativeCode=META-INF/native/libconscrypt_openjdk_jni-linux-x86_64.so")
.start());
res.add(mavenBundle().groupId("org.conscrypt").artifactId("conscrypt-openjdk-uber").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty.osgi").artifactId("jetty-osgi-alpn").versionAsInProject().noStart());
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-conscrypt-server").versionAsInProject().start());
res.add(mavenBundle().groupId("org.eclipse.jetty").artifactId("jetty-alpn-server").versionAsInProject().start());

View File

@ -12,7 +12,7 @@
<description>Generates a (maven based) P2 Updatesite</description>
<packaging>pom</packaging>
<properties>
<tycho-version>2.7.2</tycho-version>
<tycho-version>2.7.3</tycho-version>
</properties>
<build>
<plugins>

View File

@ -21,18 +21,11 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional</Require-Capability>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Require-Capability>osgi.serviceloader; filter:="(osgi.serviceloader=org.eclipse.jetty.security.Authenticator$Factory)";resolution:=optional;cardinality:=multiple, osgi.extender; filter:="(osgi.extender=osgi.serviceloader.processor)";resolution:=optional</Require-Capability>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -55,6 +55,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
private final LongAdder _expires = new LongAdder();
private final LongAdder _errors = new LongAdder();
private final LongAdder _responsesThrown = new LongAdder();
private final LongAdder _responses1xx = new LongAdder();
private final LongAdder _responses2xx = new LongAdder();
private final LongAdder _responses3xx = new LongAdder();
@ -91,7 +92,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
long elapsed = System.currentTimeMillis() - request.getTimeStamp();
_requestStats.decrement();
_requestTimeStats.record(elapsed);
updateResponse(request);
updateResponse(request, false);
_asyncWaitStats.decrement();
if (_shutdown.isShutdown())
@ -166,10 +167,16 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
_asyncDispatches.increment();
}
boolean thrownError = false;
try
{
handler.handle(path, baseRequest, request, response);
}
catch (Throwable t)
{
thrownError = true;
throw t;
}
finally
{
final long now = System.currentTimeMillis();
@ -189,7 +196,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
{
_requestStats.decrement();
_requestTimeStats.record(dispatched);
updateResponse(baseRequest);
updateResponse(baseRequest, thrownError);
}
}
@ -198,10 +205,14 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
}
}
protected void updateResponse(Request request)
protected void updateResponse(Request request, boolean thrownError)
{
Response response = request.getResponse();
if (request.isHandled())
if (thrownError)
{
_responsesThrown.increment();
}
else if (request.isHandled())
{
switch (response.getStatus() / 100)
{
@ -537,6 +548,18 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
return _responses5xx.intValue();
}
/**
* @return the number of requests that threw an exception during handling
* since {@link #statsReset()} was last called. These may have resulted in
* some error responses which were unrecorded by the {@link StatisticsHandler}.
*/
@ManagedAttribute("number of requests that threw an exception during handling")
public int getResponsesThrown()
{
return _responsesThrown.intValue();
}
/**
* @return the milliseconds since the statistics were started with {@link #statsReset()}.
*/
@ -590,6 +613,7 @@ public class StatisticsHandler extends HandlerWrapper implements Graceful
sb.append("3xx responses: ").append(getResponses3xx()).append("<br />\n");
sb.append("4xx responses: ").append(getResponses4xx()).append("<br />\n");
sb.append("5xx responses: ").append(getResponses5xx()).append("<br />\n");
sb.append("responses thrown: ").append(getResponsesThrown()).append("<br />\n");
sb.append("Bytes sent total: ").append(getResponsesBytesTotal()).append("<br />\n");
return sb.toString();

View File

@ -168,6 +168,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
// non-static, as other GzipHandler instances may have different configurations
private final IncludeExclude<String> _methods = new IncludeExclude<>();
private final IncludeExclude<String> _paths = new IncludeExclude<>(PathSpecSet.class);
private final IncludeExclude<String> _inflatePaths = new IncludeExclude<>(PathSpecSet.class);
private final IncludeExclude<String> _mimeTypes = new IncludeExclude<>(AsciiLowerCaseSet.class);
private HttpField _vary = GzipHttpOutputInterceptor.VARY_ACCEPT_ENCODING;
@ -354,6 +355,41 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
}
}
/**
* Adds excluded Path Specs for request filtering on request inflation.
*
* <p>
* There are 2 syntaxes supported, Servlet <code>url-pattern</code> based, and
* Regex based. This means that the initial characters on the path spec
* line are very strict, and determine the behavior of the path matching.
* <ul>
* <li>If the spec starts with <code>'^'</code> the spec is assumed to be
* a regex based path spec and will match with normal Java regex rules.</li>
* <li>If the spec starts with <code>'/'</code> then spec is assumed to be
* a Servlet url-pattern rules path spec for either an exact match
* or prefix based match.</li>
* <li>If the spec starts with <code>'*.'</code> then spec is assumed to be
* a Servlet url-pattern rules path spec for a suffix based match.</li>
* <li>All other syntaxes are unsupported</li>
* </ul>
* <p>
* Note: inclusion takes precedence over exclude.
*
* @param pathspecs Path specs (as per servlet spec) to exclude. If a
* ServletContext is available, the paths are relative to the context path,
* otherwise they are absolute.<br>
* For backward compatibility the pathspecs may be comma separated strings, but this
* will not be supported in future versions.
* @see #addIncludedInflationPaths(String...)
*/
public void addExcludedInflationPaths(String... pathspecs)
{
for (String p : pathspecs)
{
_inflatePaths.exclude(StringUtil.csvSplit(p));
}
}
/**
* Adds included HTTP Methods (eg: POST, PATCH, DELETE) for filtering.
*
@ -440,6 +476,38 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
}
}
/**
* Add included Path Specs for filtering on request inflation.
*
* <p>
* There are 2 syntaxes supported, Servlet <code>url-pattern</code> based, and
* Regex based. This means that the initial characters on the path spec
* line are very strict, and determine the behavior of the path matching.
* <ul>
* <li>If the spec starts with <code>'^'</code> the spec is assumed to be
* a regex based path spec and will match with normal Java regex rules.</li>
* <li>If the spec starts with <code>'/'</code> then spec is assumed to be
* a Servlet url-pattern rules path spec for either an exact match
* or prefix based match.</li>
* <li>If the spec starts with <code>'*.'</code> then spec is assumed to be
* a Servlet url-pattern rules path spec for a suffix based match.</li>
* <li>All other syntaxes are unsupported</li>
* </ul>
* <p>
* Note: inclusion takes precedence over exclusion.
*
* @param pathspecs Path specs (as per servlet spec) to include. If a
* ServletContext is available, the paths are relative to the context path,
* otherwise they are absolute
*/
public void addIncludedInflationPaths(String... pathspecs)
{
for (String p : pathspecs)
{
_inflatePaths.include(StringUtil.csvSplit(p));
}
}
@Override
public DeflaterPool.Entry getDeflaterEntry(Request request, long contentLength)
{
@ -495,6 +563,18 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
return excluded.toArray(new String[0]);
}
/**
* Get the current filter list of excluded Path Specs for request inflation.
*
* @return the filter list of excluded Path Specs
* @see #getIncludedInflationPaths()
*/
public String[] getExcludedInflationPaths()
{
Set<String> excluded = _inflatePaths.getExcluded();
return excluded.toArray(new String[0]);
}
/**
* Get the current filter list of included HTTP Methods
*
@ -531,6 +611,18 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
return includes.toArray(new String[0]);
}
/**
* Get the current filter list of included Path Specs for request inflation.
*
* @return the filter list of included Path Specs
* @see #getExcludedInflationPaths()
*/
public String[] getIncludedInflationPaths()
{
Set<String> includes = _inflatePaths.getIncluded();
return includes.toArray(new String[0]);
}
/**
* Get the minimum size, in bytes, that a response {@code Content-Length} must be
* before compression will trigger.
@ -585,7 +677,7 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
// Handle request inflation
HttpFields httpFields = baseRequest.getHttpFields();
boolean inflated = _inflateBufferSize > 0 && httpFields.contains(HttpHeader.CONTENT_ENCODING, "gzip");
boolean inflated = _inflateBufferSize > 0 && httpFields.contains(HttpHeader.CONTENT_ENCODING, "gzip") && isPathInflatable(path);
if (inflated)
{
if (LOG.isDebugEnabled())
@ -750,6 +842,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
return _paths.test(requestURI);
}
/**
* Test if the provided Request URI is allowed to be inflated based on the Path Specs filters.
*
* @param requestURI the request uri
* @return whether decompressing is allowed for the given the path.
*/
protected boolean isPathInflatable(String requestURI)
{
if (requestURI == null)
return true;
return _inflatePaths.test(requestURI);
}
/**
* Set the excluded filter list of HTTP methods (replacing any previously set)
*
@ -799,6 +905,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
_paths.exclude(pathspecs);
}
/**
* Set the excluded filter list of Path specs (replacing any previously set)
*
* @param pathspecs Path specs (as per servlet spec) to exclude from inflation. If a
* ServletContext is available, the paths are relative to the context path,
* otherwise they are absolute.
* @see #setIncludedInflatePaths(String...)
*/
public void setExcludedInflatePaths(String... pathspecs)
{
_inflatePaths.getExcluded().clear();
_inflatePaths.exclude(pathspecs);
}
/**
* Set of supported {@link DispatcherType} that this filter will operate on.
*
@ -861,6 +981,20 @@ public class GzipHandler extends HandlerWrapper implements GzipFactory
_paths.include(pathspecs);
}
/**
* Set the included filter list of Path specs (replacing any previously set)
*
* @param pathspecs Path specs (as per servlet spec) to include for inflation. If a
* ServletContext is available, the paths are relative to the context path,
* otherwise they are absolute
* @see #setExcludedInflatePaths(String...)
*/
public void setIncludedInflatePaths(String... pathspecs)
{
_inflatePaths.getIncluded().clear();
_inflatePaths.include(pathspecs);
}
/**
* Set the minimum response size to trigger dynamic compression.
* <p>

View File

@ -30,6 +30,8 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.ConnectionStatistics;
import org.eclipse.jetty.logging.StacklessLogging;
import org.eclipse.jetty.server.HttpChannel;
import org.eclipse.jetty.server.LocalConnector;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Server;
@ -38,6 +40,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -420,6 +423,60 @@ public class StatisticsHandlerTest
barrier[3].await();
}
@Test
public void testThrownResponse() throws Exception
{
_statsHandler.setHandler(new AbstractHandler()
{
@Override
public void handle(String path, Request request, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException
{
try
{
throw new IllegalStateException("expected");
}
catch (IllegalStateException e)
{
throw e;
}
catch (Exception e)
{
throw new IOException(e);
}
}
});
_server.start();
try (StacklessLogging ignored = new StacklessLogging(HttpChannel.class))
{
String request = "GET / HTTP/1.1\r\n" +
"Host: localhost\r\n" +
"\r\n";
String response = _connector.getResponse(request);
assertThat(response, containsString("HTTP/1.1 500 Server Error"));
}
assertEquals(1, _statsHandler.getRequests());
assertEquals(0, _statsHandler.getRequestsActive());
assertEquals(1, _statsHandler.getRequestsActiveMax());
assertEquals(1, _statsHandler.getDispatched());
assertEquals(0, _statsHandler.getDispatchedActive());
assertEquals(1, _statsHandler.getDispatchedActiveMax());
assertEquals(0, _statsHandler.getAsyncRequests());
assertEquals(0, _statsHandler.getAsyncDispatches());
assertEquals(0, _statsHandler.getExpires());
// We get no recorded status, but we get a recorded thrown response.
assertEquals(0, _statsHandler.getResponses1xx());
assertEquals(0, _statsHandler.getResponses2xx());
assertEquals(0, _statsHandler.getResponses3xx());
assertEquals(0, _statsHandler.getResponses4xx());
assertEquals(0, _statsHandler.getResponses5xx());
assertEquals(1, _statsHandler.getResponsesThrown());
}
@Test
public void waitForSuspendedRequestTest() throws Exception
{

View File

@ -16,6 +16,7 @@ package org.eclipse.jetty.servlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.StringTokenizer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
@ -170,7 +171,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
_resourceService.setAcceptRanges(getInitBoolean("acceptRanges", _resourceService.isAcceptRanges()));
_resourceService.setDirAllowed(getInitBoolean("dirAllowed", _resourceService.isDirAllowed()));
_resourceService.setRedirectWelcome(getInitBoolean("redirectWelcome", _resourceService.isRedirectWelcome()));
_resourceService.setPrecompressedFormats(parsePrecompressedFormats(getInitParameter("precompressed"), getInitBoolean("gzip", false)));
_resourceService.setPrecompressedFormats(parsePrecompressedFormats(getInitParameter("precompressed"), getInitBoolean("gzip"), _resourceService.getPrecompressedFormats()));
_resourceService.setPathInfoOnly(getInitBoolean("pathInfoOnly", _resourceService.isPathInfoOnly()));
_resourceService.setEtags(getInitBoolean("etags", _resourceService.isEtags()));
@ -303,8 +304,12 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
LOG.debug("resource base = {}", _resourceBase);
}
private CompressedContentFormat[] parsePrecompressedFormats(String precompressed, boolean gzip)
private CompressedContentFormat[] parsePrecompressedFormats(String precompressed, Boolean gzip, CompressedContentFormat[] dft)
{
if (precompressed == null && gzip == null)
{
return dft;
}
List<CompressedContentFormat> ret = new ArrayList<>();
if (precompressed != null && precompressed.indexOf('=') > 0)
{
@ -314,7 +319,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
String encoding = setting[0].trim();
String extension = setting[1].trim();
ret.add(new CompressedContentFormat(encoding, extension));
if (gzip && !ret.contains(CompressedContentFormat.GZIP))
if (gzip == Boolean.TRUE && !ret.contains(CompressedContentFormat.GZIP))
ret.add(CompressedContentFormat.GZIP);
}
}
@ -326,7 +331,7 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
ret.add(CompressedContentFormat.GZIP);
}
}
else if (gzip)
else if (gzip == Boolean.TRUE)
{
// gzip handling is for backwards compatibility with older Jetty
ret.add(CompressedContentFormat.GZIP);
@ -367,11 +372,11 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
return value;
}
private boolean getInitBoolean(String name, boolean dft)
private Boolean getInitBoolean(String name)
{
String value = getInitParameter(name);
if (value == null || value.length() == 0)
return dft;
return null;
return (value.startsWith("t") ||
value.startsWith("T") ||
value.startsWith("y") ||
@ -379,6 +384,11 @@ public class DefaultServlet extends HttpServlet implements ResourceFactory, Welc
value.startsWith("1"));
}
private boolean getInitBoolean(String name, boolean dft)
{
return Optional.ofNullable(getInitBoolean(name)).orElse(dft);
}
private int getInitInt(String name, int dft)
{
String value = getInitParameter(name);

View File

@ -40,6 +40,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.DateGenerator;
import org.eclipse.jetty.http.HttpContent;
import org.eclipse.jetty.http.HttpField;
@ -1968,6 +1969,51 @@ public class DefaultServletTest
assertThat(body, containsString("fake gzip"));
}
@Test
public void testProgrammaticCustomCompressionFormats() throws Exception
{
createFile(docRoot.resolve("data0.txt"), "Hello Text 0");
createFile(docRoot.resolve("data0.txt.br"), "fake brotli");
createFile(docRoot.resolve("data0.txt.gz"), "fake gzip");
createFile(docRoot.resolve("data0.txt.bz2"), "fake bzip2");
ResourceService resourceService = new ResourceService();
resourceService.setPrecompressedFormats(new CompressedContentFormat[]{
new CompressedContentFormat("bzip2", ".bz2"),
new CompressedContentFormat("gzip", ".gz"),
new CompressedContentFormat("br", ".br")
});
ServletHolder defholder = new ServletHolder(new DefaultServlet(resourceService));
context.addServlet(defholder, "/");
defholder.setInitParameter("resourceBase", docRoot.toString());
String rawResponse;
HttpTester.Response response;
String body;
rawResponse = connector.getResponse("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:bzip2, br, gzip\r\n\r\n");
response = HttpTester.parseResponse(rawResponse);
assertThat(response.toString(), response.getStatus(), is(HttpStatus.OK_200));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "10"));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_TYPE, "text/plain"));
assertThat(response, containsHeaderValue(HttpHeader.VARY, "Accept-Encoding"));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_ENCODING, "bzip2"));
body = response.getContent();
assertThat(body, containsString("fake bzip2"));
// TODO: show accept-encoding search order issue (shouldn't this request return data0.txt.br?)
rawResponse = connector.getResponse("GET /context/data0.txt HTTP/1.0\r\nHost:localhost:8080\r\nAccept-Encoding:br, gzip\r\n\r\n");
response = HttpTester.parseResponse(rawResponse);
assertThat(response.toString(), response.getStatus(), is(HttpStatus.OK_200));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_LENGTH, "9"));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_TYPE, "text/plain"));
assertThat(response, containsHeaderValue(HttpHeader.VARY, "Accept-Encoding"));
assertThat(response, containsHeaderValue(HttpHeader.CONTENT_ENCODING, "gzip"));
body = response.getContent();
assertThat(body, containsString("fake gzip"));
}
@Test
public void testControlCharacter() throws Exception
{

View File

@ -40,6 +40,7 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.CompressedContentFormat;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.http.HttpTester;
import org.eclipse.jetty.server.HttpOutput;
import org.eclipse.jetty.server.LocalConnector;
@ -55,6 +56,7 @@ import org.junit.jupiter.api.Test;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.equalToIgnoringCase;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
@ -688,6 +690,49 @@ public class GzipHandlerTest
assertEquals(__icontent, testOut.toString("UTF8"));
}
@Test
public void testIncludeExcludeGzipHandlerInflate() throws Exception
{
gzipHandler.addExcludedInflationPaths("/ctx/echo/exclude");
gzipHandler.addIncludedInflationPaths("/ctx/echo/include");
String message = "hello world";
byte[] gzippedMessage = gzipContent(message);
// The included path does deflate the content.
HttpTester.Response response = sendGzipRequest("/ctx/echo/include", message);
assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
assertThat(response.getContent(), equalTo(message));
// The excluded path does not deflate the content.
response = sendGzipRequest("/ctx/echo/exclude", message);
assertThat(response.getStatus(), equalTo(HttpStatus.OK_200));
assertThat(response.getContentBytes(), equalTo(gzippedMessage));
}
private byte[] gzipContent(String content) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream output = new GZIPOutputStream(baos);
output.write(content.getBytes(StandardCharsets.UTF_8));
output.close();
return baos.toByteArray();
}
private HttpTester.Response sendGzipRequest(String uri, String data) throws Exception
{
HttpTester.Request request = HttpTester.newRequest();
request.setMethod("GET");
request.setURI(uri);
request.setVersion("HTTP/1.0");
request.setHeader("Host", "tester");
request.setHeader("Content-Type", "text/plain");
request.setHeader("Content-Encoding", "gzip");
request.setContent(gzipContent(data));
return HttpTester.parseResponse(_connector.getResponse(request.generate()));
}
@Test
public void testAddGetPaths()
{

View File

@ -36,19 +36,11 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>generate-manifest</id>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Export-Package>*,org.eclipse.jetty.websocket.core.client.internal.*</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Export-Package>*,org.eclipse.jetty.websocket.core.client.internal.*</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -35,25 +35,18 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<id>generate-manifest</id>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Export-Package>*,org.eclipse.jetty.websocket.core.common.internal.*</Export-Package>
<Require-Capability>
osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"
</Require-Capability>
<Provide-Capability>
osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.websocket.core.Extension
</Provide-Capability>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Description>Jetty Websocket Core Common</Bundle-Description>
<Export-Package>*,org.eclipse.jetty.websocket.core.common.internal.*</Export-Package>
<Require-Capability>
osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)"; resolution:=optional
</Require-Capability>
<Provide-Capability>
osgi.serviceloader; osgi.serviceloader=org.eclipse.jetty.websocket.core.Extension
</Provide-Capability>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -59,28 +59,21 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-Description>javax.websocket.client Implementation</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.client.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
<Require-Capability>
osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional
</Require-Capability>
<Provide-Capability>
osgi.serviceloader;osgi.serviceloader=javax.websocket.ContainerProvider,
osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer
</Provide-Capability>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Description>javax.websocket.client Implementation</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.client.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
<Require-Capability>
osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional
</Require-Capability>
<Provide-Capability>
osgi.serviceloader;osgi.serviceloader=javax.websocket.ContainerProvider,
osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer
</Provide-Capability>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -20,21 +20,14 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-Description>javax.websocket.client Implementation</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Description>javax.websocket.client Implementation</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -56,25 +56,18 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-Description>javax.websocket.server Implementation</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>
osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.webapp.Configuration,osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=javax.websocket.server.ServerEndpointConfig$Configurator
</Provide-Capability>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Description>javax.websocket.server Implementation</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.server.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Provide-Capability>
osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.webapp.Configuration,osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer,osgi.serviceloader;osgi.serviceloader=javax.websocket.server.ServerEndpointConfig$Configurator
</Provide-Capability>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -77,21 +77,14 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-Description>javax.websocket Integration Tests</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Description>javax.websocket Integration Tests</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.javax.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -64,9 +64,12 @@
<configuration>
<instructions>
<Bundle-Description>Jetty Websocket Server</Bundle-Description>
<Require-Capability>osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional</Require-Capability>
<Require-Capability>
osgi.extender; filter:="(osgi.extender=osgi.serviceloader.registrar)";resolution:=optional
</Require-Capability>
<Provide-Capability>
osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.webapp.Configuration,osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer
osgi.serviceloader;osgi.serviceloader=org.eclipse.jetty.webapp.Configuration,
osgi.serviceloader;osgi.serviceloader=javax.servlet.ServletContainerInitializer
</Provide-Capability>
</instructions>
</configuration>

View File

@ -98,21 +98,14 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-Description>jetty.websocket Integration Tests</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.jetty.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Description>jetty.websocket Integration Tests</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.jetty.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

32
pom.xml
View File

@ -32,7 +32,7 @@
<asciidoctorj.version>2.5.3</asciidoctorj.version>
<asm.version>9.3</asm.version>
<awaitility.version>4.2.0</awaitility.version>
<bndlib.version>5.3.0</bndlib.version>
<bndlib.version>6.2.0</bndlib.version>
<build-support.version>1.5</build-support.version>
<checkstyle.version>10.2</checkstyle.version>
<commons-codec.version>1.15</commons-codec.version>
@ -49,9 +49,9 @@
<guava.version>31.1-jre</guava.version>
<guice.version>5.1.0</guice.version>
<hamcrest.version>2.2</hamcrest.version>
<hawtio.version>2.14.5</hawtio.version>
<hawtio.version>2.15.0</hawtio.version>
<hazelcast.version>4.2.5</hazelcast.version>
<infinispan.protostream.version>4.4.2.Final</infinispan.protostream.version>
<infinispan.protostream.version>4.4.3.Final</infinispan.protostream.version>
<infinispan.version>11.0.15.Final</infinispan.version>
<jackson.annotations.version>2.13.2</jackson.annotations.version>
<jackson.core.version>2.13.2</jackson.core.version>
@ -101,18 +101,20 @@
<json-smart.version>2.4.8</json-smart.version>
<jsp.impl.version>9.0.52</jsp.impl.version>
<junit.version>5.8.2</junit.version>
<kerb-simplekdc.version>2.0.1</kerb-simplekdc.version>
<kerb-simplekdc.version>2.0.2</kerb-simplekdc.version>
<log4j2.version>2.17.2</log4j2.version>
<logback.version>1.3.0-alpha14</logback.version>
<logback.version>1.3.0-alpha15</logback.version>
<mariadb.version>3.0.4</mariadb.version>
<mariadb.docker.version>10.3.6</mariadb.docker.version>
<maven-artifact-transfer.version>0.13.1</maven-artifact-transfer.version>
<maven.resolver.version>1.8.0</maven.resolver.version>
<maven.version>3.8.4</maven.version>
<mongodb.version>3.2.2</mongodb.version>
<mongodb.version>3.12.11</mongodb.version>
<openpojo.version>0.9.1</openpojo.version>
<org.osgi.annotation.version>8.1.0</org.osgi.annotation.version>
<org.osgi.core.version>6.0.0</org.osgi.core.version>
<org.osgi.util.function.version>1.2.0</org.osgi.util.function.version>
<org.osgi.util.promise.version>1.2.0</org.osgi.util.promise.version>
<plexus-component-annotations.version>2.1.1</plexus-component-annotations.version>
<plexus-utils.version>3.4.1</plexus-utils.version>
<slf4j.version>2.0.0-alpha6</slf4j.version>
@ -813,7 +815,6 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>${maven.bundle.plugin.version}</version>
<extensions>true</extensions>
<configuration>
<supportedProjectTypes>
<supportedProjectType>jar</supportedProjectType>
@ -1965,14 +1966,31 @@
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<!-- older artifact location, some of our transitive deps still use this coordinate -->
<artifactId>org.osgi.core</artifactId>
<version>${org.osgi.core.version}</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<!-- newer artifact location, some of our transitive deps use this up to date coordinate -->
<artifactId>osgi.core</artifactId>
<version>${org.osgi.core.version}</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>osgi.annotation</artifactId>
<version>${org.osgi.annotation.version}</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.util.function</artifactId>
<version>${org.osgi.util.function.version}</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.util.promise</artifactId>
<version>${org.osgi.util.promise.version}</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>

View File

@ -91,21 +91,14 @@
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<executions>
<execution>
<goals>
<goal>manifest</goal>
</goals>
<configuration>
<instructions>
<Bundle-Description>jetty.websocket Autobahn Tests</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.jetty.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-Description>jetty.websocket Autobahn Tests</Bundle-Description>
<Export-Package>
org.eclipse.jetty.websocket.jetty.tests.*;version="${parsedVersion.majorVersion}.${parsedVersion.minorVersion}.${parsedVersion.incrementalVersion}"
</Export-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>