diff options
author | Christian Halstrick <christian.halstrick@sap.com> | 2013-08-04 23:37:50 +0200 |
---|---|---|
committer | Christian Halstrick <christian.halstrick@sap.com> | 2014-02-18 21:04:17 +0100 |
commit | 2290516ddb5a92ccc296df500aa5e9e30cbc240e (patch) | |
tree | 04397a7a84eddccdc7fed53e5aa47efbb7fa77c5 | |
parent | 38c4f35d8b911426e007716697b37d746740b788 (diff) | |
download | jgit-2290516ddb5a92ccc296df500aa5e9e30cbc240e.tar.gz jgit-2290516ddb5a92ccc296df500aa5e9e30cbc240e.zip |
Add an implementation for HttpConnection using Apache HttpClient
This change implements the http connection abstraction with the help of
org.apache.http.client.HttpClient. The default implementation used by
JGit is still the JDK HttpURLConnection. But now JGit users have the
possibility to switch completely to org.apache.httpclient. The reason
for this is that in certain (e.g. cloud) environments you are forced to
use the org.apache classes.
Change-Id: I0b357f23243ed13a014c79ba179fa327dfe318b2
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
18 files changed, 677 insertions, 1 deletions
diff --git a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF index ce69bfb58c..4bc2e74593 100644 --- a/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.http.test/META-INF/MANIFEST.MF @@ -35,7 +35,11 @@ Import-Package: javax.servlet;version="[2.5.0,3.0.0)", org.eclipse.jgit.revwalk;version="[3.3.0,3.4.0)", org.eclipse.jgit.storage.file;version="[3.3.0,3.4.0)", org.eclipse.jgit.transport;version="[3.3.0,3.4.0)", + org.eclipse.jgit.transport.http;version="[3.3.0,3.4.0)", + org.eclipse.jgit.transport.http.apache;version="[3.3.0,3.4.0)", org.eclipse.jgit.transport.resolver;version="[3.3.0,3.4.0)", org.eclipse.jgit.util;version="[3.3.0,3.4.0)", org.hamcrest.core;version="[1.1.0,2.0.0)", - org.junit;version="[4.0.0,5.0.0)" + org.junit;version="[4.0.0,5.0.0)", + org.junit.runner;version="[4.0.0,5.0.0)", + org.junit.runners;version="[4.0.0,5.0.0)" diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java index 1726dc5eb9..dec9b59f2d 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java @@ -55,6 +55,8 @@ import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.net.URI; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -76,9 +78,16 @@ import org.eclipse.jgit.transport.HttpTransport; import org.eclipse.jgit.transport.Transport; import org.eclipse.jgit.transport.TransportHttp; import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.http.HttpConnectionFactory; +import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory; +import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +@RunWith(Parameterized.class) public class DumbClientDumbServerTest extends HttpTestCase { private Repository remoteRepository; @@ -88,6 +97,18 @@ public class DumbClientDumbServerTest extends HttpTestCase { private RevCommit A, B; + @Parameters + public static Collection<Object[]> data() { + // run all tests with both connection factories we have + return Arrays.asList(new Object[][] { + { new JDKHttpConnectionFactory() }, + { new HttpClientConnectionFactory() } }); + } + + public DumbClientDumbServerTest(HttpConnectionFactory cf) { + HttpTransport.setConnectionFactory(cf); + } + @Before public void setUp() throws Exception { super.setUp(); diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java index 354b0439ab..7b4270f1b8 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java @@ -55,6 +55,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import java.util.List; import java.util.Map; @@ -79,11 +81,18 @@ import org.eclipse.jgit.transport.HttpTransport; import org.eclipse.jgit.transport.Transport; import org.eclipse.jgit.transport.TransportHttp; import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.http.HttpConnectionFactory; +import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory; +import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory; import org.eclipse.jgit.transport.resolver.RepositoryResolver; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +@RunWith(Parameterized.class) public class DumbClientSmartServerTest extends HttpTestCase { private Repository remoteRepository; @@ -93,6 +102,18 @@ public class DumbClientSmartServerTest extends HttpTestCase { private RevCommit A, B; + @Parameters + public static Collection<Object[]> data() { + // run all tests with both connection factories we have + return Arrays.asList(new Object[][] { + { new JDKHttpConnectionFactory() }, + { new HttpClientConnectionFactory() } }); + } + + public DumbClientSmartServerTest(HttpConnectionFactory cf) { + HttpTransport.setConnectionFactory(cf); + } + @Before public void setUp() throws Exception { super.setUp(); diff --git a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java index 7b3c717afd..bb612b1a68 100644 --- a/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java +++ b/org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java @@ -56,6 +56,8 @@ import static org.junit.Assert.fail; import java.io.IOException; import java.io.PrintWriter; import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -98,11 +100,18 @@ import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.Transport; import org.eclipse.jgit.transport.TransportHttp; import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.http.HttpConnectionFactory; +import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory; +import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory; import org.eclipse.jgit.transport.resolver.RepositoryResolver; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +@RunWith(Parameterized.class) public class SmartClientSmartServerTest extends HttpTestCase { private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding"; @@ -116,6 +125,18 @@ public class SmartClientSmartServerTest extends HttpTestCase { private RevCommit A, B; + @Parameters + public static Collection<Object[]> data() { + // run all tests with both connection factories we have + return Arrays.asList(new Object[][] { + { new JDKHttpConnectionFactory() }, + { new HttpClientConnectionFactory() } }); + } + + public SmartClientSmartServerTest(HttpConnectionFactory cf) { + HttpTransport.setConnectionFactory(cf); + } + @Before public void setUp() throws Exception { super.setUp(); diff --git a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF index 0991fb61d5..61058ed143 100644 --- a/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF @@ -9,6 +9,7 @@ Bundle-ActivationPolicy: lazy Bundle-RequiredExecutionEnvironment: J2SE-1.5 Import-Package: javax.servlet;version="[2.5.0,3.0.0)", javax.servlet.http;version="[2.5.0,3.0.0)", + org.apache.commons.logging;version="[1.1.1,2.0.0)", org.eclipse.jetty.http;version="[7.6.0,8.0.0)", org.eclipse.jetty.security;version="[7.6.0,8.0.0)", org.eclipse.jetty.security.authentication;version="[7.6.0,8.0.0)", diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml index 4ca2629220..443fffe07c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml @@ -57,4 +57,18 @@ version="0.0.0" unpack="false"/> + <plugin + id="org.apache.httpcomponents.httpcore" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + + <plugin + id="org.apache.httpcomponents.httpclient" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + </feature> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml index d23e4d72d5..6877a5f24f 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml @@ -47,4 +47,11 @@ version="0.0.0" unpack="false"/> + <plugin + id="org.apache.commons.logging" + download-size="0" + install-size="0" + version="0.0.0" + unpack="false"/> + </feature> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target index 7e1673b50c..9bf94ccc8a 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target @@ -35,6 +35,12 @@ <unit id="org.apache.ant" version="1.8.4.v201303080030"/> <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/> <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/> + <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/> + <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/> + <unit id="org.apache.httpcomponents.httpcore" version="4.1.4.v201203221030"/> + <unit id="org.apache.httpcomponents.httpcore.source" version="4.1.4.v201203221030"/> + <unit id="org.apache.httpcomponents.httpclient" version="4.1.3.v201209201135"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.1.3.v201209201135"/> <unit id="org.apache.log4j" version="1.2.15.v201012070815"/> <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/> <unit id="org.kohsuke.args4j" version="2.0.21.v201301150030"/> diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target index dabfae0ddd..a99cfd64f2 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target @@ -35,6 +35,12 @@ <unit id="org.apache.ant" version="1.9.2.v201307241445"/> <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/> <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/> + <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/> + <unit id="org.apache.commons.logging.source" version="1.1.1.v201101211721"/> + <unit id="org.apache.httpcomponents.httpcore" version="4.1.4.v201203221030"/> + <unit id="org.apache.httpcomponents.httpcore.source" version="4.1.4.v201203221030"/> + <unit id="org.apache.httpcomponents.httpclient" version="4.1.3.v201209201135"/> + <unit id="org.apache.httpcomponents.httpclient.source" version="4.1.3.v201209201135"/> <unit id="org.apache.log4j" version="1.2.15.v201012070815"/> <unit id="org.apache.log4j.source" version="1.2.15.v201012070815"/> <unit id="org.kohsuke.args4j" version="2.0.21.v201301150030"/> diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF index 2b05980510..1249b29c6a 100644 --- a/org.eclipse.jgit/META-INF/MANIFEST.MF +++ b/org.eclipse.jgit/META-INF/MANIFEST.MF @@ -109,6 +109,12 @@ Export-Package: org.eclipse.jgit.api;version="3.3.0"; org.eclipse.jgit.storage.pack", org.eclipse.jgit.transport.http;version="3.3.0"; uses:="javax.net.ssl", + org.eclipse.jgit.transport.http.apache;version="3.3.0"; + uses:="org.eclipse.jgit.transport.http, + javax.net.ssl, + org.apache.http.client, + org.apache.http.client.methods, + org.apache.http", org.eclipse.jgit.transport.resolver;version="3.3.0"; uses:="org.eclipse.jgit.lib,org.eclipse.jgit.transport", org.eclipse.jgit.treewalk;version="3.3.0"; @@ -128,5 +134,17 @@ Require-Bundle: com.jcraft.jsch;bundle-version="[0.1.37,0.2.0)" Import-Package: com.googlecode.javaewah;version="[0.7.9,0.8.0)", javax.crypto, javax.net.ssl, + org.apache.http;version="[4.1.0,5.0.0)", + org.apache.http.client;version="[4.1.0,5.0.0)", + org.apache.http.client.methods;version="[4.1.0,5.0.0)", + org.apache.http.client.params;version="[4.1.0,5.0.0)", + org.apache.http.conn;version="[4.1.0,5.0.0)", + org.apache.http.conn.params;version="[4.1.0,5.0.0)", + org.apache.http.conn.scheme;version="[4.1.0,5.0.0)", + org.apache.http.conn.ssl;version="[4.1.0,5.0.0)", + org.apache.http.entity;version="[4.1.0,5.0.0)", + org.apache.http.impl.client;version="[4.1.0,5.0.0)", + org.apache.http.impl.client.cache;version="[4.1.0,5.0.0)", + org.apache.http.params;version="[4.1.0,5.0.0)", org.xml.sax, org.xml.sax.helpers diff --git a/org.eclipse.jgit/pom.xml b/org.eclipse.jgit/pom.xml index f45c4f8a8b..c3f681e9c6 100644 --- a/org.eclipse.jgit/pom.xml +++ b/org.eclipse.jgit/pom.xml @@ -78,6 +78,11 @@ <groupId>com.googlecode.javaewah</groupId> <artifactId>JavaEWAH</artifactId> </dependency> + + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + </dependency> </dependencies> <build> diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties index bb67c127a7..40b5c0b2d2 100644 --- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties +++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties @@ -522,6 +522,7 @@ unexpectedOddResult=odd: {0} + {1} - {2} unexpectedRefReport={0}: unexpected ref report: {1} unexpectedReportLine=unexpected report line: {0} unexpectedReportLine2={0} unexpected report line: {1} +unexpectedSSLContextException=unexpected exception when searching for the TLS protocol unknownOrUnsupportedCommand=Unknown or unsupported command "{0}", only "{1}" is allowed. unknownDIRCVersion=Unknown DIRC version {0} unknownHost=unknown host diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java index f9700a1ff4..dcee707275 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java @@ -584,6 +584,7 @@ public class JGitText extends TranslationBundle { /***/ public String unexpectedRefReport; /***/ public String unexpectedReportLine; /***/ public String unexpectedReportLine2; + /***/ public String unexpectedSSLContextException; /***/ public String unknownOrUnsupportedCommand; /***/ public String unknownDIRCVersion; /***/ public String unknownHost; diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java index 0cf12aaa26..09613fd7ac 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java @@ -258,6 +258,7 @@ public interface HttpConnection { * @param random * the source of randomness for this generator or null. See * {@link SSLContext#init(KeyManager[], TrustManager[], SecureRandom)} + * * @throws NoSuchAlgorithmException * @throws KeyManagementException */ diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java new file mode 100644 index 0000000000..16003df1f9 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java @@ -0,0 +1,366 @@ +/* + * Copyright (C) 2013 Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport.http.apache; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.Proxy; +import java.net.URL; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.cert.X509Certificate; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.KeyManager; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManager; + +import org.apache.http.Header; +import org.apache.http.HeaderElement; +import org.apache.http.HttpEntity; +import org.apache.http.HttpEntityEnclosingRequest; +import org.apache.http.HttpHost; +import org.apache.http.HttpResponse; +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.client.params.ClientPNames; +import org.apache.http.conn.params.ConnRoutePNames; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.conn.ssl.X509HostnameVerifier; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.params.CoreConnectionPNames; +import org.apache.http.params.HttpParams; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.transport.http.HttpConnection; +import org.eclipse.jgit.util.TemporaryBuffer; +import org.eclipse.jgit.util.TemporaryBuffer.LocalFile; + +/** + * A {@link HttpConnection} which uses {@link HttpClient} + * + * @since 3.3 + */ +public class HttpClientConnection implements HttpConnection { + HttpClient client; + + String urlStr; + + HttpUriRequest req; + + HttpResponse resp = null; + + String method = "GET"; //$NON-NLS-1$ + + private TemporaryBufferEntity entity; + + private boolean isUsingProxy = false; + + private Proxy proxy; + + private Integer timeout = null; + + private Integer readTimeout; + + private Boolean followRedirects; + + private X509HostnameVerifier hostnameverifier; + + SSLContext ctx; + + private HttpClient getClient() { + if (client == null) + client = new DefaultHttpClient(); + HttpParams params = client.getParams(); + if (proxy != null && !Proxy.NO_PROXY.equals(proxy)) { + isUsingProxy = true; + InetSocketAddress adr = (InetSocketAddress) proxy.address(); + params.setParameter(ConnRoutePNames.DEFAULT_PROXY, + new HttpHost(adr.getHostName(), adr.getPort())); + } + if (timeout != null) + params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, + timeout.intValue()); + if (readTimeout != null) + params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, + readTimeout.intValue()); + if (followRedirects != null) + params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, + followRedirects.booleanValue()); + if (hostnameverifier != null) { + SSLSocketFactory sf; + sf = new SSLSocketFactory(getSSLContext(), hostnameverifier); + Scheme https = new Scheme("https", 443, sf); //$NON-NLS-1$ + client.getConnectionManager().getSchemeRegistry().register(https); + } + + return client; + } + + private SSLContext getSSLContext() { + if (ctx == null) { + try { + ctx = SSLContext.getInstance("TLS"); //$NON-NLS-1$ + } catch (NoSuchAlgorithmException e) { + throw new IllegalStateException( + JGitText.get().unexpectedSSLContextException, e); + } + } + return ctx; + } + + /** + * Sets the buffer from which to take the request body + * + * @param buffer + */ + public void setBuffer(TemporaryBuffer buffer) { + this.entity = new TemporaryBufferEntity(buffer); + } + + /** + * @param urlStr + */ + public HttpClientConnection(String urlStr) { + this(urlStr, null); + } + + /** + * @param urlStr + * @param proxy + */ + public HttpClientConnection(String urlStr, Proxy proxy) { + this(urlStr, proxy, null); + } + + /** + * @param urlStr + * @param proxy + * @param cl + */ + public HttpClientConnection(String urlStr, Proxy proxy, HttpClient cl) { + this.client = cl; + this.urlStr = urlStr; + this.proxy = proxy; + } + + public int getResponseCode() throws IOException { + execute(); + return resp.getStatusLine().getStatusCode(); + } + + public URL getURL() { + try { + return new URL(urlStr); + } catch (MalformedURLException e) { + return null; + } + } + + public String getResponseMessage() throws IOException { + execute(); + return resp.getStatusLine().getReasonPhrase(); + } + + private void execute() throws IOException, ClientProtocolException { + if (resp == null) + if (entity != null) { + if (req instanceof HttpEntityEnclosingRequest) { + HttpEntityEnclosingRequest eReq = (HttpEntityEnclosingRequest) req; + eReq.setEntity(entity); + } + resp = getClient().execute(req); + entity.getBuffer().close(); + entity = null; + } else + resp = getClient().execute(req); + } + + public Map<String, List<String>> getHeaderFields() { + Map<String, List<String>> ret = new HashMap<String, List<String>>(); + for (Header hdr : resp.getAllHeaders()) { + List<String> list = new LinkedList<String>(); + for (HeaderElement hdrElem : hdr.getElements()) + list.add(hdrElem.toString()); + ret.put(hdr.getName(), list); + } + return ret; + } + + public void setRequestProperty(String name, String value) { + req.addHeader(name, value); + } + + public void setRequestMethod(String method) throws ProtocolException { + this.method = method; + if ("GET".equalsIgnoreCase(method)) //$NON-NLS-1$ + req = new HttpGet(urlStr); + else if ("PUT".equalsIgnoreCase(method)) //$NON-NLS-1$ + req = new HttpPut(urlStr); + else if ("POST".equalsIgnoreCase(method)) //$NON-NLS-1$ + req = new HttpPost(urlStr); + else { + this.method = null; + throw new UnsupportedOperationException(); + } + } + + public void setUseCaches(boolean usecaches) { + // not needed + } + + public void setConnectTimeout(int timeout) { + this.timeout = new Integer(timeout); + } + + public void setReadTimeout(int readTimeout) { + this.readTimeout = new Integer(readTimeout); + } + + public String getContentType() { + HttpEntity responseEntity = resp.getEntity(); + if (responseEntity != null) { + Header contentType = responseEntity.getContentType(); + if (contentType != null) + return contentType.getValue(); + } + return null; + } + + public InputStream getInputStream() throws IOException { + return resp.getEntity().getContent(); + } + + // will return only the first field + public String getHeaderField(String name) { + Header header = resp.getFirstHeader(name); + return (header == null) ? null : header.getValue(); + } + + public int getContentLength() { + return Integer.parseInt(resp.getFirstHeader("content-length") //$NON-NLS-1$ + .getValue()); + } + + public void setInstanceFollowRedirects(boolean followRedirects) { + this.followRedirects = new Boolean(followRedirects); + } + + public void setDoOutput(boolean dooutput) { + // TODO: check whether we can really ignore this. + } + + public void setFixedLengthStreamingMode(int contentLength) { + if (entity != null) + throw new IllegalArgumentException(); + entity = new TemporaryBufferEntity(new LocalFile()); + entity.setContentLength(contentLength); + } + + public OutputStream getOutputStream() throws IOException { + if (entity == null) + entity = new TemporaryBufferEntity(new LocalFile()); + return entity.getBuffer(); + } + + public void setChunkedStreamingMode(int chunklen) { + if (entity == null) + entity = new TemporaryBufferEntity(new LocalFile()); + entity.setChunked(true); + } + + public String getRequestMethod() { + return method; + } + + public boolean usingProxy() { + return isUsingProxy; + } + + public void connect() throws IOException { + execute(); + } + + public void setHostnameVerifier(final HostnameVerifier hostnameverifier) { + this.hostnameverifier = new X509HostnameVerifier() { + public boolean verify(String hostname, SSLSession session) { + return hostnameverifier.verify(hostname, session); + } + + public void verify(String host, String[] cns, String[] subjectAlts) + throws SSLException { + throw new UnsupportedOperationException(); // TODO message + } + + public void verify(String host, X509Certificate cert) + throws SSLException { + throw new UnsupportedOperationException(); // TODO message + } + + public void verify(String host, SSLSocket ssl) throws IOException { + hostnameverifier.verify(host, ssl.getSession()); + } + }; + } + + public void configure(KeyManager[] km, TrustManager[] tm, + SecureRandom random) throws KeyManagementException { + getSSLContext().init(km, tm, random); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java new file mode 100644 index 0000000000..fe1eef484a --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2013 Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport.http.apache; + +import java.io.IOException; +import java.net.Proxy; +import java.net.URL; + +import org.eclipse.jgit.transport.http.HttpConnection; +import org.eclipse.jgit.transport.http.HttpConnectionFactory; + +/** + * A factory returning instances of {@link HttpClientConnection} + * + * @since 3.3 + */ +public class HttpClientConnectionFactory implements HttpConnectionFactory { + public HttpConnection create(URL url) throws IOException { + return new HttpClientConnection(url.toString()); + } + + public HttpConnection create(URL url, Proxy proxy) + throws IOException { + return new HttpClientConnection(url.toString(), proxy); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java new file mode 100644 index 0000000000..1ff168e237 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2014 Christian Halstrick <christian.halstrick@sap.com> + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.eclipse.jgit.transport.http.apache; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.apache.http.HttpEntity; +import org.apache.http.entity.AbstractHttpEntity; +import org.eclipse.jgit.util.TemporaryBuffer; + +/** + * A {@link HttpEntity} which takes it's content from a {@link TemporaryBuffer} + * + * @since 3.3 + */ +public class TemporaryBufferEntity extends AbstractHttpEntity { + private TemporaryBuffer buffer; + + private Integer contentLength; + + /** + * Construct a new {@link HttpEntity} which will contain the content stored + * in the specified buffer + * + * @param buffer + */ + public TemporaryBufferEntity(TemporaryBuffer buffer) { + this.buffer = buffer; + } + + /** + * @return buffer containing the content + */ + public TemporaryBuffer getBuffer() { + return buffer; + } + + public boolean isRepeatable() { + return true; + } + + public long getContentLength() { + if (contentLength != null) + return contentLength.intValue(); + return buffer.length(); + } + + public InputStream getContent() throws IOException, IllegalStateException { + return buffer.openInputStream(); + } + + public void writeTo(OutputStream outstream) throws IOException { + // TODO: dont we need a progressmonitor + buffer.writeTo(outstream, null); + } + + public boolean isStreaming() { + return false; + } + + /** + * @param contentLength + */ + public void setContentLength(int contentLength) { + this.contentLength = new Integer(contentLength); + } +} @@ -186,6 +186,7 @@ <servlet-api-version>2.5</servlet-api-version> <jetty-version>7.6.14.v20131031</jetty-version> <clirr-version>2.4</clirr-version> + <httpclient-version>4.1.3</httpclient-version> </properties> <repositories> @@ -193,6 +194,7 @@ <id>jgit-repository</id> <url>http://download.eclipse.org/jgit/maven</url> </repository> + </repositories> <pluginRepositories> @@ -474,6 +476,12 @@ <artifactId>org.osgi.core</artifactId> <version>${osgi-core-version}</version> </dependency> + + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>${httpclient-version}</version> + </dependency> </dependencies> </dependencyManagement> |