This reverts commit f802f06e7f
.
I had misunderstood how protocol V2 works. This implementation only
works if the negotiation during fetch is done in one round.
Fixing this is substantial work in BasePackFetchConnection. Basically
I think I'd have to change back negotiate to the V0 version, and have
a doFetch() that does
if protocol V2
doFetchV2()
else
doFetchV0()
with doFetchV0 the old code, and doFetchV2 completely new.
Plus there would need to be a HTTP test case requiring several
negotiation rounds.
This is a couple of days work at least, and I don't know when I will
have the time to revisit this. So although the rest of the code is
fine I prefer to back this out completely and not leave a only half
working implementation in the code for an indeterminate time.
Bug: 553083
Change-Id: Icbbbb09882b3b83f9897deac4a06d5f8dc99d84e
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
tags/v5.10.0.202011041322-m2
@@ -1,99 +0,0 @@ | |||
/* | |||
* Copyright (C) 2020, Thomas Wolf <thomas.wolf@paranor.ch> and others | |||
* | |||
* This program and the accompanying materials are made available under the | |||
* terms of the Eclipse Distribution License v. 1.0 which is available at | |||
* https://www.eclipse.org/org/documents/edl-v10.php. | |||
* | |||
* SPDX-License-Identifier: BSD-3-Clause | |||
*/ | |||
package org.eclipse.jgit.http.test; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.List; | |||
import org.eclipse.jgit.junit.http.HttpTestCase; | |||
import org.eclipse.jgit.transport.HttpTransport; | |||
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.AfterClass; | |||
import org.junit.BeforeClass; | |||
import org.junit.Ignore; | |||
import org.junit.runner.RunWith; | |||
import org.junit.runners.Parameterized; | |||
import org.junit.runners.Parameterized.Parameters; | |||
/** | |||
* Abstract test base class for running HTTP-related tests with all connection | |||
* factories provided in JGit and with both protocol V0 and V2. | |||
*/ | |||
@Ignore | |||
@RunWith(Parameterized.class) | |||
public abstract class AllProtocolsHttpTestCase extends HttpTestCase { | |||
protected static class TestParameters { | |||
public final HttpConnectionFactory factory; | |||
public final boolean enableProtocolV2; | |||
public TestParameters(HttpConnectionFactory factory, | |||
boolean enableProtocolV2) { | |||
this.factory = factory; | |||
this.enableProtocolV2 = enableProtocolV2; | |||
} | |||
@Override | |||
public String toString() { | |||
return factory.toString() + " protocol " | |||
+ (enableProtocolV2 ? "V2" : "V0"); | |||
} | |||
} | |||
@Parameters(name = "{0}") | |||
public static Collection<TestParameters> data() { | |||
// run all tests with both connection factories we have | |||
HttpConnectionFactory[] factories = new HttpConnectionFactory[] { | |||
new JDKHttpConnectionFactory() { | |||
@Override | |||
public String toString() { | |||
return this.getClass().getSuperclass().getName(); | |||
} | |||
}, new HttpClientConnectionFactory() { | |||
@Override | |||
public String toString() { | |||
return this.getClass().getSuperclass().getName(); | |||
} | |||
} }; | |||
List<TestParameters> result = new ArrayList<>(); | |||
for (HttpConnectionFactory factory : factories) { | |||
result.add(new TestParameters(factory, false)); | |||
result.add(new TestParameters(factory, true)); | |||
} | |||
return result; | |||
} | |||
protected final boolean enableProtocolV2; | |||
protected AllProtocolsHttpTestCase(TestParameters params) { | |||
HttpTransport.setConnectionFactory(params.factory); | |||
enableProtocolV2 = params.enableProtocolV2; | |||
} | |||
private static HttpConnectionFactory originalFactory; | |||
@BeforeClass | |||
public static void saveConnectionFactory() { | |||
originalFactory = HttpTransport.getConnectionFactory(); | |||
} | |||
@AfterClass | |||
public static void restoreConnectionFactory() { | |||
HttpTransport.setConnectionFactory(originalFactory); | |||
} | |||
} |
@@ -42,10 +42,11 @@ 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.junit.Before; | |||
import org.junit.Test; | |||
public class DumbClientDumbServerTest extends AllProtocolsHttpTestCase { | |||
public class DumbClientDumbServerTest extends AllFactoriesHttpTestCase { | |||
private Repository remoteRepository; | |||
private URIish remoteURI; | |||
@@ -54,8 +55,8 @@ public class DumbClientDumbServerTest extends AllProtocolsHttpTestCase { | |||
private RevCommit A, B; | |||
public DumbClientDumbServerTest(TestParameters params) { | |||
super(params); | |||
public DumbClientDumbServerTest(HttpConnectionFactory cf) { | |||
super(cf); | |||
} | |||
@Override | |||
@@ -76,9 +77,6 @@ public class DumbClientDumbServerTest extends AllProtocolsHttpTestCase { | |||
remoteRepository = src.getRepository(); | |||
remoteURI = toURIish(app, srcGit.getName()); | |||
if (enableProtocolV2) { | |||
remoteRepository.getConfig().setInt("protocol", null, "version", 2); | |||
} | |||
A_txt = src.blob("A"); | |||
A = src.commit().add("A_txt", A_txt).create(); |
@@ -42,10 +42,11 @@ 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.junit.Before; | |||
import org.junit.Test; | |||
public class DumbClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
public class DumbClientSmartServerTest extends AllFactoriesHttpTestCase { | |||
private Repository remoteRepository; | |||
private URIish remoteURI; | |||
@@ -54,8 +55,8 @@ public class DumbClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
private RevCommit A, B; | |||
public DumbClientSmartServerTest(TestParameters params) { | |||
super(params); | |||
public DumbClientSmartServerTest(HttpConnectionFactory cf) { | |||
super(cf); | |||
} | |||
@Override | |||
@@ -75,9 +76,6 @@ public class DumbClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
remoteRepository = src.getRepository(); | |||
remoteURI = toURIish(app, srcName); | |||
if (enableProtocolV2) { | |||
remoteRepository.getConfig().setInt("protocol", null, "version", 2); | |||
} | |||
A_txt = src.blob("A"); | |||
A = src.commit().add("A_txt", A_txt).create(); |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2017, 2020 Thomas Wolf <thomas.wolf@paranor.ch> and others | |||
* Copyright (C) 2017 Thomas Wolf <thomas.wolf@paranor.ch> and others | |||
* | |||
* This program and the accompanying materials are made available under the | |||
* terms of the Eclipse Distribution License v. 1.0 which is available at | |||
@@ -48,6 +48,7 @@ import org.eclipse.jgit.transport.CredentialsProvider; | |||
import org.eclipse.jgit.transport.Transport; | |||
import org.eclipse.jgit.transport.URIish; | |||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; | |||
import org.eclipse.jgit.transport.http.HttpConnectionFactory; | |||
import org.eclipse.jgit.util.HttpSupport; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
@@ -55,7 +56,7 @@ import org.junit.runner.RunWith; | |||
import org.junit.runners.Parameterized; | |||
@RunWith(Parameterized.class) | |||
public class SmartClientSmartServerSslTest extends AllProtocolsHttpTestCase { | |||
public class SmartClientSmartServerSslTest extends AllFactoriesHttpTestCase { | |||
// We run these tests with a server on localhost with a self-signed | |||
// certificate. We don't do authentication tests here, so there's no need | |||
@@ -111,8 +112,8 @@ public class SmartClientSmartServerSslTest extends AllProtocolsHttpTestCase { | |||
private RevCommit A, B; | |||
public SmartClientSmartServerSslTest(TestParameters params) { | |||
super(params); | |||
public SmartClientSmartServerSslTest(HttpConnectionFactory cf) { | |||
super(cf); | |||
} | |||
@Override | |||
@@ -131,10 +132,6 @@ public class SmartClientSmartServerSslTest extends AllProtocolsHttpTestCase { | |||
.getConfig() | |||
.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true); | |||
if (enableProtocolV2) { | |||
src.getRepository().getConfig().setInt("protocol", null, "version", | |||
2); | |||
} | |||
GitServlet gs = new GitServlet(); | |||
@@ -241,7 +238,7 @@ public class SmartClientSmartServerSslTest extends AllProtocolsHttpTestCase { | |||
fsck(dst, B); | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 3 : 2, requests.size()); | |||
assertEquals(2, requests.size()); | |||
} | |||
@Test | |||
@@ -259,7 +256,7 @@ public class SmartClientSmartServerSslTest extends AllProtocolsHttpTestCase { | |||
fsck(dst, B); | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); | |||
assertEquals(3, requests.size()); | |||
} | |||
@Test |
@@ -1,5 +1,5 @@ | |||
/* | |||
* Copyright (C) 2010, 2020 Google Inc. and others | |||
* Copyright (C) 2010, 2017 Google Inc. and others | |||
* | |||
* This program and the accompanying materials are made available under the | |||
* terms of the Eclipse Distribution License v. 1.0 which is available at | |||
@@ -86,12 +86,13 @@ import org.eclipse.jgit.transport.TransportHttp; | |||
import org.eclipse.jgit.transport.URIish; | |||
import org.eclipse.jgit.transport.UploadPack; | |||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider; | |||
import org.eclipse.jgit.transport.http.HttpConnectionFactory; | |||
import org.eclipse.jgit.util.HttpSupport; | |||
import org.eclipse.jgit.util.SystemReader; | |||
import org.junit.Before; | |||
import org.junit.Test; | |||
public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
public class SmartClientSmartServerTest extends AllFactoriesHttpTestCase { | |||
private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding"; | |||
private AdvertiseRefsHook advertiseRefsHook; | |||
@@ -119,8 +120,8 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
private RevCommit A, B, unreachableCommit; | |||
public SmartClientSmartServerTest(TestParameters params) { | |||
super(params); | |||
public SmartClientSmartServerTest(HttpConnectionFactory cf) { | |||
super(cf); | |||
} | |||
@Override | |||
@@ -131,12 +132,9 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
final TestRepository<Repository> src = createTestRepository(); | |||
final String srcName = src.getRepository().getDirectory().getName(); | |||
src.getRepository() | |||
.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, | |||
null, ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, | |||
true); | |||
if (enableProtocolV2) { | |||
src.getRepository().getConfig().setInt("protocol", null, "version", 2); | |||
} | |||
.getConfig() | |||
.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, | |||
ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true); | |||
GitServlet gs = new GitServlet(); | |||
gs.setUploadPackFactory((HttpServletRequest req, Repository db) -> { | |||
@@ -450,7 +448,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(B, map.get(Constants.HEAD).getObjectId()); | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 2 : 1, requests.size()); | |||
assertEquals(1, requests.size()); | |||
AccessEvent info = requests.get(0); | |||
assertEquals("GET", info.getMethod()); | |||
@@ -460,22 +458,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(200, info.getStatus()); | |||
assertEquals("application/x-git-upload-pack-advertisement", info | |||
.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (!enableProtocolV2) { | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} else { | |||
AccessEvent lsRefs = requests.get(1); | |||
assertEquals("POST", lsRefs.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath()); | |||
assertEquals(0, lsRefs.getParameters().size()); | |||
assertNotNull("has content-length", | |||
lsRefs.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol")); | |||
assertEquals(200, lsRefs.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
lsRefs.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} | |||
@Test | |||
@@ -593,10 +576,9 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 3 : 2, requests.size()); | |||
assertEquals(2, requests.size()); | |||
int requestNumber = 0; | |||
AccessEvent info = requests.get(requestNumber++); | |||
AccessEvent info = requests.get(0); | |||
assertEquals("GET", info.getMethod()); | |||
assertEquals(join(remoteURI, "info/refs"), info.getPath()); | |||
assertEquals(1, info.getParameters().size()); | |||
@@ -604,24 +586,9 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(200, info.getStatus()); | |||
assertEquals("application/x-git-upload-pack-advertisement", info | |||
.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (!enableProtocolV2) { | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} else { | |||
AccessEvent lsRefs = requests.get(requestNumber++); | |||
assertEquals("POST", lsRefs.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath()); | |||
assertEquals(0, lsRefs.getParameters().size()); | |||
assertNotNull("has content-length", | |||
lsRefs.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol")); | |||
assertEquals(200, lsRefs.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
lsRefs.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
AccessEvent service = requests.get(requestNumber); | |||
AccessEvent service = requests.get(1); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
@@ -661,8 +628,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals((enableProtocolV2 ? 3 : 2) + nofRedirects, | |||
requests.size()); | |||
assertEquals(2 + nofRedirects, requests.size()); | |||
int n = 0; | |||
while (n < nofRedirects) { | |||
@@ -678,22 +644,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(200, info.getStatus()); | |||
assertEquals("application/x-git-upload-pack-advertisement", | |||
info.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (!enableProtocolV2) { | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} else { | |||
AccessEvent lsRefs = requests.get(n++); | |||
assertEquals("POST", lsRefs.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath()); | |||
assertEquals(0, lsRefs.getParameters().size()); | |||
assertNotNull("has content-length", | |||
lsRefs.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol")); | |||
assertEquals(200, lsRefs.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
lsRefs.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
AccessEvent service = requests.get(n++); | |||
assertEquals("POST", service.getMethod()); | |||
@@ -805,7 +756,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); | |||
assertEquals(3, requests.size()); | |||
AccessEvent info = requests.get(0); | |||
assertEquals("GET", info.getMethod()); | |||
@@ -815,27 +766,24 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(200, info.getStatus()); | |||
assertEquals("application/x-git-upload-pack-advertisement", | |||
info.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (!enableProtocolV2) { | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
AccessEvent redirect = requests.get(1); | |||
assertEquals("POST", redirect.getMethod()); | |||
assertEquals(301, redirect.getStatus()); | |||
for (int i = 2; i < requests.size(); i++) { | |||
AccessEvent service = requests.get(i); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
assertNotNull("has content-length", | |||
service.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
service.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals(200, service.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
service.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
AccessEvent service = requests.get(2); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
assertNotNull("has content-length", | |||
service.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
service.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals(200, service.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
service.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
@Test | |||
@@ -882,7 +830,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); | |||
assertEquals(3, requests.size()); | |||
AccessEvent info = requests.get(0); | |||
assertEquals("GET", info.getMethod()); | |||
@@ -896,24 +844,20 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(200, info.getStatus()); | |||
assertEquals("application/x-git-upload-pack-advertisement", | |||
info.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (!enableProtocolV2) { | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
for (int i = 2; i < requests.size(); i++) { | |||
AccessEvent service = requests.get(i); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(authURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
assertNotNull("has content-length", | |||
service.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
service.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals(200, service.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
service.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
AccessEvent service = requests.get(2); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(authURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
assertNotNull("has content-length", | |||
service.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
service.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals(200, service.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
service.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
@Test | |||
@@ -993,20 +937,19 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 5 : 4, requests.size()); | |||
assertEquals(4, requests.size()); | |||
int requestNumber = 0; | |||
AccessEvent redirect = requests.get(requestNumber++); | |||
AccessEvent redirect = requests.get(0); | |||
assertEquals("GET", redirect.getMethod()); | |||
assertEquals(join(cloneFrom, "info/refs"), redirect.getPath()); | |||
assertEquals(301, redirect.getStatus()); | |||
AccessEvent info = requests.get(requestNumber++); | |||
AccessEvent info = requests.get(1); | |||
assertEquals("GET", info.getMethod()); | |||
assertEquals(join(authURI, "info/refs"), info.getPath()); | |||
assertEquals(401, info.getStatus()); | |||
info = requests.get(requestNumber++); | |||
info = requests.get(2); | |||
assertEquals("GET", info.getMethod()); | |||
assertEquals(join(authURI, "info/refs"), info.getPath()); | |||
assertEquals(1, info.getParameters().size()); | |||
@@ -1014,24 +957,9 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(200, info.getStatus()); | |||
assertEquals("application/x-git-upload-pack-advertisement", | |||
info.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (!enableProtocolV2) { | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} else { | |||
AccessEvent lsRefs = requests.get(requestNumber++); | |||
assertEquals("POST", lsRefs.getMethod()); | |||
assertEquals(join(authURI, "git-upload-pack"), lsRefs.getPath()); | |||
assertEquals(0, lsRefs.getParameters().size()); | |||
assertNotNull("has content-length", | |||
lsRefs.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol")); | |||
assertEquals(200, lsRefs.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
lsRefs.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
AccessEvent service = requests.get(requestNumber); | |||
AccessEvent service = requests.get(3); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(authURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
@@ -1059,7 +987,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
} | |||
List<AccessEvent> requests = getRequests(); | |||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); | |||
assertEquals(3, requests.size()); | |||
AccessEvent info = requests.get(0); | |||
assertEquals("GET", info.getMethod()); | |||
@@ -1069,30 +997,25 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals(200, info.getStatus()); | |||
assertEquals("application/x-git-upload-pack-advertisement", | |||
info.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (!enableProtocolV2) { | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
} | |||
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING)); | |||
AccessEvent service = requests.get(1); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(401, service.getStatus()); | |||
for (int i = 2; i < requests.size(); i++) { | |||
service = requests.get(i); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(authOnPostURI, "git-upload-pack"), | |||
service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
assertNotNull("has content-length", | |||
service.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
service.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals(200, service.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
service.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
service = requests.get(2); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
assertNotNull("has content-length", | |||
service.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
service.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals(200, service.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
service.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
@Test | |||
@@ -1129,11 +1052,9 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
List<AccessEvent> requests = getRequests(); | |||
requests.removeAll(cloneRequests); | |||
assertEquals(2, requests.size()); | |||
assertEquals(enableProtocolV2 ? 3 : 2, requests.size()); | |||
int requestNumber = 0; | |||
AccessEvent info = requests.get(requestNumber++); | |||
AccessEvent info = requests.get(0); | |||
assertEquals("GET", info.getMethod()); | |||
assertEquals(join(remoteURI, "info/refs"), info.getPath()); | |||
assertEquals(1, info.getParameters().size()); | |||
@@ -1142,24 +1063,9 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals("application/x-git-upload-pack-advertisement", | |||
info.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (enableProtocolV2) { | |||
AccessEvent lsRefs = requests.get(requestNumber++); | |||
assertEquals("POST", lsRefs.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath()); | |||
assertEquals(0, lsRefs.getParameters().size()); | |||
assertNotNull("has content-length", | |||
lsRefs.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol")); | |||
assertEquals(200, lsRefs.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
lsRefs.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
// We should have needed one request to perform the fetch. | |||
// | |||
AccessEvent service = requests.get(requestNumber); | |||
AccessEvent service = requests.get(1); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
@@ -1210,10 +1116,9 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
List<AccessEvent> requests = getRequests(); | |||
requests.removeAll(cloneRequests); | |||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size()); | |||
assertEquals(3, requests.size()); | |||
int requestNumber = 0; | |||
AccessEvent info = requests.get(requestNumber++); | |||
AccessEvent info = requests.get(0); | |||
assertEquals("GET", info.getMethod()); | |||
assertEquals(join(remoteURI, "info/refs"), info.getPath()); | |||
assertEquals(1, info.getParameters().size()); | |||
@@ -1222,25 +1127,10 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals("application/x-git-upload-pack-advertisement", info | |||
.getResponseHeader(HDR_CONTENT_TYPE)); | |||
if (enableProtocolV2) { | |||
AccessEvent lsRefs = requests.get(requestNumber++); | |||
assertEquals("POST", lsRefs.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath()); | |||
assertEquals(0, lsRefs.getParameters().size()); | |||
assertNotNull("has content-length", | |||
lsRefs.getRequestHeader(HDR_CONTENT_LENGTH)); | |||
assertNull("not chunked", | |||
lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING)); | |||
assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol")); | |||
assertEquals(200, lsRefs.getStatus()); | |||
assertEquals("application/x-git-upload-pack-result", | |||
lsRefs.getResponseHeader(HDR_CONTENT_TYPE)); | |||
} | |||
// We should have needed two requests to perform the fetch | |||
// due to the high number of local unknown commits. | |||
// | |||
AccessEvent service = requests.get(requestNumber++); | |||
AccessEvent service = requests.get(1); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
@@ -1253,7 +1143,7 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
assertEquals("application/x-git-upload-pack-result", service | |||
.getResponseHeader(HDR_CONTENT_TYPE)); | |||
service = requests.get(requestNumber); | |||
service = requests.get(2); | |||
assertEquals("POST", service.getMethod()); | |||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath()); | |||
assertEquals(0, service.getParameters().size()); | |||
@@ -1539,4 +1429,5 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase { | |||
cfg.setBoolean("http", null, "receivepack", true); | |||
cfg.save(); | |||
} | |||
} |
@@ -1,24 +0,0 @@ | |||
/* | |||
* Copyright (C) 2020 Thomas Wolf <thomas.wolf@paranor.ch> and others | |||
* | |||
* This program and the accompanying materials are made available under the | |||
* terms of the Eclipse Distribution License v. 1.0 which is available at | |||
* https://www.eclipse.org/org/documents/edl-v10.php. | |||
* | |||
* SPDX-License-Identifier: BSD-3-Clause | |||
*/ | |||
package org.eclipse.jgit.transport.sshd; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.lib.StoredConfig; | |||
public class ApacheSshProtocol2Test extends ApacheSshTest { | |||
@Override | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
StoredConfig config = ((Repository) db).getConfig(); | |||
config.setInt("protocol", null, "version", 2); | |||
config.save(); | |||
} | |||
} |
@@ -24,7 +24,6 @@ import java.util.Collections; | |||
import java.util.EnumSet; | |||
import java.util.LinkedList; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.concurrent.CopyOnWriteArrayList; | |||
import java.util.concurrent.TimeUnit; | |||
import java.util.concurrent.atomic.AtomicReference; | |||
@@ -54,7 +53,7 @@ import org.eclipse.jgit.errors.TransportException; | |||
import org.eclipse.jgit.internal.transport.sshd.JGitSshClient; | |||
import org.eclipse.jgit.internal.transport.sshd.SshdText; | |||
import org.eclipse.jgit.transport.FtpChannel; | |||
import org.eclipse.jgit.transport.RemoteSession2; | |||
import org.eclipse.jgit.transport.RemoteSession; | |||
import org.eclipse.jgit.transport.SshConstants; | |||
import org.eclipse.jgit.transport.URIish; | |||
import org.eclipse.jgit.util.StringUtils; | |||
@@ -62,12 +61,11 @@ import org.slf4j.Logger; | |||
import org.slf4j.LoggerFactory; | |||
/** | |||
* An implementation of {@link org.eclipse.jgit.transport.RemoteSession | |||
* RemoteSession} based on Apache MINA sshd. | |||
* An implementation of {@link RemoteSession} based on Apache MINA sshd. | |||
* | |||
* @since 5.2 | |||
*/ | |||
public class SshdSession implements RemoteSession2 { | |||
public class SshdSession implements RemoteSession { | |||
private static final Logger LOG = LoggerFactory | |||
.getLogger(SshdSession.class); | |||
@@ -292,15 +290,8 @@ public class SshdSession implements RemoteSession2 { | |||
@Override | |||
public Process exec(String commandName, int timeout) throws IOException { | |||
return exec(commandName, Collections.emptyMap(), timeout); | |||
} | |||
@Override | |||
public Process exec(String commandName, Map<String, String> environment, | |||
int timeout) throws IOException { | |||
@SuppressWarnings("resource") | |||
ChannelExec exec = session.createExecChannel(commandName, null, | |||
environment); | |||
ChannelExec exec = session.createExecChannel(commandName); | |||
if (timeout <= 0) { | |||
try { | |||
exec.open().verify(); |
@@ -1,26 +0,0 @@ | |||
/* | |||
* Copyright (C) 2020 Thomas Wolf <thomas.wolf@paranor.ch> and others | |||
* | |||
* This program and the accompanying materials are made available under the | |||
* terms of the Eclipse Distribution License v. 1.0 which is available at | |||
* https://www.eclipse.org/org/documents/edl-v10.php. | |||
* | |||
* SPDX-License-Identifier: BSD-3-Clause | |||
*/ | |||
//TODO(ms): move to org.eclipse.jgit.ssh.jsch in 6.0 | |||
package org.eclipse.jgit.transport; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.lib.StoredConfig; | |||
public class JSchSshProtocol2Test extends JSchSshTest { | |||
@Override | |||
public void setUp() throws Exception { | |||
super.setUp(); | |||
StoredConfig config = ((Repository) db).getConfig(); | |||
config.setInt("protocol", null, "version", 2); | |||
config.save(); | |||
} | |||
} |
@@ -22,9 +22,7 @@ import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.ArrayList; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.List; | |||
import java.util.Map; | |||
import java.util.concurrent.Callable; | |||
import java.util.concurrent.TimeUnit; | |||
@@ -46,7 +44,7 @@ import com.jcraft.jsch.SftpException; | |||
* {@link org.eclipse.jgit.transport.JschConfigSessionFactory} is used to create | |||
* the actual session passed to the constructor. | |||
*/ | |||
public class JschSession implements RemoteSession2 { | |||
public class JschSession implements RemoteSession { | |||
final Session sock; | |||
final URIish uri; | |||
@@ -67,14 +65,7 @@ public class JschSession implements RemoteSession2 { | |||
/** {@inheritDoc} */ | |||
@Override | |||
public Process exec(String command, int timeout) throws IOException { | |||
return exec(command, Collections.emptyMap(), timeout); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public Process exec(String command, Map<String, String> environment, | |||
int timeout) throws IOException { | |||
return new JschProcess(command, environment, timeout); | |||
return new JschProcess(command, timeout); | |||
} | |||
/** {@inheritDoc} */ | |||
@@ -133,8 +124,6 @@ public class JschSession implements RemoteSession2 { | |||
* | |||
* @param commandName | |||
* the command to execute | |||
* @param environment | |||
* environment variables to pass on | |||
* @param tms | |||
* the timeout value, in seconds, for the command. | |||
* @throws TransportException | |||
@@ -143,17 +132,11 @@ public class JschSession implements RemoteSession2 { | |||
* @throws IOException | |||
* on problems opening streams | |||
*/ | |||
JschProcess(String commandName, Map<String, String> environment, | |||
int tms) throws TransportException, IOException { | |||
JschProcess(String commandName, int tms) | |||
throws TransportException, IOException { | |||
timeout = tms; | |||
try { | |||
channel = (ChannelExec) sock.openChannel("exec"); //$NON-NLS-1$ | |||
if (environment != null) { | |||
for (Map.Entry<String, String> envVar : environment | |||
.entrySet()) { | |||
channel.setEnv(envVar.getKey(), envVar.getValue()); | |||
} | |||
} | |||
channel.setCommand(commandName); | |||
setupStreams(); | |||
channel.connect(timeout > 0 ? timeout * 1000 : 0); |
@@ -232,7 +232,6 @@ downloadCancelled=Download cancelled | |||
downloadCancelledDuringIndexing=Download cancelled during indexing | |||
duplicateAdvertisementsOf=duplicate advertisements of {0} | |||
duplicateRef=Duplicate ref: {0} | |||
duplicateRefAttribute=Duplicate ref attribute: {0} | |||
duplicateRemoteRefUpdateIsIllegal=Duplicate remote ref update is illegal. Affected remote name: {0} | |||
duplicateStagesNotAllowed=Duplicate stages not allowed | |||
eitherGitDirOrWorkTreeRequired=One of setGitDir or setWorkTree must be called. |
@@ -164,7 +164,7 @@ public class LsRemoteCommand extends | |||
refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$ | |||
Collection<Ref> refs; | |||
Map<String, Ref> refmap = new HashMap<>(); | |||
try (FetchConnection fc = transport.openFetch(refSpecs)) { | |||
try (FetchConnection fc = transport.openFetch()) { | |||
refs = fc.getRefs(); | |||
if (refSpecs.isEmpty()) | |||
for (Ref r : refs) |
@@ -260,7 +260,6 @@ public class JGitText extends TranslationBundle { | |||
/***/ public String downloadCancelledDuringIndexing; | |||
/***/ public String duplicateAdvertisementsOf; | |||
/***/ public String duplicateRef; | |||
/***/ public String duplicateRefAttribute; | |||
/***/ public String duplicateRemoteRefUpdateIsIllegal; | |||
/***/ public String duplicateStagesNotAllowed; | |||
/***/ public String eitherGitDirOrWorkTreeRequired; |
@@ -13,12 +13,7 @@ | |||
package org.eclipse.jgit.transport; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_LS_REFS; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.REF_ATTR_PEELED; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.REF_ATTR_SYMREF_TARGET; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.VERSION_1; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.VERSION_2; | |||
import java.io.EOFException; | |||
import java.io.IOException; | |||
@@ -26,28 +21,20 @@ import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.text.MessageFormat; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.HashMap; | |||
import java.util.HashSet; | |||
import java.util.LinkedHashMap; | |||
import java.util.Map; | |||
import java.util.Objects; | |||
import java.util.Set; | |||
import org.eclipse.jgit.annotations.NonNull; | |||
import org.eclipse.jgit.errors.InvalidObjectIdException; | |||
import org.eclipse.jgit.errors.NoRemoteRepositoryException; | |||
import org.eclipse.jgit.errors.PackProtocolException; | |||
import org.eclipse.jgit.errors.RemoteRepositoryException; | |||
import org.eclipse.jgit.errors.TransportException; | |||
import org.eclipse.jgit.internal.JGitText; | |||
import org.eclipse.jgit.lib.Constants; | |||
import org.eclipse.jgit.lib.ObjectId; | |||
import org.eclipse.jgit.lib.ObjectIdRef; | |||
import org.eclipse.jgit.lib.Ref; | |||
import org.eclipse.jgit.lib.Repository; | |||
import org.eclipse.jgit.util.TemporaryBuffer; | |||
import org.eclipse.jgit.util.io.InterruptTimer; | |||
import org.eclipse.jgit.util.io.TimeoutInputStream; | |||
import org.eclipse.jgit.util.io.TimeoutOutputStream; | |||
@@ -99,27 +86,17 @@ abstract class BasePackConnection extends BaseConnection { | |||
protected boolean statelessRPC; | |||
/** Capability tokens advertised by the remote side. */ | |||
private final Map<String, String> remoteCapabilities = new HashMap<>(); | |||
private final Set<String> remoteCapablities = new HashSet<>(); | |||
/** Extra objects the remote has, but which aren't offered as refs. */ | |||
protected final Set<ObjectId> additionalHaves = new HashSet<>(); | |||
private TransferConfig.ProtocolVersion protocol = TransferConfig.ProtocolVersion.V0; | |||
BasePackConnection(PackTransport packTransport) { | |||
transport = (Transport) packTransport; | |||
local = transport.local; | |||
uri = transport.uri; | |||
} | |||
TransferConfig.ProtocolVersion getProtocolVersion() { | |||
return protocol; | |||
} | |||
void setProtocolVersion(@NonNull TransferConfig.ProtocolVersion protocol) { | |||
this.protocol = protocol; | |||
} | |||
/** | |||
* Configure this connection with the directional pipes. | |||
* | |||
@@ -164,15 +141,12 @@ abstract class BasePackConnection extends BaseConnection { | |||
* {@link #close()} and the exception is wrapped (if necessary) and thrown | |||
* as a {@link org.eclipse.jgit.errors.TransportException}. | |||
* | |||
* @return {@code true} if the refs were read; {@code false} otherwise | |||
* indicating that {@link #lsRefs} must be called | |||
* | |||
* @throws org.eclipse.jgit.errors.TransportException | |||
* the reference list could not be scanned. | |||
*/ | |||
protected boolean readAdvertisedRefs() throws TransportException { | |||
protected void readAdvertisedRefs() throws TransportException { | |||
try { | |||
return readAdvertisedRefsImpl(); | |||
readAdvertisedRefsImpl(); | |||
} catch (TransportException err) { | |||
close(); | |||
throw err; | |||
@@ -182,66 +156,35 @@ abstract class BasePackConnection extends BaseConnection { | |||
} | |||
} | |||
private String readLine() throws IOException { | |||
String line = pckIn.readString(); | |||
if (PacketLineIn.isEnd(line)) { | |||
return null; | |||
} | |||
if (line.startsWith("ERR ")) { //$NON-NLS-1$ | |||
// This is a customized remote service error. | |||
// Users should be informed about it. | |||
throw new RemoteRepositoryException(uri, line.substring(4)); | |||
} | |||
return line; | |||
} | |||
private boolean readAdvertisedRefsImpl() throws IOException { | |||
private void readAdvertisedRefsImpl() throws IOException { | |||
final LinkedHashMap<String, Ref> avail = new LinkedHashMap<>(); | |||
for (boolean first = true;; first = false) { | |||
for (;;) { | |||
String line; | |||
if (first) { | |||
boolean isV1 = false; | |||
try { | |||
line = readLine(); | |||
} catch (EOFException e) { | |||
try { | |||
line = pckIn.readString(); | |||
} catch (EOFException eof) { | |||
if (avail.isEmpty()) | |||
throw noRepository(); | |||
} | |||
if (line != null && VERSION_1.equals(line)) { | |||
// Same as V0, except for this extra line. We shouldn't get | |||
// it since we never request V1. | |||
setProtocolVersion(TransferConfig.ProtocolVersion.V0); | |||
isV1 = true; | |||
line = readLine(); | |||
} | |||
if (line == null) { | |||
break; | |||
} | |||
throw eof; | |||
} | |||
if (PacketLineIn.isEnd(line)) | |||
break; | |||
if (line.startsWith("ERR ")) { //$NON-NLS-1$ | |||
// This is a customized remote service error. | |||
// Users should be informed about it. | |||
throw new RemoteRepositoryException(uri, line.substring(4)); | |||
} | |||
if (avail.isEmpty()) { | |||
final int nul = line.indexOf('\0'); | |||
if (nul >= 0) { | |||
// Protocol V0: The first line (if any) may contain | |||
// "hidden" capability values after a NUL byte. | |||
for (String capability : line.substring(nul + 1) | |||
.split(" ")) { //$NON-NLS-1$ | |||
addCapability(capability); | |||
} | |||
// The first line (if any) may contain "hidden" | |||
// capability values after a NUL byte. | |||
remoteCapablities.addAll( | |||
Arrays.asList(line.substring(nul + 1).split(" "))); //$NON-NLS-1$ | |||
line = line.substring(0, nul); | |||
setProtocolVersion(TransferConfig.ProtocolVersion.V0); | |||
} else if (!isV1 && VERSION_2.equals(line)) { | |||
// Protocol V2: remaining lines are capabilities as | |||
// key=value pairs | |||
setProtocolVersion(TransferConfig.ProtocolVersion.V2); | |||
readCapabilitiesV2(); | |||
// Break out here so that stateless RPC transports get a | |||
// chance to set up the output stream. | |||
return false; | |||
} else { | |||
setProtocolVersion(TransferConfig.ProtocolVersion.V0); | |||
} | |||
} else { | |||
line = readLine(); | |||
if (line == null) { | |||
break; | |||
} | |||
} | |||
@@ -250,230 +193,44 @@ abstract class BasePackConnection extends BaseConnection { | |||
throw invalidRefAdvertisementLine(line); | |||
} | |||
String name = line.substring(41, line.length()); | |||
if (first && name.equals("capabilities^{}")) { //$NON-NLS-1$ | |||
// special line from git-receive-pack (protocol V0) to show | |||
if (avail.isEmpty() && name.equals("capabilities^{}")) { //$NON-NLS-1$ | |||
// special line from git-receive-pack to show | |||
// capabilities when there are no refs to advertise | |||
// TODO: throw error if protocol version is >= V2? | |||
continue; | |||
} | |||
final ObjectId id = toId(line, line.substring(0, 40)); | |||
final ObjectId id; | |||
try { | |||
id = ObjectId.fromString(line.substring(0, 40)); | |||
} catch (InvalidObjectIdException e) { | |||
PackProtocolException ppe = invalidRefAdvertisementLine(line); | |||
ppe.initCause(e); | |||
throw ppe; | |||
} | |||
if (name.equals(".have")) { //$NON-NLS-1$ | |||
additionalHaves.add(id); | |||
} else { | |||
processLineV1(name, id, avail); | |||
} | |||
} | |||
available(avail); | |||
return true; | |||
} | |||
} else if (name.endsWith("^{}")) { //$NON-NLS-1$ | |||
name = name.substring(0, name.length() - 3); | |||
final Ref prior = avail.get(name); | |||
if (prior == null) | |||
throw new PackProtocolException(uri, MessageFormat.format( | |||
JGitText.get().advertisementCameBefore, name, name)); | |||
/** | |||
* Issue a protocol V2 ls-refs command and read its response. | |||
* | |||
* @param refSpecs | |||
* to produce ref prefixes from if the server supports git | |||
* protocol V2 | |||
* @param additionalPatterns | |||
* to use for ref prefixes if the server supports git protocol V2 | |||
* @throws TransportException | |||
* if the command could not be run or its output not be read | |||
*/ | |||
protected void lsRefs(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) throws TransportException { | |||
try { | |||
lsRefsImpl(refSpecs, additionalPatterns); | |||
} catch (TransportException err) { | |||
close(); | |||
throw err; | |||
} catch (IOException | RuntimeException err) { | |||
close(); | |||
throw new TransportException(err.getMessage(), err); | |||
} | |||
} | |||
if (prior.getPeeledObjectId() != null) | |||
throw duplicateAdvertisement(name + "^{}"); //$NON-NLS-1$ | |||
private void lsRefsImpl(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) throws IOException { | |||
TemporaryBuffer state = null; | |||
PacketLineOut pckState = null; | |||
PacketLineOut output = pckOut; | |||
if (statelessRPC) { | |||
state = new TemporaryBuffer.Heap(Integer.MAX_VALUE); | |||
pckState = new PacketLineOut(state); | |||
output = pckState; | |||
} | |||
output.writeString("command=" + COMMAND_LS_REFS); //$NON-NLS-1$ | |||
// Add the user-agent | |||
String agent = UserAgent.get(); | |||
if (agent != null && isCapableOf(OPTION_AGENT)) { | |||
output.writeString(OPTION_AGENT + '=' + agent); | |||
} | |||
output.writeDelim(); | |||
output.writeString("peel"); //$NON-NLS-1$ | |||
for (String refPrefix : getRefPrefixes(refSpecs, additionalPatterns)) { | |||
output.writeString("ref-prefix " + refPrefix); //$NON-NLS-1$ | |||
} | |||
output.end(); | |||
output.flush(); | |||
if (state != null) { | |||
state.writeTo(out, null); | |||
out.flush(); | |||
state = null; | |||
pckState = null; | |||
} | |||
final LinkedHashMap<String, Ref> avail = new LinkedHashMap<>(); | |||
for (;;) { | |||
String line = readLine(); | |||
if (line == null) { | |||
break; | |||
} | |||
// Expecting to get a line in the form "sha1 refname" | |||
if (line.length() < 41 || line.charAt(40) != ' ') { | |||
throw invalidRefAdvertisementLine(line); | |||
} | |||
String name = line.substring(41, line.length()); | |||
final ObjectId id = toId(line, line.substring(0, 40)); | |||
if (name.equals(".have")) { //$NON-NLS-1$ | |||
additionalHaves.add(id); | |||
avail.put(name, new ObjectIdRef.PeeledTag( | |||
Ref.Storage.NETWORK, name, prior.getObjectId(), id)); | |||
} else { | |||
processLineV2(line, id, name, avail); | |||
final Ref prior = avail.put(name, new ObjectIdRef.PeeledNonTag( | |||
Ref.Storage.NETWORK, name, id)); | |||
if (prior != null) | |||
throw duplicateAdvertisement(name); | |||
} | |||
} | |||
available(avail); | |||
} | |||
private Collection<String> getRefPrefixes(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) { | |||
if (refSpecs.isEmpty() && (additionalPatterns == null | |||
|| additionalPatterns.length == 0)) { | |||
return Collections.emptyList(); | |||
} | |||
Set<String> patterns = new HashSet<>(); | |||
if (additionalPatterns != null) { | |||
Arrays.stream(additionalPatterns).filter(Objects::nonNull) | |||
.forEach(patterns::add); | |||
} | |||
for (RefSpec spec : refSpecs) { | |||
// TODO: for now we only do protocol V2 for fetch. For push | |||
// RefSpecs, the logic would need to be different. (At the | |||
// minimum, take spec.getDestination().) | |||
String src = spec.getSource(); | |||
if (ObjectId.isId(src)) { | |||
continue; | |||
} | |||
if (spec.isWildcard()) { | |||
patterns.add(src.substring(0, src.indexOf('*'))); | |||
} else { | |||
patterns.add(src); | |||
patterns.add(Constants.R_REFS + src); | |||
patterns.add(Constants.R_HEADS + src); | |||
patterns.add(Constants.R_TAGS + src); | |||
} | |||
} | |||
return patterns; | |||
} | |||
private void readCapabilitiesV2() throws IOException { | |||
// In git protocol V2, capabilities are different. If it's a key-value | |||
// pair, the key may be a command name, and the value a space-separated | |||
// list of capabilities for that command. We still store it in the same | |||
// map as for protocol v0/v1. Protocol v2 code has to account for this. | |||
for (;;) { | |||
String line = readLine(); | |||
if (line == null) { | |||
break; | |||
} | |||
addCapability(line); | |||
} | |||
} | |||
private void addCapability(String capability) { | |||
String parts[] = capability.split("=", 2); //$NON-NLS-1$ | |||
if (parts.length == 2) { | |||
remoteCapabilities.put(parts[0], parts[1]); | |||
} | |||
remoteCapabilities.put(capability, null); | |||
} | |||
private ObjectId toId(String line, String value) | |||
throws PackProtocolException { | |||
try { | |||
return ObjectId.fromString(value); | |||
} catch (InvalidObjectIdException e) { | |||
PackProtocolException ppe = invalidRefAdvertisementLine(line); | |||
ppe.initCause(e); | |||
throw ppe; | |||
} | |||
} | |||
private void processLineV1(String name, ObjectId id, Map<String, Ref> avail) | |||
throws IOException { | |||
if (name.endsWith("^{}")) { //$NON-NLS-1$ | |||
name = name.substring(0, name.length() - 3); | |||
final Ref prior = avail.get(name); | |||
if (prior == null) { | |||
throw new PackProtocolException(uri, MessageFormat.format( | |||
JGitText.get().advertisementCameBefore, name, name)); | |||
} | |||
if (prior.getPeeledObjectId() != null) { | |||
throw duplicateAdvertisement(name + "^{}"); //$NON-NLS-1$ | |||
} | |||
avail.put(name, new ObjectIdRef.PeeledTag(Ref.Storage.NETWORK, name, | |||
prior.getObjectId(), id)); | |||
} else { | |||
final Ref prior = avail.put(name, new ObjectIdRef.PeeledNonTag( | |||
Ref.Storage.NETWORK, name, id)); | |||
if (prior != null) { | |||
throw duplicateAdvertisement(name); | |||
} | |||
} | |||
} | |||
private void processLineV2(String line, ObjectId id, String rest, | |||
Map<String, Ref> avail) throws IOException { | |||
String[] parts = rest.split(" "); //$NON-NLS-1$ | |||
String name = parts[0]; | |||
// Two attributes possible, symref-target or peeled | |||
String symRefTarget = null; | |||
String peeled = null; | |||
for (int i = 1; i < parts.length; i++) { | |||
if (parts[i].startsWith(REF_ATTR_SYMREF_TARGET)) { | |||
if (symRefTarget != null) { | |||
throw new PackProtocolException(uri, MessageFormat.format( | |||
JGitText.get().duplicateRefAttribute, line)); | |||
} | |||
symRefTarget = parts[i] | |||
.substring(REF_ATTR_SYMREF_TARGET.length()); | |||
} else if (parts[i].startsWith(REF_ATTR_PEELED)) { | |||
if (peeled != null) { | |||
throw new PackProtocolException(uri, MessageFormat.format( | |||
JGitText.get().duplicateRefAttribute, line)); | |||
} | |||
peeled = parts[i].substring(REF_ATTR_PEELED.length()); | |||
} | |||
if (peeled != null && symRefTarget != null) { | |||
break; | |||
} | |||
} | |||
Ref idRef; | |||
if (peeled != null) { | |||
idRef = new ObjectIdRef.PeeledTag(Ref.Storage.NETWORK, name, id, | |||
toId(line, peeled)); | |||
} else { | |||
idRef = new ObjectIdRef.PeeledNonTag(Ref.Storage.NETWORK, name, id); | |||
} | |||
Ref prior = avail.put(name, idRef); | |||
if (prior != null) { | |||
throw duplicateAdvertisement(name); | |||
} | |||
if (symRefTarget != null) { | |||
// What do we have to do with this information? In protocol V0, this | |||
// info comes in the capability advertisement, but OPTION_SYMREF is | |||
// used only in RefAdvertiser. JGit's client side doesn't make use | |||
// of this information, and actually never requests it. | |||
} | |||
} | |||
/** | |||
* Create an exception to indicate problems finding a remote repository. The | |||
* caller is expected to throw the returned exception. | |||
@@ -495,7 +252,7 @@ abstract class BasePackConnection extends BaseConnection { | |||
* @return whether this option is supported | |||
*/ | |||
protected boolean isCapableOf(String option) { | |||
return remoteCapabilities.containsKey(option); | |||
return remoteCapablities.contains(option); | |||
} | |||
/** | |||
@@ -515,17 +272,6 @@ abstract class BasePackConnection extends BaseConnection { | |||
return true; | |||
} | |||
/** | |||
* Return a capability value. | |||
* | |||
* @param option | |||
* to get | |||
* @return the value stored, if any. | |||
*/ | |||
protected String getCapability(String option) { | |||
return remoteCapabilities.get(option); | |||
} | |||
/** | |||
* Add user agent capability | |||
* | |||
@@ -534,7 +280,7 @@ abstract class BasePackConnection extends BaseConnection { | |||
*/ | |||
protected void addUserAgentCapability(StringBuilder b) { | |||
String a = UserAgent.get(); | |||
if (a != null && remoteCapabilities.get(OPTION_AGENT) != null) { | |||
if (a != null && UserAgent.hasAgent(remoteCapablities)) { | |||
b.append(' ').append(OPTION_AGENT).append('=').append(a); | |||
} | |||
} | |||
@@ -542,8 +288,7 @@ abstract class BasePackConnection extends BaseConnection { | |||
/** {@inheritDoc} */ | |||
@Override | |||
public String getPeerUserAgent() { | |||
String agent = remoteCapabilities.get(OPTION_AGENT); | |||
return agent != null ? agent : super.getPeerUserAgent(); | |||
return UserAgent.getAgent(remoteCapablities, super.getPeerUserAgent()); | |||
} | |||
private PackProtocolException duplicateAdvertisement(String name) { |
@@ -16,12 +16,9 @@ import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.text.MessageFormat; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Date; | |||
import java.util.HashSet; | |||
import java.util.LinkedHashSet; | |||
import java.util.Set; | |||
import org.eclipse.jgit.errors.PackProtocolException; | |||
@@ -215,8 +212,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
private PacketLineOut pckState; | |||
private Set<String> fetchCapabilities = new HashSet<>(); | |||
/** | |||
* Either FilterSpec.NO_FILTER for a filter that doesn't filter | |||
* anything, or a filter that indicates what and what not to send to the | |||
@@ -359,28 +354,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
pckState = new PacketLineOut(state); | |||
} | |||
if (TransferConfig.ProtocolVersion.V2 | |||
.equals(getProtocolVersion())) { | |||
sideband = true; | |||
noDone = true; | |||
multiAck = MultiAck.DETAILED; | |||
setFetchOptions(); | |||
PacketLineOut output = statelessRPC ? pckState : pckOut; | |||
output.writeString( | |||
"command=" + GitProtocolConstants.COMMAND_FETCH); //$NON-NLS-1$ | |||
// Capabilities are sent as command arguments in protocol V2 | |||
String agent = UserAgent.get(); | |||
if (agent != null | |||
&& isCapableOf(GitProtocolConstants.OPTION_AGENT)) { | |||
output.writeString( | |||
GitProtocolConstants.OPTION_AGENT + '=' + agent); | |||
} | |||
output.writeDelim(); | |||
// Arguments | |||
for (String capability : getCapabilitiesV2()) { | |||
output.writeString(capability); | |||
} | |||
} | |||
if (sendWants(want)) { | |||
negotiate(monitor); | |||
@@ -389,25 +362,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
state = null; | |||
pckState = null; | |||
if (TransferConfig.ProtocolVersion.V2 | |||
.equals(getProtocolVersion())) { | |||
String header = pckIn.readString(); | |||
if (PacketLineIn.isEnd(header)) { | |||
// No packfile following. | |||
return; | |||
} | |||
if (header.startsWith("ERR ")) { //$NON-NLS-1$ | |||
// Protocol V2 may give us an error here (for instance, | |||
// invalid want) | |||
throw new PackProtocolException(header.substring(4)); | |||
} | |||
if (!GitProtocolConstants.SECTION_PACKFILE.equals(header)) { | |||
throw new PackProtocolException(MessageFormat.format( | |||
JGitText.get().expectedGot, | |||
GitProtocolConstants.SECTION_PACKFILE, header)); | |||
} | |||
} | |||
receivePack(monitor, outputStream); | |||
} | |||
} catch (CancelledException ce) { | |||
@@ -427,14 +381,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
super.close(); | |||
} | |||
private void setFetchOptions() { | |||
String advertised = getCapability(GitProtocolConstants.COMMAND_FETCH); | |||
if (advertised == null) { | |||
return; | |||
} | |||
fetchCapabilities.addAll(Arrays.asList(advertised.split(" "))); //$NON-NLS-1$ | |||
} | |||
FetchConfig getFetchConfig() { | |||
return local.getConfig().get(FetchConfig::new); | |||
} | |||
@@ -533,11 +479,10 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
final StringBuilder line = new StringBuilder(46); | |||
line.append("want "); //$NON-NLS-1$ | |||
line.append(objectId.name()); | |||
if (first && TransferConfig.ProtocolVersion.V0 | |||
.equals(getProtocolVersion())) { | |||
if (first) { | |||
line.append(enableCapabilities()); | |||
first = false; | |||
} | |||
first = false; | |||
line.append('\n'); | |||
p.writeString(line.toString()); | |||
} | |||
@@ -547,35 +492,11 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
if (!filterSpec.isNoOp()) { | |||
p.writeString(filterSpec.filterLine()); | |||
} | |||
if (TransferConfig.ProtocolVersion.V0.equals(getProtocolVersion())) { | |||
p.end(); | |||
outNeedsEnd = false; | |||
} | |||
p.end(); | |||
outNeedsEnd = false; | |||
return true; | |||
} | |||
private Set<String> getCapabilitiesV2() throws TransportException { | |||
Set<String> capabilities = new LinkedHashSet<>(); | |||
if (noProgress) { | |||
capabilities.add(OPTION_NO_PROGRESS); | |||
} | |||
if (includeTags) { | |||
capabilities.add(OPTION_INCLUDE_TAG); | |||
} | |||
if (allowOfsDelta) { | |||
capabilities.add(OPTION_OFS_DELTA); | |||
} | |||
if (thinPack) { | |||
capabilities.add(OPTION_THIN_PACK); | |||
} | |||
if (!filterSpec.isNoOp() | |||
&& !fetchCapabilities.contains(OPTION_FILTER)) { | |||
throw new PackProtocolException(uri, | |||
JGitText.get().filterRequiresCapability); | |||
} | |||
return capabilities; | |||
} | |||
private String enableCapabilities() throws TransportException { | |||
final StringBuilder line = new StringBuilder(); | |||
if (noProgress) | |||
@@ -629,7 +550,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
boolean receivedContinue = false; | |||
boolean receivedAck = false; | |||
boolean receivedReady = false; | |||
boolean needsAcknowledgementV2 = true; | |||
if (statelessRPC) { | |||
state.writeTo(out, null); | |||
@@ -643,7 +563,7 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
} | |||
ObjectId o = c.getId(); | |||
pckOut.writeString("have " + o.name() + '\n'); //$NON-NLS-1$ | |||
pckOut.writeString("have " + o.name() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ | |||
havesSent++; | |||
havesSinceLastContinue++; | |||
@@ -660,7 +580,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
} | |||
pckOut.end(); | |||
outNeedsEnd = false; | |||
resultsPending++; // Each end will cause a result to come back. | |||
if (havesSent == 32 && !statelessRPC) { | |||
@@ -672,32 +591,9 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
continue; | |||
} | |||
// Read the section header | |||
if (needsAcknowledgementV2 && TransferConfig.ProtocolVersion.V2 | |||
.equals(getProtocolVersion())) { | |||
String header = pckIn.readString(); | |||
if (!GitProtocolConstants.SECTION_ACKNOWLEDGMENTS | |||
.equals(header)) { | |||
throw new PackProtocolException(MessageFormat.format( | |||
JGitText.get().expectedGot, | |||
GitProtocolConstants.SECTION_ACKNOWLEDGMENTS, | |||
header)); | |||
} | |||
needsAcknowledgementV2 = false; | |||
} | |||
READ_RESULT: for (;;) { | |||
AckNackResult anr = pckIn.readACKorEOF(ackId); | |||
final AckNackResult anr = pckIn.readACK(ackId); | |||
switch (anr) { | |||
case ACK_EOF: | |||
if (TransferConfig.ProtocolVersion.V0 | |||
.equals(getProtocolVersion())) { | |||
throw new PackProtocolException( | |||
JGitText.get().expectedACKNAKFoundEOF); | |||
} | |||
// More lines needed | |||
resultsPending--; | |||
break READ_RESULT; | |||
case NAK: | |||
// More have lines are necessary to compute the | |||
// pack on the remote side. Keep doing that. | |||
@@ -706,24 +602,17 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
break READ_RESULT; | |||
case ACK: | |||
if (TransferConfig.ProtocolVersion.V0 | |||
.equals(getProtocolVersion())) { | |||
// The remote side is happy and knows exactly what | |||
// to send us. There is no further negotiation and | |||
// we can break out immediately. | |||
// | |||
multiAck = MultiAck.OFF; | |||
resultsPending = 0; | |||
receivedAck = true; | |||
if (statelessRPC) { | |||
state.writeTo(out, null); | |||
} | |||
break SEND_HAVES; | |||
} | |||
// Keep on reading ACKs until we get the ACK_READY | |||
markCommon(walk.parseAny(ackId), AckNackResult.ACK_COMMON); | |||
// The remote side is happy and knows exactly what | |||
// to send us. There is no further negotiation and | |||
// we can break out immediately. | |||
// | |||
multiAck = MultiAck.OFF; | |||
resultsPending = 0; | |||
receivedAck = true; | |||
break; | |||
if (statelessRPC) { | |||
state.writeTo(out, null); | |||
} | |||
break SEND_HAVES; | |||
case ACK_CONTINUE: | |||
case ACK_COMMON: | |||
@@ -739,12 +628,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
havesSinceLastContinue = 0; | |||
if (anr == AckNackResult.ACK_READY) { | |||
receivedReady = true; | |||
if (TransferConfig.ProtocolVersion.V2 | |||
.equals(getProtocolVersion())) { | |||
multiAck = MultiAck.OFF; | |||
resultsPending = 0; | |||
break SEND_HAVES; | |||
} | |||
} | |||
break; | |||
} | |||
@@ -778,36 +661,15 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
throw new CancelledException(); | |||
} | |||
if (receivedReady && TransferConfig.ProtocolVersion.V2 | |||
.equals(getProtocolVersion())) { | |||
// We'll get the packfile right away. Skip the delimiter. | |||
String delim = pckIn.readString(); | |||
if (!PacketLineIn.isDelimiter(delim)) { | |||
throw new PackProtocolException(MessageFormat | |||
.format(JGitText.get().expectedGot, "0001", delim)); //$NON-NLS-1$ | |||
} | |||
return; | |||
} | |||
if (!receivedReady || !noDone) { | |||
// When statelessRPC is true we should always leave SEND_HAVES | |||
// loop above while in the middle of a request. This allows us | |||
// to just write done immediately. | |||
// | |||
pckOut.writeString("done\n"); //$NON-NLS-1$ | |||
if (TransferConfig.ProtocolVersion.V2 | |||
.equals(getProtocolVersion())) { | |||
pckOut.end(); | |||
outNeedsEnd = false; | |||
pckOut.flush(); | |||
// Protocol V2 will skip acknowledgments completely if we send | |||
// a done. | |||
return; | |||
} | |||
pckOut.flush(); | |||
} | |||
// Below is protocol V0 only. | |||
if (!receivedAck) { | |||
// Apparently if we have never received an ACK earlier | |||
// there is one more result expected from the done we | |||
@@ -827,14 +689,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
// | |||
break; | |||
case ACK_EOF: | |||
if (TransferConfig.ProtocolVersion.V0 | |||
.equals(getProtocolVersion())) { | |||
throw new PackProtocolException( | |||
JGitText.get().expectedACKNAKFoundEOF); | |||
} | |||
break READ_RESULT; | |||
case ACK: | |||
// A solitary ACK at this point means the remote won't | |||
// speak anymore, but is going to send us a pack now. | |||
@@ -843,16 +697,7 @@ public abstract class BasePackFetchConnection extends BasePackConnection | |||
case ACK_CONTINUE: | |||
case ACK_COMMON: | |||
// We will expect a normal ACK to break out of the loop. | |||
// | |||
multiAck = MultiAck.CONTINUE; | |||
break; | |||
case ACK_READY: | |||
if (TransferConfig.ProtocolVersion.V2 | |||
.equals(getProtocolVersion())) { | |||
break READ_RESULT; | |||
} | |||
// We will expect a normal ACK to break out of the loop. | |||
// | |||
multiAck = MultiAck.CONTINUE; |
@@ -102,21 +102,7 @@ class FetchProcess { | |||
private void executeImp(final ProgressMonitor monitor, | |||
final FetchResult result) throws NotSupportedException, | |||
TransportException { | |||
final TagOpt tagopt = transport.getTagOpt(); | |||
String getTags = (tagopt == TagOpt.NO_TAGS) ? null : Constants.R_TAGS; | |||
String getHead = null; | |||
try { | |||
// If we don't have a HEAD yet, we're cloning and need to get the | |||
// upstream HEAD, too. | |||
Ref head = transport.local.exactRef(Constants.HEAD); | |||
ObjectId id = head != null ? head.getObjectId() : null; | |||
if (id == null || id.equals(ObjectId.zeroId())) { | |||
getHead = Constants.HEAD; | |||
} | |||
} catch (IOException e) { | |||
// Ignore | |||
} | |||
conn = transport.openFetch(toFetch, getTags, getHead); | |||
conn = transport.openFetch(); | |||
try { | |||
result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap()); | |||
result.peerUserAgent = conn.getPeerUserAgent(); | |||
@@ -133,6 +119,7 @@ class FetchProcess { | |||
} | |||
Collection<Ref> additionalTags = Collections.<Ref> emptyList(); | |||
final TagOpt tagopt = transport.getTagOpt(); | |||
if (tagopt == TagOpt.AUTO_FOLLOW) | |||
additionalTags = expandAutoFollowTags(); | |||
else if (tagopt == TagOpt.FETCH_TAGS) | |||
@@ -266,17 +253,7 @@ class FetchProcess { | |||
if (conn != null) | |||
return; | |||
// Build prefixes | |||
Set<String> prefixes = new HashSet<>(); | |||
for (Ref toGet : askFor.values()) { | |||
String src = toGet.getName(); | |||
prefixes.add(src); | |||
prefixes.add(Constants.R_REFS + src); | |||
prefixes.add(Constants.R_HEADS + src); | |||
prefixes.add(Constants.R_TAGS + src); | |||
} | |||
conn = transport.openFetch(Collections.emptyList(), | |||
prefixes.toArray(new String[0])); | |||
conn = transport.openFetch(); | |||
// Since we opened a new connection we cannot be certain | |||
// that the system we connected to has the same exact set |
@@ -247,74 +247,6 @@ public final class GitProtocolConstants { | |||
*/ | |||
public static final String COMMAND_FETCH = "fetch"; //$NON-NLS-1$ | |||
/** | |||
* HTTP header to set by clients to request a specific git protocol version | |||
* in the HTTP transport. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String PROTOCOL_HEADER = "Git-Protocol"; //$NON-NLS-1$ | |||
/** | |||
* Environment variable to set by clients to request a specific git protocol | |||
* in the file:// and ssh:// transports. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String PROTOCOL_ENVIRONMENT_VARIABLE = "GIT_PROTOCOL"; //$NON-NLS-1$ | |||
/** | |||
* Protocol V2 ref advertisement attribute containing the peeled object id | |||
* for annotated tags. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String REF_ATTR_PEELED = "peeled:"; //$NON-NLS-1$ | |||
/** | |||
* Protocol V2 ref advertisement attribute containing the name of the ref | |||
* for symbolic refs. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String REF_ATTR_SYMREF_TARGET = "symref-target:"; //$NON-NLS-1$ | |||
/** | |||
* Protocol V2 acknowledgments section header. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String SECTION_ACKNOWLEDGMENTS = "acknowledgments"; //$NON-NLS-1$ | |||
/** | |||
* Protocol V2 packfile section header. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String SECTION_PACKFILE = "packfile"; //$NON-NLS-1$ | |||
/** | |||
* Protocol announcement for protocol version 1. This is the same as V0, | |||
* except for this initial line. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String VERSION_1 = "version 1"; //$NON-NLS-1$ | |||
/** | |||
* Protocol announcement for protocol version 2. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String VERSION_2 = "version 2"; //$NON-NLS-1$ | |||
/** | |||
* Protocol request for protocol version 2. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public static final String VERSION_2_REQUEST = "version=2"; //$NON-NLS-1$ | |||
enum MultiAck { | |||
OFF, CONTINUE, DETAILED; | |||
} |
@@ -72,9 +72,7 @@ public class PacketLineIn { | |||
/** ACK + common */ | |||
ACK_COMMON, | |||
/** ACK + ready */ | |||
ACK_READY, | |||
/** EOF (0000) recieved in protocol V2 when expecting an ACK/NAK */ | |||
ACK_EOF; | |||
ACK_READY; | |||
} | |||
private final byte[] lineBuffer = new byte[SideBandOutputStream.SMALL_BUF]; | |||
@@ -105,26 +103,12 @@ public class PacketLineIn { | |||
this.limit = limit; | |||
} | |||
AckNackResult readACK(MutableObjectId returnedId) throws IOException { | |||
AckNackResult result = readACKorEOF(returnedId); | |||
if (result == AckNackResult.ACK_EOF) { | |||
throw new PackProtocolException( | |||
JGitText.get().expectedACKNAKFoundEOF); | |||
} | |||
return result; | |||
} | |||
AckNackResult readACKorEOF(MutableObjectId returnedId) throws IOException { | |||
final String line = readString(); | |||
if (line.length() == 0) | |||
return AckNackResult.ACK_EOF; | |||
throw new PackProtocolException(JGitText.get().expectedACKNAKFoundEOF); | |||
if ("NAK".equals(line)) //$NON-NLS-1$ | |||
return AckNackResult.NAK; | |||
if ("ready".equals(line)) { //$NON-NLS-1$ | |||
// Protocol V2 | |||
return AckNackResult.ACK_READY; | |||
} | |||
if (line.startsWith("ACK ")) { //$NON-NLS-1$ | |||
returnedId.fromString(line.substring(4, 44)); | |||
if (line.length() == 44) |
@@ -13,8 +13,6 @@ package org.eclipse.jgit.transport; | |||
import static java.nio.charset.StandardCharsets.UTF_8; | |||
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SYMREF; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.REF_ATTR_PEELED; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.REF_ATTR_SYMREF_TARGET; | |||
import java.io.IOException; | |||
import java.nio.ByteBuffer; | |||
@@ -289,8 +287,7 @@ public abstract class RefAdvertiser { | |||
if (useProtocolV2) { | |||
String symrefPart = symrefs.containsKey(ref.getName()) | |||
? (' ' + REF_ATTR_SYMREF_TARGET | |||
+ symrefs.get(ref.getName())) | |||
? (" symref-target:" + symrefs.get(ref.getName())) //$NON-NLS-1$ | |||
: ""; //$NON-NLS-1$ | |||
String peelPart = ""; //$NON-NLS-1$ | |||
if (derefTags) { | |||
@@ -299,8 +296,7 @@ public abstract class RefAdvertiser { | |||
} | |||
ObjectId peeledObjectId = ref.getPeeledObjectId(); | |||
if (peeledObjectId != null) { | |||
peelPart = ' ' + REF_ATTR_PEELED | |||
+ peeledObjectId.getName(); | |||
peelPart = " peeled:" + peeledObjectId.getName(); //$NON-NLS-1$ | |||
} | |||
} | |||
writeOne(objectId.getName() + " " + ref.getName() + symrefPart //$NON-NLS-1$ |
@@ -1,45 +0,0 @@ | |||
/* | |||
* Copyright (C) 2020, Thomas Wolf <thoams.wolf@paranor.ch> | |||
* | |||
* This program and the accompanying materials are made available under the | |||
* terms of the Eclipse Distribution License v. 1.0 which is available at | |||
* https://www.eclipse.org/org/documents/edl-v10.php. | |||
* | |||
* SPDX-License-Identifier: BSD-3-Clause | |||
*/ | |||
package org.eclipse.jgit.transport; | |||
import java.io.IOException; | |||
import java.util.Map; | |||
/** | |||
* A {@link RemoteSession} that supports passing environment variables to | |||
* commands. | |||
* | |||
* @since 5.10 | |||
*/ | |||
public interface RemoteSession2 extends RemoteSession { | |||
/** | |||
* Creates a new remote {@link Process} to execute the given command. The | |||
* returned process's streams exist and are connected, and execution of the | |||
* process is already started. | |||
* | |||
* @param commandName | |||
* command to execute | |||
* @param environment | |||
* environment variables to pass on | |||
* @param timeout | |||
* timeout value, in seconds, for creating the remote process | |||
* @return a new remote process, already started | |||
* @throws java.io.IOException | |||
* may be thrown in several cases. For example, on problems | |||
* opening input or output streams or on problems connecting or | |||
* communicating with the remote host. For the latter two cases, | |||
* a TransportException may be thrown (a subclass of | |||
* java.io.IOException). | |||
*/ | |||
Process exec(String commandName, Map<String, String> environment, | |||
int timeout) throws IOException; | |||
} |
@@ -39,7 +39,6 @@ import java.util.Vector; | |||
import java.util.concurrent.CopyOnWriteArrayList; | |||
import org.eclipse.jgit.annotations.NonNull; | |||
import org.eclipse.jgit.annotations.Nullable; | |||
import org.eclipse.jgit.api.errors.AbortedByHookException; | |||
import org.eclipse.jgit.errors.NotSupportedException; | |||
import org.eclipse.jgit.errors.TransportException; | |||
@@ -775,10 +774,6 @@ public abstract class Transport implements AutoCloseable { | |||
private PrintStream hookOutRedirect; | |||
private PrePushHook prePush; | |||
@Nullable | |||
TransferConfig.ProtocolVersion protocol; | |||
/** | |||
* Create a new transport instance. | |||
* | |||
@@ -794,7 +789,6 @@ public abstract class Transport implements AutoCloseable { | |||
final TransferConfig tc = local.getConfig().get(TransferConfig.KEY); | |||
this.local = local; | |||
this.uri = uri; | |||
this.protocol = tc.protocolVersion; | |||
this.objectChecker = tc.newObjectChecker(); | |||
this.credentialsProvider = CredentialsProvider.getDefault(); | |||
prePush = Hooks.prePush(local, hookOutRedirect); | |||
@@ -1458,43 +1452,6 @@ public abstract class Transport implements AutoCloseable { | |||
public abstract FetchConnection openFetch() throws NotSupportedException, | |||
TransportException; | |||
/** | |||
* Begins a new connection for fetching from the remote repository. | |||
* <p> | |||
* If the transport has no local repository, the fetch connection can only | |||
* be used for reading remote refs. | |||
* </p> | |||
* <p> | |||
* If the server supports git protocol V2, the {@link RefSpec}s and the | |||
* additional patterns, if any, are used to restrict the server's ref | |||
* advertisement to matching refs only. | |||
* </p> | |||
* <p> | |||
* Transports that want to support git protocol V2 <em>must</em> override | |||
* this; the default implementation ignores its arguments and calls | |||
* {@link #openFetch()}. | |||
* </p> | |||
* | |||
* @param refSpecs | |||
* that will be fetched via | |||
* {@link FetchConnection#fetch(ProgressMonitor, Collection, java.util.Set, OutputStream)} later | |||
* @param additionalPatterns | |||
* that will be set as ref prefixes if the server supports git | |||
* protocol V2; {@code null} values are ignored | |||
* | |||
* @return a fresh connection to fetch from the remote repository. | |||
* @throws org.eclipse.jgit.errors.NotSupportedException | |||
* the implementation does not support fetching. | |||
* @throws org.eclipse.jgit.errors.TransportException | |||
* the remote connection could not be established. | |||
* @since 5.10 | |||
*/ | |||
public FetchConnection openFetch(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) | |||
throws NotSupportedException, TransportException { | |||
return openFetch(); | |||
} | |||
/** | |||
* Begins a new connection for pushing into the remote repository. | |||
* |
@@ -22,7 +22,6 @@ import java.net.InetAddress; | |||
import java.net.InetSocketAddress; | |||
import java.net.Socket; | |||
import java.net.UnknownHostException; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.EnumSet; | |||
import java.util.Set; | |||
@@ -95,13 +94,6 @@ class TransportGitAnon extends TcpTransport implements PackTransport { | |||
return new TcpFetchConnection(); | |||
} | |||
@Override | |||
public FetchConnection openFetch(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) | |||
throws NotSupportedException, TransportException { | |||
return new TcpFetchConnection(refSpecs, additionalPatterns); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public PushConnection openPush() throws TransportException { | |||
@@ -138,8 +130,7 @@ class TransportGitAnon extends TcpTransport implements PackTransport { | |||
return s; | |||
} | |||
void service(String name, PacketLineOut pckOut, | |||
TransferConfig.ProtocolVersion gitProtocol) | |||
void service(String name, PacketLineOut pckOut) | |||
throws IOException { | |||
final StringBuilder cmd = new StringBuilder(); | |||
cmd.append(name); | |||
@@ -153,11 +144,6 @@ class TransportGitAnon extends TcpTransport implements PackTransport { | |||
cmd.append(uri.getPort()); | |||
} | |||
cmd.append('\0'); | |||
if (TransferConfig.ProtocolVersion.V2.equals(gitProtocol)) { | |||
cmd.append('\0'); | |||
cmd.append(GitProtocolConstants.VERSION_2_REQUEST); | |||
cmd.append('\0'); | |||
} | |||
pckOut.writeString(cmd.toString()); | |||
pckOut.flush(); | |||
} | |||
@@ -166,11 +152,6 @@ class TransportGitAnon extends TcpTransport implements PackTransport { | |||
private Socket sock; | |||
TcpFetchConnection() throws TransportException { | |||
this(Collections.emptyList()); | |||
} | |||
TcpFetchConnection(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) throws TransportException { | |||
super(TransportGitAnon.this); | |||
sock = openConnection(); | |||
try { | |||
@@ -181,19 +162,13 @@ class TransportGitAnon extends TcpTransport implements PackTransport { | |||
sOut = new BufferedOutputStream(sOut); | |||
init(sIn, sOut); | |||
TransferConfig.ProtocolVersion gitProtocol = protocol; | |||
if (gitProtocol == null) { | |||
gitProtocol = TransferConfig.ProtocolVersion.V2; | |||
} | |||
service("git-upload-pack", pckOut, gitProtocol); //$NON-NLS-1$ | |||
service("git-upload-pack", pckOut); //$NON-NLS-1$ | |||
} catch (IOException err) { | |||
close(); | |||
throw new TransportException(uri, | |||
JGitText.get().remoteHungUpUnexpectedly, err); | |||
} | |||
if (!readAdvertisedRefs()) { | |||
lsRefs(refSpecs, additionalPatterns); | |||
} | |||
readAdvertisedRefs(); | |||
} | |||
@Override | |||
@@ -226,7 +201,7 @@ class TransportGitAnon extends TcpTransport implements PackTransport { | |||
sOut = new BufferedOutputStream(sOut); | |||
init(sIn, sOut); | |||
service("git-receive-pack", pckOut, null); //$NON-NLS-1$ | |||
service("git-receive-pack", pckOut); //$NON-NLS-1$ | |||
} catch (IOException err) { | |||
close(); | |||
throw new TransportException(uri, |
@@ -19,13 +19,11 @@ import java.io.InputStream; | |||
import java.text.MessageFormat; | |||
import java.util.ArrayList; | |||
import java.util.Arrays; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.EnumSet; | |||
import java.util.LinkedHashSet; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import org.eclipse.jgit.errors.NoRemoteRepositoryException; | |||
@@ -146,13 +144,6 @@ public class TransportGitSsh extends SshTransport implements PackTransport { | |||
return new SshFetchConnection(); | |||
} | |||
@Override | |||
public FetchConnection openFetch(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) | |||
throws NotSupportedException, TransportException { | |||
return new SshFetchConnection(refSpecs, additionalPatterns); | |||
} | |||
/** {@inheritDoc} */ | |||
@Override | |||
public PushConnection openPush() throws TransportException { | |||
@@ -205,38 +196,29 @@ public class TransportGitSsh extends SshTransport implements PackTransport { | |||
return SystemReader.getInstance().getenv("GIT_SSH") != null; //$NON-NLS-1$ | |||
} | |||
private class ExtSession implements RemoteSession2 { | |||
private class ExtSession implements RemoteSession { | |||
@Override | |||
public Process exec(String command, int timeout) | |||
throws TransportException { | |||
return exec(command, null, timeout); | |||
} | |||
@Override | |||
public Process exec(String command, Map<String, String> environment, | |||
int timeout) throws TransportException { | |||
String ssh = SystemReader.getInstance().getenv("GIT_SSH"); //$NON-NLS-1$ | |||
boolean putty = ssh.toLowerCase(Locale.ROOT).contains("plink"); //$NON-NLS-1$ | |||
List<String> args = new ArrayList<>(); | |||
args.add(ssh); | |||
if (putty && !ssh.toLowerCase(Locale.ROOT) | |||
.contains("tortoiseplink")) {//$NON-NLS-1$ | |||
if (putty | |||
&& !ssh.toLowerCase(Locale.ROOT).contains("tortoiseplink")) //$NON-NLS-1$ | |||
args.add("-batch"); //$NON-NLS-1$ | |||
} | |||
if (0 < getURI().getPort()) { | |||
args.add(putty ? "-P" : "-p"); //$NON-NLS-1$ //$NON-NLS-2$ | |||
args.add(String.valueOf(getURI().getPort())); | |||
} | |||
if (getURI().getUser() != null) { | |||
if (getURI().getUser() != null) | |||
args.add(getURI().getUser() + "@" + getURI().getHost()); //$NON-NLS-1$ | |||
} else { | |||
else | |||
args.add(getURI().getHost()); | |||
} | |||
args.add(command); | |||
ProcessBuilder pb = createProcess(args, environment); | |||
ProcessBuilder pb = createProcess(args); | |||
try { | |||
return pb.start(); | |||
} catch (IOException err) { | |||
@@ -244,13 +226,9 @@ public class TransportGitSsh extends SshTransport implements PackTransport { | |||
} | |||
} | |||
private ProcessBuilder createProcess(List<String> args, | |||
Map<String, String> environment) { | |||
private ProcessBuilder createProcess(List<String> args) { | |||
ProcessBuilder pb = new ProcessBuilder(); | |||
pb.command(args); | |||
if (environment != null) { | |||
pb.environment().putAll(environment); | |||
} | |||
File directory = local != null ? local.getDirectory() : null; | |||
if (directory != null) { | |||
pb.environment().put(Constants.GIT_DIR_KEY, | |||
@@ -271,31 +249,10 @@ public class TransportGitSsh extends SshTransport implements PackTransport { | |||
private StreamCopyThread errorThread; | |||
SshFetchConnection() throws TransportException { | |||
this(Collections.emptyList()); | |||
} | |||
SshFetchConnection(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) throws TransportException { | |||
super(TransportGitSsh.this); | |||
try { | |||
RemoteSession session = getSession(); | |||
TransferConfig.ProtocolVersion gitProtocol = protocol; | |||
if (gitProtocol == null) { | |||
gitProtocol = TransferConfig.ProtocolVersion.V2; | |||
} | |||
if (session instanceof RemoteSession2 | |||
&& TransferConfig.ProtocolVersion.V2 | |||
.equals(gitProtocol)) { | |||
process = ((RemoteSession2) session).exec( | |||
commandFor(getOptionUploadPack()), Collections | |||
.singletonMap( | |||
GitProtocolConstants.PROTOCOL_ENVIRONMENT_VARIABLE, | |||
GitProtocolConstants.VERSION_2_REQUEST), | |||
getTimeout()); | |||
} else { | |||
process = session.exec(commandFor(getOptionUploadPack()), | |||
getTimeout()); | |||
} | |||
process = getSession().exec(commandFor(getOptionUploadPack()), | |||
getTimeout()); | |||
final MessageWriter msg = new MessageWriter(); | |||
setMessageWriter(msg); | |||
@@ -315,9 +272,7 @@ public class TransportGitSsh extends SshTransport implements PackTransport { | |||
} | |||
try { | |||
if (!readAdvertisedRefs()) { | |||
lsRefs(refSpecs, additionalPatterns); | |||
} | |||
readAdvertisedRefs(); | |||
} catch (NoRemoteRepositoryException notFound) { | |||
final String msgs = getMessages(); | |||
checkExecFailure(process.exitValue(), getOptionUploadPack(), |
@@ -33,8 +33,8 @@ import static org.eclipse.jgit.util.HttpSupport.HDR_WWW_AUTHENTICATE; | |||
import static org.eclipse.jgit.util.HttpSupport.METHOD_GET; | |||
import static org.eclipse.jgit.util.HttpSupport.METHOD_POST; | |||
import java.io.BufferedInputStream; | |||
import java.io.BufferedReader; | |||
import java.io.ByteArrayInputStream; | |||
import java.io.FileNotFoundException; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
@@ -339,15 +339,11 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
@SuppressWarnings("resource") // Closed by caller | |||
private FetchConnection getConnection(HttpConnection c, InputStream in, | |||
String service, Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) throws IOException { | |||
String service) throws IOException { | |||
BaseConnection f; | |||
if (isSmartHttp(c, service)) { | |||
InputStream withMark = in.markSupported() ? in | |||
: new BufferedInputStream(in); | |||
readSmartHeaders(withMark, service); | |||
f = new SmartHttpFetchConnection(withMark, refSpecs, | |||
additionalPatterns); | |||
readSmartHeaders(in, service); | |||
f = new SmartHttpFetchConnection(in); | |||
} else { | |||
// Assume this server doesn't support smart HTTP fetch | |||
// and fall back on dumb object walking. | |||
@@ -361,23 +357,11 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
@Override | |||
public FetchConnection openFetch() throws TransportException, | |||
NotSupportedException { | |||
return openFetch(Collections.emptyList()); | |||
} | |||
@Override | |||
public FetchConnection openFetch(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) | |||
throws NotSupportedException, TransportException { | |||
final String service = SVC_UPLOAD_PACK; | |||
try { | |||
TransferConfig.ProtocolVersion gitProtocol = protocol; | |||
if (gitProtocol == null) { | |||
gitProtocol = TransferConfig.ProtocolVersion.V2; | |||
} | |||
HttpConnection c = connect(service, gitProtocol); | |||
final HttpConnection c = connect(service); | |||
try (InputStream in = openInputStream(c)) { | |||
return getConnection(c, in, service, refSpecs, | |||
additionalPatterns); | |||
return getConnection(c, in, service); | |||
} | |||
} catch (NotSupportedException | TransportException err) { | |||
throw err; | |||
@@ -472,9 +456,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
private PushConnection smartPush(String service, HttpConnection c, | |||
InputStream in) throws IOException, TransportException { | |||
BufferedInputStream inBuf = new BufferedInputStream(in); | |||
readSmartHeaders(inBuf, service); | |||
SmartHttpPushConnection p = new SmartHttpPushConnection(inBuf); | |||
readSmartHeaders(in, service); | |||
SmartHttpPushConnection p = new SmartHttpPushConnection(in); | |||
p.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER)); | |||
return p; | |||
} | |||
@@ -511,12 +494,6 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
private HttpConnection connect(String service) | |||
throws TransportException, NotSupportedException { | |||
return connect(service, null); | |||
} | |||
private HttpConnection connect(String service, | |||
TransferConfig.ProtocolVersion protocolVersion) | |||
throws TransportException, NotSupportedException { | |||
URL u = getServiceURL(service); | |||
int authAttempts = 1; | |||
int redirects = 0; | |||
@@ -530,11 +507,6 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
} else { | |||
conn.setRequestProperty(HDR_ACCEPT, "*/*"); //$NON-NLS-1$ | |||
} | |||
if (TransferConfig.ProtocolVersion.V2.equals(protocolVersion)) { | |||
conn.setRequestProperty( | |||
GitProtocolConstants.PROTOCOL_HEADER, | |||
GitProtocolConstants.VERSION_2_REQUEST); | |||
} | |||
final int status = HttpSupport.response(conn); | |||
processResponseCookies(conn); | |||
switch (status) { | |||
@@ -1176,37 +1148,20 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
private void readSmartHeaders(InputStream in, String service) | |||
throws IOException { | |||
// A smart protocol V0 reply will have a '#' after the first 4 bytes, | |||
// but a dumb reply cannot contain a '#' until after byte 41. Do a | |||
// A smart reply will have a '#' after the first 4 bytes, but | |||
// a dumb reply cannot contain a '#' until after byte 41. Do a | |||
// quick check to make sure its a smart reply before we parse | |||
// as a pkt-line stream. | |||
// | |||
// There appears to be a confusion about this in protocol V2. Github | |||
// sends the # service line as a git (not http) header also when | |||
// protocol V2 is used. Gitlab also does so. JGit's UploadPack doesn't, | |||
// and thus Gerrit also does not. | |||
final byte[] magic = new byte[14]; | |||
if (!in.markSupported()) { | |||
throw new TransportException(uri, | |||
JGitText.get().inputStreamMustSupportMark); | |||
} | |||
in.mark(14); | |||
final byte[] magic = new byte[5]; | |||
IO.readFully(in, magic, 0, magic.length); | |||
// Did we get 000dversion 2 or similar? (Canonical is 000eversion 2\n, | |||
// but JGit and thus Gerrit omits the \n.) | |||
if (Arrays.equals(Arrays.copyOfRange(magic, 4, 11), | |||
"version".getBytes()) && magic[12] >= '1' && magic[12] <= '9') { //$NON-NLS-1$ | |||
// It's a smart server doing version 1 or greater, but not sending | |||
// the # service line header. Don't consume the version line. | |||
in.reset(); | |||
return; | |||
} | |||
if (magic[4] != '#') { | |||
throw new TransportException(uri, MessageFormat.format( | |||
JGitText.get().expectedPktLineWithService, RawParseUtils.decode(magic))); | |||
} | |||
in.reset(); | |||
final PacketLineIn pckIn = new PacketLineIn(in); | |||
final PacketLineIn pckIn = new PacketLineIn(new UnionInputStream( | |||
new ByteArrayInputStream(magic), in)); | |||
final String exp = "# service=" + service; //$NON-NLS-1$ | |||
final String act = pckIn.readString(); | |||
if (!exp.equals(act)) { | |||
@@ -1372,24 +1327,12 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
SmartHttpFetchConnection(InputStream advertisement) | |||
throws TransportException { | |||
this(advertisement, Collections.emptyList()); | |||
} | |||
SmartHttpFetchConnection(InputStream advertisement, | |||
Collection<RefSpec> refSpecs, String... additionalPatterns) | |||
throws TransportException { | |||
super(TransportHttp.this); | |||
statelessRPC = true; | |||
init(advertisement, DisabledOutputStream.INSTANCE); | |||
outNeedsEnd = false; | |||
if (!readAdvertisedRefs()) { | |||
// Must be protocol V2 | |||
LongPollService service = new LongPollService(SVC_UPLOAD_PACK, | |||
getProtocolVersion()); | |||
init(service.getInputStream(), service.getOutputStream()); | |||
lsRefs(refSpecs, additionalPatterns); | |||
} | |||
readAdvertisedRefs(); | |||
} | |||
@Override | |||
@@ -1397,8 +1340,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
final Collection<Ref> want, final Set<ObjectId> have, | |||
final OutputStream outputStream) throws TransportException { | |||
try { | |||
svc = new MultiRequestService(SVC_UPLOAD_PACK, | |||
getProtocolVersion()); | |||
svc = new MultiRequestService(SVC_UPLOAD_PACK); | |||
init(svc.getInputStream(), svc.getOutputStream()); | |||
super.doFetch(monitor, want, have, outputStream); | |||
} finally { | |||
@@ -1427,8 +1369,7 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
protected void doPush(final ProgressMonitor monitor, | |||
final Map<String, RemoteRefUpdate> refUpdates, | |||
OutputStream outputStream) throws TransportException { | |||
final Service svc = new MultiRequestService(SVC_RECEIVE_PACK, | |||
getProtocolVersion()); | |||
final Service svc = new MultiRequestService(SVC_RECEIVE_PACK); | |||
init(svc.getInputStream(), svc.getOutputStream()); | |||
super.doPush(monitor, refUpdates, outputStream); | |||
} | |||
@@ -1448,14 +1389,10 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
protected final HttpExecuteStream execute; | |||
protected final TransferConfig.ProtocolVersion protocolVersion; | |||
final UnionInputStream in; | |||
Service(String serviceName, | |||
TransferConfig.ProtocolVersion protocolVersion) { | |||
Service(String serviceName) { | |||
this.serviceName = serviceName; | |||
this.protocolVersion = protocolVersion; | |||
this.requestType = "application/x-" + serviceName + "-request"; //$NON-NLS-1$ //$NON-NLS-2$ | |||
this.responseType = "application/x-" + serviceName + "-result"; //$NON-NLS-1$ //$NON-NLS-2$ | |||
@@ -1471,10 +1408,6 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
conn.setDoOutput(true); | |||
conn.setRequestProperty(HDR_CONTENT_TYPE, requestType); | |||
conn.setRequestProperty(HDR_ACCEPT, responseType); | |||
if (TransferConfig.ProtocolVersion.V2.equals(protocolVersion)) { | |||
conn.setRequestProperty(GitProtocolConstants.PROTOCOL_HEADER, | |||
GitProtocolConstants.VERSION_2_REQUEST); | |||
} | |||
} | |||
void sendRequest() throws IOException { | |||
@@ -1730,9 +1663,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
class MultiRequestService extends Service { | |||
boolean finalRequest; | |||
MultiRequestService(String serviceName, | |||
TransferConfig.ProtocolVersion protocolVersion) { | |||
super(serviceName, protocolVersion); | |||
MultiRequestService(String serviceName) { | |||
super(serviceName); | |||
} | |||
/** Keep opening send-receive pairs to the given URI. */ | |||
@@ -1769,10 +1701,11 @@ public class TransportHttp extends HttpTransport implements WalkTransport, | |||
/** Service for maintaining a single long-poll connection. */ | |||
class LongPollService extends Service { | |||
LongPollService(String serviceName, | |||
TransferConfig.ProtocolVersion protocolVersion) { | |||
super(serviceName, protocolVersion); | |||
/** | |||
* @param serviceName | |||
*/ | |||
LongPollService(String serviceName) { | |||
super(serviceName); | |||
} | |||
/** Only open one send-receive request. */ |
@@ -20,7 +20,6 @@ import java.io.File; | |||
import java.io.IOException; | |||
import java.io.InputStream; | |||
import java.io.OutputStream; | |||
import java.util.Collection; | |||
import java.util.Collections; | |||
import java.util.Map; | |||
import java.util.Set; | |||
@@ -154,17 +153,11 @@ class TransportLocal extends Transport implements PackTransport { | |||
/** {@inheritDoc} */ | |||
@Override | |||
public FetchConnection openFetch() throws TransportException { | |||
return openFetch(Collections.emptyList()); | |||
} | |||
@Override | |||
public FetchConnection openFetch(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) throws TransportException { | |||
final String up = getOptionUploadPack(); | |||
if (!"git-upload-pack".equals(up) //$NON-NLS-1$ | |||
&& !"git upload-pack".equals(up)) {//$NON-NLS-1$ | |||
return new ForkLocalFetchConnection(refSpecs, additionalPatterns); | |||
} | |||
&& !"git upload-pack".equals(up)) //$NON-NLS-1$ | |||
return new ForkLocalFetchConnection(); | |||
UploadPackFactory<Void> upf = (Void req, | |||
Repository db) -> createUploadPack(db); | |||
return new InternalFetchConnection<>(this, upf, null, openRepo()); | |||
@@ -200,23 +193,6 @@ class TransportLocal extends Transport implements PackTransport { | |||
*/ | |||
protected Process spawn(String cmd) | |||
throws TransportException { | |||
return spawn(cmd, null); | |||
} | |||
/** | |||
* Spawn process | |||
* | |||
* @param cmd | |||
* command | |||
* @param protocolVersion | |||
* to use | |||
* @return a {@link java.lang.Process} object. | |||
* @throws org.eclipse.jgit.errors.TransportException | |||
* if any. | |||
*/ | |||
private Process spawn(String cmd, | |||
TransferConfig.ProtocolVersion protocolVersion) | |||
throws TransportException { | |||
try { | |||
String[] args = { "." }; //$NON-NLS-1$ | |||
ProcessBuilder proc = local.getFS().runInShell(cmd, args); | |||
@@ -232,10 +208,7 @@ class TransportLocal extends Transport implements PackTransport { | |||
env.remove("GIT_GRAFT_FILE"); //$NON-NLS-1$ | |||
env.remove("GIT_INDEX_FILE"); //$NON-NLS-1$ | |||
env.remove("GIT_NO_REPLACE_OBJECTS"); //$NON-NLS-1$ | |||
if (TransferConfig.ProtocolVersion.V2.equals(protocolVersion)) { | |||
env.put(GitProtocolConstants.PROTOCOL_ENVIRONMENT_VARIABLE, | |||
GitProtocolConstants.VERSION_2_REQUEST); | |||
} | |||
return proc.start(); | |||
} catch (IOException err) { | |||
throw new TransportException(uri, err.getMessage(), err); | |||
@@ -248,21 +221,12 @@ class TransportLocal extends Transport implements PackTransport { | |||
private Thread errorReaderThread; | |||
ForkLocalFetchConnection() throws TransportException { | |||
this(Collections.emptyList()); | |||
} | |||
ForkLocalFetchConnection(Collection<RefSpec> refSpecs, | |||
String... additionalPatterns) throws TransportException { | |||
super(TransportLocal.this); | |||
final MessageWriter msg = new MessageWriter(); | |||
setMessageWriter(msg); | |||
TransferConfig.ProtocolVersion gitProtocol = protocol; | |||
if (gitProtocol == null) { | |||
gitProtocol = TransferConfig.ProtocolVersion.V2; | |||
} | |||
uploadPack = spawn(getOptionUploadPack(), gitProtocol); | |||
uploadPack = spawn(getOptionUploadPack()); | |||
final InputStream upErr = uploadPack.getErrorStream(); | |||
errorReaderThread = new StreamCopyThread(upErr, msg.getRawStream()); | |||
@@ -275,9 +239,7 @@ class TransportLocal extends Transport implements PackTransport { | |||
upOut = new BufferedOutputStream(upOut); | |||
init(upIn, upOut); | |||
if (!readAdvertisedRefs()) { | |||
lsRefs(refSpecs, additionalPatterns); | |||
} | |||
readAdvertisedRefs(); | |||
} | |||
@Override |
@@ -33,7 +33,6 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDEBAND_AL | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK; | |||
import static org.eclipse.jgit.transport.GitProtocolConstants.VERSION_2_REQUEST; | |||
import static org.eclipse.jgit.util.RefMap.toRefMap; | |||
import java.io.ByteArrayOutputStream; | |||
@@ -710,7 +709,7 @@ public class UploadPack { | |||
* @since 5.0 | |||
*/ | |||
public void setExtraParameters(Collection<String> params) { | |||
this.clientRequestedV2 = params.contains(VERSION_2_REQUEST); | |||
this.clientRequestedV2 = params.contains("version=2"); //$NON-NLS-1$ | |||
} | |||
/** | |||
@@ -1195,8 +1194,7 @@ public class UploadPack { | |||
new PacketLineOut(NullOutputStream.INSTANCE), | |||
accumulator); | |||
} else { | |||
pckOut.writeString( | |||
GitProtocolConstants.SECTION_ACKNOWLEDGMENTS + '\n'); | |||
pckOut.writeString("acknowledgments\n"); //$NON-NLS-1$ | |||
for (ObjectId id : req.getPeerHas()) { | |||
if (walk.getObjectReader().has(id)) { | |||
pckOut.writeString("ACK " + id.getName() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ | |||
@@ -1245,8 +1243,7 @@ public class UploadPack { | |||
if (!pckOut.isUsingSideband()) { | |||
// sendPack will write "packfile\n" for us if sideband-all is used. | |||
// But sideband-all is not used, so we have to write it ourselves. | |||
pckOut.writeString( | |||
GitProtocolConstants.SECTION_PACKFILE + '\n'); | |||
pckOut.writeString("packfile\n"); //$NON-NLS-1$ | |||
} | |||
accumulator.timeNegotiating = Duration | |||
@@ -2330,8 +2327,7 @@ public class UploadPack { | |||
// for us if provided a PackfileUriConfig. In this case, we | |||
// are not providing a PackfileUriConfig, so we have to | |||
// write this line ourselves. | |||
pckOut.writeString( | |||
GitProtocolConstants.SECTION_PACKFILE + '\n'); | |||
pckOut.writeString("packfile\n"); //$NON-NLS-1$ | |||
} | |||
} | |||
pw.writePack(pm, NullProgressMonitor.INSTANCE, packOut); |