/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.internal.communication.core.proxyselector;
import java.net.InetSocketAddress;
import java.net.Proxy;
import java.net.SocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
/**
* Helper for dealing with proxies and proxy definition strings.
*/
public final class ProxySelectorUtils {
static final private int PROXY_DEFAULT_PORT = 80;
static final private int HTTPPROXY_DEFAULT_PORT = PROXY_DEFAULT_PORT;
static final private int HTTPSPROXY_DEFAULT_PORT = 443;
static final private int SOCKSPROXY_DEFAULT_PORT = 1080;
public final static List<Proxy> NO_PROXY_LIST = Collections.singletonList(Proxy.NO_PROXY);
public final static List<Proxy> EMPTY_PROXY_LIST = Collections.emptyList();
private ProxySelectorUtils() {
// utility
}
/**
* Scan the proxy definition string and fill this information in the correct
* list or map. <br>
* The proxy definition is of the form:<br>
* <code><pre>
* proxyDef := "" | proxy | {"," proxy}
* proxy := [<scheme>=][<scheme> "://" ]<server>[ ":" <port>]
* </pre></code>
*
* @param proxyDefinitions
* @param universalProxies
* @param protocolSpecificProxies
*/
public static void fillProxies(final String proxyDefinitions, final List<Proxy> universalProxies,
final Map<String, List<Proxy>> protocolSpecificProxies) {
final Scanner scanner = new Scanner(proxyDefinitions);
scanner.useDelimiter(","); //$NON-NLS-1$
while (scanner.hasNext()) {
fillProxy(scanner.next(), universalProxies, protocolSpecificProxies);
}
}
public static void fillProxy(final String proxyDefinition, final List<Proxy> universalProxies,
final Map<String, List<Proxy>> protocolSpecificProxies) {
String protocol = null;
String host = null;
int port = 0;
int urlStart = 0;
// if there is no '=' character within the proxy definition we have a proxy
// definition that serves all protocols. In this case we MUST ignore the protocol,
// otherwise the protocol MUST be used to determine the specific proxy settings
if (proxyDefinition.indexOf("=") != -1) { //$NON-NLS-1$
protocol = proxyDefinition.substring(0, proxyDefinition.indexOf("=")); //$NON-NLS-1$
urlStart = proxyDefinition.indexOf("=") + 1; //$NON-NLS-1$
}
try {
// The scheme of the uri is irrelevant. We add the http://
// scheme to enable class URI to parse the stuff
String augmentedURI = proxyDefinition.substring(urlStart);
if (augmentedURI.indexOf("://") == -1) { //$NON-NLS-1$
augmentedURI = "http://" + augmentedURI; //$NON-NLS-1$
}
final URI uri = new URI(augmentedURI);
host = uri.getHost();
port = uri.getPort() > 0 ? uri.getPort() : getProxyDefaultPort(protocol);
} catch (final Exception ex) {
throw new ProxySelectorUtils.IllegalFormatException(
"not a valid proxy definition: '" + proxyDefinition + "'.", ex); //$NON-NLS-1$ //$NON-NLS-2$
}
if (host == null) {
throw new ProxySelectorUtils.IllegalFormatException("not a valid proxy definition: '" + proxyDefinition //$NON-NLS-1$
+ "'."); //$NON-NLS-1$
}
if (protocol == null) {
universalProxies.add(createProxy(Proxy.Type.HTTP, host, port));
} else {
addProtocolSpecificProxy(protocolSpecificProxies, protocol,
createProxy(resolveProxyType(protocol), host, port));
}
}
/**
* Resort proxies such that we shuffle the failed proxies to the end of the
* list.
*
* @param proxies
* @param failedProxies
*/
public static void resort(final Collection<Proxy> proxies, final Collection<Proxy> failedProxies) {
if (failedProxies.isEmpty()) {
return;
}
final List<Proxy> moveToTheEnd = new ArrayList<Proxy>(failedProxies.size());
for (final Proxy badProxy : failedProxies) {
if (proxies.remove(badProxy)) {
moveToTheEnd.add(badProxy);
}
}
proxies.addAll(moveToTheEnd);
}
private static int getProxyDefaultPort(final String protocol) {
if (protocol == null) {
return PROXY_DEFAULT_PORT;
}
if ("http".equalsIgnoreCase(protocol)) { //$NON-NLS-1$
return HTTPPROXY_DEFAULT_PORT;
}
if ("https".equalsIgnoreCase(protocol)) { //$NON-NLS-1$
return HTTPSPROXY_DEFAULT_PORT;
}
if ("socks".equalsIgnoreCase(protocol)) { //$NON-NLS-1$
return SOCKSPROXY_DEFAULT_PORT;
}
if ("socket".equalsIgnoreCase(protocol)) { //$NON-NLS-1$
return SOCKSPROXY_DEFAULT_PORT;
}
return PROXY_DEFAULT_PORT;
}
private static void addProtocolSpecificProxy(final Map<String, List<Proxy>> protocolSpecificProxies,
final String protocol, final Proxy proxy) {
List<Proxy> list = protocolSpecificProxies.get(protocol);
if (list == null) {
list = new ArrayList<Proxy>();
protocolSpecificProxies.put(protocol, list);
}
list.add(proxy);
}
/**
* @param type
* @param host
* @param port
* @return
*/
public static Proxy createProxy(final Proxy.Type type, final String host, final int port) {
return new Proxy(type, InetSocketAddress.createUnresolved(host, port));
}
/**
* @param protocol
* @return
*/
public static Proxy.Type resolveProxyType(final String protocol) {
if (protocol != null && (protocol.equalsIgnoreCase("socks") || protocol.equalsIgnoreCase("socket"))) { //$NON-NLS-1$ //$NON-NLS-2$
return Proxy.Type.SOCKS;
} else {
return Proxy.Type.HTTP;
}
}
/**
* @param scheme
* @param sa
* @return
*/
public static Proxy createProxy(final String scheme, final SocketAddress sa) {
final Proxy.Type type = resolveProxyType(scheme);
return new Proxy(type, sa);
}
public static class IllegalFormatException extends IllegalArgumentException {
private static final long serialVersionUID = 3597432896264559897L;
public IllegalFormatException(final String message, final Throwable throwable) {
super(message, throwable);
}
public IllegalFormatException(final String message) {
super(message);
}
}
}