001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.eclipse.aether.util.connector.transport.http;
020
021import java.net.InetAddress;
022import java.net.UnknownHostException;
023import java.nio.charset.Charset;
024import java.util.Collections;
025import java.util.HashSet;
026import java.util.Map;
027import java.util.Optional;
028import java.util.Set;
029
030import org.eclipse.aether.ConfigurationProperties;
031import org.eclipse.aether.RepositorySystemSession;
032import org.eclipse.aether.repository.RemoteRepository;
033import org.eclipse.aether.util.ConfigUtils;
034
035/**
036 * A utility class to read HTTP transport related configuration. It implements all HTTP transport related configurations from
037 * {@link ConfigurationProperties} and transport implementations are free to use those that are supported by themselves.
038 *
039 * @see ConfigurationProperties
040 * @see RepositorySystemSession#getConfigProperties()
041 * @since 2.0.15
042 */
043public final class HttpTransporterUtils {
044    private HttpTransporterUtils() {}
045
046    /**
047     * Getter for {@link ConfigurationProperties#USER_AGENT}.
048     */
049    public static String getUserAgent(RepositorySystemSession session, RemoteRepository repository) {
050        return ConfigUtils.getString(
051                session,
052                ConfigurationProperties.DEFAULT_USER_AGENT,
053                ConfigurationProperties.USER_AGENT,
054                "aether.connector.userAgent");
055    }
056
057    /**
058     * Getter for {@link ConfigurationProperties#HTTPS_SECURITY_MODE}.
059     */
060    public static String getHttpsSecurityMode(RepositorySystemSession session, RemoteRepository repository) {
061        String result = ConfigUtils.getString(
062                session,
063                ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT,
064                ConfigurationProperties.HTTPS_SECURITY_MODE + "." + repository.getId(),
065                ConfigurationProperties.HTTPS_SECURITY_MODE);
066        if (!ConfigurationProperties.HTTPS_SECURITY_MODE_DEFAULT.equals(result)
067                && !ConfigurationProperties.HTTPS_SECURITY_MODE_INSECURE.equals(result)) {
068            throw new IllegalArgumentException("Unsupported '" + result + "' HTTPS security mode.");
069        }
070        return result;
071    }
072
073    /**
074     * Getter for {@link ConfigurationProperties#HTTP_CONNECTION_MAX_TTL}.
075     */
076    public static int getHttpConnectionMaxTtlSeconds(RepositorySystemSession session, RemoteRepository repository) {
077        int result = ConfigUtils.getInteger(
078                session,
079                ConfigurationProperties.DEFAULT_HTTP_CONNECTION_MAX_TTL,
080                ConfigurationProperties.HTTP_CONNECTION_MAX_TTL + "." + repository.getId(),
081                ConfigurationProperties.HTTP_CONNECTION_MAX_TTL);
082        if (result < 0) {
083            throw new IllegalArgumentException(ConfigurationProperties.HTTP_CONNECTION_MAX_TTL + " value must be >= 0");
084        }
085        return result;
086    }
087
088    /**
089     * Getter for {@link ConfigurationProperties#HTTP_MAX_CONNECTIONS_PER_ROUTE}.
090     */
091    public static int getHttpMaxConnectionsPerRoute(RepositorySystemSession session, RemoteRepository repository) {
092        int result = ConfigUtils.getInteger(
093                session,
094                ConfigurationProperties.DEFAULT_HTTP_MAX_CONNECTIONS_PER_ROUTE,
095                ConfigurationProperties.HTTP_MAX_CONNECTIONS_PER_ROUTE + "." + repository.getId(),
096                ConfigurationProperties.HTTP_MAX_CONNECTIONS_PER_ROUTE);
097        if (result < 1) {
098            throw new IllegalArgumentException(
099                    ConfigurationProperties.HTTP_MAX_CONNECTIONS_PER_ROUTE + " value must be > 0");
100        }
101        return result;
102    }
103
104    /**
105     * Getter for {@link ConfigurationProperties#HTTP_HEADERS}.
106     */
107    @SuppressWarnings("unchecked")
108    public static Map<String, String> getHttpHeaders(RepositorySystemSession session, RemoteRepository repository) {
109        return (Map<String, String>) ConfigUtils.getMap(
110                session,
111                Collections.emptyMap(),
112                ConfigurationProperties.HTTP_HEADERS + "." + repository.getId(),
113                ConfigurationProperties.HTTP_HEADERS);
114    }
115
116    /**
117     * Getter for {@link ConfigurationProperties#HTTP_PREEMPTIVE_AUTH}.
118     */
119    public static boolean isHttpPreemptiveAuth(RepositorySystemSession session, RemoteRepository repository) {
120        return ConfigUtils.getBoolean(
121                session,
122                ConfigurationProperties.DEFAULT_HTTP_PREEMPTIVE_AUTH,
123                ConfigurationProperties.HTTP_PREEMPTIVE_AUTH + "." + repository.getId(),
124                ConfigurationProperties.HTTP_PREEMPTIVE_AUTH);
125    }
126
127    /**
128     * Getter for {@link ConfigurationProperties#HTTP_PREEMPTIVE_PUT_AUTH}.
129     */
130    public static boolean isHttpPreemptivePutAuth(RepositorySystemSession session, RemoteRepository repository) {
131        return ConfigUtils.getBoolean(
132                session,
133                ConfigurationProperties.DEFAULT_HTTP_PREEMPTIVE_PUT_AUTH,
134                ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH + "." + repository.getId(),
135                ConfigurationProperties.HTTP_PREEMPTIVE_PUT_AUTH);
136    }
137
138    /**
139     * Getter for {@link ConfigurationProperties#HTTP_SUPPORT_WEBDAV}.
140     */
141    public static boolean isHttpSupportWebDav(RepositorySystemSession session, RemoteRepository repository) {
142        return ConfigUtils.getBoolean(
143                session,
144                ConfigurationProperties.DEFAULT_HTTP_SUPPORT_WEBDAV,
145                ConfigurationProperties.HTTP_SUPPORT_WEBDAV + "." + repository.getId(),
146                ConfigurationProperties.HTTP_SUPPORT_WEBDAV);
147    }
148
149    /**
150     * Getter for {@link ConfigurationProperties#HTTP_CREDENTIAL_ENCODING}.
151     */
152    public static Charset getHttpCredentialsEncoding(RepositorySystemSession session, RemoteRepository repository) {
153        return Charset.forName(ConfigUtils.getString(
154                session,
155                ConfigurationProperties.DEFAULT_HTTP_CREDENTIAL_ENCODING,
156                ConfigurationProperties.HTTP_CREDENTIAL_ENCODING + "." + repository.getId(),
157                ConfigurationProperties.HTTP_CREDENTIAL_ENCODING));
158    }
159
160    /**
161     * Getter for {@link ConfigurationProperties#CONNECT_TIMEOUT}.
162     */
163    public static int getHttpConnectTimeout(RepositorySystemSession session, RemoteRepository repository) {
164        return ConfigUtils.getInteger(
165                session,
166                ConfigurationProperties.DEFAULT_CONNECT_TIMEOUT,
167                ConfigurationProperties.CONNECT_TIMEOUT + "." + repository.getId(),
168                ConfigurationProperties.CONNECT_TIMEOUT);
169    }
170
171    /**
172     * Getter for {@link ConfigurationProperties#REQUEST_TIMEOUT}.
173     */
174    public static int getHttpRequestTimeout(RepositorySystemSession session, RemoteRepository repository) {
175        return ConfigUtils.getInteger(
176                session,
177                ConfigurationProperties.DEFAULT_REQUEST_TIMEOUT,
178                ConfigurationProperties.REQUEST_TIMEOUT + "." + repository.getId(),
179                ConfigurationProperties.REQUEST_TIMEOUT);
180    }
181
182    /**
183     * Getter for {@link ConfigurationProperties#HTTP_RETRY_HANDLER_COUNT}.
184     */
185    public static int getHttpRetryHandlerCount(RepositorySystemSession session, RemoteRepository repository) {
186        int result = ConfigUtils.getInteger(
187                session,
188                ConfigurationProperties.DEFAULT_HTTP_RETRY_HANDLER_COUNT,
189                ConfigurationProperties.HTTP_RETRY_HANDLER_COUNT + "." + repository.getId(),
190                ConfigurationProperties.HTTP_RETRY_HANDLER_COUNT);
191        if (result < 0) {
192            throw new IllegalArgumentException(
193                    ConfigurationProperties.HTTP_RETRY_HANDLER_COUNT + " value must be >= 0");
194        }
195        return result;
196    }
197
198    /**
199     * Getter for {@link ConfigurationProperties#HTTP_RETRY_HANDLER_INTERVAL}.
200     */
201    public static long getHttpRetryHandlerInterval(RepositorySystemSession session, RemoteRepository repository) {
202        long result = ConfigUtils.getLong(
203                session,
204                ConfigurationProperties.DEFAULT_HTTP_RETRY_HANDLER_INTERVAL,
205                ConfigurationProperties.HTTP_RETRY_HANDLER_INTERVAL + "." + repository.getId(),
206                ConfigurationProperties.HTTP_RETRY_HANDLER_INTERVAL);
207        if (result < 0) {
208            throw new IllegalArgumentException(
209                    ConfigurationProperties.HTTP_RETRY_HANDLER_INTERVAL + " value must be >= 0");
210        }
211        return result;
212    }
213
214    /**
215     * Getter for {@link ConfigurationProperties#HTTP_RETRY_HANDLER_INTERVAL_MAX}.
216     */
217    public static long getHttpRetryHandlerIntervalMax(RepositorySystemSession session, RemoteRepository repository) {
218        long result = ConfigUtils.getLong(
219                session,
220                ConfigurationProperties.DEFAULT_HTTP_RETRY_HANDLER_INTERVAL_MAX,
221                ConfigurationProperties.HTTP_RETRY_HANDLER_INTERVAL_MAX + "." + repository.getId(),
222                ConfigurationProperties.HTTP_RETRY_HANDLER_INTERVAL_MAX);
223        if (result < 0) {
224            throw new IllegalArgumentException(
225                    ConfigurationProperties.HTTP_RETRY_HANDLER_INTERVAL_MAX + " value must be >= 0");
226        }
227        return result;
228    }
229
230    /**
231     * Getter for {@link ConfigurationProperties#HTTP_EXPECT_CONTINUE}.
232     */
233    public static Optional<Boolean> getHttpExpectContinue(
234            RepositorySystemSession session, RemoteRepository repository) {
235        String expectContinue = ConfigUtils.getString(
236                session,
237                null,
238                ConfigurationProperties.HTTP_EXPECT_CONTINUE + "." + repository.getId(),
239                ConfigurationProperties.HTTP_EXPECT_CONTINUE);
240        if (expectContinue != null) {
241            return Optional.of(Boolean.parseBoolean(expectContinue));
242        }
243        return Optional.empty();
244    }
245
246    /**
247     * Getter for {@link ConfigurationProperties#HTTP_REUSE_CONNECTIONS}.
248     */
249    public static boolean isHttpReuseConnections(RepositorySystemSession session, RemoteRepository repository) {
250        return ConfigUtils.getBoolean(
251                session,
252                ConfigurationProperties.DEFAULT_HTTP_REUSE_CONNECTIONS,
253                ConfigurationProperties.HTTP_REUSE_CONNECTIONS + "." + repository.getId(),
254                ConfigurationProperties.HTTP_REUSE_CONNECTIONS);
255    }
256
257    /**
258     * Getter for {@link ConfigurationProperties#HTTP_RETRY_HANDLER_SERVICE_UNAVAILABLE}.
259     */
260    public static Set<Integer> getHttpServiceUnavailableCodes(
261            RepositorySystemSession session, RemoteRepository repository) {
262        String stringValue = ConfigUtils.getString(
263                session,
264                ConfigurationProperties.DEFAULT_HTTP_RETRY_HANDLER_SERVICE_UNAVAILABLE,
265                ConfigurationProperties.HTTP_RETRY_HANDLER_SERVICE_UNAVAILABLE + "." + repository.getId(),
266                ConfigurationProperties.HTTP_RETRY_HANDLER_SERVICE_UNAVAILABLE);
267        Set<Integer> result = new HashSet<>();
268        try {
269            for (String code : ConfigUtils.parseCommaSeparatedUniqueNames(stringValue)) {
270                result.add(Integer.parseInt(code));
271            }
272        } catch (NumberFormatException e) {
273            throw new IllegalArgumentException(
274                    "Illegal HTTP codes for " + ConfigurationProperties.HTTP_RETRY_HANDLER_SERVICE_UNAVAILABLE
275                            + " (list of integers): " + stringValue);
276        }
277        return result;
278    }
279
280    /**
281     * Getter for {@link ConfigurationProperties#HTTP_LOCAL_ADDRESS}.
282     */
283    public static Optional<InetAddress> getHttpLocalAddress(
284            RepositorySystemSession session, RemoteRepository repository) {
285        String bindAddress = ConfigUtils.getString(
286                session,
287                null,
288                ConfigurationProperties.HTTP_LOCAL_ADDRESS + "." + repository.getId(),
289                ConfigurationProperties.HTTP_LOCAL_ADDRESS);
290        if (bindAddress != null) {
291            try {
292                return Optional.of(InetAddress.getByName(bindAddress));
293            } catch (UnknownHostException uhe) {
294                throw new IllegalArgumentException(
295                        "Given bind address (" + bindAddress + ") cannot be resolved for remote repository "
296                                + repository,
297                        uhe);
298            }
299        }
300        return Optional.empty();
301    }
302}