diff --git a/mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/HttpTransporter.java b/mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/HttpTransporter.java index 3962c43..07ebcd0 100644 --- a/mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/HttpTransporter.java +++ b/mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/HttpTransporter.java @@ -38,7 +38,6 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; import java.nio.file.Files; import java.nio.file.attribute.FileTime; import java.text.DateFormat; @@ -70,75 +69,8 @@ final class HttpTransporter extends AbstractTransporter { RemoteRepository repository, RepositorySystemSession session) throws Exception { - System.err.println("Custom HttpTransporter created!!!"); - // Checking http3 support is available (loaded) - PreEncodedHttpField f = new PreEncodedHttpField("Host", "localhost"); - for (final HttpVersion v: HttpVersion.values()) { - int len = 0; - try { - len = f.getEncodedLength(v); - } catch (Exception ex) { - len = -1; - } - System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len); - } - - // TODO: Force http3 initialization (HACK!) - final ServiceLoader load = ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader()); - /*ServiceLoader load = null; - ClassLoader saveCl = Thread.currentThread().getContextClassLoader(); - try { - Thread.currentThread().setContextClassLoader(PreEncodedHttpField.class.getClassLoader()); - load = ServiceLoader.load(HttpFieldPreEncoder.class); - }finally { - Thread.currentThread().setContextClassLoader(saveCl); - }*/ - - /*System.err.println("\tCustom HttpTransporter ServiceLoader=" + load); - Stream> providerStream = TypeUtil.serviceProviderStream(load); - System.err.println("\tCustom HttpTransporter Stream> = " + providerStream); - ArrayList calls = new ArrayList<>(); - providerStream.forEach((provider) -> { - try { - calls.add(calls.size()); - HttpFieldPreEncoder encoder = (HttpFieldPreEncoder)provider.get(); - HttpVersion v = encoder.getHttpVersion(); - System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder: encoder=" + encoder + "; ver=" + v); - } catch (RuntimeException | Error var3) { - System.err.println("\tCustom HttpTransporter Error processing encoder: " + provider.get()); - } - }); - System.err.println("\tCustom HttpTransporter providerStream calls=" + calls.size());*/ - - HashMap encoders = new HashMap<>(); - for (HttpFieldPreEncoder val: load) { - System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder val=" + val); - encoders.put(val.getHttpVersion(), val); - } - - Field ff = PreEncodedHttpField.class.getDeclaredField("__encoders"); - ff.setAccessible(true); - String fldDescr = ff.get(null).toString(); - System.err.println("\tCustom HttpTransporter __encoders BEFORE: " + fldDescr + "; this=" + this); - @SuppressWarnings("unchecked") EnumMap obj = (EnumMap)ff.get(null); - if (encoders.containsKey(HttpVersion.HTTP_3) && !obj.containsKey(HttpVersion.HTTP_3)) { - System.err.println("\tCustom HttpTransporter adding to __encoders: " + obj + "; this=" + this); - obj.put(HttpVersion.HTTP_3, encoders.get(HttpVersion.HTTP_3)); - } - System.err.println("\tCustom HttpTransporter __encoders AFTER: " + obj + "; this=" + this); - - // Rechecking http3 support is available (loaded) - f = new PreEncodedHttpField("Host", "localhost"); - for (final HttpVersion v: HttpVersion.values()) { - int len = 0; - try { - len = f.getEncodedLength(v); - } catch (Exception ex) { - len = -1; - } - System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len); - } + forceLoadHttp3Support(); if (!"http".equalsIgnoreCase(repository.getProtocol()) && !"https".equalsIgnoreCase(repository.getProtocol())) { throw new NoTransporterException(repository); @@ -286,4 +218,83 @@ private void extractChecksums(ContentResponse response, GetTask task) { } } } + + /** + * TOOD: For unknown reason when running inside Maven, HttpFieldPreEncoder for HTTP3 is missing. + * It is not available in Jetty static initializer when that library is loaded by Maven. + * However, it is available the moment later. + * Here I use reflection to force-register missing HttpFieldPreEncoder for HTTP3. + * @throws NoSuchFieldException + * @throws IllegalAccessException + */ + private void forceLoadHttp3Support() throws NoSuchFieldException, IllegalAccessException { + System.err.println("Custom HttpTransporter.forceLoadHttp3Support() called!"); + // Checking http3 support is available (loaded) + PreEncodedHttpField f = new PreEncodedHttpField("Host", "localhost"); + for (final HttpVersion v: HttpVersion.values()) { + int len = 0; + try { + len = f.getEncodedLength(v); + } catch (Exception ex) { + len = -1; + } + System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len); + } + + // TODO: Force http3 initialization (HACK!) + final ServiceLoader load = ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader()); + /*ServiceLoader load = null; + ClassLoader saveCl = Thread.currentThread().getContextClassLoader(); + try { + Thread.currentThread().setContextClassLoader(PreEncodedHttpField.class.getClassLoader()); + load = ServiceLoader.load(HttpFieldPreEncoder.class); + }finally { + Thread.currentThread().setContextClassLoader(saveCl); + }*/ + + /*System.err.println("\tCustom HttpTransporter ServiceLoader=" + load); + Stream> providerStream = TypeUtil.serviceProviderStream(load); + System.err.println("\tCustom HttpTransporter Stream> = " + providerStream); + ArrayList calls = new ArrayList<>(); + providerStream.forEach((provider) -> { + try { + calls.add(calls.size()); + HttpFieldPreEncoder encoder = (HttpFieldPreEncoder)provider.get(); + HttpVersion v = encoder.getHttpVersion(); + System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder: encoder=" + encoder + "; ver=" + v); + } catch (RuntimeException | Error var3) { + System.err.println("\tCustom HttpTransporter Error processing encoder: " + provider.get()); + } + }); + System.err.println("\tCustom HttpTransporter providerStream calls=" + calls.size());*/ + + HashMap encoders = new HashMap<>(); + for (HttpFieldPreEncoder val: load) { + System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder val=" + val); + encoders.put(val.getHttpVersion(), val); + } + + Field ff = PreEncodedHttpField.class.getDeclaredField("__encoders"); + ff.setAccessible(true); + String fldDescr = ff.get(null).toString(); + System.err.println("\tCustom HttpTransporter __encoders BEFORE: " + fldDescr + "; this=" + this); + @SuppressWarnings("unchecked") EnumMap obj = (EnumMap)ff.get(null); + if (encoders.containsKey(HttpVersion.HTTP_3) && !obj.containsKey(HttpVersion.HTTP_3)) { + System.err.println("\tCustom HttpTransporter adding to __encoders: " + obj + "; this=" + this); + obj.put(HttpVersion.HTTP_3, encoders.get(HttpVersion.HTTP_3)); + } + System.err.println("\tCustom HttpTransporter __encoders AFTER: " + obj + "; this=" + this); + + // Rechecking http3 support is available (loaded) + f = new PreEncodedHttpField("Host", "localhost"); + for (final HttpVersion v: HttpVersion.values()) { + int len = 0; + try { + len = f.getEncodedLength(v); + } catch (Exception ex) { + len = -1; + } + System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len); + } + } } diff --git a/mvn-resolver-transport-http3/src/test/java/com/artipie/aether/transport/http3/MavenResolverIT.java b/mvn-resolver-transport-http3/src/test/java/com/artipie/aether/transport/http3/MavenResolverIT.java index a9a22a4..1e63e0d 100644 --- a/mvn-resolver-transport-http3/src/test/java/com/artipie/aether/transport/http3/MavenResolverIT.java +++ b/mvn-resolver-transport-http3/src/test/java/com/artipie/aether/transport/http3/MavenResolverIT.java @@ -8,7 +8,6 @@ import org.eclipse.aether.spi.connector.transport.GetTask; import org.eclipse.aether.spi.connector.transport.TransportListener; import org.eclipse.aether.spi.connector.transport.Transporter; -import org.eclipse.aether.transfer.TransferCancelledException; import org.eclipse.jetty.client.ContentResponse; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.HttpRequestException; @@ -23,7 +22,6 @@ import org.testcontainers.containers.InternetProtocol; import org.testcontainers.containers.wait.strategy.ShellStrategy; import java.net.URI; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import static org.junit.Assert.*; @@ -32,63 +30,68 @@ */ public class MavenResolverIT { - private static GenericContainer caddy; - private static GenericContainer caddyAuth; + private static final String REMOTE_PATH = "commons-cli/commons-cli/1.4/commons-cli-1.4.pom"; + private static final String LOCAL_PATH = "commons-cli-1.4.pom"; + + private static GenericContainer caddyProxy; + private static GenericContainer caddyProxyAuth; @Test public void testTransporterAuth() throws Exception { final byte[] data = testTransporter("https://demo:demo@localhost:7444/maven2"); assertNotEquals(null, data); - System.err.println(new String(data, StandardCharsets.UTF_8)); - assertTrue(data.length > 0); + final byte[] local = getClass().getClassLoader().getResourceAsStream(LOCAL_PATH).readAllBytes(); + assertArrayEquals(local, data); } - @Test(expected = HttpResponseException.class) - public void testTransporterAuthFail() throws Exception { - final byte[] data = testTransporter("https://demo1:demo1@localhost:7444/maven2"); - assertNull(data); + @Test + public void testTransporterAuthFail() { + HttpResponseException exception = assertThrows( + "Invalid exception thrown", HttpResponseException.class, + () -> testTransporter("https://demo1:demo1@localhost:7444/maven2") + ); + assertEquals("401", exception.getMessage()); } - @Test(expected = HttpResponseException.class) - public void testTransporterAnonAuthFail() throws Exception { - testTransporter("https://localhost:7444/maven2"); + @Test + public void testTransporterAnonAuthFail() { + HttpResponseException exception = assertThrows( + "Invalid exception thrown", HttpResponseException.class, + () -> testTransporter("https://localhost:7444/maven2") + ); + assertEquals("401", exception.getMessage()); } @Test public void testTransporterAnon() throws Exception { final byte[] data = testTransporter("https://localhost:7443/maven2"); assertNotEquals(null, data); - System.err.println(new String(data, StandardCharsets.UTF_8)); - assertTrue(data.length > 0); - } + final byte[] local = getClass().getClassLoader().getResourceAsStream(LOCAL_PATH).readAllBytes(); + assertArrayEquals(local, data); } @Test public void testAnonTransporterSuccess() throws Exception { final byte[] data = testTransporter("https://demo:demo@localhost:7443/maven2"); assertNotNull(data); - assertTrue(data.length > 0); + final byte[] local = getClass().getClassLoader().getResourceAsStream(LOCAL_PATH).readAllBytes(); + assertArrayEquals(local, data); } - @Test(expected = HttpRequestException.class) - public void testTransporterInvalidUrl() throws Exception { - testTransporter("https://localhost:7445/maven2"); + @Test() + public void testTransporterInvalidUrl() { + HttpRequestException exception = assertThrows( + "Invalid exception thrown", HttpRequestException.class, + () -> testTransporter("https://localhost:7445/maven2") + ); + assertEquals("java.net.SocketTimeoutException: connect timeout", exception.getMessage()); } private byte[] testTransporter(final String repo) throws Exception { final RepositorySystemSession session = newSession(); final RemoteRepository repository = newRepo(repo); final HttpTransporterFactory factory = new HttpTransporterFactory(); - TransportListener listener = new TransportListener() { - @Override - public void transportStarted(long dataOffset, long dataLength) throws TransferCancelledException { - super.transportStarted(dataOffset, dataLength); - } - @Override - public void transportProgressed(ByteBuffer data) throws TransferCancelledException { - super.transportProgressed(data); - } - }; - final GetTask task = new GetTask(URI.create("commons-cli/commons-cli/1.4/commons-cli-1.4.pom")).setListener(listener); + final GetTask task = new GetTask(URI.create(REMOTE_PATH)) + .setListener(new TransportListener() {}); try (final Transporter transporter = factory.newInstance(session, repository)) { transporter.get(task); } @@ -111,36 +114,36 @@ public void testJettyLocalhostConnection() throws Exception { @BeforeClass public static void prepare() { try { - caddy = new FixedHostPortGenericContainer<>("library/caddy:2.7.5") + caddyProxy = new FixedHostPortGenericContainer<>("library/caddy:2.7.5") .withReuse(false) - .withFileSystemBind("src/test/resources/Caddyfile.docker", "/etc/caddy/Caddyfile") + .withFileSystemBind("src/test/resources/Caddyfile.proxy", "/etc/caddy/Caddyfile") .withFileSystemBind("src/test/resources/stunnel.pem", "/etc/caddy/stunnel.pem") .waitingFor(new ShellStrategy().withCommand("nc -u -z localhost 7443")) .withFixedExposedPort(7443, 7443, InternetProtocol.UDP) .withFixedExposedPort(8080, 8080, InternetProtocol.TCP) .withAccessToHost(true); - caddyAuth = new FixedHostPortGenericContainer<>("library/caddy:2.7.5") + caddyProxyAuth = new FixedHostPortGenericContainer<>("library/caddy:2.7.5") .withReuse(false) - .withFileSystemBind("src/test/resources/Caddyfile.auth.docker", "/etc/caddy/Caddyfile") + .withFileSystemBind("src/test/resources/Caddyfile.proxy.auth", "/etc/caddy/Caddyfile") .withFileSystemBind("src/test/resources/stunnel.pem", "/etc/caddy/stunnel.pem") .waitingFor(new ShellStrategy().withCommand("nc -u -z localhost 7444")) .withFixedExposedPort(7444, 7444, InternetProtocol.UDP) .withAccessToHost(true); - caddy.start(); - caddyAuth.start(); + caddyProxy.start(); + caddyProxyAuth.start(); } catch (Exception ex) { - System.err.println(caddy.getLogs()); - System.err.println(caddyAuth.getLogs()); + System.err.println(caddyProxy.getLogs()); + System.err.println(caddyProxyAuth.getLogs()); throw ex; } } @AfterClass public static void finish() { - caddy.stop(); - caddyAuth.stop(); + caddyProxy.stop(); + caddyProxyAuth.stop(); } private static DefaultRepositorySystemSession newSession() { diff --git a/mvn-resolver-transport-http3/src/test/resources/Caddyfile.docker b/mvn-resolver-transport-http3/src/test/resources/Caddyfile.proxy similarity index 100% rename from mvn-resolver-transport-http3/src/test/resources/Caddyfile.docker rename to mvn-resolver-transport-http3/src/test/resources/Caddyfile.proxy diff --git a/mvn-resolver-transport-http3/src/test/resources/Caddyfile.auth.docker b/mvn-resolver-transport-http3/src/test/resources/Caddyfile.proxy.auth similarity index 100% rename from mvn-resolver-transport-http3/src/test/resources/Caddyfile.auth.docker rename to mvn-resolver-transport-http3/src/test/resources/Caddyfile.proxy.auth diff --git a/mvn-resolver-transport-http3/src/test/resources/commons-cli-1.4.pom b/mvn-resolver-transport-http3/src/test/resources/commons-cli-1.4.pom new file mode 100644 index 0000000..1a65965 --- /dev/null +++ b/mvn-resolver-transport-http3/src/test/resources/commons-cli-1.4.pom @@ -0,0 +1,333 @@ + + + + + org.apache.commons + commons-parent + 42 + + 4.0.0 + commons-cli + commons-cli + 1.4 + Apache Commons CLI + + 2002 + + Apache Commons CLI provides a simple API for presenting, processing and validating a command line interface. + + + http://commons.apache.org/proper/commons-cli/ + + + jira + http://issues.apache.org/jira/browse/CLI + + + + scm:svn:http://svn.apache.org/repos/asf/commons/proper/cli/trunk/ + scm:svn:https://svn.apache.org/repos/asf/commons/proper/cli/trunk/ + http://svn.apache.org/viewvc/commons/proper/cli/trunk/ + + + + + James Strachan + jstrachan + jstrachan@apache.org + SpiritSoft, Inc. + + + Bob McWhirter + bob + bob@werken.com + Werken + + contributed ideas and code from werken.opt + + + + John Keyes + jkeyes + jbjk@mac.com + integral Source + + contributed ideas and code from Optz + + + + Rob Oxspring + roxspring + roxspring@imapmail.org + Indigo Stone + + designed CLI2 + + + + Emmanuel Bourg + ebourg + ebourg@apache.org + Ariane Software + + + Thomas Neidhart + tn + tn@apache.org + + + + + + Beluga Behr + + + Peter Donald + + contributed ideas and code from Avalon Excalibur's cli package + + + + Brian Egge + + made the 1.1 release happen + + + + Duncan Jones + + supplied patches + + + + Berin Loritsch + bloritsch@apache.org + + helped in the Avalon CLI merge + + + + Peter Maddocks + peter_maddocks@hp.com + Hewlett-Packard + + supplied patch + + + + Alexandru Mocanu + + supplied patch + + + + Andrew Shirley + + lots of fixes for 1.1 + + + + Greg Thomas + + + Slawek Zachcial + + unit tests + + + + + + + + junit + junit + 4.12 + test + + + + + 1.5 + 1.5 + cli + 1.4 + commons-cli-${commons.release.version} + org.apache.commons.cli + CLI + 12310463 + + RC1 + + site-content + utf-8 + + + + + + maven-assembly-plugin + + + src/assembly/bin.xml + src/assembly/src.xml + + gnu + + + + + + + org.apache.rat + apache-rat-plugin + + + src/site/resources/.htaccess + + + + + org.apache.maven.plugins + maven-scm-publish-plugin + + + javadocs** + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + + true + + http://download.oracle.com/javase/6/docs/api + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 2.15 + + ${basedir}/src/conf/checkstyle.xml + false + ${basedir}/src/conf/checkstyle-suppressions.xml + + + + + checkstyle + + + + + + org.codehaus.mojo + findbugs-maven-plugin + 3.0.1 + + Normal + Default + ${basedir}/src/conf/findbugs-exclude-filter.xml + + + + maven-pmd-plugin + 3.5 + + ${maven.compiler.target} + + + + + + + + apache.website + Apache Commons Site + scm:svn:${commons.scmPubUrl} + + + + + + rc + + + + apache.website + Apache Commons Release Candidate Staging Site + ${commons.deployment.protocol}://people.apache.org/www/people.apache.org/builds/commons/${commons.componentid}/${commons.release.version}/${commons.rc.version}/site + + + + + setup-checkout + + + site-content + + + + + + org.apache.maven.plugins + maven-antrun-plugin + 1.7 + + + prepare-checkout + pre-site + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + +