]> source.dussan.org Git - jgit.git/commitdiff
Add an implementation for HttpConnection using Apache HttpClient 91/22091/3
authorChristian Halstrick <christian.halstrick@sap.com>
Sun, 4 Aug 2013 21:37:50 +0000 (23:37 +0200)
committerChristian Halstrick <christian.halstrick@sap.com>
Tue, 18 Feb 2014 20:04:17 +0000 (21:04 +0100)
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:
org.eclipse.jgit.http.test/META-INF/MANIFEST.MF
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
org.eclipse.jgit.junit.http/META-INF/MANIFEST.MF
org.eclipse.jgit.packaging/org.eclipse.jgit.feature/feature.xml
org.eclipse.jgit.packaging/org.eclipse.jgit.junit.feature/feature.xml
org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.3.target
org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.4.target
org.eclipse.jgit/META-INF/MANIFEST.MF
org.eclipse.jgit/pom.xml
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/http/HttpConnection.java
org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnection.java [new file with mode: 0644]
org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/HttpClientConnectionFactory.java [new file with mode: 0644]
org.eclipse.jgit/src/org/eclipse/jgit/transport/http/apache/TemporaryBufferEntity.java [new file with mode: 0644]
pom.xml

index ce69bfb58c5e9dbdb624e7c0d7f2a36d208b12f1..4bc2e74593d806cc702939aa44f8fa551de965bb 100644 (file)
@@ -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)"
index 1726dc5eb90da24f08d608e4a491db8f334e709b..dec9b59f2dddd1b300f9b90c0bea12b92d4024a9 100644 (file)
@@ -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();
index 354b0439abbb17751f6008106967a202efe0ef46..7b4270f1b81d12a60cf03fcfc4c702460940c8d9 100644 (file)
@@ -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();
index 7b3c717afd0a3f08ee4d0a96dbbbe980836bd1c3..bb612b1a6859716bb0c194036c64b4e5948b0d55 100644 (file)
@@ -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();
index 0991fb61d5490421381edb752c47ca2b9698d8b1..61058ed14373010e03c314d9b934ab6ac2440e77 100644 (file)
@@ -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)",
index 4ca26292205b6cf36aa02e4dc67bc876f0238f72..443fffe07c318922a8590004a823bda3dbb9f675 100644 (file)
          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>
index d23e4d72d5bbd7dc5b573c4e6bcc734ba099b417..6877a5f24ff598ee172f4ee501eac6f06e790ab0 100644 (file)
          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>
index 7e1673b50cf083e421c2c8e7f55fd604984e1990..9bf94ccc8a2d689cc7422492ca1c8dd1b066c192 100644 (file)
       <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"/>
index dabfae0ddd2cdad6ff1692822402218757ec24c3..a99cfd64f2ff8bafa2090922fecc010c73ed8232 100644 (file)
       <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"/>
index 2b05980510b949d429cca2df8f70c509356e1f87..1249b29c6a53d1fd4579ce7336c5123def1face9 100644 (file)
@@ -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
index f45c4f8a8b6dc95b96f86a665ba4e8687bb7a8d6..c3f681e9c68dfb2b62d23896c457751b8b0c485c 100644 (file)
       <groupId>com.googlecode.javaewah</groupId>
       <artifactId>JavaEWAH</artifactId>
     </dependency>
+
+    <dependency>
+      <groupId>org.apache.httpcomponents</groupId>
+      <artifactId>httpclient</artifactId>
+    </dependency>
   </dependencies>
 
   <build>
index bb67c127a797b55d6e723d87634f44920c5ca985..40b5c0b2d202c3bc6d83ce4e55138753f07dab6a 100644 (file)
@@ -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
index f9700a1ff41bd9ff692febbd9719b10af5d1ebe5..dcee707275e5e30e09790ac1e70188ebd3cbf11b 100644 (file)
@@ -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;
index 0cf12aaa2670b00efb647eed19d00aa86cfa16cc..09613fd7accbe1243f5bdf3f1a612f0498f4bfda 100644 (file)
@@ -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 (file)
index 0000000..16003df
--- /dev/null
@@ -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 (file)
index 0000000..fe1eef4
--- /dev/null
@@ -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 (file)
index 0000000..1ff168e
--- /dev/null
@@ -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);
+       }
+}
diff --git a/pom.xml b/pom.xml
index 84ac44814564689a7b07da29a604df5f652a275f..5d564d27ee11cc0bf2c7ef63e661bcfae5148575 100644 (file)
--- a/pom.xml
+++ b/pom.xml
     <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>
       <id>jgit-repository</id>
       <url>http://download.eclipse.org/jgit/maven</url>
     </repository>
+
   </repositories>
 
   <pluginRepositories>
         <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>