diff options
author | Tomasz Zarna | 2008-04-24 13:10:33 +0000 |
---|---|---|
committer | Tomasz Zarna | 2008-04-24 13:10:33 +0000 |
commit | 8bad68e595f10fdeaea93f282f33db7ae2fe5c62 (patch) | |
tree | 592f6a502f2e2c34a8bb06e5ffd8464ed659b417 | |
parent | 9471f4471a2a3d30964b3cf7d835c00d837e2e40 (diff) | |
download | eclipse.platform.team-8bad68e595f10fdeaea93f282f33db7ae2fe5c62.tar.gz eclipse.platform.team-8bad68e595f10fdeaea93f282f33db7ae2fe5c62.tar.xz eclipse.platform.team-8bad68e595f10fdeaea93f282f33db7ae2fe5c62.zip |
bug 227498: [Proxy] Refactoring in win32 proxy settings support
7 files changed, 554 insertions, 465 deletions
diff --git a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxyBypass.java b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxyBypass.java index c1c6ad858..3111d1ff6 100644 --- a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxyBypass.java +++ b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxyBypass.java @@ -14,8 +14,8 @@ import java.net.URI; import java.util.regex.Pattern; /** - * Encapsulates the windows specific proxy bypass list. It transforms the native API proxy bypass - * list into queryable java object. + * Encapsulates the windows specific proxy bypass list. It transforms the native + * API proxy bypass list into queryable java object. * * @see "http://msdn2.microsoft.com/en-us/library/aa383912(VS.85).aspx" */ @@ -25,7 +25,7 @@ public class ProxyBypass { private final Pattern proxyBypassPattern; - private final static String BYPASS_LOCAL_ADDESSES_TOKEN= "<local>"; //$NON-NLS-1$ + private final static String BYPASS_LOCAL_ADDESSES_TOKEN = "<local>"; //$NON-NLS-1$ /** * Create a ProxyBypass instance from the proxy bypass list string. @@ -33,15 +33,15 @@ public class ProxyBypass { * @param proxyBypass */ public ProxyBypass(String proxyBypass) { - this.proxyBypass= proxyBypass != null ? proxyBypass : ""; //$NON-NLS-1$ + this.proxyBypass = proxyBypass != null ? proxyBypass : ""; //$NON-NLS-1$ if (proxyBypass != null) { - String regExp= replace(proxyBypass, ";", "|"); //$NON-NLS-1$ //$NON-NLS-2$ - regExp= replace(regExp, ".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ - regExp= replace(regExp, "*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$ - this.proxyBypassPattern= Pattern.compile(regExp); + String regExp = ProxyProviderUtil.replace(proxyBypass, ";", "|"); //$NON-NLS-1$ //$NON-NLS-2$ + regExp = ProxyProviderUtil.replace(regExp, ".", "\\."); //$NON-NLS-1$ //$NON-NLS-2$ + regExp = ProxyProviderUtil.replace(regExp, "*", ".*"); //$NON-NLS-1$ //$NON-NLS-2$ + this.proxyBypassPattern = Pattern.compile(regExp); } else { - this.proxyBypassPattern= Pattern.compile(""); //$NON-NLS-1$ + this.proxyBypassPattern = Pattern.compile(""); //$NON-NLS-1$ } } @@ -52,10 +52,11 @@ public class ProxyBypass { * @return true if the the uri should bypass the proxy; otherwise false */ public boolean bypassProxyFor(URI uri) { - final String host= uri.getHost(); + final String host = uri.getHost(); if (host == null) return false; - return (isLocal(host) && isBypassLocalAddresses(proxyBypass)) || isInBypassList(host); + return (isLocal(host) && isBypassLocalAddresses(proxyBypass)) + || isInBypassList(host); } /** @@ -83,32 +84,4 @@ public class ProxyBypass { return proxyBypass.indexOf(BYPASS_LOCAL_ADDESSES_TOKEN) != -1; } - /** - * Replace within <code>source</code> the occurrences of <code>from</code> with - * <code>to</code>. - * - * @param source - * @param from - * @param to - * @return the substituted string - */ - private static String replace(String source, String from, String to) { - if (from.length() == 0) - return source; - StringBuffer buffer= new StringBuffer(); - int current= 0; - int pos= 0; - while (pos != -1) { - pos= source.indexOf(from, current); - if (pos == -1) { - buffer.append(source.substring(current)); - } else { - buffer.append(source.substring(current, pos)); - buffer.append(to); - current= pos + from.length(); - } - } - return buffer.toString(); - } - } diff --git a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxyProviderUtil.java b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxyProviderUtil.java new file mode 100644 index 000000000..04f31df86 --- /dev/null +++ b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxyProviderUtil.java @@ -0,0 +1,297 @@ +/******************************************************************************* + * Copyright (c) 2008 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 (Stefan Liebig) - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.internal.net.proxy.win32.winhttp; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import org.eclipse.core.internal.net.Activator; +import org.eclipse.core.internal.net.ProxyData; +import org.eclipse.core.net.proxy.IProxyData; + +/** + * A helper class that transforms strings (proxy lists, ..) from the native API + * into a format suitable for the proxy provider API. + */ +public final class ProxyProviderUtil { + + static private int PROXY_DEFAULT_PORT = 80; + static private int HTTPPROXY_DEFAULT_PORT = PROXY_DEFAULT_PORT; + static private int HTTPSPROXY_DEFAULT_PORT = 443; + static private int SOCKSPROXY_DEFAULT_PORT = 1080; + + private ProxyProviderUtil() { + super(); + } + + /** + * Scan the proxy list string and fill this information in the correct list + * or map. <br> + * The proxy list contains one or more of the following strings separated by + * semicolons:<br> + * <code><pre> + * ([<scheme>=][<scheme> "://" ]<server>[ ":" <port>]) + * </pre></code> + * + * @param proxyList + * the proxy list as a string + * @param universalProxies + * the list of proxies receiving the universal proxies + * @param protocolSpecificProxies + * a map from http schemes to the list of scheme specific proxies + */ + public static void fillProxyLists(String proxyList, List universalProxies, + Map protocolSpecificProxies) { + StringTokenizer tokenizer = new StringTokenizer(proxyList, ";"); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) { + createProxy(tokenizer.nextToken(), universalProxies, + protocolSpecificProxies); + } + } + + private static void createProxy(final String proxyDefinition, + List universalProxies, Map 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 + int equalsChar = proxyDefinition.indexOf("="); //$NON-NLS-1$ + if (equalsChar != -1) { + protocol = proxyDefinition.substring(0, equalsChar).toUpperCase(); + urlStart = equalsChar + 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$ + URI uri = new URI(augmentedURI); + host = uri.getHost(); + port = uri.getPort() > 0 ? uri.getPort() + : getProxyDefaultPort(protocol); + } catch (Exception ex) { + Activator + .logError( + "not a valid proxy definition: '" + proxyDefinition + "'.", ex); //$NON-NLS-1$ //$NON-NLS-2$ + return; + } + + if (host == null) { + Activator + .logError( + "not a valid proxy definition: '" + proxyDefinition + "'.", null); //$NON-NLS-1$ //$NON-NLS-2$ + return; + } + + if (protocol == null) + universalProxies.add(createProxy(IProxyData.HTTP_PROXY_TYPE, host, + port)); + else + addProtocolSpecificProxy(protocolSpecificProxies, protocol, + createProxy(resolveProxyType(protocol), host, port)); + } + + private static int getProxyDefaultPort(String protocol) { + if (protocol == null) + return PROXY_DEFAULT_PORT; + if (IProxyData.HTTP_PROXY_TYPE.equalsIgnoreCase(protocol)) + return HTTPPROXY_DEFAULT_PORT; + if (IProxyData.HTTPS_PROXY_TYPE.equalsIgnoreCase(protocol)) + return HTTPSPROXY_DEFAULT_PORT; + if (IProxyData.SOCKS_PROXY_TYPE.equalsIgnoreCase(protocol)) + return SOCKSPROXY_DEFAULT_PORT; + + return PROXY_DEFAULT_PORT; + } + + private static void addProtocolSpecificProxy(Map protocolSpecificProxies, + String protocol, IProxyData proxy) { + List list = (List) protocolSpecificProxies.get(protocol); + if (list == null) { + list = new ArrayList(); + protocolSpecificProxies.put(protocol, list); + } + + list.add(proxy); + } + + private static String resolveProxyType(String protocol) { + if (protocol.equalsIgnoreCase("socks") || protocol.equalsIgnoreCase("socket")) //$NON-NLS-1$ //$NON-NLS-2$ + return IProxyData.SOCKS_PROXY_TYPE; + if (protocol.equalsIgnoreCase("https")) //$NON-NLS-1$ + return IProxyData.HTTPS_PROXY_TYPE; + return IProxyData.HTTP_PROXY_TYPE; + } + + private static IProxyData createProxy(String scheme, String host, int port) { + String type = resolveProxyType(scheme); + IProxyData proxy = new ProxyData(type); + proxy.setHost(host); + proxy.setPort(port); + return proxy; + } + + /* + * Pac related helper methods below here. + */ + + private static final Map PROXY_TYPE_MAP; + + /* + * @see "http://wp.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html" + */ + private static final String PAC_PROXY_TYPE_DIRECT = "DIRECT"; //$NON-NLS-1$ + private static final String PAC_PROXY_TYPE_PROXY = "PROXY"; //$NON-NLS-1$ + private static final String PAC_PROXY_TYPE_SOCKS = "SOCKS"; //$NON-NLS-1$ + private static final String NO_PROXY = "DIRECT"; //$NON-NLS-1$ + + static { + // mapping of pacProgram proxy type names to java proxy types: + final Map temp = new HashMap(); + temp.put(PAC_PROXY_TYPE_DIRECT, NO_PROXY); + temp.put(PAC_PROXY_TYPE_PROXY, IProxyData.HTTP_PROXY_TYPE); + temp.put(PAC_PROXY_TYPE_SOCKS, IProxyData.SOCKS_PROXY_TYPE); + PROXY_TYPE_MAP = Collections.unmodifiableMap(temp); + } + + /** + * @param pacFindProxyForUrlResult + * @return a list of IProxyData objects + */ + public static List getProxies(String pacFindProxyForUrlResult) { + if (pacFindProxyForUrlResult == null + || pacFindProxyForUrlResult.trim().length() == 0) + return Collections.EMPTY_LIST; + + final List result = new ArrayList(); + final StringTokenizer scanner = new StringTokenizer( + pacFindProxyForUrlResult, ";"); //$NON-NLS-1$ + while (scanner.hasMoreTokens()) { + final String pacProxy = scanner.nextToken().trim(); + final IProxyData proxy = getProxy(pacProxy); + if (proxy != null) + result.add(proxy); + } + + return result; + } + + private static IProxyData getProxy(String pacProxy) { + if (pacProxy == null || pacProxy.length() == 0) + return null; + + if (!startsWithProxyType(pacProxy)) + // Assume "PROXY" type! + pacProxy = "PROXY " + pacProxy; //$NON-NLS-1$ + StringTokenizer scanner = new StringTokenizer(pacProxy); + String pacProxyType = scanner.nextToken(); + String proxyType = (String) PROXY_TYPE_MAP.get(pacProxyType); + if (proxyType == null || proxyType.equals(NO_PROXY)) + return null; + + String pacHostnameAndPort = null; + if (scanner.hasMoreTokens()) + pacHostnameAndPort = scanner.nextToken(); + String hostname = getHostname(pacHostnameAndPort); + if (hostname != null) { + int port = getPort(pacHostnameAndPort); + IProxyData proxy = new ProxyData(proxyType); + proxy.setHost(hostname); + proxy.setPort(port); + return proxy; + } + return null; + } + + private static boolean startsWithProxyType(String pacProxy) { + Iterator iter = PROXY_TYPE_MAP.keySet().iterator(); + while (iter.hasNext()) + if (pacProxy.startsWith((String) iter.next())) + return true; + + return false; + } + + private static String getHostname(String pacHostnameAndPort) { + return pacHostnameAndPort != null ? pacHostnameAndPort.substring(0, + pacHostnameAndPort.indexOf(':')) : null; + } + + private static int getPort(String pacHostnameAndPort) { + return pacHostnameAndPort != null + && pacHostnameAndPort.indexOf(':') > -1 ? Integer + .parseInt(pacHostnameAndPort.substring(pacHostnameAndPort + .indexOf(':') + 1)) : 0; + } + + /** + * Tests equality of the given strings. + * + * @param sequence1 + * candidate 1, may be null + * @param sequence2 + * candidate 2, may be null + * @return true if both sequences are null or the sequences are equal + */ + public static final boolean equals(final CharSequence sequence1, + final CharSequence sequence2) { + if (sequence1 == sequence2) + return true; + else if (sequence1 == null || sequence2 == null) + return false; + else + return sequence1.equals(sequence2); + } + + /** + * Replace within <code>source</code> the occurrences of <code>from</code> + * with <code>to</code>.<br> + * <b>Note:</b> This has the same behavior as the + * <code>String.replace()</code> method within JDK 1.5. + * + * @param source + * @param from + * @param to + * @return the substituted string + */ + public static String replace(String source, String from, String to) { + if (from.length() == 0) + return source; + StringBuffer buffer = new StringBuffer(); + int current = 0; + int pos = 0; + while (pos != -1) { + pos = source.indexOf(from, current); + if (pos == -1) { + buffer.append(source.substring(current)); + } else { + buffer.append(source.substring(current, pos)); + buffer.append(to); + current = pos + from.length(); + } + } + return buffer.toString(); + } + +} diff --git a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxySelectorUtils.java b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxySelectorUtils.java deleted file mode 100644 index 78a2c8b46..000000000 --- a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/ProxySelectorUtils.java +++ /dev/null @@ -1,245 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 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 (Stefan Liebig) - initial API and implementation - *******************************************************************************/ -package org.eclipse.core.internal.net.proxy.win32.winhttp; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import org.eclipse.core.internal.net.Activator; -import org.eclipse.core.internal.net.ProxyData; -import org.eclipse.core.net.proxy.IProxyData; - -/** - * A helper class that transforms strings (proxy lists, ..) from the native API into a format - * suitable for the proxy provider API. - */ -public final class ProxySelectorUtils { - - static private int PROXY_DEFAULT_PORT= 80; - - static private int HTTPPROXY_DEFAULT_PORT= PROXY_DEFAULT_PORT; - - static private int HTTPSPROXY_DEFAULT_PORT= 443; - - static private int SOCKSPROXY_DEFAULT_PORT= 1080; - - private ProxySelectorUtils() { - super(); - } - - /** - * Scan the proxy list string and fill this information in the correct list or map. <br> - * The proxy list contains one or more of the following strings separated by semicolons:<br> - * <code><pre> - * ([<scheme>=][<scheme> "://" ]<server>[ ":" <port>]) - * </pre></code> - * - * @param proxyList the proxy list as a string - * @param universalProxies the list of proxies receiving the universal proxies - * @param protocolSpecificProxies a map from http schemes to the list of scheme specific proxies - */ - public static void fillProxyLists(String proxyList, List universalProxies, Map protocolSpecificProxies) { - StringTokenizer tokenizer= new StringTokenizer(proxyList, ";"); //$NON-NLS-1$ - while (tokenizer.hasMoreTokens()) { - createProxy(tokenizer.nextToken(), universalProxies, protocolSpecificProxies); - } - } - - private static void createProxy(final String proxyDefinition, List universalProxies, Map 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("=")).toUpperCase(); //$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$ - } - URI uri= new URI(augmentedURI); - host= uri.getHost(); - port= uri.getPort() > 0 ? uri.getPort() : getProxyDefaultPort(protocol); - } catch (Exception ex) { - Activator.logError("not a valid proxy definition: '" + proxyDefinition + "'.", ex); //$NON-NLS-1$ //$NON-NLS-2$ - return; - } - - if (host == null) { - Activator.logError("not a valid proxy definition: '" + proxyDefinition + "'.", null); //$NON-NLS-1$ //$NON-NLS-2$ - return; - } - - if (protocol == null) { - universalProxies.add(createProxy(IProxyData.HTTP_PROXY_TYPE, host, port)); - } else { - addProtocolSpecificProxy(protocolSpecificProxies, protocol, createProxy(resolveProxyType(protocol), host, port)); - } - } - - private static int getProxyDefaultPort(String protocol) { - if (protocol == null) - return PROXY_DEFAULT_PORT; - if (IProxyData.HTTP_PROXY_TYPE.equalsIgnoreCase(protocol)) - return HTTPPROXY_DEFAULT_PORT; - if (IProxyData.HTTPS_PROXY_TYPE.equalsIgnoreCase(protocol)) - return HTTPSPROXY_DEFAULT_PORT; - if (IProxyData.SOCKS_PROXY_TYPE.equalsIgnoreCase(protocol)) - return SOCKSPROXY_DEFAULT_PORT; - - return PROXY_DEFAULT_PORT; - } - - private static void addProtocolSpecificProxy(Map protocolSpecificProxies, String protocol, IProxyData proxy) { - List list= (List)protocolSpecificProxies.get(protocol); - if (list == null) { - list= new ArrayList(); - protocolSpecificProxies.put(protocol, list); - } - - list.add(proxy); - } - - private static String resolveProxyType(String protocol) { - // TODO: return HTTP proxy for well-known high level protocols only? - if (protocol.equalsIgnoreCase("socks") || protocol.equalsIgnoreCase("socket")) //$NON-NLS-1$ //$NON-NLS-2$ - return IProxyData.SOCKS_PROXY_TYPE; - if (protocol.equalsIgnoreCase("https")) //$NON-NLS-1$ - return IProxyData.HTTPS_PROXY_TYPE; - return IProxyData.HTTP_PROXY_TYPE; - } - - private static IProxyData createProxy(String scheme, String host, int port) { - String type= resolveProxyType(scheme); - IProxyData proxy= new ProxyData(type); - proxy.setHost(host); - proxy.setPort(port); - return proxy; - } - - /* - * Pac related helper methods below here. - */ - - private static final Map PROXY_TYPE_MAP; - - /* - * @see "http://wp.netscape.com/eng/mozilla/2.0/relnotes/demo/proxy-live.html" - */ - private static final String PAC_PROXY_TYPE_DIRECT= "DIRECT"; //$NON-NLS-1$ - - private static final String PAC_PROXY_TYPE_PROXY= "PROXY"; //$NON-NLS-1$ - - private static final String PAC_PROXY_TYPE_SOCKS= "SOCKS"; //$NON-NLS-1$ - - private static final String NO_PROXY= "DIRECT"; //$NON-NLS-1$ - - static { - // mapping of pacProgram proxy type names to java proxy types: - final Map temp= new HashMap(); - temp.put(PAC_PROXY_TYPE_DIRECT, NO_PROXY); - temp.put(PAC_PROXY_TYPE_PROXY, IProxyData.HTTP_PROXY_TYPE); - temp.put(PAC_PROXY_TYPE_SOCKS, IProxyData.SOCKS_PROXY_TYPE); - PROXY_TYPE_MAP= Collections.unmodifiableMap(temp); - } - - /** - * @param pacFindProxyForUrlResult - * @return a list of IProxyData objects - */ - public static List getProxies(String pacFindProxyForUrlResult) { - if (pacFindProxyForUrlResult == null || pacFindProxyForUrlResult.trim().length() == 0) - return Collections.EMPTY_LIST; - - final List result= new ArrayList(); - final StringTokenizer scanner= new StringTokenizer(pacFindProxyForUrlResult, ";"); //$NON-NLS-1$ - while (scanner.hasMoreTokens()) { - final String pacProxy= scanner.nextToken().trim(); - final IProxyData proxy= getProxy(pacProxy); - if (proxy != null) { - result.add(proxy); - } - } - - return result; - } - - private static IProxyData getProxy(String pacProxy) { - if (pacProxy == null || pacProxy.length() == 0) - return null; - - if (!startsWithProxyType(pacProxy)) { - // Assume "PROXY" type! - pacProxy= "PROXY " + pacProxy; //$NON-NLS-1$ - } - StringTokenizer scanner= new StringTokenizer(pacProxy); - String pacProxyType= scanner.nextToken(); - String proxyType= (String)PROXY_TYPE_MAP.get(pacProxyType); - if (proxyType == null || proxyType.equals(NO_PROXY)) - return null; - - String pacHostnameAndPort= null; - if (scanner.hasMoreTokens()) { - pacHostnameAndPort= scanner.nextToken(); - } - String hostname= getHostname(pacHostnameAndPort); - if (hostname != null) { - int port= getPort(pacHostnameAndPort); - IProxyData proxy= new ProxyData(proxyType); - proxy.setHost(hostname); - proxy.setPort(port); - return proxy; - } - return null; - } - - private static boolean startsWithProxyType(String pacProxy) { - Iterator iter= PROXY_TYPE_MAP.keySet().iterator(); - while (iter.hasNext()) { - if (pacProxy.startsWith((String)iter.next())) { - return true; - } - } - - return false; - } - - static String getHostname(String pacHostnameAndPort) { - if (pacHostnameAndPort != null) { - return pacHostnameAndPort.substring(0, pacHostnameAndPort.indexOf(':')); - } - return null; - } - - static int getPort(String pacHostnameAndPort) { - if (pacHostnameAndPort != null && pacHostnameAndPort.indexOf(':') > -1) { - return Integer.parseInt(pacHostnameAndPort.substring(pacHostnameAndPort.indexOf(':') + 1)); - } - return 0; - } - -} diff --git a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/StaticProxyConfig.java b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/StaticProxyConfig.java new file mode 100644 index 000000000..d49861641 --- /dev/null +++ b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/StaticProxyConfig.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2008 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 (Stefan Liebig) - initial API and implementation + *******************************************************************************/ +package org.eclipse.core.internal.net.proxy.win32.winhttp; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * StaticProxyConfig wraps certain information of WinHttpCurrentIEProxyConfig, + * i.e. the Windows specific list of proxies and the proxy bypass list. + */ +public class StaticProxyConfig { + + private List universalProxies = new ArrayList(); + private Map protocolSpecificProxies = new HashMap(); + private ProxyBypass proxyBypass; + + /** + * @param proxiesString + * @param proxyBypassString + */ + public StaticProxyConfig(String proxiesString, String proxyBypassString) { + ProxyProviderUtil.fillProxyLists(proxiesString, universalProxies, + protocolSpecificProxies); + proxyBypass = new ProxyBypass(proxyBypassString); + } + + /** + * Select the static proxies for the given uri and add it to the given list + * of proxies.<br> + * This respects also the proxy bypass definition. + * + * @param uri + * @param proxies + */ + public void select(URI uri, List proxies) { + if (proxyBypass.bypassProxyFor(uri)) + return; + + if (!protocolSpecificProxies.isEmpty()) { + List protocolProxies = (List) protocolSpecificProxies.get(uri + .getScheme().toUpperCase()); + if (protocolProxies == null) + return; + proxies.addAll(protocolProxies); + } else + proxies.addAll(universalProxies); + } + +} diff --git a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpConfig.java b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpConfig.java deleted file mode 100644 index 1c982f544..000000000 --- a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpConfig.java +++ /dev/null @@ -1,60 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2008 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 (Stefan Liebig) - initial API and implementation - *******************************************************************************/ -package org.eclipse.core.internal.net.proxy.win32.winhttp; - -import java.net.URI; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * WinHttpConfig unwraps the information from WinHttpCurrentIEProxyConfig. - * <p> - * The fields will be written by the jni glue code. - * </p> - */ -public class WinHttpConfig { - - public List universalProxies= new ArrayList(); - - public Map protocolSpecificProxies= new HashMap(); - - public ProxyBypass proxyBypass; - - /** - * @param proxyConfig - */ - public WinHttpConfig(WinHttpCurrentUserIEProxyConfig proxyConfig) { - ProxySelectorUtils.fillProxyLists(proxyConfig.getProxy(), universalProxies, protocolSpecificProxies); - proxyBypass= new ProxyBypass(proxyConfig.getProxyBypass()); - } - - public boolean useUniversalProxy() { - return !universalProxies.isEmpty(); - } - - public boolean useProtocolSpecificProxies() { - return !protocolSpecificProxies.isEmpty(); - } - - public List getProtocolSpecificProxies(URI uri) { - return (List)protocolSpecificProxies.get(uri.getScheme().toUpperCase()); - } - - public List getUniversalProxies() { - return universalProxies; - } - - public boolean bypassProxyFor(URI uri) { - return proxyBypass.bypassProxyFor(uri); - } -} diff --git a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpCurrentUserIEProxyConfig.java b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpCurrentUserIEProxyConfig.java index 07b5e8040..91e679bfa 100644 --- a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpCurrentUserIEProxyConfig.java +++ b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpCurrentUserIEProxyConfig.java @@ -11,7 +11,8 @@ package org.eclipse.core.internal.net.proxy.win32.winhttp; /** - * Wrapper for Win32 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG structure. + * Wrapper for Win32 WINHTTP_CURRENT_USER_IE_PROXY_CONFIG structure.<br> + * Plus a few helper methods that enrich the plain C structure. * <p> * The fields will be written by the jni glue code. * </p> @@ -19,11 +20,8 @@ package org.eclipse.core.internal.net.proxy.win32.winhttp; public class WinHttpCurrentUserIEProxyConfig { public boolean isAutoDetect; - public String autoConfigUrl; - public String proxy; - public String proxyBypass; /** @@ -34,6 +32,22 @@ public class WinHttpCurrentUserIEProxyConfig { } /** + * @return the proxy + */ + public String getProxy() { + return proxy; + } + + /** + * @return the proxyBypass + */ + public String getProxyBypass() { + return proxyBypass; + } + + /** + * I auto detection requested? + * * @return the isAutoDetect */ public boolean isAutoDetect() { @@ -41,55 +55,64 @@ public class WinHttpCurrentUserIEProxyConfig { } /** - * @return the proxy + * Is a auto config url reqested? + * + * @return true if there is a auto config url */ - public String getProxy() { - return proxy; + public boolean isAutoConfigUrl() { + return autoConfigUrl != null && autoConfigUrl.length() != 0; } /** - * @return the proxyBypass + * Are static proxies defined? + * + * @return the isStaticProxy */ - public String getProxyBypass() { - return proxyBypass; + public boolean isStaticProxy() { + return proxy != null && proxy.length() != 0; } /** - * @see java.lang.Object#equals(java.lang.Object) + * Did the auto-detect change? + * + * @param proxyConfig + * the proxy config; maybe null + * @return true if changed */ - public boolean equals(Object obj) { - if (this == obj) + public boolean autoDetectChanged(WinHttpCurrentUserIEProxyConfig proxyConfig) { + if (proxyConfig == null) return true; - if (obj instanceof WinHttpCurrentUserIEProxyConfig) { - WinHttpCurrentUserIEProxyConfig that= (WinHttpCurrentUserIEProxyConfig)obj; - return (this.isAutoDetect == that.isAutoDetect) && equals(this.autoConfigUrl, that.autoConfigUrl) && equals(this.proxy, that.proxy) && equals(this.proxyBypass, that.proxyBypass); - } - - return false; + return isAutoDetect != proxyConfig.isAutoDetect; } /** - * Tests equality of the given strings. + * Did the auto-config url change? * - * @param sequence1 candidate 1, may be null - * @param sequence2 candidate 2, may be null - * @return true if both sequences are null or the sequences are equal + * @param proxyConfig + * the proxy config; maybe null + * @return true if changed */ - private static final boolean equals(final CharSequence sequence1, final CharSequence sequence2) { - if (sequence1 == sequence2) { + public boolean autoConfigUrlChanged( + WinHttpCurrentUserIEProxyConfig proxyConfig) { + if (proxyConfig == null) return true; - } else if (sequence1 == null || sequence2 == null) { - return false; - } else { - return sequence1.equals(sequence2); - } + return !ProxyProviderUtil.equals(autoConfigUrl, + proxyConfig.autoConfigUrl); } /** - * @see java.lang.Object#hashCode() + * Did the static proxy information change? + * + * @param proxyConfig + * the proxy config; maybe null + * @return true if changed */ - public int hashCode() { - return (autoConfigUrl + proxy).hashCode(); + public boolean staticProxyChanged( + WinHttpCurrentUserIEProxyConfig proxyConfig) { + if (proxyConfig == null) + return true; + return !(ProxyProviderUtil.equals(proxy, proxyConfig.proxy) && ProxyProviderUtil + .equals(proxyBypass, proxyConfig.proxyBypass)); } } diff --git a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpProxyProvider.java b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpProxyProvider.java index 26cea71c9..8165fcc57 100644 --- a/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpProxyProvider.java +++ b/bundles/org.eclipse.core.net/src/org/eclipse/core/internal/net/proxy/win32/winhttp/WinHttpProxyProvider.java @@ -20,98 +20,103 @@ import org.eclipse.core.internal.net.ProxyData; import org.eclipse.core.net.proxy.IProxyData; /** - * The provider that gets its settings from the "internet options >> connection settings". For this - * it uses the Windows WinHttp API. + * The <code>WinHttpProxyProvivider</code> gets its settings from the + * "internet options >> connection settings". For this it uses the Windows + * WinHttp API. * * @see "http://msdn2.microsoft.com/en-us/library/aa382925(VS.85).aspx" */ public class WinHttpProxyProvider { - private WinHttpCurrentUserIEProxyConfig proxyConfig= null; - - private WinHttpConfig winHttpConfig; - + private WinHttpCurrentUserIEProxyConfig proxyConfig; + private StaticProxyConfig staticProxyConfig; private String wpadAutoConfigUrl; - - private boolean retryWpad= false; - - private static final ProxyData[] EMPTY_PROXIES= new ProxyData[0]; - - private static final String MY_NAME= WinHttpProxyProvider.class.getName(); + private boolean tryWpadGetUrl; + private boolean tryPac; + + // Buffered delayed logging to avoid deadlocks. Logging itself might trigger + // through listeners/appenders other threads to do some communication which in + // turn uses this proxy provider. + private String logMessage; + private Throwable logThrowable; + + private static final ProxyData[] EMPTY_PROXIES = new ProxyData[0]; + private static final String MY_NAME = WinHttpProxyProvider.class.getName(); /** - * Retrieve the proxies that are suitable for the given uri. An empty array of proxies indicates - * that no proxy should be used. This method considers already the īno proxy forī definition of - * the internet options dialog. + * Retrieve the proxies that are suitable for the given uri. An empty array + * of proxies indicates that no proxy should be used (direct connection). + * This method considers already the īno proxy forī definition of the + * internet options dialog. * * @param uri * @return an array of proxies */ public IProxyData[] getProxyData(URI uri) { - WinHttpCurrentUserIEProxyConfig newProxyConfig= new WinHttpCurrentUserIEProxyConfig(); + logMessage = null; + IProxyData[] proxies; + synchronized (this) { + proxies = getProxyDataUnsynchronized(uri); + } + if (logMessage != null) + Activator.logError(logMessage, logThrowable); + return proxies; + } + + /** + * This method is the not synchronized counterpart of <code>getProxyData</code>. + * + * @param uri + * @return an array of proxies + */ + private IProxyData[] getProxyDataUnsynchronized(URI uri) { + WinHttpCurrentUserIEProxyConfig newProxyConfig = new WinHttpCurrentUserIEProxyConfig(); if (!WinHttp.getIEProxyConfigForCurrentUser(newProxyConfig)) { - Activator.logError("WinHttp.GetIEProxyConfigForCurrentUser failed with error '" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + logError( + "WinHttp.GetIEProxyConfigForCurrentUser failed with error '" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return EMPTY_PROXIES; } - if (proxyConfig == null) { - proxyConfig= newProxyConfig; - retryWpad= proxyConfig.isAutoDetect(); - } + List proxies = new ArrayList(); // Letīs find out if auto detect has changed. - if (newProxyConfig.isAutoDetect() != proxyConfig.isAutoDetect()) - retryWpad= proxyConfig.isAutoDetect(); - - boolean proxyConfigChanged= !newProxyConfig.equals(proxyConfig); - - if (proxyConfigChanged) - proxyConfig= newProxyConfig; + if (newProxyConfig.autoDetectChanged(proxyConfig)) { + tryWpadGetUrl = newProxyConfig.isAutoDetect(); + if (!tryWpadGetUrl) + wpadAutoConfigUrl = null; + } - List proxies= new ArrayList(); + // Letīs find out if pac file url has changed. + if (newProxyConfig.autoConfigUrlChanged(proxyConfig)) + tryPac = newProxyConfig.isAutoConfigUrl(); // Explicit proxies defined? - if (proxyConfig.getProxy() != null && proxyConfig.getProxy().length() != 0) { - // Yes, letīs see if we are still up-to-date or not yet initialized. - if (proxyConfigChanged || winHttpConfig == null) { - winHttpConfig= new WinHttpConfig(proxyConfig); - } + if (newProxyConfig.isStaticProxy()) { + // Yes, letīs see if we are still up-to-date + if (newProxyConfig.staticProxyChanged(proxyConfig)) + staticProxyConfig = new StaticProxyConfig(newProxyConfig + .getProxy(), newProxyConfig.getProxyBypass()); - if (!winHttpConfig.bypassProxyFor(uri)) { - if (winHttpConfig.useProtocolSpecificProxies()) { - List protocolSpecificProxies= winHttpConfig.getProtocolSpecificProxies(uri); - if (protocolSpecificProxies != null) { - proxies.addAll(protocolSpecificProxies); - } - } else { - proxies.addAll(winHttpConfig.getUniversalProxies()); - } - } + staticProxyConfig.select(uri, proxies); } + proxyConfig = newProxyConfig; - boolean isPac= proxyConfig.getAutoConfigUrl() != null; - boolean isWpad= proxyConfig.isAutoDetect(); - - if (!isPac && !isWpad) + if (!tryPac && wpadAutoConfigUrl == null) return toArray(proxies); // Create the WinHTTP session. - int hHttpSession= WinHttp.open(MY_NAME, WinHttpProxyInfo.WINHTTP_ACCESS_TYPE_NO_PROXY, WinHttp.NO_PROXY_NAME, WinHttp.NO_PROXY_BYPASS, 0); + int hHttpSession = WinHttp.open(MY_NAME, + WinHttpProxyInfo.WINHTTP_ACCESS_TYPE_NO_PROXY, + WinHttp.NO_PROXY_NAME, WinHttp.NO_PROXY_BYPASS, 0); if (hHttpSession == 0) { - Activator.logError("WinHttp.Open failed with error'" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + logError( + "WinHttp.Open failed with error'" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return toArray(proxies); } try { - // PAC file? - if (isPac) { - proxies.addAll(pacSelect(hHttpSession, uri)); - } - - // WPAD? - if (isWpad) { - proxies.addAll(wpadSelect(hHttpSession, uri)); - } + pacSelect(hHttpSession, uri, proxies); + wpadSelect(hHttpSession, uri, proxies); } finally { WinHttp.closeHandle(hHttpSession); } @@ -119,50 +124,85 @@ public class WinHttpProxyProvider { return toArray(proxies); } - private static IProxyData[] toArray(List proxies) { - return (IProxyData[])proxies.toArray(new IProxyData[proxies.size()]); + protected void pacSelect(int hHttpSession, URI uri, List proxies) { + if (!tryPac) + return; + List pacProxies = pacSelect(hHttpSession, proxyConfig + .getAutoConfigUrl(), uri); + if (pacProxies == null) + tryPac = false; + else + proxies.addAll(pacProxies); + } - protected List pacSelect(int hHttpSession, URI uri) { - return pacSelect(hHttpSession, proxyConfig.getAutoConfigUrl(), uri); + protected void wpadSelect(int hHttpSession, URI uri, List proxies) { + if (tryWpadGetUrl) { + tryWpadGetUrl = false; + AutoProxyHolder autoProxyHolder = new AutoProxyHolder(); + autoProxyHolder + .setAutoDetectFlags(WinHttpAutoProxyOptions.WINHTTP_AUTO_DETECT_TYPE_DHCP + | WinHttpAutoProxyOptions.WINHTTP_AUTO_DETECT_TYPE_DNS_A); + boolean ok = WinHttp.detectAutoProxyConfigUrl(autoProxyHolder); + if (!ok) { + logError( + "WinHttp.DetectAutoProxyConfigUrl for wpad failed with error '" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return; + } + wpadAutoConfigUrl = autoProxyHolder.getAutoConfigUrl(); + } + if (wpadAutoConfigUrl == null) + return; + List wpadProxies = pacSelect(hHttpSession, wpadAutoConfigUrl, uri); + if (wpadProxies == null) + wpadAutoConfigUrl = null; + else + proxies.addAll(wpadProxies); } + /** + * Retrieve the proxies from the specified pac file url. + * + * @param hHttpSession + * @param configUrl + * @param uri + * @return a list of proxies (IProxyData) or null in case of an error. + */ protected List pacSelect(int hHttpSession, String configUrl, URI uri) { - // Donīt ask for anything else than http or https since that is not supported - // by WinHttp pac file support: ERROR_WINHTTP_UNRECOGNIZED_SCHEME - if ( !IProxyData.HTTP_PROXY_TYPE.equalsIgnoreCase(uri.getScheme()) && !IProxyData.HTTPS_PROXY_TYPE.equalsIgnoreCase(uri.getScheme())) - return Collections.EMPTY_LIST; + // Donīt ask for anything else than http or https since that is not + // supported by WinHttp pac file support: + // ERROR_WINHTTP_UNRECOGNIZED_SCHEME + if (!IProxyData.HTTP_PROXY_TYPE.equalsIgnoreCase(uri.getScheme()) + && !IProxyData.HTTPS_PROXY_TYPE.equalsIgnoreCase(uri + .getScheme())) + return Collections.EMPTY_LIST; // Set up the autoproxy call. - WinHttpAutoProxyOptions autoProxyOptions= new WinHttpAutoProxyOptions(); - autoProxyOptions.setFlags(WinHttpAutoProxyOptions.WINHTTP_AUTOPROXY_CONFIG_URL); + WinHttpAutoProxyOptions autoProxyOptions = new WinHttpAutoProxyOptions(); + autoProxyOptions + .setFlags(WinHttpAutoProxyOptions.WINHTTP_AUTOPROXY_CONFIG_URL); autoProxyOptions.setAutoConfigUrl(configUrl); autoProxyOptions.setAutoLogonIfChallenged(true); - WinHttpProxyInfo proxyInfo= new WinHttpProxyInfo(); + WinHttpProxyInfo proxyInfo = new WinHttpProxyInfo(); - boolean ok= WinHttp.getProxyForUrl(hHttpSession, uri.toString(), autoProxyOptions, proxyInfo); + boolean ok = WinHttp.getProxyForUrl(hHttpSession, uri.toString(), + autoProxyOptions, proxyInfo); if (!ok) { - Activator.logError("WinHttp.GetProxyForUrl for pac failed with error '" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - return Collections.EMPTY_LIST; + logError( + "WinHttp.GetProxyForUrl for pac failed with error '" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + return null; } - ProxyBypass proxyBypass= new ProxyBypass(proxyInfo.getProxyBypass()); + ProxyBypass proxyBypass = new ProxyBypass(proxyInfo.getProxyBypass()); if (proxyBypass.bypassProxyFor(uri)) return Collections.EMPTY_LIST; - return ProxySelectorUtils.getProxies(proxyInfo.getProxy()); + return ProxyProviderUtil.getProxies(proxyInfo.getProxy()); } - protected List wpadSelect(int hHttpSession, URI uri) { - if (wpadAutoConfigUrl == null || retryWpad) { - AutoProxyHolder autoProxyHolder= new AutoProxyHolder(); - autoProxyHolder.setAutoDetectFlags(WinHttpAutoProxyOptions.WINHTTP_AUTO_DETECT_TYPE_DHCP | WinHttpAutoProxyOptions.WINHTTP_AUTO_DETECT_TYPE_DNS_A); - boolean ok= WinHttp.detectAutoProxyConfigUrl(autoProxyHolder); - if (!ok) { - Activator.logError("WinHttp.DetectAutoProxyConfigUrl for wpad failed with error '" + WinHttp.getLastErrorMessage() + "' #" + WinHttp.getLastError() + ".", null); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - return Collections.EMPTY_LIST; - } - wpadAutoConfigUrl= autoProxyHolder.getAutoConfigUrl(); - retryWpad= false; - } - return pacSelect(hHttpSession, wpadAutoConfigUrl, uri); + private void logError(String message, Throwable throwable) { + this.logMessage = message; + this.logThrowable = throwable; } + private static IProxyData[] toArray(List proxies) { + return (IProxyData[]) proxies.toArray(new IProxyData[proxies.size()]); + } } |