Index: httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionManagerBase.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionManagerBase.java (revision 1405730)
+++ httpclient/src/main/java/org/apache/http/impl/conn/HttpClientConnectionManagerBase.java (revision )
@@ -74,6 +74,7 @@
}
this.pool = pool;
this.connectionOperator = new HttpClientConnectionOperator(schemeRegistry, dnsResolver);
+ ClientConnectionManagerTracker.getTracker().add(this);
}
@Override
Index: httpclient/src/main/java/org/apache/http/conn/proxy/ConfigurableProxySelector.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/conn/proxy/ConfigurableProxySelector.java (revision )
+++ httpclient/src/main/java/org/apache/http/conn/proxy/ConfigurableProxySelector.java (revision )
@@ -0,0 +1,136 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.conn.proxy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The ProxyConfigurationManager holds all known {@link ProxyConfiguration}s.
+ */
+public class ConfigurableProxySelector extends ProxySelector {
+
+ private static final int MAX_FAILURES = 3;
+
+ public static ConfigurableProxySelector instance;
+
+ private final Log log = LogFactory.getLog(getClass());
+ private final Set configs = new HashSet();
+
+ /**
+ * Returns a singleton ProxyConfigurationManager instance. The first call will construct the
+ * singleton.
+ *
+ * @return The ProxyConfigurationManager
+ */
+ public static ConfigurableProxySelector getSelector() {
+ if (null == instance) {
+ instance = new ConfigurableProxySelector();
+ }
+ return instance;
+ }
+
+ /**
+ * Adds the given {@link ProxyConfiguration} to the configs held by this manager, replacing the config if already
+ * present.
+ *
+ * @param configuration The proxy configuration.
+ */
+ public void addProxyConfiguration(final ProxyConfiguration configuration) {
+ synchronized (configs) {
+ removeProxyConfiguration(configuration);
+ log.info("added proxy configuration: " + configuration + "(now " + configs.size() + " configs)");
+ configs.add(configuration);
+ }
+ }
+
+ /**
+ * Removes the given {@link ProxyConfiguration} from this manager.
+ *
+ * @param configuration The configuration to remove.
+ */
+ public void removeProxyConfiguration(final ProxyConfiguration configuration) {
+ synchronized (configs) {
+ log.info("removed proxy configuration: " + configuration + "(now " + configs.size() + " configs)");
+ configs.remove(configuration);
+ }
+ }
+
+ @Override
+ public List select(final URI uri) {
+ if (null == uri) {
+ throw new IllegalArgumentException("URI must not be null");
+ }
+
+ final List proxies = new ArrayList();
+
+ for (final ProxyConfiguration config : configs) {
+ if (config.accepts(uri)) {
+ proxies.add(config.getProxy());
+ }
+ }
+
+ if (proxies.size() == 0) {
+ proxies.add(Proxy.NO_PROXY);
+ }
+
+ return proxies;
+ }
+
+ @Override
+ public void connectFailed(final URI uri, final SocketAddress address, final IOException ioe) {
+
+ if (null == uri || null == address || null == ioe) {
+ throw new IllegalArgumentException("arguments may not be null.");
+ }
+
+ final Iterator iterator = configs.iterator();
+ while (iterator.hasNext()) {
+ final ProxyConfiguration config = iterator.next();
+ if (address.equals(config.getAddress())) {
+ final int failures = config.failed();
+ log.error("Connection to proxy [" + config + "] failed (" + failures + " time(s)).");
+ if (failures >= MAX_FAILURES) {
+ iterator.remove();
+ log.error("Proxy [" + config + "] failed more than " + MAX_FAILURES + " times, removed.");
+ }
+ break;
+ }
+ }
+ }
+}
Index: httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java (revision 1405730)
+++ httpclient/src/main/java/org/apache/http/conn/routing/HttpRoute.java (revision )
@@ -27,9 +27,17 @@
package org.apache.http.conn.routing;
+import java.lang.reflect.UndeclaredThrowableException;
import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.List;
import org.apache.http.annotation.Immutable;
+import org.apache.http.conn.proxy.ConfigurableProxySelector;
import org.apache.http.util.LangUtils;
import org.apache.http.HttpHost;
@@ -103,6 +111,32 @@
if ((tunnelled == TunnelType.TUNNELLED) && (proxies.length == 0)) {
throw new IllegalArgumentException
("Proxy required if tunnelled.");
+ }
+
+ // select a proxy from the configurable proxy selector. e.g. in an OSGi-environment,
+ // the proxy selector is set fed with OSGi-originating configurations,
+ // and thus provides centrally configured proxies without the knowledge of the API user
+ if (proxies.length == 0) {
+ try {
+ // get list of proxies from the default proxy selector
+ final List defaultProxyList =
+ ConfigurableProxySelector.getSelector().select(new URI(target.toURI()));
+ final ArrayList defaultProxyHosts = new ArrayList();
+ for (final Proxy proxy : defaultProxyList) {
+ // downcast to InetSocketAddress for host and port accessors
+ final InetSocketAddress address = (InetSocketAddress) proxy.address();
+
+ // only HTTP proxies are supported, the address of which is not null
+ if (Proxy.Type.HTTP == proxy.type() && null != address) {
+ defaultProxyHosts.add(new HttpHost(address.getHostName(), address.getPort()));
+ }
+ }
+
+ proxies = defaultProxyHosts.toArray(new HttpHost[defaultProxyHosts.size()]);
+
+ } catch (URISyntaxException e) {
+ throw new UndeclaredThrowableException(e);
+ }
}
// tunnelled is already checked above, that is in line with the default
Index: httpclient-osgi/pom.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/pom.xml (revision 1405730)
+++ httpclient-osgi/pom.xml (revision )
@@ -72,6 +72,18 @@
${project.version}compile
+
+ org.osgi
+ org.osgi.core
+ 4.2.0
+ provided
+
+
+ org.osgi
+ org.osgi.compendium
+ 4.2.0
+ provided
+
@@ -88,6 +100,7 @@
true**/*.properties
+ **/metatype.*
@@ -98,6 +111,7 @@
true
+ org.apache.http.osgi.ActivatorApache ${project.name}${project.groupId}.httpclient
<_exportcontents>
@@ -117,6 +131,8 @@
javax.crypto.spec,
javax.net.ssl,javax.security.auth.x500,
org.ietf.jgss,
+ org.osgi.framework,
+ org.osgi.service.cm,
org.apache.commons.logging;version=${commons-logging.version},
org.apache.http;version=${httpcore.version},
org.apache.http.concurrent;version=${httpcore.version},
Index: httpclient/src/main/java/org/apache/http/impl/conn/BasicHttpClientConnectionManager.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/BasicHttpClientConnectionManager.java (revision 1405730)
+++ httpclient/src/main/java/org/apache/http/impl/conn/BasicHttpClientConnectionManager.java (revision )
@@ -103,6 +103,7 @@
this.connectionOperator = new HttpClientConnectionOperator(schemeRegistry, dnsResolver);
this.connFactory = connFactory != null ? connFactory : DefaultClientConnectionFactory.INSTANCE;
this.expiry = Long.MAX_VALUE;
+ ClientConnectionManagerTracker.getTracker().add(this);
}
public BasicHttpClientConnectionManager(final SchemeRegistry schemeRegistry) {
Index: httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.xml (revision )
+++ httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.xml (revision )
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Index: httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.properties
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>MacRoman
===================================================================
--- httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.properties (revision )
+++ httpclient-osgi/src/main/resources/OSGI-INF/metatype/metatype.properties (revision )
@@ -0,0 +1,58 @@
+proxyconfigurator.name = Apache HTTP Components Proxy Configurator
+proxyconfigurator.description = Factory configuration for transparent proxies used by every HTTP Client.
+
+proxyconfig.name = Apache HTTP Components Proxy Configuration
+proxyconfig.description = Proxy configuration for central and transparent proxying of http client connections.
+
+proxy.enabled.name = Enable HTTP Proxy
+proxy.enabled.description = Whether to enable or disable this particular proxy configuration. \
+The default value is false.
+
+proxy.host.name = HTTP Proxy Host
+proxy.host.description = Host name (or IP Address) of the HTTP Proxy. This property is ignored if \
+ this proxy configuration is disabled. This property does not have a default value. Enabling \
+ this proxy but not setting the HTTP Proxy Host effectively disables this configuration.
+
+proxy.port.name = HTTP Proxy Port
+proxy.port.description = TCP port of the HTTP Proxy. This property is ignored if \
+ this proxy configuration is disabled. This property does not have a default value. Enabling \
+ this proxy but not setting the HTTP Proxy Port effectively disables this configuration.
+
+proxy.user.name = HTTP Proxy User
+proxy.user.description = The name of the user to authenticate as with the HTTP \
+ Proxy Host. If this field is empty, the proxy is considered to not be \
+ authenticated. The default is empty. This property is ignored if proxying is \
+ disabled or the proxy host is not properly configured.
+
+proxy.password.name = HTTP Proxy Password
+proxy.password.description = The password of the HTTP Proxy user to authenticate \
+ with. The default is empty. This property is ignored if proxying is \
+ disabled or the proxy host is not properly configured.
+
+proxy.ntlm.host.name = HTTP Proxy NTLM Host
+proxy.ntlm.host.description = The host the authentication request is \
+ originating from. Essentially, the computer name for this machine. By default \
+ the credentials assume simple username password authentication. If the proxy \
+ happens to be a Microsoft IIS Server using NTLM authentication this property \
+ must be set to the NT Domain name of the user to authenticate as. This is \
+ not set by default.
+
+proxy.ntlm.domain.name = HTTP Proxy NTLM Domain
+proxy.ntlm.domain.description = The NTLM domain to authenticate within. By \
+ default the credentials assume simple username password authentication. If \
+ the proxy happens to be a Microsoft IIS Server using NTLM authentication this \
+ property must be set to the NT Domain name of the user to authenticate as. \
+ This is not set by default.
+
+proxy.exceptions.name = No Proxy For
+proxy.exceptions.description = Lists domain names, host names, IP Addresses or \
+ or network addresses for which this proxy configuration should not be used. A domain \
+ name indicating all hosts of a domain is indicated by a leading dot, e.g. \
+ ".day.com". A network address is indicated with subnet mask notation indicating \
+ the number of bits make up the network address, e.g 192.168.1.0/24 means the \
+ class C network "192.168.1". Note that for proxy selection, the host name of \
+ URL is not resolved but directly compared to the list of exceptions. For this \
+ reason you might want to indicate both the network address and the domain for \
+ targets which should not be passed through the proxy. This property has no \
+ effect if this proxy configuration is disabled. The default value is [ localhost, \
+ 127.0.0.1 ].
Index: httpclient/src/main/java/org/apache/http/impl/conn/ClientConnectionManagerTracker.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/ClientConnectionManagerTracker.java (revision )
+++ httpclient/src/main/java/org/apache/http/impl/conn/ClientConnectionManagerTracker.java (revision )
@@ -0,0 +1,91 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.impl.conn;
+
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.HttpClientConnectionManager;
+
+import java.util.Set;
+import java.util.WeakHashMap;
+
+/**
+ * The ClientConnectionManagerTracker should be used by any implementations of {@link
+ * HttpClientConnectionManager}, which should in the constructor add its instance via {@link
+ * #add(org.apache.http.conn.HttpClientConnectionManager)}:
+ *
+ * ClientConnectionManagerTracker.getInstance().add(this);
+ *
+ * ClientConnectionManagers added thus are tracked using {@link java.lang.ref.WeakReference}s. The purpose of the
+ * tracking is such, that all active ClientConnectionManagers can be retrieved via {@link #getAll()} and tasks, such as
+ * shutting down all clients in order to ensure proper stopping of an application using this library.
+ */
+public final class ClientConnectionManagerTracker {
+
+ public static ClientConnectionManagerTracker instance;
+
+ private final WeakHashMap managers
+ = new WeakHashMap();
+
+ // do not allow public construction
+ private ClientConnectionManagerTracker() {
+ }
+
+ /**
+ * Returns a singleton ClientConnectionManagerTracker instance. The first call will construct the
+ * singleton.
+ *
+ * @return The ClientConnectionManagerTracker
+ */
+ public static ClientConnectionManagerTracker getTracker() {
+ if (null == instance) {
+ instance = new ClientConnectionManagerTracker();
+ }
+ return instance;
+ }
+
+ /**
+ * Adds a {@link HttpClientConnectionManager} as a {@link java.lang.ref.WeakReference} to this tracker.
+ *
+ * @param manager The {@link HttpClientConnectionManager} to add.
+ */
+ public void add(final HttpClientConnectionManager manager) {
+ synchronized (managers) {
+ // only the key is weakly referenced, the map value can be ignored
+ managers.put(manager, null);
+ }
+ }
+
+ /**
+ * Returnes a {@link Set} of {@link java.lang.ref.WeakReference}s to {@link ClientConnectionManager}s. An element of
+ * the set may be null.
+ *
+ * @return A Set representing weakly referenced ClientConnectionManagers.
+ */
+ public Set getAll() {
+ return managers.keySet();
+ }
+}
Index: httpclient/src/main/java/org/apache/http/impl/conn/proxy/ProxyConfigurationImpl.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/proxy/ProxyConfigurationImpl.java (revision )
+++ httpclient/src/main/java/org/apache/http/impl/conn/proxy/ProxyConfigurationImpl.java (revision )
@@ -0,0 +1,287 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.impl.conn.proxy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.client.utils.PropertiesUtil;
+import org.apache.http.conn.proxy.ProxyConfiguration;
+
+import java.net.InetSocketAddress;
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * A ProxyConfiguration no proxy (not this one)
+ for (final HostMatcher matcher : exceptions) {
+ if (matcher.matches(uri.getHost())) {
+ return false;
+ }
+ }
+
+ } else {
+ return false;
+ }
+
+ return true;
+ }
+
+ private void setProxyExceptions(String[] exceptions) {
+ ArrayList exceptionList = new ArrayList();
+ if (exceptions != null) {
+ for (final String exception : exceptions) {
+ exceptionList.add(createMatcher(exception.trim()));
+ }
+ }
+ this.exceptions = exceptionList.toArray(new HostMatcher[exceptionList.size()]);
+ }
+
+ private static HostMatcher createMatcher(final String name) {
+ final NetworkAddress na = NetworkAddress.parse(name);
+ if (na != null) {
+ return new IPAddressMatcher(na);
+ }
+
+ if (name.startsWith(".")) {
+ return new DomainNameMatcher(name);
+ }
+
+ return new HostNameMatcher(name);
+ }
+
+ private static interface HostMatcher {
+
+ boolean matches(String host);
+ }
+
+ private static class HostNameMatcher implements HostMatcher {
+
+ private final String hostName;
+
+ HostNameMatcher(String hostName) {
+ this.hostName = hostName;
+ }
+
+ public boolean matches(String host) {
+ return hostName.equalsIgnoreCase(host);
+ }
+ }
+
+ private static class DomainNameMatcher implements HostMatcher {
+
+ private final String domainName;
+
+ DomainNameMatcher(String domainName) {
+ this.domainName = domainName.toLowerCase();
+ }
+
+ public boolean matches(String host) {
+ return host.toLowerCase().endsWith(domainName);
+ }
+ }
+
+ private static class IPAddressMatcher implements HostMatcher {
+
+ private final NetworkAddress address;
+
+ IPAddressMatcher(NetworkAddress address) {
+ this.address = address;
+ }
+
+ public boolean matches(String host) {
+ NetworkAddress hostAddress = NetworkAddress.parse(host);
+ return hostAddress != null && address.address == (hostAddress.address & address.mask);
+ }
+ }
+
+ private static class NetworkAddress {
+
+ final int address;
+
+ final int mask;
+
+ static NetworkAddress parse(String adrSpec) {
+
+ if (null != adrSpec) {
+ final Matcher nameMatcher = IP_MASK_PATTERN.matcher(adrSpec);
+ if (nameMatcher.matches()) {
+ try {
+ int i1 = toInt(nameMatcher.group(1), 255);
+ int i2 = toInt(nameMatcher.group(2), 255);
+ int i3 = toInt(nameMatcher.group(3), 255);
+ int i4 = toInt(nameMatcher.group(4), 255);
+ int ip = i1 << 24 | i2 << 16 | i3 << 8 | i4;
+
+ int mask = toInt(nameMatcher.group(6), 32);
+ mask = (mask == 32) ? -1 : -1 - (-1 >>> mask);
+
+ return new NetworkAddress(ip, mask);
+ } catch (NumberFormatException nfe) {
+ // not expected after the pattern match !
+ }
+ }
+ }
+
+ return null;
+ }
+
+ private static int toInt(String value, int max) {
+ if (value == null || value.length() == 0) {
+ return max;
+ }
+
+ int number = Integer.parseInt(value);
+ if (number > max) {
+ number = max;
+ }
+ return number;
+ }
+
+ NetworkAddress(int address, int mask) {
+ this.address = address;
+ this.mask = mask;
+ }
+ }
+}
Index: httpclient/src/main/java/org/apache/http/conn/proxy/ProxyConfiguration.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/conn/proxy/ProxyConfiguration.java (revision )
+++ httpclient/src/main/java/org/apache/http/conn/proxy/ProxyConfiguration.java (revision )
@@ -0,0 +1,111 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.conn.proxy;
+
+import java.net.Proxy;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.Dictionary;
+
+/**
+ * ProxyConfiguration...
+ */
+public interface ProxyConfiguration {
+
+ /**
+ * Property indicating whether this particular proxy is enabled (shall be used or not). Defaults to true.
+ */
+ String PROPERTYNAME_PROXY_ENABLED = "proxy.enabled";
+ /**
+ * Property representing the hostname of the proxy. Defaults to empty.
+ */
+ String PROPERTYNAME_PROXY_HOSTNAME = "proxy.host";
+ /**
+ * Property representing the port of the proxy. Defaults to 0.
+ */
+ String PROPERTYNAME_PROXY_PORT = "proxy.port";
+ /**
+ * Property representing the username to authenticate with towards the proxy. Defaults to empty.
+ */
+ String PROPERTYNAME_PROXY_USERNAME = "proxy.user";
+ /**
+ * Property representing the password to authenticate with towards the proxy. Defaults to empty.
+ */
+ String PROPERTYNAME_PROXY_PASSWORD = "proxy.password";
+ /**
+ * Property representing the NTLM domain to use for authentication towards the proxy. If this is set, authentication
+ * is switched from basic to NTLM.
+ */
+ String PROPERTYNAME_PROXY_NTLMHOST = "proxy.ntlm.host";
+ /**
+ * A multivalue property representing host patterns for which no proxy shall be used. By default localhost is
+ * excluded.
+ */
+ String PROPERTYNAME_PROXY_EXCEPTIONS = "proxy.exceptions";
+
+ void update(Dictionary config);
+
+ SocketAddress getAddress();
+
+ String getHostname();
+
+ int getPort();
+
+ String getUsername();
+
+ String getPassword();
+
+ String getNtlmhost();
+
+ Proxy getProxy();
+
+ /**
+ * Indicates whether this config is valid and can be used. A valid configuration is enabled by configuration and has
+ * a valid proxy address configured.
+ *
+ * @return true if the proxy configuration is valid.
+ */
+ boolean isValid();
+
+ /**
+ * Indicates the number of times connecting to the proxy based on this configuration has failed.
+ *
+ * @return An int representing the number of connection failures.
+ */
+ int failed();
+
+ /**
+ * Indicates whether the given uri is accepted by this proxy configuration, i.e. that the proxy is
+ * suitable for usage with that URI. All URIs of scheme HTTP and HTTPS are accepted. Additionally the hostname of
+ * the URI must not be on the configurable exclusion list. By default localhost is exluced.
+ *
+ * @param uri The {@link java.net.URI} to check.
+ *
+ * @return true if the URI is accepted.
+ */
+ boolean accepts(URI uri);
+}
Index: httpclient/src/main/java/org/apache/http/impl/conn/proxy/TransparentProxySelector.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/impl/conn/proxy/TransparentProxySelector.java (revision )
+++ httpclient/src/main/java/org/apache/http/impl/conn/proxy/TransparentProxySelector.java (revision )
@@ -0,0 +1,113 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.impl.conn.proxy;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.http.conn.proxy.ConfigurableProxySelector;
+
+import java.io.IOException;
+import java.net.Proxy;
+import java.net.ProxySelector;
+import java.net.SocketAddress;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class TransparentProxySelector extends ProxySelector {
+
+ private final Log log = LogFactory.getLog(getClass());
+
+ private static int MAX_FAILURES = 3;
+
+ /**
+ * The map holding valid and enabled proxy configurations
+ */
+ private final Map proxyConfigurations = new HashMap();
+ private final ConfigurableProxySelector manager;
+
+ // ------- Constructor
+
+ public TransparentProxySelector(final ConfigurableProxySelector manager) {
+ this.manager = manager;
+ }
+
+ // ------- API
+
+ @Override
+ public List select(final URI uri) {
+
+ if (null == uri) {
+ throw new IllegalArgumentException("URI must not be null");
+ }
+
+ final List proxies = new ArrayList();
+
+ for (final ProxyConfigurationImpl config : proxyConfigurations.values()) {
+ if (config.accepts(uri)) {
+ proxies.add(config.getProxy());
+ }
+ }
+
+ if (proxies.size() == 0) {
+ return ProxySelector.getDefault().select(uri);
+ }
+
+ return proxies;
+ }
+
+ @Override
+ public void connectFailed(final URI uri, final SocketAddress address, final IOException ioe) {
+
+ if (null == uri || null == address || null == ioe) {
+ throw new IllegalArgumentException("arguments may not be null.");
+ }
+
+ String toBeRemoved = null;
+
+ for (final Map.Entry entry : proxyConfigurations.entrySet()) {
+ final ProxyConfigurationImpl config = entry.getValue();
+ if (address.equals(config.getAddress())) {
+ final int failures = config.failed();
+ log.error("Connection to proxy [" + config + "] failed (" + failures + " time(s)).");
+ if (failures >= MAX_FAILURES) {
+ toBeRemoved = entry.getKey();
+ log.error("Proxy [" + config + "] failed more than " + MAX_FAILURES + " times, removed.");
+ }
+ break;
+ }
+ }
+
+ if (null != toBeRemoved) {
+ synchronized (proxyConfigurations) {
+ proxyConfigurations.remove(toBeRemoved);
+ }
+ }
+ }
+}
Index: httpclient-osgi/src/main/java/org/apache/http/osgi/Activator.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient-osgi/src/main/java/org/apache/http/osgi/Activator.java (revision )
+++ httpclient-osgi/src/main/java/org/apache/http/osgi/Activator.java (revision )
@@ -0,0 +1,129 @@
+/*
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.osgi;
+
+import org.apache.http.conn.HttpClientConnectionManager;
+import org.apache.http.conn.proxy.ConfigurableProxySelector;
+import org.apache.http.conn.proxy.ProxyConfiguration;
+import org.apache.http.impl.conn.ClientConnectionManagerTracker;
+import org.apache.http.impl.conn.proxy.ProxyConfigurationImpl;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+
+/**
+ * This is the bundle activator. It registers the activator as a service factory, so it can receive proxy
+ * configurations. Once a configuration is updated, it registers a proxy configuration with the {@link
+ * org.apache.http.conn.proxy.ConfigurableProxySelector} based on the configuration properties.
+ *
+ * The activator also is responsible for unregistering the service factory and proxy configurations upon bundle
+ * shutdown. Additionally the shutdown ensures that all open connections of all http-clients are terminated, so the OSGi
+ * container may shutdown irrespective of any open HTTP client connections.
+ */
+public class Activator implements BundleActivator, ManagedServiceFactory {
+
+ private static final String SERVICE_FACTORY_NAME = "Apache HTTP Client Proxy Configuration Factory";
+ private static final String SERVICE_PID = "org.apache.http.proxyconfigurator";
+
+ private ServiceRegistration configurator;
+ private ConfigurableProxySelector manager;
+ private HashMap serviceRegistrations;
+ private BundleContext context;
+
+ public void start(final BundleContext context) throws Exception {
+
+ this.context = context;
+ this.serviceRegistrations = new HashMap();
+ this.manager = ConfigurableProxySelector.getSelector();
+
+ // ensure we receive configurations for the proxy selector
+ final Hashtable props = new Hashtable();
+ props.put(Constants.SERVICE_PID, getName());
+ props.put(Constants.SERVICE_VENDOR, context.getBundle().getHeaders(Constants.BUNDLE_VENDOR));
+ props.put(Constants.SERVICE_DESCRIPTION, SERVICE_FACTORY_NAME);
+
+ configurator = context.registerService(ManagedServiceFactory.class.getName(), this, props);
+ }
+
+ public void stop(final BundleContext context) throws Exception {
+
+ // unregister services
+ for (final ServiceRegistration service : serviceRegistrations.values()) {
+ service.unregister();
+ }
+
+ // unregister service factory
+ if (configurator != null) {
+ configurator.unregister();
+ }
+
+ // ensure all http clients are terminated
+ for (final HttpClientConnectionManager manager : ClientConnectionManagerTracker.getTracker().getAll()) {
+ if (null != manager) {
+ manager.shutdown();
+ }
+ }
+ }
+
+ public String getName() {
+ return SERVICE_PID;
+ }
+
+ public void updated(final String serviceId, final Dictionary config) throws ConfigurationException {
+
+ final ProxyConfiguration proxyConfiguration;
+ final ServiceRegistration registration = serviceRegistrations.get(serviceId);
+
+ if (null == registration) {
+ proxyConfiguration = new ProxyConfigurationImpl();
+ serviceRegistrations.put(serviceId, context.registerService(ProxyConfiguration.class.getName(),
+ proxyConfiguration,
+ config));
+ } else {
+ proxyConfiguration = (ProxyConfiguration) context.getService(registration.getReference());
+ }
+
+ proxyConfiguration.update(config);
+ manager.addProxyConfiguration(proxyConfiguration);
+ }
+
+ public void deleted(final String serviceId) {
+ final ServiceRegistration registration = serviceRegistrations.get(serviceId);
+ if (null != registration) {
+ manager.removeProxyConfiguration((ProxyConfiguration) context.getService(registration.getReference()));
+ registration.unregister();
+ serviceRegistrations.remove(serviceId);
+ }
+ }
+}
Index: httpclient/src/main/java/org/apache/http/client/utils/PropertiesUtil.java
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
--- httpclient/src/main/java/org/apache/http/client/utils/PropertiesUtil.java (revision )
+++ httpclient/src/main/java/org/apache/http/client/utils/PropertiesUtil.java (revision )
@@ -0,0 +1,219 @@
+/*
+ * 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.apache.http.client.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * The PropertiesUtil is a utility class providing some
+ * usefull utility methods for converting property types.
+ *
+ * @since 2.1
+ */
+public class PropertiesUtil {
+
+ /**
+ * Returns the boolean value of the parameter or the
+ * defaultValue if the parameter is null.
+ * If the parameter is not a Boolean it is converted
+ * by calling Boolean.valueOf on the string value of the
+ * object.
+ * @param propValue the property value or null
+ * @param defaultValue the default boolean value
+ */
+ public static boolean toBoolean(Object propValue, boolean defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Boolean) {
+ return (Boolean) propValue;
+ } else if (propValue != null) {
+ return Boolean.valueOf(String.valueOf(propValue));
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a string or the
+ * defaultValue if the parameter is null.
+ * @param propValue the property value or null
+ * @param defaultValue the default string value
+ */
+ public static String toString(Object propValue, String defaultValue) {
+ propValue = toObject(propValue);
+ return (propValue != null) ? propValue.toString() : defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a long or the
+ * defaultValue if the parameter is null or if
+ * the parameter is not a Long and cannot be converted to
+ * a Long from the parameter's string value.
+ * @param propValue the property value or null
+ * @param defaultValue the default long value
+ */
+ public static long toLong(Object propValue, long defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Long) {
+ return (Long) propValue;
+ } else if (propValue != null) {
+ try {
+ return Long.valueOf(String.valueOf(propValue));
+ } catch (NumberFormatException nfe) {
+ // don't care, fall through to default value
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as an integer or the
+ * defaultValue if the parameter is null or if
+ * the parameter is not an Integer and cannot be converted to
+ * an Integer from the parameter's string value.
+ * @param propValue the property value or null
+ * @param defaultValue the default integer value
+ */
+ public static int toInteger(Object propValue, int defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Integer) {
+ return (Integer) propValue;
+ } else if (propValue != null) {
+ try {
+ return Integer.valueOf(String.valueOf(propValue));
+ } catch (NumberFormatException nfe) {
+ // don't care, fall through to default value
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a double or the
+ * defaultValue if the parameter is null or if
+ * the parameter is not a Double and cannot be converted to
+ * a Double from the parameter's string value.
+ * @param propValue the property value or null
+ * @param defaultValue the default double value
+ */
+ public static double toDouble(Object propValue, double defaultValue) {
+ propValue = toObject(propValue);
+ if (propValue instanceof Double) {
+ return (Double) propValue;
+ } else if (propValue != null) {
+ try {
+ return Double.valueOf(String.valueOf(propValue));
+ } catch (NumberFormatException nfe) {
+ // don't care, fall through to default value
+ }
+ }
+
+ return defaultValue;
+ }
+
+ /**
+ * Returns the parameter as a single value. If the
+ * parameter is neither an array nor a java.util.Collection the
+ * parameter is returned unmodified. If the parameter is a non-empty array,
+ * the first array element is returned. If the property is a non-empty
+ * java.util.Collection, the first collection element is returned.
+ * Otherwise null is returned.
+ * @param propValue the parameter to convert.
+ */
+ public static Object toObject(Object propValue) {
+ if (propValue == null) {
+ return null;
+ } else if (propValue.getClass().isArray()) {
+ Object[] prop = (Object[]) propValue;
+ return prop.length > 0 ? prop[0] : null;
+ } else if (propValue instanceof Collection>) {
+ Collection> prop = (Collection>) propValue;
+ return prop.isEmpty() ? null : prop.iterator().next();
+ } else {
+ return propValue;
+ }
+ }
+
+ /**
+ * Returns the parameter as an array of Strings. If
+ * the parameter is a scalar value its string value is returned as a single
+ * element array. If the parameter is an array, the elements are converted to
+ * String objects and returned as an array. If the parameter is a collection, the
+ * collection elements are converted to String objects and returned as an array.
+ * Otherwise (if the parameter is null) null is
+ * returned.
+ * @param propValue The object to convert.
+ */
+ public static String[] toStringArray(Object propValue) {
+ return toStringArray(propValue, null);
+ }
+
+ /**
+ * Returns the parameter as an array of Strings. If
+ * the parameter is a scalar value its string value is returned as a single
+ * element array. If the parameter is an array, the elements are converted to
+ * String objects and returned as an array. If the parameter is a collection, the
+ * collection elements are converted to String objects and returned as an array.
+ * Otherwise (if the property is null) a provided default value is
+ * returned.
+ * @param propValue The object to convert.
+ * @param defaultArray The default array to return.
+ */
+ public static String[] toStringArray(Object propValue, String[] defaultArray) {
+ if (propValue == null) {
+ // no value at all
+ return defaultArray;
+
+ } else if (propValue instanceof String) {
+ // single string
+ return new String[] { (String) propValue };
+
+ } else if (propValue instanceof String[]) {
+ // String[]
+ return (String[]) propValue;
+
+ } else if (propValue.getClass().isArray()) {
+ // other array
+ Object[] valueArray = (Object[]) propValue;
+ List values = new ArrayList(valueArray.length);
+ for (Object value : valueArray) {
+ if (value != null) {
+ values.add(value.toString());
+ }
+ }
+ return values.toArray(new String[values.size()]);
+
+ } else if (propValue instanceof Collection>) {
+ // collection
+ Collection> valueCollection = (Collection>) propValue;
+ List valueList = new ArrayList(valueCollection.size());
+ for (Object value : valueCollection) {
+ if (value != null) {
+ valueList.add(value.toString());
+ }
+ }
+ return valueList.toArray(new String[valueList.size()]);
+ }
+
+ return defaultArray;
+ }
+}
\ No newline at end of file