Skip to content

Commit

Permalink
Fixes #12063 - Introduce Jetty module for HTTP/2 client dependencies. (
Browse files Browse the repository at this point in the history
…#12170)

Introduced http2-client.mod and http2-client-transport.mod.
These modules download dependencies via a [files] section.
They can be used to have the server provide the dependencies in case of a web application proxies request using HTTP/2.

Fixed ContentProvider to set the context ClassLoader before reading the Jetty XML context file, which may reference classes from the web application.

Signed-off-by: Simone Bordet <[email protected]>
  • Loading branch information
sbordet authored Aug 23, 2024
1 parent 6527aa5 commit bb52d95
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 4 deletions.
8 changes: 6 additions & 2 deletions jetty-core/jetty-client/src/main/config/modules/client.mod
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
# DO NOT EDIT THIS FILE - See: https://jetty.org/docs/

[description]
Adds the Jetty HTTP client to the server classpath.
Adds the Jetty HTTP client dependencies to the server classpath.

[tags]
client

[lib]
lib/jetty-client-${jetty.version}.jar
lib/jetty-alpn-client-${jetty.version}.jar
lib/jetty-alpn-java-client-${jetty.version}.jar
lib/jetty-client-${jetty.version}.jar
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ public ContextHandler createContextHandler(final App app) throws Exception
// Handle a context XML file
if (FileID.isXml(path))
{
ClassLoader coreContextClassLoader = Environment.CORE.equals(environment) ? findCoreContextClassLoader(path) : null;
if (coreContextClassLoader != null)
Thread.currentThread().setContextClassLoader(coreContextClassLoader);

context = applyXml(context, path, env, properties);

// Look for the contextHandler itself
Expand All @@ -401,13 +405,11 @@ else if (context instanceof Supplier<?> supplier)
throw new IllegalStateException("Unknown context type of " + context);

// Set the classloader if we have a coreContextClassLoader
ClassLoader coreContextClassLoader = Environment.CORE.equals(environment) ? findCoreContextClassLoader(path) : null;
if (coreContextClassLoader != null)
contextHandler.setClassLoader(coreContextClassLoader);

return contextHandler;
}

// Otherwise it must be a directory or an archive
else if (!Files.isDirectory(path) && !FileID.isWebArchive(path))
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
[description]
Adds the Jetty HTTP/2 client transport dependencies to the server classpath.

[tags]
client
http2

[depends]
client
http2-client

[files]
maven://org.eclipse.jetty.http2/jetty-http2-client-transport/${jetty.version}/jar|lib/http2/jetty-http2-client-transport-${jetty.version}.jar

[lib]
lib/http2/jetty-http2-client-transport-${jetty.version}.jar
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[description]
Adds the Jetty HTTP/2 client dependencies to the server classpath.

[tags]
client
http2

[files]
maven://org.eclipse.jetty/jetty-alpn-client/${jetty.version}/jar|lib/jetty-alpn-client-${jetty.version}.jar
maven://org.eclipse.jetty/jetty-alpn-java-client/${jetty.version}/jar|lib/jetty-alpn-java-client-${jetty.version}.jar
maven://org.eclipse.jetty.http2/jetty-http2-client/${jetty.version}/jar|lib/http2/jetty-http2-client-${jetty.version}.jar

[lib]
lib/jetty-alpn-client-${jetty.version}.jar
lib/jetty-alpn-java-client-${jetty.version}.jar
lib/http2/jetty-http2-client-${jetty.version}.jar
lib/http2/jetty-http2-common-${jetty.version}.jar
lib/http2/jetty-http2-hpack-${jetty.version}.jar
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-tests</artifactId>
<version>12.0.13-SNAPSHOT</version>
</parent>

<artifactId>jetty-test-http2-client-transport-provided-webapp</artifactId>
<name>Core :: Tests :: HTTP/2 Client Transport Provided WebApp</name>

<properties>
<maven.deploy.skip>true</maven.deploy.skip>
</properties>

<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>jetty-http2-client-transport</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
//
// ========================================================================
// 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.test.http2.client.transport.provided;

import java.util.concurrent.TimeUnit;

import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.transport.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;

public class HTTP2ClientTransportProvidedHandler extends Handler.Abstract
{
private final HttpClient httpClient = new HttpClient(new HttpClientTransportOverHTTP2(new HTTP2Client()));

@Override
protected void doStart() throws Exception
{
addBean(httpClient);
super.doStart();
}

@Override
public boolean handle(Request request, Response response, Callback callback) throws Exception
{
// Verify that the HTTP2Client dependencies are provided by the server
// by making a request to an external server, as if this Handler was a proxy.

httpClient.newRequest("https://webtide.com/")
.timeout(15, TimeUnit.SECONDS)
.send(result ->
{
if (result.isSucceeded())
{
response.setStatus(result.getResponse().getStatus());
callback.succeeded();
}
else
{
callback.failed(result.getFailure());
}
});
return true;
}
}
1 change: 1 addition & 0 deletions jetty-core/jetty-tests/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
<modules>
<module>jetty-test-client-transports</module>
<module>jetty-test-jmx</module>
<module>jetty-test-http2-client-transport-provided-webapp</module>
</modules>

<properties>
Expand Down
4 changes: 4 additions & 0 deletions jetty-home/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@
<artifactId>jetty-gcloud-session-manager</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>jetty-http2-client-transport</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>jetty-http2-server</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1892,4 +1892,54 @@ public void testStateTrackingModule() throws Exception
}
}
}

@Test
public void testHTTP2ClientInCoreWebAppProvidedByServer() throws Exception
{
String jettyVersion = System.getProperty("jettyVersion");
JettyHomeTester distribution = JettyHomeTester.Builder.newInstance()
.jettyVersion(jettyVersion)
.build();

try (JettyHomeTester.Run run1 = distribution.start("--add-modules=http,http2-client-transport,core-deploy"))
{
assertTrue(run1.awaitFor(START_TIMEOUT, TimeUnit.SECONDS));
assertEquals(0, run1.getExitValue());

Path jettyLogging = distribution.getJettyBase().resolve("resources/jetty-logging.properties");
String loggingConfig = """
org.eclipse.jetty.LEVEL=DEBUG
""";
Files.writeString(jettyLogging, loggingConfig, StandardOpenOption.TRUNCATE_EXISTING);

String name = "test-webapp";
Path webapps = distribution.getJettyBase().resolve("webapps");
Path webAppDirLib = webapps.resolve(name + ".d").resolve("lib");
Path webAppJar = distribution.resolveArtifact("org.eclipse.jetty:jetty-test-http2-client-transport-provided-webapp:jar:" + jettyVersion);
Files.copy(webAppJar, Files.createDirectories(webAppDirLib).resolve("webapp.jar"));
Files.writeString(webapps.resolve(name + ".xml"), """
<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">
<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
<Set name="contextPath">/test</Set>
<Set name="handler">
<New class="org.eclipse.jetty.test.http2.client.transport.provided.HTTP2ClientTransportProvidedHandler" />
</Set>
</Configure>
""");

int port = Tester.freePort();
try (JettyHomeTester.Run run2 = distribution.start("jetty.http.port=" + port))
{
assertTrue(run2.awaitConsoleLogsFor("Started oejs.Server@", START_TIMEOUT, TimeUnit.SECONDS));

startHttpClient();
URI serverUri = URI.create("http://localhost:" + port + "/test/");
ContentResponse response = client.newRequest(serverUri)
.timeout(15, TimeUnit.SECONDS)
.send();
assertEquals(HttpStatus.OK_200, response.getStatus());
}
}
}
}

0 comments on commit bb52d95

Please sign in to comment.