Skip to content

Commit

Permalink
[MRESOLVER-426] Make some HTTP configuration shared (#356)
Browse files Browse the repository at this point in the history
Many of HTTP related options are not Apache HTTP transport specific. Also, make possible some newer java.net.http.HttpClient options to be applied.

---

https://issues.apache.org/jira/browse/MRESOLVER-426
  • Loading branch information
cstamas authored Nov 8, 2023
1 parent 9abe2f1 commit b3d0aea
Show file tree
Hide file tree
Showing 12 changed files with 493 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,44 @@ public final class ConfigurationProperties {
*/
public static final int DEFAULT_HTTP_MAX_CONNECTIONS_PER_ROUTE = 50;

/**
* The local address (interface) to use with HTTP transport. Not all transport supports this option.
*
* @since 2.0.0
*/
public static final String HTTP_LOCAL_ADDRESS = PREFIX_CONNECTOR + "http.localAddress";

/**
* Boolean flag should the HTTP transport support WebDAV remote. Not all transport support this option.
*
* @see #DEFAULT_HTTP_SUPPORT_WEBDAV
* @since 2.0.0 (moved out from maven-resolver-transport-http).
*/
public static final String HTTP_SUPPORT_WEBDAV = PREFIX_CONNECTOR + "http.supportWebDav";

/**
* Default value to use if {@link #HTTP_SUPPORT_WEBDAV} is not set: {@code false}.
*
* @since 2.0.0
*/
public static final boolean DEFAULT_HTTP_SUPPORT_WEBDAV = false;

/**
* Boolean flag should the HTTP transport use preemptive-auth for PUT requests. Not all transport support this
* option.
*
* @see #DEFAULT_HTTP_PREEMPTIVE_PUT_AUTH
* @since 2.0.0 (moved out from maven-resolver-transport-http).
*/
public static final String HTTP_PREEMPTIVE_PUT_AUTH = PREFIX_CONNECTOR + "http.preemptivePutAuth";

/**
* Default value if {@link #HTTP_PREEMPTIVE_PUT_AUTH} is not set: {@code true}.
*
* @since 2.0.0
*/
public static final boolean DEFAULT_HTTP_PREEMPTIVE_PUT_AUTH = true;

/**
* The mode that sets HTTPS transport "security mode": to ignore any SSL errors (certificate validity checks,
* hostname verification). The default value is {@link #HTTPS_SECURITY_MODE_DEFAULT}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,12 +106,6 @@
*/
final class HttpTransporter extends AbstractTransporter {

static final String BIND_ADDRESS = "aether.connector.bind.address";

static final String SUPPORT_WEBDAV = "aether.connector.http.supportWebDav";

static final String PREEMPTIVE_PUT_AUTH = "aether.connector.http.preemptivePutAuth";

static final String USE_SYSTEM_PROPERTIES = "aether.connector.http.useSystemProperties";

static final String HTTP_RETRY_HANDLER_NAME = "aether.connector.http.retryHandler.name";
Expand Down Expand Up @@ -211,11 +205,16 @@ final class HttpTransporter extends AbstractTransporter {
ConfigurationProperties.DEFAULT_HTTP_PREEMPTIVE_AUTH,
ConfigurationProperties.HTTP_PREEMPTIVE_AUTH + "." + repository.getId(),
ConfigurationProperties.HTTP_PREEMPTIVE_AUTH);
this.preemptivePutAuth = // defaults to true: Wagon does same
ConfigUtils.getBoolean(
session, true, PREEMPTIVE_PUT_AUTH + "." + repository.getId(), PREEMPTIVE_PUT_AUTH);
this.supportWebDav = // defaults to false: who needs it will enable it
ConfigUtils.getBoolean(session, false, SUPPORT_WEBDAV + "." + repository.getId(), SUPPORT_WEBDAV);
this.preemptivePutAuth = ConfigUtils.getBoolean(
session,
ConfigurationProperties.DEFAULT_HTTP_PREEMPTIVE_PUT_AUTH,
ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH + "." + repository.getId(),
ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH);
this.supportWebDav = ConfigUtils.getBoolean(
session,
ConfigurationProperties.DEFAULT_HTTP_SUPPORT_WEBDAV,
ConfigurationProperties.HTTP_SUPPORT_WEBDAV + "." + repository.getId(),
ConfigurationProperties.HTTP_SUPPORT_WEBDAV);
String credentialEncoding = ConfigUtils.getString(
session,
ConfigurationProperties.DEFAULT_HTTP_CREDENTIAL_ENCODING,
Expand Down Expand Up @@ -277,7 +276,7 @@ final class HttpTransporter extends AbstractTransporter {
RequestConfig requestConfig = RequestConfig.custom()
.setConnectTimeout(connectTimeout)
.setConnectionRequestTimeout(connectTimeout)
.setLocalAddress(getBindAddress(session, repository))
.setLocalAddress(getHttpLocalAddress(session, repository))
.setSocketTimeout(requestTimeout)
.build();

Expand Down Expand Up @@ -338,9 +337,12 @@ final class HttpTransporter extends AbstractTransporter {
/**
* Returns non-null {@link InetAddress} if set in configuration, {@code null} otherwise.
*/
private InetAddress getBindAddress(RepositorySystemSession session, RemoteRepository repository) {
String bindAddress =
ConfigUtils.getString(session, null, BIND_ADDRESS + "." + repository.getId(), BIND_ADDRESS);
private InetAddress getHttpLocalAddress(RepositorySystemSession session, RemoteRepository repository) {
String bindAddress = ConfigUtils.getString(
session,
null,
ConfigurationProperties.HTTP_LOCAL_ADDRESS + "." + repository.getId(),
ConfigurationProperties.HTTP_LOCAL_ADDRESS);
if (bindAddress == null) {
return null;
}
Expand Down Expand Up @@ -591,7 +593,7 @@ private <T extends HttpUriRequest> T commonHeaders(T request) {
}

@SuppressWarnings("checkstyle:magicnumber")
private <T extends HttpUriRequest> T resume(T request, GetTask task) {
private <T extends HttpUriRequest> void resume(T request, GetTask task) {
long resumeOffset = task.getResumeOffset();
if (resumeOffset > 0L && task.getDataFile() != null) {
request.setHeader(HttpHeaders.RANGE, "bytes=" + resumeOffset + '-');
Expand All @@ -600,7 +602,6 @@ private <T extends HttpUriRequest> T resume(T request, GetTask task) {
DateUtils.formatDate(new Date(task.getDataFile().lastModified() - 60L * 1000L)));
request.setHeader(HttpHeaders.ACCEPT_ENCODING, "identity");
}
return request;
}

@SuppressWarnings("checkstyle:magicnumber")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ void testPut_Authenticated_ExpectContinue() throws Exception {
@Test
void testPut_Authenticated_ExpectContinueBroken() throws Exception {
// this makes OPTIONS recover, and have only 1 PUT (startedCount=1 as OPTIONS is not counted)
session.setConfigProperty(HttpTransporter.SUPPORT_WEBDAV, true);
session.setConfigProperty(ConfigurationProperties.HTTP_SUPPORT_WEBDAV, true);
httpServer.setAuthentication("testuser", "testpass");
httpServer.setExpectSupport(HttpServer.ExpectContinue.BROKEN);
auth = new AuthenticationBuilder()
Expand Down Expand Up @@ -828,7 +828,7 @@ void testPut_SSL() throws Exception {
@Test
void testPut_WebDav() throws Exception {
httpServer.setWebDav(true);
session.setConfigProperty(HttpTransporter.SUPPORT_WEBDAV, true);
session.setConfigProperty(ConfigurationProperties.HTTP_SUPPORT_WEBDAV, true);
newTransporter(httpServer.getHttpUrl());

RecordingTransportListener listener = new RecordingTransportListener();
Expand Down Expand Up @@ -943,7 +943,7 @@ void testPut_PreemptiveIsDefault() throws Exception {

@Test
void testPut_AuthCache() throws Exception {
session.setConfigProperty(HttpTransporter.PREEMPTIVE_PUT_AUTH, false);
session.setConfigProperty(ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH, false);
httpServer.setAuthentication("testuser", "testpass");
auth = new AuthenticationBuilder()
.addUsername("testuser")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ private static HttpClient getOrCreateClient(RepositorySystemSession session, Rem
.connectTimeout(Duration.ofMillis(connectTimeout))
.sslContext(sslContext);

JdkHttpTransporterCustomizer.customizeBuilder(session, repository, builder);

if (repository.getProxy() != null) {
ProxySelector proxy = ProxySelector.of(new InetSocketAddress(
repository.getProxy().getHost(),
Expand Down Expand Up @@ -417,7 +419,9 @@ protected PasswordAuthentication getPasswordAuthentication() {
});
}

return builder.build();
HttpClient result = builder.build();
JdkHttpTransporterCustomizer.customizeHttpClient(session, repository, result);
return result;
} catch (NoSuchAlgorithmException e) {
throw new WrapperEx(e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.eclipse.aether.transport.jdk;

import java.net.http.HttpClient;

import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.RemoteRepository;

/**
* JDK Transport customizer.
*
* @since TBD
*/
final class JdkHttpTransporterCustomizer {
private JdkHttpTransporterCustomizer() {}

static void customizeBuilder(
RepositorySystemSession session, RemoteRepository repository, HttpClient.Builder builder) {}

static void customizeHttpClient(RepositorySystemSession session, RemoteRepository repository, HttpClient client) {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<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.apache.maven.resolver</groupId>
<artifactId>maven-resolver-transport-jdk-parent</artifactId>
<version>2.0.0-SNAPSHOT</version>
</parent>

<artifactId>maven-resolver-transport-jdk-19</artifactId>
<packaging>jar</packaging>

<name>Maven Artifact Resolver Transport JDK (19)</name>
<description>Maven Artifact Transport JDK Java 11+.</description>

<properties>
<Automatic-Module-Name>org.apache.maven.resolver.transport.jdk</Automatic-Module-Name>
<Bundle-SymbolicName>${Automatic-Module-Name}</Bundle-SymbolicName>

<javaVersion>19</javaVersion>
</properties>

<dependencies>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-spi</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven.resolver</groupId>
<artifactId>maven-resolver-util</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<scope>provided</scope>
<optional>true</optional>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.eclipse.sisu</groupId>
<artifactId>sisu-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>biz.aQute.bnd</groupId>
<artifactId>bnd-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
</plugins>
</build>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.eclipse.aether.transport.jdk;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.net.http.HttpClient;

import org.eclipse.aether.ConfigurationProperties;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.util.ConfigUtils;

/**
* JDK Transport customizer.
*
* @since TBD
*/
final class JdkHttpTransporterCustomizer {
private JdkHttpTransporterCustomizer() {}

static void customizeBuilder(
RepositorySystemSession session, RemoteRepository repository, HttpClient.Builder builder) {
InetAddress localAddress = getHttpLocalAddress(session, repository);
if (localAddress != null) {
builder.localAddress(localAddress);
}
}

static void customizeHttpClient(RepositorySystemSession session, RemoteRepository repository, HttpClient client) {}

/**
* Returns non-null {@link InetAddress} if set in configuration, {@code null} otherwise.
*/
private static InetAddress getHttpLocalAddress(RepositorySystemSession session, RemoteRepository repository) {
String bindAddress = ConfigUtils.getString(
session,
null,
ConfigurationProperties.HTTP_LOCAL_ADDRESS + "." + repository.getId(),
ConfigurationProperties.HTTP_LOCAL_ADDRESS);
if (bindAddress == null) {
return null;
}
try {
return InetAddress.getByName(bindAddress);
} catch (UnknownHostException uhe) {
throw new IllegalArgumentException(
"Given bind address (" + bindAddress + ") cannot be resolved for remote repository " + repository,
uhe);
}
}
}
Loading

0 comments on commit b3d0aea

Please sign in to comment.