From f47a061928a8b9ab657a9164bae31029a5829082 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Sun, 11 May 2008 17:01:35 -0400 Subject: [PATCH] Use the Eclipse network proxy configuration for HTTP connections Eclipse provides support for proxy configuration within the workbench, but this information is not pushed down into the J2SE library itself so our naive use of java.net.URL to open connections cannot get to the proxy information. By installing our own ProxySelector and Authenticator implementations we can push the Eclipse proxy information down into the J2SE library and make use of it during transport operations. Signed-off-by: Shawn O. Pearce --- org.spearce.egit.ui/META-INF/MANIFEST.MF | 1 + .../src/org/spearce/egit/ui/Activator.java | 17 +++++ .../org/spearce/egit/ui/EclipseAuthenticator.java | 66 ++++++++++++++++++ .../org/spearce/egit/ui/EclipseProxySelector.java | 81 ++++++++++++++++++++++ .../org/spearce/jgit/transport/TransportHttp.java | 19 ++++- 5 files changed, 182 insertions(+), 2 deletions(-) create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseAuthenticator.java create mode 100644 org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseProxySelector.java diff --git a/org.spearce.egit.ui/META-INF/MANIFEST.MF b/org.spearce.egit.ui/META-INF/MANIFEST.MF index 56010b7c..62afd51e 100644 --- a/org.spearce.egit.ui/META-INF/MANIFEST.MF +++ b/org.spearce.egit.ui/META-INF/MANIFEST.MF @@ -9,6 +9,7 @@ Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime, org.eclipse.core.resources, org.eclipse.core.filesystem, + org.eclipse.core.net, org.eclipse.ui, org.eclipse.team.core, org.eclipse.team.ui, diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java index 259a9f40..2a863c1d 100644 --- a/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/Activator.java @@ -16,6 +16,10 @@ */ package org.spearce.egit.ui; +import java.net.Authenticator; +import java.net.ProxySelector; + +import org.eclipse.core.net.proxy.IProxyService; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; @@ -143,6 +147,7 @@ public class Activator extends AbstractUIPlugin { super.start(context); traceVerbose = isOptionSet("/trace/verbose"); setupSSH(context); + setupProxy(context); } private void setupSSH(final BundleContext context) { @@ -155,6 +160,18 @@ public class Activator extends AbstractUIPlugin { } } + private void setupProxy(final BundleContext context) { + final ServiceReference proxy; + + proxy = context.getServiceReference(IProxyService.class.getName()); + if (proxy != null) { + ProxySelector.setDefault(new EclipseProxySelector( + (IProxyService) context.getService(proxy))); + Authenticator.setDefault(new EclipseAuthenticator( + (IProxyService) context.getService(proxy))); + } + } + public void stop(final BundleContext context) throws Exception { super.stop(context); plugin = null; diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseAuthenticator.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseAuthenticator.java new file mode 100644 index 00000000..970ae6d3 --- /dev/null +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseAuthenticator.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2008 Shawn Pearce + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ +package org.spearce.egit.ui; + +import java.net.Authenticator; +import java.net.InetAddress; +import java.net.PasswordAuthentication; +import java.net.UnknownHostException; + +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.net.proxy.IProxyService; + +class EclipseAuthenticator extends Authenticator { + private final IProxyService service; + + EclipseAuthenticator(final IProxyService s) { + service = s; + } + + @Override + protected PasswordAuthentication getPasswordAuthentication() { + final IProxyData[] data = service.getProxyData(); + if (data == null) + return null; + for (final IProxyData d : data) { + if (d.getUserId() == null || d.getHost() == null) + continue; + if (d.getPort() == getRequestingPort() && hostMatches(d)) + return auth(d); + } + return null; + } + + private PasswordAuthentication auth(final IProxyData d) { + final String user = d.getUserId(); + final String pass = d.getPassword(); + final char[] passChar = pass != null ? pass.toCharArray() : new char[0]; + return new PasswordAuthentication(user, passChar); + } + + private boolean hostMatches(final IProxyData d) { + try { + final InetAddress dHost = InetAddress.getByName(d.getHost()); + InetAddress rHost = getRequestingSite(); + if (rHost == null) + rHost = InetAddress.getByName(getRequestingHost()); + return dHost.equals(rHost); + } catch (UnknownHostException err) { + return false; + } + } +} diff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseProxySelector.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseProxySelector.java new file mode 100644 index 00000000..1878aed5 --- /dev/null +++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/EclipseProxySelector.java @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2008 Shawn Pearce + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License, version 2.1, as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 + */ +package org.spearce.egit.ui; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.SocketAddress; +import java.net.URI; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.net.proxy.IProxyData; +import org.eclipse.core.net.proxy.IProxyService; + +class EclipseProxySelector extends ProxySelector { + private final IProxyService service; + + EclipseProxySelector(final IProxyService s) { + service = s; + } + + @Override + public List select(final URI uri) { + final ArrayList r = new ArrayList(); + final String host = uri.getHost(); + + String type = IProxyData.SOCKS_PROXY_TYPE; + if ("http".equals(uri.getScheme())) + type = IProxyData.HTTP_PROXY_TYPE; + else if ("ftp".equals(uri.getScheme())) + type = IProxyData.HTTP_PROXY_TYPE; + else if ("https".equals(uri.getScheme())) + type = IProxyData.HTTPS_PROXY_TYPE; + + final IProxyData data = service.getProxyDataForHost(host, type); + if (data != null) { + if (IProxyData.HTTP_PROXY_TYPE.equals(data.getType())) + addProxy(r, Proxy.Type.HTTP, data); + else if (IProxyData.HTTPS_PROXY_TYPE.equals(data.getType())) + addProxy(r, Proxy.Type.HTTP, data); + else if (IProxyData.SOCKS_PROXY_TYPE.equals(data.getType())) + addProxy(r, Proxy.Type.SOCKS, data); + } + if (r.isEmpty()) + r.add(Proxy.NO_PROXY); + return r; + } + + private void addProxy(final ArrayList r, final Proxy.Type type, + final IProxyData d) { + try { + r.add(new Proxy(type, new InetSocketAddress(InetAddress.getByName(d + .getHost()), d.getPort()))); + } catch (UnknownHostException uhe) { + // Oh well. + } + } + + @Override + public void connectFailed(URI uri, SocketAddress sa, IOException ioe) { + // Don't tell Eclipse. + } +} diff --git a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java index 597611dd..7b54300b 100644 --- a/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java +++ b/org.spearce.jgit/src/org/spearce/jgit/transport/TransportHttp.java @@ -22,6 +22,9 @@ import java.io.IOException; import java.io.InputStream; import java.net.ConnectException; import java.net.MalformedURLException; +import java.net.Proxy; +import java.net.ProxySelector; +import java.net.URISyntaxException; import java.net.URL; import java.net.URLConnection; import java.util.ArrayList; @@ -57,6 +60,8 @@ class TransportHttp extends WalkTransport { private final URL objectsUrl; + private final ProxySelector proxySelector; + TransportHttp(final Repository local, final URIish uri) throws NotSupportedException { super(local, uri); @@ -69,6 +74,7 @@ class TransportHttp extends WalkTransport { } catch (MalformedURLException e) { throw new NotSupportedException("Invalid URL " + uri, e); } + proxySelector = ProxySelector.getDefault(); } @Override @@ -79,7 +85,11 @@ class TransportHttp extends WalkTransport { return r; } - static class HttpObjectDB extends WalkRemoteObjectDatabase { + Proxy proxyFor(final URL u) throws URISyntaxException { + return proxySelector.select(u.toURI()).get(0); + } + + class HttpObjectDB extends WalkRemoteObjectDatabase { private static final String INFO_REFS = "../info/refs"; private final URL objectsUrl; @@ -139,7 +149,7 @@ class TransportHttp extends WalkTransport { final URL base = objectsUrl; try { final URL u = new URL(base, path); - final URLConnection c = u.openConnection(); + final URLConnection c = u.openConnection(proxyFor(u)); final InputStream in = c.getInputStream(); final int len = c.getContentLength(); return new FileStream(in, len); @@ -149,6 +159,11 @@ class TransportHttp extends WalkTransport { if ("Connection timed out: connect".equals(ce.getMessage())) throw new ConnectException("Connection timed out: " + base); throw new ConnectException(ce.getMessage() + " " + base); + } catch (URISyntaxException e) { + final ConnectException err; + err = new ConnectException("Cannot determine proxy for " + base); + err.initCause(e); + throw err; } } -- 2.11.4.GIT