Revert "Client-side protocol V2 support for fetching"
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>
This commit is contained in:
parent
5dcc46591a
commit
d69fb4d4ac
|
@ -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.Transport;
|
import org.eclipse.jgit.transport.Transport;
|
||||||
import org.eclipse.jgit.transport.TransportHttp;
|
import org.eclipse.jgit.transport.TransportHttp;
|
||||||
import org.eclipse.jgit.transport.URIish;
|
import org.eclipse.jgit.transport.URIish;
|
||||||
|
import org.eclipse.jgit.transport.http.HttpConnectionFactory;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class DumbClientDumbServerTest extends AllProtocolsHttpTestCase {
|
public class DumbClientDumbServerTest extends AllFactoriesHttpTestCase {
|
||||||
private Repository remoteRepository;
|
private Repository remoteRepository;
|
||||||
|
|
||||||
private URIish remoteURI;
|
private URIish remoteURI;
|
||||||
|
@ -54,8 +55,8 @@ public class DumbClientDumbServerTest extends AllProtocolsHttpTestCase {
|
||||||
|
|
||||||
private RevCommit A, B;
|
private RevCommit A, B;
|
||||||
|
|
||||||
public DumbClientDumbServerTest(TestParameters params) {
|
public DumbClientDumbServerTest(HttpConnectionFactory cf) {
|
||||||
super(params);
|
super(cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,9 +77,6 @@ public void setUp() throws Exception {
|
||||||
|
|
||||||
remoteRepository = src.getRepository();
|
remoteRepository = src.getRepository();
|
||||||
remoteURI = toURIish(app, srcGit.getName());
|
remoteURI = toURIish(app, srcGit.getName());
|
||||||
if (enableProtocolV2) {
|
|
||||||
remoteRepository.getConfig().setInt("protocol", null, "version", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
A_txt = src.blob("A");
|
A_txt = src.blob("A");
|
||||||
A = src.commit().add("A_txt", A_txt).create();
|
A = src.commit().add("A_txt", A_txt).create();
|
||||||
|
|
|
@ -42,10 +42,11 @@
|
||||||
import org.eclipse.jgit.transport.Transport;
|
import org.eclipse.jgit.transport.Transport;
|
||||||
import org.eclipse.jgit.transport.TransportHttp;
|
import org.eclipse.jgit.transport.TransportHttp;
|
||||||
import org.eclipse.jgit.transport.URIish;
|
import org.eclipse.jgit.transport.URIish;
|
||||||
|
import org.eclipse.jgit.transport.http.HttpConnectionFactory;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class DumbClientSmartServerTest extends AllProtocolsHttpTestCase {
|
public class DumbClientSmartServerTest extends AllFactoriesHttpTestCase {
|
||||||
private Repository remoteRepository;
|
private Repository remoteRepository;
|
||||||
|
|
||||||
private URIish remoteURI;
|
private URIish remoteURI;
|
||||||
|
@ -54,8 +55,8 @@ public class DumbClientSmartServerTest extends AllProtocolsHttpTestCase {
|
||||||
|
|
||||||
private RevCommit A, B;
|
private RevCommit A, B;
|
||||||
|
|
||||||
public DumbClientSmartServerTest(TestParameters params) {
|
public DumbClientSmartServerTest(HttpConnectionFactory cf) {
|
||||||
super(params);
|
super(cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -75,9 +76,6 @@ public void setUp() throws Exception {
|
||||||
|
|
||||||
remoteRepository = src.getRepository();
|
remoteRepository = src.getRepository();
|
||||||
remoteURI = toURIish(app, srcName);
|
remoteURI = toURIish(app, srcName);
|
||||||
if (enableProtocolV2) {
|
|
||||||
remoteRepository.getConfig().setInt("protocol", null, "version", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
A_txt = src.blob("A");
|
A_txt = src.blob("A");
|
||||||
A = src.commit().add("A_txt", A_txt).create();
|
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
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
@ -48,6 +48,7 @@
|
||||||
import org.eclipse.jgit.transport.Transport;
|
import org.eclipse.jgit.transport.Transport;
|
||||||
import org.eclipse.jgit.transport.URIish;
|
import org.eclipse.jgit.transport.URIish;
|
||||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||||
|
import org.eclipse.jgit.transport.http.HttpConnectionFactory;
|
||||||
import org.eclipse.jgit.util.HttpSupport;
|
import org.eclipse.jgit.util.HttpSupport;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -55,7 +56,7 @@
|
||||||
import org.junit.runners.Parameterized;
|
import org.junit.runners.Parameterized;
|
||||||
|
|
||||||
@RunWith(Parameterized.class)
|
@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
|
// 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
|
// certificate. We don't do authentication tests here, so there's no need
|
||||||
|
@ -111,8 +112,8 @@ public boolean get(URIish uri, CredentialItem... items)
|
||||||
|
|
||||||
private RevCommit A, B;
|
private RevCommit A, B;
|
||||||
|
|
||||||
public SmartClientSmartServerSslTest(TestParameters params) {
|
public SmartClientSmartServerSslTest(HttpConnectionFactory cf) {
|
||||||
super(params);
|
super(cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,10 +132,6 @@ public void setUp() throws Exception {
|
||||||
.getConfig()
|
.getConfig()
|
||||||
.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
|
.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
|
||||||
ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
|
ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
|
||||||
if (enableProtocolV2) {
|
|
||||||
src.getRepository().getConfig().setInt("protocol", null, "version",
|
|
||||||
2);
|
|
||||||
}
|
|
||||||
|
|
||||||
GitServlet gs = new GitServlet();
|
GitServlet gs = new GitServlet();
|
||||||
|
|
||||||
|
@ -241,7 +238,7 @@ public void testInitialClone_ViaHttps() throws Exception {
|
||||||
fsck(dst, B);
|
fsck(dst, B);
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
|
assertEquals(2, requests.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -259,7 +256,7 @@ public void testInitialClone_RedirectToHttps() throws Exception {
|
||||||
fsck(dst, B);
|
fsck(dst, B);
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
|
assertEquals(3, requests.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@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
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
* terms of the Eclipse Distribution License v. 1.0 which is available at
|
||||||
|
@ -86,12 +86,13 @@
|
||||||
import org.eclipse.jgit.transport.URIish;
|
import org.eclipse.jgit.transport.URIish;
|
||||||
import org.eclipse.jgit.transport.UploadPack;
|
import org.eclipse.jgit.transport.UploadPack;
|
||||||
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
|
||||||
|
import org.eclipse.jgit.transport.http.HttpConnectionFactory;
|
||||||
import org.eclipse.jgit.util.HttpSupport;
|
import org.eclipse.jgit.util.HttpSupport;
|
||||||
import org.eclipse.jgit.util.SystemReader;
|
import org.eclipse.jgit.util.SystemReader;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase {
|
public class SmartClientSmartServerTest extends AllFactoriesHttpTestCase {
|
||||||
private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding";
|
private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding";
|
||||||
|
|
||||||
private AdvertiseRefsHook advertiseRefsHook;
|
private AdvertiseRefsHook advertiseRefsHook;
|
||||||
|
@ -119,8 +120,8 @@ public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase {
|
||||||
|
|
||||||
private RevCommit A, B, unreachableCommit;
|
private RevCommit A, B, unreachableCommit;
|
||||||
|
|
||||||
public SmartClientSmartServerTest(TestParameters params) {
|
public SmartClientSmartServerTest(HttpConnectionFactory cf) {
|
||||||
super(params);
|
super(cf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -131,12 +132,9 @@ public void setUp() throws Exception {
|
||||||
final TestRepository<Repository> src = createTestRepository();
|
final TestRepository<Repository> src = createTestRepository();
|
||||||
final String srcName = src.getRepository().getDirectory().getName();
|
final String srcName = src.getRepository().getDirectory().getName();
|
||||||
src.getRepository()
|
src.getRepository()
|
||||||
.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION,
|
.getConfig()
|
||||||
null, ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES,
|
.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
|
||||||
true);
|
ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
|
||||||
if (enableProtocolV2) {
|
|
||||||
src.getRepository().getConfig().setInt("protocol", null, "version", 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
GitServlet gs = new GitServlet();
|
GitServlet gs = new GitServlet();
|
||||||
gs.setUploadPackFactory((HttpServletRequest req, Repository db) -> {
|
gs.setUploadPackFactory((HttpServletRequest req, Repository db) -> {
|
||||||
|
@ -450,7 +448,7 @@ public void testListRemote() throws IOException {
|
||||||
assertEquals(B, map.get(Constants.HEAD).getObjectId());
|
assertEquals(B, map.get(Constants.HEAD).getObjectId());
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 2 : 1, requests.size());
|
assertEquals(1, requests.size());
|
||||||
|
|
||||||
AccessEvent info = requests.get(0);
|
AccessEvent info = requests.get(0);
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
|
@ -460,22 +458,7 @@ public void testListRemote() throws IOException {
|
||||||
assertEquals(200, info.getStatus());
|
assertEquals(200, info.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-advertisement", info
|
assertEquals("application/x-git-upload-pack-advertisement", info
|
||||||
.getResponseHeader(HDR_CONTENT_TYPE));
|
.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
if (!enableProtocolV2) {
|
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
|
||||||
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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -593,10 +576,9 @@ public void testInitialClone_Small() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
|
assertEquals(2, requests.size());
|
||||||
|
|
||||||
int requestNumber = 0;
|
AccessEvent info = requests.get(0);
|
||||||
AccessEvent info = requests.get(requestNumber++);
|
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
assertEquals(join(remoteURI, "info/refs"), info.getPath());
|
assertEquals(join(remoteURI, "info/refs"), info.getPath());
|
||||||
assertEquals(1, info.getParameters().size());
|
assertEquals(1, info.getParameters().size());
|
||||||
|
@ -604,24 +586,9 @@ public void testInitialClone_Small() throws Exception {
|
||||||
assertEquals(200, info.getStatus());
|
assertEquals(200, info.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-advertisement", info
|
assertEquals("application/x-git-upload-pack-advertisement", info
|
||||||
.getResponseHeader(HDR_CONTENT_TYPE));
|
.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
if (!enableProtocolV2) {
|
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessEvent service = requests.get(requestNumber);
|
AccessEvent service = requests.get(1);
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(0, service.getParameters().size());
|
assertEquals(0, service.getParameters().size());
|
||||||
|
@ -661,8 +628,7 @@ private void initialClone_Redirect(int nofRedirects, int code,
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals((enableProtocolV2 ? 3 : 2) + nofRedirects,
|
assertEquals(2 + nofRedirects, requests.size());
|
||||||
requests.size());
|
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
while (n < nofRedirects) {
|
while (n < nofRedirects) {
|
||||||
|
@ -678,22 +644,7 @@ private void initialClone_Redirect(int nofRedirects, int code,
|
||||||
assertEquals(200, info.getStatus());
|
assertEquals(200, info.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-advertisement",
|
assertEquals("application/x-git-upload-pack-advertisement",
|
||||||
info.getResponseHeader(HDR_CONTENT_TYPE));
|
info.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
if (!enableProtocolV2) {
|
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessEvent service = requests.get(n++);
|
AccessEvent service = requests.get(n++);
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals("POST", service.getMethod());
|
||||||
|
@ -805,7 +756,7 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
|
assertEquals(3, requests.size());
|
||||||
|
|
||||||
AccessEvent info = requests.get(0);
|
AccessEvent info = requests.get(0);
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
|
@ -815,27 +766,24 @@ public void testInitialClone_RedirectOnPostAllowed() throws Exception {
|
||||||
assertEquals(200, info.getStatus());
|
assertEquals(200, info.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-advertisement",
|
assertEquals("application/x-git-upload-pack-advertisement",
|
||||||
info.getResponseHeader(HDR_CONTENT_TYPE));
|
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);
|
AccessEvent redirect = requests.get(1);
|
||||||
assertEquals("POST", redirect.getMethod());
|
assertEquals("POST", redirect.getMethod());
|
||||||
assertEquals(301, redirect.getStatus());
|
assertEquals(301, redirect.getStatus());
|
||||||
|
|
||||||
for (int i = 2; i < requests.size(); i++) {
|
AccessEvent service = requests.get(2);
|
||||||
AccessEvent service = requests.get(i);
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
assertEquals(0, service.getParameters().size());
|
||||||
assertEquals(0, service.getParameters().size());
|
assertNotNull("has content-length",
|
||||||
assertNotNull("has content-length",
|
service.getRequestHeader(HDR_CONTENT_LENGTH));
|
||||||
service.getRequestHeader(HDR_CONTENT_LENGTH));
|
assertNull("not chunked",
|
||||||
assertNull("not chunked",
|
service.getRequestHeader(HDR_TRANSFER_ENCODING));
|
||||||
service.getRequestHeader(HDR_TRANSFER_ENCODING));
|
|
||||||
assertEquals(200, service.getStatus());
|
assertEquals(200, service.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-result",
|
assertEquals("application/x-git-upload-pack-result",
|
||||||
service.getResponseHeader(HDR_CONTENT_TYPE));
|
service.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -882,7 +830,7 @@ public void testInitialClone_WithAuthentication() throws Exception {
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
|
assertEquals(3, requests.size());
|
||||||
|
|
||||||
AccessEvent info = requests.get(0);
|
AccessEvent info = requests.get(0);
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
|
@ -896,24 +844,20 @@ public void testInitialClone_WithAuthentication() throws Exception {
|
||||||
assertEquals(200, info.getStatus());
|
assertEquals(200, info.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-advertisement",
|
assertEquals("application/x-git-upload-pack-advertisement",
|
||||||
info.getResponseHeader(HDR_CONTENT_TYPE));
|
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(2);
|
||||||
AccessEvent service = requests.get(i);
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals(join(authURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(join(authURI, "git-upload-pack"), service.getPath());
|
assertEquals(0, service.getParameters().size());
|
||||||
assertEquals(0, service.getParameters().size());
|
assertNotNull("has content-length",
|
||||||
assertNotNull("has content-length",
|
service.getRequestHeader(HDR_CONTENT_LENGTH));
|
||||||
service.getRequestHeader(HDR_CONTENT_LENGTH));
|
assertNull("not chunked",
|
||||||
assertNull("not chunked",
|
service.getRequestHeader(HDR_TRANSFER_ENCODING));
|
||||||
service.getRequestHeader(HDR_TRANSFER_ENCODING));
|
|
||||||
|
|
||||||
assertEquals(200, service.getStatus());
|
assertEquals(200, service.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-result",
|
assertEquals("application/x-git-upload-pack-result",
|
||||||
service.getResponseHeader(HDR_CONTENT_TYPE));
|
service.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -993,20 +937,19 @@ public boolean get(URIish uri, CredentialItem... items)
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 5 : 4, requests.size());
|
assertEquals(4, requests.size());
|
||||||
|
|
||||||
int requestNumber = 0;
|
AccessEvent redirect = requests.get(0);
|
||||||
AccessEvent redirect = requests.get(requestNumber++);
|
|
||||||
assertEquals("GET", redirect.getMethod());
|
assertEquals("GET", redirect.getMethod());
|
||||||
assertEquals(join(cloneFrom, "info/refs"), redirect.getPath());
|
assertEquals(join(cloneFrom, "info/refs"), redirect.getPath());
|
||||||
assertEquals(301, redirect.getStatus());
|
assertEquals(301, redirect.getStatus());
|
||||||
|
|
||||||
AccessEvent info = requests.get(requestNumber++);
|
AccessEvent info = requests.get(1);
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
assertEquals(join(authURI, "info/refs"), info.getPath());
|
assertEquals(join(authURI, "info/refs"), info.getPath());
|
||||||
assertEquals(401, info.getStatus());
|
assertEquals(401, info.getStatus());
|
||||||
|
|
||||||
info = requests.get(requestNumber++);
|
info = requests.get(2);
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
assertEquals(join(authURI, "info/refs"), info.getPath());
|
assertEquals(join(authURI, "info/refs"), info.getPath());
|
||||||
assertEquals(1, info.getParameters().size());
|
assertEquals(1, info.getParameters().size());
|
||||||
|
@ -1014,24 +957,9 @@ public boolean get(URIish uri, CredentialItem... items)
|
||||||
assertEquals(200, info.getStatus());
|
assertEquals(200, info.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-advertisement",
|
assertEquals("application/x-git-upload-pack-advertisement",
|
||||||
info.getResponseHeader(HDR_CONTENT_TYPE));
|
info.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
if (!enableProtocolV2) {
|
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessEvent service = requests.get(requestNumber);
|
AccessEvent service = requests.get(3);
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals(join(authURI, "git-upload-pack"), service.getPath());
|
assertEquals(join(authURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(0, service.getParameters().size());
|
assertEquals(0, service.getParameters().size());
|
||||||
|
@ -1059,7 +987,7 @@ public void testInitialClone_WithAuthenticationOnPostOnly()
|
||||||
}
|
}
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
|
assertEquals(3, requests.size());
|
||||||
|
|
||||||
AccessEvent info = requests.get(0);
|
AccessEvent info = requests.get(0);
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
|
@ -1069,30 +997,25 @@ public void testInitialClone_WithAuthenticationOnPostOnly()
|
||||||
assertEquals(200, info.getStatus());
|
assertEquals(200, info.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-advertisement",
|
assertEquals("application/x-git-upload-pack-advertisement",
|
||||||
info.getResponseHeader(HDR_CONTENT_TYPE));
|
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);
|
AccessEvent service = requests.get(1);
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
|
assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(401, service.getStatus());
|
assertEquals(401, service.getStatus());
|
||||||
|
|
||||||
for (int i = 2; i < requests.size(); i++) {
|
service = requests.get(2);
|
||||||
service = requests.get(i);
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(join(authOnPostURI, "git-upload-pack"),
|
assertEquals(0, service.getParameters().size());
|
||||||
service.getPath());
|
assertNotNull("has content-length",
|
||||||
assertEquals(0, service.getParameters().size());
|
service.getRequestHeader(HDR_CONTENT_LENGTH));
|
||||||
assertNotNull("has content-length",
|
assertNull("not chunked",
|
||||||
service.getRequestHeader(HDR_CONTENT_LENGTH));
|
service.getRequestHeader(HDR_TRANSFER_ENCODING));
|
||||||
assertNull("not chunked",
|
|
||||||
service.getRequestHeader(HDR_TRANSFER_ENCODING));
|
|
||||||
|
|
||||||
assertEquals(200, service.getStatus());
|
assertEquals(200, service.getStatus());
|
||||||
assertEquals("application/x-git-upload-pack-result",
|
assertEquals("application/x-git-upload-pack-result",
|
||||||
service.getResponseHeader(HDR_CONTENT_TYPE));
|
service.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1129,11 +1052,9 @@ public void testFetch_FewLocalCommits() throws Exception {
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
requests.removeAll(cloneRequests);
|
requests.removeAll(cloneRequests);
|
||||||
|
assertEquals(2, requests.size());
|
||||||
|
|
||||||
assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
|
AccessEvent info = requests.get(0);
|
||||||
|
|
||||||
int requestNumber = 0;
|
|
||||||
AccessEvent info = requests.get(requestNumber++);
|
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
assertEquals(join(remoteURI, "info/refs"), info.getPath());
|
assertEquals(join(remoteURI, "info/refs"), info.getPath());
|
||||||
assertEquals(1, info.getParameters().size());
|
assertEquals(1, info.getParameters().size());
|
||||||
|
@ -1142,24 +1063,9 @@ public void testFetch_FewLocalCommits() throws Exception {
|
||||||
assertEquals("application/x-git-upload-pack-advertisement",
|
assertEquals("application/x-git-upload-pack-advertisement",
|
||||||
info.getResponseHeader(HDR_CONTENT_TYPE));
|
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.
|
// 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("POST", service.getMethod());
|
||||||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(0, service.getParameters().size());
|
assertEquals(0, service.getParameters().size());
|
||||||
|
@ -1210,10 +1116,9 @@ public void testFetch_TooManyLocalCommits() throws Exception {
|
||||||
|
|
||||||
List<AccessEvent> requests = getRequests();
|
List<AccessEvent> requests = getRequests();
|
||||||
requests.removeAll(cloneRequests);
|
requests.removeAll(cloneRequests);
|
||||||
assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
|
assertEquals(3, requests.size());
|
||||||
|
|
||||||
int requestNumber = 0;
|
AccessEvent info = requests.get(0);
|
||||||
AccessEvent info = requests.get(requestNumber++);
|
|
||||||
assertEquals("GET", info.getMethod());
|
assertEquals("GET", info.getMethod());
|
||||||
assertEquals(join(remoteURI, "info/refs"), info.getPath());
|
assertEquals(join(remoteURI, "info/refs"), info.getPath());
|
||||||
assertEquals(1, info.getParameters().size());
|
assertEquals(1, info.getParameters().size());
|
||||||
|
@ -1222,25 +1127,10 @@ public void testFetch_TooManyLocalCommits() throws Exception {
|
||||||
assertEquals("application/x-git-upload-pack-advertisement", info
|
assertEquals("application/x-git-upload-pack-advertisement", info
|
||||||
.getResponseHeader(HDR_CONTENT_TYPE));
|
.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
|
// We should have needed two requests to perform the fetch
|
||||||
// due to the high number of local unknown commits.
|
// due to the high number of local unknown commits.
|
||||||
//
|
//
|
||||||
AccessEvent service = requests.get(requestNumber++);
|
AccessEvent service = requests.get(1);
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(0, service.getParameters().size());
|
assertEquals(0, service.getParameters().size());
|
||||||
|
@ -1253,7 +1143,7 @@ public void testFetch_TooManyLocalCommits() throws Exception {
|
||||||
assertEquals("application/x-git-upload-pack-result", service
|
assertEquals("application/x-git-upload-pack-result", service
|
||||||
.getResponseHeader(HDR_CONTENT_TYPE));
|
.getResponseHeader(HDR_CONTENT_TYPE));
|
||||||
|
|
||||||
service = requests.get(requestNumber);
|
service = requests.get(2);
|
||||||
assertEquals("POST", service.getMethod());
|
assertEquals("POST", service.getMethod());
|
||||||
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
|
||||||
assertEquals(0, service.getParameters().size());
|
assertEquals(0, service.getParameters().size());
|
||||||
|
@ -1539,4 +1429,5 @@ private void enableReceivePack() throws IOException {
|
||||||
cfg.setBoolean("http", null, "receivepack", true);
|
cfg.setBoolean("http", null, "receivepack", true);
|
||||||
cfg.save();
|
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.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
@ -54,7 +53,7 @@
|
||||||
import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
|
import org.eclipse.jgit.internal.transport.sshd.JGitSshClient;
|
||||||
import org.eclipse.jgit.internal.transport.sshd.SshdText;
|
import org.eclipse.jgit.internal.transport.sshd.SshdText;
|
||||||
import org.eclipse.jgit.transport.FtpChannel;
|
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.SshConstants;
|
||||||
import org.eclipse.jgit.transport.URIish;
|
import org.eclipse.jgit.transport.URIish;
|
||||||
import org.eclipse.jgit.util.StringUtils;
|
import org.eclipse.jgit.util.StringUtils;
|
||||||
|
@ -62,12 +61,11 @@
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An implementation of {@link org.eclipse.jgit.transport.RemoteSession
|
* An implementation of {@link RemoteSession} based on Apache MINA sshd.
|
||||||
* RemoteSession} based on Apache MINA sshd.
|
|
||||||
*
|
*
|
||||||
* @since 5.2
|
* @since 5.2
|
||||||
*/
|
*/
|
||||||
public class SshdSession implements RemoteSession2 {
|
public class SshdSession implements RemoteSession {
|
||||||
|
|
||||||
private static final Logger LOG = LoggerFactory
|
private static final Logger LOG = LoggerFactory
|
||||||
.getLogger(SshdSession.class);
|
.getLogger(SshdSession.class);
|
||||||
|
@ -292,15 +290,8 @@ private void notifyCloseListeners() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Process exec(String commandName, int timeout) throws IOException {
|
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")
|
@SuppressWarnings("resource")
|
||||||
ChannelExec exec = session.createExecChannel(commandName, null,
|
ChannelExec exec = session.createExecChannel(commandName);
|
||||||
environment);
|
|
||||||
if (timeout <= 0) {
|
if (timeout <= 0) {
|
||||||
try {
|
try {
|
||||||
exec.open().verify();
|
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.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -46,7 +44,7 @@
|
||||||
* {@link org.eclipse.jgit.transport.JschConfigSessionFactory} is used to create
|
* {@link org.eclipse.jgit.transport.JschConfigSessionFactory} is used to create
|
||||||
* the actual session passed to the constructor.
|
* the actual session passed to the constructor.
|
||||||
*/
|
*/
|
||||||
public class JschSession implements RemoteSession2 {
|
public class JschSession implements RemoteSession {
|
||||||
final Session sock;
|
final Session sock;
|
||||||
final URIish uri;
|
final URIish uri;
|
||||||
|
|
||||||
|
@ -67,14 +65,7 @@ public JschSession(Session session, URIish uri) {
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public Process exec(String command, int timeout) throws IOException {
|
public Process exec(String command, int timeout) throws IOException {
|
||||||
return exec(command, Collections.emptyMap(), timeout);
|
return new JschProcess(command, timeout);
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
|
||||||
@Override
|
|
||||||
public Process exec(String command, Map<String, String> environment,
|
|
||||||
int timeout) throws IOException {
|
|
||||||
return new JschProcess(command, environment, timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
|
@ -133,8 +124,6 @@ private class JschProcess extends Process {
|
||||||
*
|
*
|
||||||
* @param commandName
|
* @param commandName
|
||||||
* the command to execute
|
* the command to execute
|
||||||
* @param environment
|
|
||||||
* environment variables to pass on
|
|
||||||
* @param tms
|
* @param tms
|
||||||
* the timeout value, in seconds, for the command.
|
* the timeout value, in seconds, for the command.
|
||||||
* @throws TransportException
|
* @throws TransportException
|
||||||
|
@ -143,17 +132,11 @@ private class JschProcess extends Process {
|
||||||
* @throws IOException
|
* @throws IOException
|
||||||
* on problems opening streams
|
* on problems opening streams
|
||||||
*/
|
*/
|
||||||
JschProcess(String commandName, Map<String, String> environment,
|
JschProcess(String commandName, int tms)
|
||||||
int tms) throws TransportException, IOException {
|
throws TransportException, IOException {
|
||||||
timeout = tms;
|
timeout = tms;
|
||||||
try {
|
try {
|
||||||
channel = (ChannelExec) sock.openChannel("exec"); //$NON-NLS-1$
|
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);
|
channel.setCommand(commandName);
|
||||||
setupStreams();
|
setupStreams();
|
||||||
channel.connect(timeout > 0 ? timeout * 1000 : 0);
|
channel.connect(timeout > 0 ? timeout * 1000 : 0);
|
||||||
|
|
|
@ -232,7 +232,6 @@ downloadCancelled=Download cancelled
|
||||||
downloadCancelledDuringIndexing=Download cancelled during indexing
|
downloadCancelledDuringIndexing=Download cancelled during indexing
|
||||||
duplicateAdvertisementsOf=duplicate advertisements of {0}
|
duplicateAdvertisementsOf=duplicate advertisements of {0}
|
||||||
duplicateRef=Duplicate ref: {0}
|
duplicateRef=Duplicate ref: {0}
|
||||||
duplicateRefAttribute=Duplicate ref attribute: {0}
|
|
||||||
duplicateRemoteRefUpdateIsIllegal=Duplicate remote ref update is illegal. Affected remote name: {0}
|
duplicateRemoteRefUpdateIsIllegal=Duplicate remote ref update is illegal. Affected remote name: {0}
|
||||||
duplicateStagesNotAllowed=Duplicate stages not allowed
|
duplicateStagesNotAllowed=Duplicate stages not allowed
|
||||||
eitherGitDirOrWorkTreeRequired=One of setGitDir or setWorkTree must be called.
|
eitherGitDirOrWorkTreeRequired=One of setGitDir or setWorkTree must be called.
|
||||||
|
|
|
@ -164,7 +164,7 @@ private Map<String, Ref> execute() throws GitAPIException,
|
||||||
refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$
|
refSpecs.add(new RefSpec("refs/heads/*:refs/remotes/origin/*")); //$NON-NLS-1$
|
||||||
Collection<Ref> refs;
|
Collection<Ref> refs;
|
||||||
Map<String, Ref> refmap = new HashMap<>();
|
Map<String, Ref> refmap = new HashMap<>();
|
||||||
try (FetchConnection fc = transport.openFetch(refSpecs)) {
|
try (FetchConnection fc = transport.openFetch()) {
|
||||||
refs = fc.getRefs();
|
refs = fc.getRefs();
|
||||||
if (refSpecs.isEmpty())
|
if (refSpecs.isEmpty())
|
||||||
for (Ref r : refs)
|
for (Ref r : refs)
|
||||||
|
|
|
@ -260,7 +260,6 @@ public static JGitText get() {
|
||||||
/***/ public String downloadCancelledDuringIndexing;
|
/***/ public String downloadCancelledDuringIndexing;
|
||||||
/***/ public String duplicateAdvertisementsOf;
|
/***/ public String duplicateAdvertisementsOf;
|
||||||
/***/ public String duplicateRef;
|
/***/ public String duplicateRef;
|
||||||
/***/ public String duplicateRefAttribute;
|
|
||||||
/***/ public String duplicateRemoteRefUpdateIsIllegal;
|
/***/ public String duplicateRemoteRefUpdateIsIllegal;
|
||||||
/***/ public String duplicateStagesNotAllowed;
|
/***/ public String duplicateStagesNotAllowed;
|
||||||
/***/ public String eitherGitDirOrWorkTreeRequired;
|
/***/ public String eitherGitDirOrWorkTreeRequired;
|
||||||
|
|
|
@ -13,12 +13,7 @@
|
||||||
|
|
||||||
package org.eclipse.jgit.transport;
|
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.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.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -26,28 +21,20 @@
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jgit.annotations.NonNull;
|
|
||||||
import org.eclipse.jgit.errors.InvalidObjectIdException;
|
import org.eclipse.jgit.errors.InvalidObjectIdException;
|
||||||
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
|
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
|
||||||
import org.eclipse.jgit.errors.PackProtocolException;
|
import org.eclipse.jgit.errors.PackProtocolException;
|
||||||
import org.eclipse.jgit.errors.RemoteRepositoryException;
|
import org.eclipse.jgit.errors.RemoteRepositoryException;
|
||||||
import org.eclipse.jgit.errors.TransportException;
|
import org.eclipse.jgit.errors.TransportException;
|
||||||
import org.eclipse.jgit.internal.JGitText;
|
import org.eclipse.jgit.internal.JGitText;
|
||||||
import org.eclipse.jgit.lib.Constants;
|
|
||||||
import org.eclipse.jgit.lib.ObjectId;
|
import org.eclipse.jgit.lib.ObjectId;
|
||||||
import org.eclipse.jgit.lib.ObjectIdRef;
|
import org.eclipse.jgit.lib.ObjectIdRef;
|
||||||
import org.eclipse.jgit.lib.Ref;
|
import org.eclipse.jgit.lib.Ref;
|
||||||
import org.eclipse.jgit.lib.Repository;
|
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.InterruptTimer;
|
||||||
import org.eclipse.jgit.util.io.TimeoutInputStream;
|
import org.eclipse.jgit.util.io.TimeoutInputStream;
|
||||||
import org.eclipse.jgit.util.io.TimeoutOutputStream;
|
import org.eclipse.jgit.util.io.TimeoutOutputStream;
|
||||||
|
@ -99,27 +86,17 @@ abstract class BasePackConnection extends BaseConnection {
|
||||||
protected boolean statelessRPC;
|
protected boolean statelessRPC;
|
||||||
|
|
||||||
/** Capability tokens advertised by the remote side. */
|
/** 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. */
|
/** Extra objects the remote has, but which aren't offered as refs. */
|
||||||
protected final Set<ObjectId> additionalHaves = new HashSet<>();
|
protected final Set<ObjectId> additionalHaves = new HashSet<>();
|
||||||
|
|
||||||
private TransferConfig.ProtocolVersion protocol = TransferConfig.ProtocolVersion.V0;
|
|
||||||
|
|
||||||
BasePackConnection(PackTransport packTransport) {
|
BasePackConnection(PackTransport packTransport) {
|
||||||
transport = (Transport) packTransport;
|
transport = (Transport) packTransport;
|
||||||
local = transport.local;
|
local = transport.local;
|
||||||
uri = transport.uri;
|
uri = transport.uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
TransferConfig.ProtocolVersion getProtocolVersion() {
|
|
||||||
return protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setProtocolVersion(@NonNull TransferConfig.ProtocolVersion protocol) {
|
|
||||||
this.protocol = protocol;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure this connection with the directional pipes.
|
* Configure this connection with the directional pipes.
|
||||||
*
|
*
|
||||||
|
@ -164,15 +141,12 @@ protected final void init(InputStream myIn, OutputStream myOut) {
|
||||||
* {@link #close()} and the exception is wrapped (if necessary) and thrown
|
* {@link #close()} and the exception is wrapped (if necessary) and thrown
|
||||||
* as a {@link org.eclipse.jgit.errors.TransportException}.
|
* 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
|
* @throws org.eclipse.jgit.errors.TransportException
|
||||||
* the reference list could not be scanned.
|
* the reference list could not be scanned.
|
||||||
*/
|
*/
|
||||||
protected boolean readAdvertisedRefs() throws TransportException {
|
protected void readAdvertisedRefs() throws TransportException {
|
||||||
try {
|
try {
|
||||||
return readAdvertisedRefsImpl();
|
readAdvertisedRefsImpl();
|
||||||
} catch (TransportException err) {
|
} catch (TransportException err) {
|
||||||
close();
|
close();
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -182,66 +156,35 @@ protected boolean readAdvertisedRefs() throws TransportException {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readLine() throws IOException {
|
private void readAdvertisedRefsImpl() 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 {
|
|
||||||
final LinkedHashMap<String, Ref> avail = new LinkedHashMap<>();
|
final LinkedHashMap<String, Ref> avail = new LinkedHashMap<>();
|
||||||
for (boolean first = true;; first = false) {
|
for (;;) {
|
||||||
String line;
|
String line;
|
||||||
|
|
||||||
if (first) {
|
try {
|
||||||
boolean isV1 = false;
|
line = pckIn.readString();
|
||||||
try {
|
} catch (EOFException eof) {
|
||||||
line = readLine();
|
if (avail.isEmpty())
|
||||||
} catch (EOFException e) {
|
|
||||||
throw noRepository();
|
throw noRepository();
|
||||||
}
|
throw eof;
|
||||||
if (line != null && VERSION_1.equals(line)) {
|
}
|
||||||
// Same as V0, except for this extra line. We shouldn't get
|
if (PacketLineIn.isEnd(line))
|
||||||
// it since we never request V1.
|
break;
|
||||||
setProtocolVersion(TransferConfig.ProtocolVersion.V0);
|
|
||||||
isV1 = true;
|
if (line.startsWith("ERR ")) { //$NON-NLS-1$
|
||||||
line = readLine();
|
// This is a customized remote service error.
|
||||||
}
|
// Users should be informed about it.
|
||||||
if (line == null) {
|
throw new RemoteRepositoryException(uri, line.substring(4));
|
||||||
break;
|
}
|
||||||
}
|
|
||||||
|
if (avail.isEmpty()) {
|
||||||
final int nul = line.indexOf('\0');
|
final int nul = line.indexOf('\0');
|
||||||
if (nul >= 0) {
|
if (nul >= 0) {
|
||||||
// Protocol V0: The first line (if any) may contain
|
// The first line (if any) may contain "hidden"
|
||||||
// "hidden" capability values after a NUL byte.
|
// capability values after a NUL byte.
|
||||||
for (String capability : line.substring(nul + 1)
|
remoteCapablities.addAll(
|
||||||
.split(" ")) { //$NON-NLS-1$
|
Arrays.asList(line.substring(nul + 1).split(" "))); //$NON-NLS-1$
|
||||||
addCapability(capability);
|
|
||||||
}
|
|
||||||
line = line.substring(0, nul);
|
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,228 +193,42 @@ private boolean readAdvertisedRefsImpl() throws IOException {
|
||||||
throw invalidRefAdvertisementLine(line);
|
throw invalidRefAdvertisementLine(line);
|
||||||
}
|
}
|
||||||
String name = line.substring(41, line.length());
|
String name = line.substring(41, line.length());
|
||||||
if (first && name.equals("capabilities^{}")) { //$NON-NLS-1$
|
if (avail.isEmpty() && name.equals("capabilities^{}")) { //$NON-NLS-1$
|
||||||
// special line from git-receive-pack (protocol V0) to show
|
// special line from git-receive-pack to show
|
||||||
// capabilities when there are no refs to advertise
|
// capabilities when there are no refs to advertise
|
||||||
// TODO: throw error if protocol version is >= V2?
|
|
||||||
continue;
|
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$
|
if (name.equals(".have")) { //$NON-NLS-1$
|
||||||
additionalHaves.add(id);
|
additionalHaves.add(id);
|
||||||
|
} 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));
|
||||||
|
|
||||||
|
if (prior.getPeeledObjectId() != null)
|
||||||
|
throw duplicateAdvertisement(name + "^{}"); //$NON-NLS-1$
|
||||||
|
|
||||||
|
avail.put(name, new ObjectIdRef.PeeledTag(
|
||||||
|
Ref.Storage.NETWORK, name, prior.getObjectId(), id));
|
||||||
} else {
|
} else {
|
||||||
processLineV1(name, id, avail);
|
final Ref prior = avail.put(name, new ObjectIdRef.PeeledNonTag(
|
||||||
|
Ref.Storage.NETWORK, name, id));
|
||||||
|
if (prior != null)
|
||||||
|
throw duplicateAdvertisement(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
available(avail);
|
available(avail);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
|
||||||
processLineV2(line, id, name, avail);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -495,7 +252,7 @@ protected TransportException noRepository() {
|
||||||
* @return whether this option is supported
|
* @return whether this option is supported
|
||||||
*/
|
*/
|
||||||
protected boolean isCapableOf(String option) {
|
protected boolean isCapableOf(String option) {
|
||||||
return remoteCapabilities.containsKey(option);
|
return remoteCapablities.contains(option);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -515,17 +272,6 @@ protected boolean wantCapability(StringBuilder b, String option) {
|
||||||
return true;
|
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
|
* Add user agent capability
|
||||||
*
|
*
|
||||||
|
@ -534,7 +280,7 @@ protected String getCapability(String option) {
|
||||||
*/
|
*/
|
||||||
protected void addUserAgentCapability(StringBuilder b) {
|
protected void addUserAgentCapability(StringBuilder b) {
|
||||||
String a = UserAgent.get();
|
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);
|
b.append(' ').append(OPTION_AGENT).append('=').append(a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -542,8 +288,7 @@ protected void addUserAgentCapability(StringBuilder b) {
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public String getPeerUserAgent() {
|
public String getPeerUserAgent() {
|
||||||
String agent = remoteCapabilities.get(OPTION_AGENT);
|
return UserAgent.getAgent(remoteCapablities, super.getPeerUserAgent());
|
||||||
return agent != null ? agent : super.getPeerUserAgent();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PackProtocolException duplicateAdvertisement(String name) {
|
private PackProtocolException duplicateAdvertisement(String name) {
|
||||||
|
|
|
@ -16,12 +16,9 @@
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedHashSet;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jgit.errors.PackProtocolException;
|
import org.eclipse.jgit.errors.PackProtocolException;
|
||||||
|
@ -215,8 +212,6 @@ public abstract class BasePackFetchConnection extends BasePackConnection
|
||||||
|
|
||||||
private PacketLineOut pckState;
|
private PacketLineOut pckState;
|
||||||
|
|
||||||
private Set<String> fetchCapabilities = new HashSet<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Either FilterSpec.NO_FILTER for a filter that doesn't filter
|
* 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
|
* anything, or a filter that indicates what and what not to send to the
|
||||||
|
@ -359,28 +354,6 @@ protected void doFetch(final ProgressMonitor monitor,
|
||||||
pckState = new PacketLineOut(state);
|
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)) {
|
if (sendWants(want)) {
|
||||||
negotiate(monitor);
|
negotiate(monitor);
|
||||||
|
|
||||||
|
@ -389,25 +362,6 @@ && isCapableOf(GitProtocolConstants.OPTION_AGENT)) {
|
||||||
state = null;
|
state = null;
|
||||||
pckState = 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);
|
receivePack(monitor, outputStream);
|
||||||
}
|
}
|
||||||
} catch (CancelledException ce) {
|
} catch (CancelledException ce) {
|
||||||
|
@ -427,14 +381,6 @@ public void close() {
|
||||||
super.close();
|
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() {
|
FetchConfig getFetchConfig() {
|
||||||
return local.getConfig().get(FetchConfig::new);
|
return local.getConfig().get(FetchConfig::new);
|
||||||
}
|
}
|
||||||
|
@ -533,11 +479,10 @@ private boolean sendWants(Collection<Ref> want) throws IOException {
|
||||||
final StringBuilder line = new StringBuilder(46);
|
final StringBuilder line = new StringBuilder(46);
|
||||||
line.append("want "); //$NON-NLS-1$
|
line.append("want "); //$NON-NLS-1$
|
||||||
line.append(objectId.name());
|
line.append(objectId.name());
|
||||||
if (first && TransferConfig.ProtocolVersion.V0
|
if (first) {
|
||||||
.equals(getProtocolVersion())) {
|
|
||||||
line.append(enableCapabilities());
|
line.append(enableCapabilities());
|
||||||
|
first = false;
|
||||||
}
|
}
|
||||||
first = false;
|
|
||||||
line.append('\n');
|
line.append('\n');
|
||||||
p.writeString(line.toString());
|
p.writeString(line.toString());
|
||||||
}
|
}
|
||||||
|
@ -547,35 +492,11 @@ private boolean sendWants(Collection<Ref> want) throws IOException {
|
||||||
if (!filterSpec.isNoOp()) {
|
if (!filterSpec.isNoOp()) {
|
||||||
p.writeString(filterSpec.filterLine());
|
p.writeString(filterSpec.filterLine());
|
||||||
}
|
}
|
||||||
if (TransferConfig.ProtocolVersion.V0.equals(getProtocolVersion())) {
|
p.end();
|
||||||
p.end();
|
outNeedsEnd = false;
|
||||||
outNeedsEnd = false;
|
|
||||||
}
|
|
||||||
return true;
|
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 {
|
private String enableCapabilities() throws TransportException {
|
||||||
final StringBuilder line = new StringBuilder();
|
final StringBuilder line = new StringBuilder();
|
||||||
if (noProgress)
|
if (noProgress)
|
||||||
|
@ -629,7 +550,6 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
boolean receivedContinue = false;
|
boolean receivedContinue = false;
|
||||||
boolean receivedAck = false;
|
boolean receivedAck = false;
|
||||||
boolean receivedReady = false;
|
boolean receivedReady = false;
|
||||||
boolean needsAcknowledgementV2 = true;
|
|
||||||
|
|
||||||
if (statelessRPC) {
|
if (statelessRPC) {
|
||||||
state.writeTo(out, null);
|
state.writeTo(out, null);
|
||||||
|
@ -643,7 +563,7 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectId o = c.getId();
|
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++;
|
havesSent++;
|
||||||
havesSinceLastContinue++;
|
havesSinceLastContinue++;
|
||||||
|
|
||||||
|
@ -660,7 +580,6 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
}
|
}
|
||||||
|
|
||||||
pckOut.end();
|
pckOut.end();
|
||||||
outNeedsEnd = false;
|
|
||||||
resultsPending++; // Each end will cause a result to come back.
|
resultsPending++; // Each end will cause a result to come back.
|
||||||
|
|
||||||
if (havesSent == 32 && !statelessRPC) {
|
if (havesSent == 32 && !statelessRPC) {
|
||||||
|
@ -672,32 +591,9 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
continue;
|
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 (;;) {
|
READ_RESULT: for (;;) {
|
||||||
AckNackResult anr = pckIn.readACKorEOF(ackId);
|
final AckNackResult anr = pckIn.readACK(ackId);
|
||||||
switch (anr) {
|
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:
|
case NAK:
|
||||||
// More have lines are necessary to compute the
|
// More have lines are necessary to compute the
|
||||||
// pack on the remote side. Keep doing that.
|
// pack on the remote side. Keep doing that.
|
||||||
|
@ -706,24 +602,17 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
break READ_RESULT;
|
break READ_RESULT;
|
||||||
|
|
||||||
case ACK:
|
case ACK:
|
||||||
if (TransferConfig.ProtocolVersion.V0
|
// The remote side is happy and knows exactly what
|
||||||
.equals(getProtocolVersion())) {
|
// to send us. There is no further negotiation and
|
||||||
// The remote side is happy and knows exactly what
|
// we can break out immediately.
|
||||||
// to send us. There is no further negotiation and
|
//
|
||||||
// we can break out immediately.
|
multiAck = MultiAck.OFF;
|
||||||
//
|
resultsPending = 0;
|
||||||
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);
|
|
||||||
receivedAck = true;
|
receivedAck = true;
|
||||||
break;
|
if (statelessRPC) {
|
||||||
|
state.writeTo(out, null);
|
||||||
|
}
|
||||||
|
break SEND_HAVES;
|
||||||
|
|
||||||
case ACK_CONTINUE:
|
case ACK_CONTINUE:
|
||||||
case ACK_COMMON:
|
case ACK_COMMON:
|
||||||
|
@ -739,12 +628,6 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
havesSinceLastContinue = 0;
|
havesSinceLastContinue = 0;
|
||||||
if (anr == AckNackResult.ACK_READY) {
|
if (anr == AckNackResult.ACK_READY) {
|
||||||
receivedReady = true;
|
receivedReady = true;
|
||||||
if (TransferConfig.ProtocolVersion.V2
|
|
||||||
.equals(getProtocolVersion())) {
|
|
||||||
multiAck = MultiAck.OFF;
|
|
||||||
resultsPending = 0;
|
|
||||||
break SEND_HAVES;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -778,36 +661,15 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
throw new CancelledException();
|
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) {
|
if (!receivedReady || !noDone) {
|
||||||
// When statelessRPC is true we should always leave SEND_HAVES
|
// When statelessRPC is true we should always leave SEND_HAVES
|
||||||
// loop above while in the middle of a request. This allows us
|
// loop above while in the middle of a request. This allows us
|
||||||
// to just write done immediately.
|
// to just write done immediately.
|
||||||
//
|
//
|
||||||
pckOut.writeString("done\n"); //$NON-NLS-1$
|
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();
|
pckOut.flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Below is protocol V0 only.
|
|
||||||
|
|
||||||
if (!receivedAck) {
|
if (!receivedAck) {
|
||||||
// Apparently if we have never received an ACK earlier
|
// Apparently if we have never received an ACK earlier
|
||||||
// there is one more result expected from the done we
|
// there is one more result expected from the done we
|
||||||
|
@ -827,14 +689,6 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
//
|
//
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case ACK_EOF:
|
|
||||||
if (TransferConfig.ProtocolVersion.V0
|
|
||||||
.equals(getProtocolVersion())) {
|
|
||||||
throw new PackProtocolException(
|
|
||||||
JGitText.get().expectedACKNAKFoundEOF);
|
|
||||||
}
|
|
||||||
break READ_RESULT;
|
|
||||||
|
|
||||||
case ACK:
|
case ACK:
|
||||||
// A solitary ACK at this point means the remote won't
|
// A solitary ACK at this point means the remote won't
|
||||||
// speak anymore, but is going to send us a pack now.
|
// speak anymore, but is going to send us a pack now.
|
||||||
|
@ -843,16 +697,7 @@ private void negotiate(ProgressMonitor monitor) throws IOException,
|
||||||
|
|
||||||
case ACK_CONTINUE:
|
case ACK_CONTINUE:
|
||||||
case ACK_COMMON:
|
case ACK_COMMON:
|
||||||
// We will expect a normal ACK to break out of the loop.
|
|
||||||
//
|
|
||||||
multiAck = MultiAck.CONTINUE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ACK_READY:
|
case ACK_READY:
|
||||||
if (TransferConfig.ProtocolVersion.V2
|
|
||||||
.equals(getProtocolVersion())) {
|
|
||||||
break READ_RESULT;
|
|
||||||
}
|
|
||||||
// We will expect a normal ACK to break out of the loop.
|
// We will expect a normal ACK to break out of the loop.
|
||||||
//
|
//
|
||||||
multiAck = MultiAck.CONTINUE;
|
multiAck = MultiAck.CONTINUE;
|
||||||
|
|
|
@ -102,21 +102,7 @@ void execute(ProgressMonitor monitor, FetchResult result)
|
||||||
private void executeImp(final ProgressMonitor monitor,
|
private void executeImp(final ProgressMonitor monitor,
|
||||||
final FetchResult result) throws NotSupportedException,
|
final FetchResult result) throws NotSupportedException,
|
||||||
TransportException {
|
TransportException {
|
||||||
final TagOpt tagopt = transport.getTagOpt();
|
conn = transport.openFetch();
|
||||||
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);
|
|
||||||
try {
|
try {
|
||||||
result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
|
result.setAdvertisedRefs(transport.getURI(), conn.getRefsMap());
|
||||||
result.peerUserAgent = conn.getPeerUserAgent();
|
result.peerUserAgent = conn.getPeerUserAgent();
|
||||||
|
@ -133,6 +119,7 @@ private void executeImp(final ProgressMonitor monitor,
|
||||||
}
|
}
|
||||||
|
|
||||||
Collection<Ref> additionalTags = Collections.<Ref> emptyList();
|
Collection<Ref> additionalTags = Collections.<Ref> emptyList();
|
||||||
|
final TagOpt tagopt = transport.getTagOpt();
|
||||||
if (tagopt == TagOpt.AUTO_FOLLOW)
|
if (tagopt == TagOpt.AUTO_FOLLOW)
|
||||||
additionalTags = expandAutoFollowTags();
|
additionalTags = expandAutoFollowTags();
|
||||||
else if (tagopt == TagOpt.FETCH_TAGS)
|
else if (tagopt == TagOpt.FETCH_TAGS)
|
||||||
|
@ -266,17 +253,7 @@ private void reopenConnection() throws NotSupportedException,
|
||||||
if (conn != null)
|
if (conn != null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Build prefixes
|
conn = transport.openFetch();
|
||||||
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]));
|
|
||||||
|
|
||||||
// Since we opened a new connection we cannot be certain
|
// Since we opened a new connection we cannot be certain
|
||||||
// that the system we connected to has the same exact set
|
// 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$
|
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 {
|
enum MultiAck {
|
||||||
OFF, CONTINUE, DETAILED;
|
OFF, CONTINUE, DETAILED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,9 +72,7 @@ enum AckNackResult {
|
||||||
/** ACK + common */
|
/** ACK + common */
|
||||||
ACK_COMMON,
|
ACK_COMMON,
|
||||||
/** ACK + ready */
|
/** ACK + ready */
|
||||||
ACK_READY,
|
ACK_READY;
|
||||||
/** EOF (0000) recieved in protocol V2 when expecting an ACK/NAK */
|
|
||||||
ACK_EOF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private final byte[] lineBuffer = new byte[SideBandOutputStream.SMALL_BUF];
|
private final byte[] lineBuffer = new byte[SideBandOutputStream.SMALL_BUF];
|
||||||
|
@ -105,26 +103,12 @@ public PacketLineIn(InputStream in, long limit) {
|
||||||
this.limit = limit;
|
this.limit = limit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
AckNackResult readACK(MutableObjectId returnedId) throws IOException {
|
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();
|
final String line = readString();
|
||||||
if (line.length() == 0)
|
if (line.length() == 0)
|
||||||
return AckNackResult.ACK_EOF;
|
throw new PackProtocolException(JGitText.get().expectedACKNAKFoundEOF);
|
||||||
if ("NAK".equals(line)) //$NON-NLS-1$
|
if ("NAK".equals(line)) //$NON-NLS-1$
|
||||||
return AckNackResult.NAK;
|
return AckNackResult.NAK;
|
||||||
if ("ready".equals(line)) { //$NON-NLS-1$
|
|
||||||
// Protocol V2
|
|
||||||
return AckNackResult.ACK_READY;
|
|
||||||
}
|
|
||||||
if (line.startsWith("ACK ")) { //$NON-NLS-1$
|
if (line.startsWith("ACK ")) { //$NON-NLS-1$
|
||||||
returnedId.fromString(line.substring(4, 44));
|
returnedId.fromString(line.substring(4, 44));
|
||||||
if (line.length() == 44)
|
if (line.length() == 44)
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||||
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
|
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.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.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
@ -289,8 +287,7 @@ public Set<ObjectId> send(Collection<Ref> refs) throws IOException {
|
||||||
|
|
||||||
if (useProtocolV2) {
|
if (useProtocolV2) {
|
||||||
String symrefPart = symrefs.containsKey(ref.getName())
|
String symrefPart = symrefs.containsKey(ref.getName())
|
||||||
? (' ' + REF_ATTR_SYMREF_TARGET
|
? (" symref-target:" + symrefs.get(ref.getName())) //$NON-NLS-1$
|
||||||
+ symrefs.get(ref.getName()))
|
|
||||||
: ""; //$NON-NLS-1$
|
: ""; //$NON-NLS-1$
|
||||||
String peelPart = ""; //$NON-NLS-1$
|
String peelPart = ""; //$NON-NLS-1$
|
||||||
if (derefTags) {
|
if (derefTags) {
|
||||||
|
@ -299,8 +296,7 @@ public Set<ObjectId> send(Collection<Ref> refs) throws IOException {
|
||||||
}
|
}
|
||||||
ObjectId peeledObjectId = ref.getPeeledObjectId();
|
ObjectId peeledObjectId = ref.getPeeledObjectId();
|
||||||
if (peeledObjectId != null) {
|
if (peeledObjectId != null) {
|
||||||
peelPart = ' ' + REF_ATTR_PEELED
|
peelPart = " peeled:" + peeledObjectId.getName(); //$NON-NLS-1$
|
||||||
+ peeledObjectId.getName();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeOne(objectId.getName() + " " + ref.getName() + symrefPart //$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.concurrent.CopyOnWriteArrayList;
|
import java.util.concurrent.CopyOnWriteArrayList;
|
||||||
|
|
||||||
import org.eclipse.jgit.annotations.NonNull;
|
import org.eclipse.jgit.annotations.NonNull;
|
||||||
import org.eclipse.jgit.annotations.Nullable;
|
|
||||||
import org.eclipse.jgit.api.errors.AbortedByHookException;
|
import org.eclipse.jgit.api.errors.AbortedByHookException;
|
||||||
import org.eclipse.jgit.errors.NotSupportedException;
|
import org.eclipse.jgit.errors.NotSupportedException;
|
||||||
import org.eclipse.jgit.errors.TransportException;
|
import org.eclipse.jgit.errors.TransportException;
|
||||||
|
@ -775,10 +774,6 @@ private static String findTrackingRefName(final String remoteName,
|
||||||
private PrintStream hookOutRedirect;
|
private PrintStream hookOutRedirect;
|
||||||
|
|
||||||
private PrePushHook prePush;
|
private PrePushHook prePush;
|
||||||
|
|
||||||
@Nullable
|
|
||||||
TransferConfig.ProtocolVersion protocol;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new transport instance.
|
* Create a new transport instance.
|
||||||
*
|
*
|
||||||
|
@ -794,7 +789,6 @@ protected Transport(Repository local, URIish uri) {
|
||||||
final TransferConfig tc = local.getConfig().get(TransferConfig.KEY);
|
final TransferConfig tc = local.getConfig().get(TransferConfig.KEY);
|
||||||
this.local = local;
|
this.local = local;
|
||||||
this.uri = uri;
|
this.uri = uri;
|
||||||
this.protocol = tc.protocolVersion;
|
|
||||||
this.objectChecker = tc.newObjectChecker();
|
this.objectChecker = tc.newObjectChecker();
|
||||||
this.credentialsProvider = CredentialsProvider.getDefault();
|
this.credentialsProvider = CredentialsProvider.getDefault();
|
||||||
prePush = Hooks.prePush(local, hookOutRedirect);
|
prePush = Hooks.prePush(local, hookOutRedirect);
|
||||||
|
@ -1458,43 +1452,6 @@ public Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
|
||||||
public abstract FetchConnection openFetch() throws NotSupportedException,
|
public abstract FetchConnection openFetch() throws NotSupportedException,
|
||||||
TransportException;
|
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.
|
* Begins a new connection for pushing into the remote repository.
|
||||||
*
|
*
|
||||||
|
|
|
@ -22,7 +22,6 @@
|
||||||
import java.net.InetSocketAddress;
|
import java.net.InetSocketAddress;
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -95,13 +94,6 @@ public FetchConnection openFetch() throws TransportException {
|
||||||
return new TcpFetchConnection();
|
return new TcpFetchConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public FetchConnection openFetch(Collection<RefSpec> refSpecs,
|
|
||||||
String... additionalPatterns)
|
|
||||||
throws NotSupportedException, TransportException {
|
|
||||||
return new TcpFetchConnection(refSpecs, additionalPatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public PushConnection openPush() throws TransportException {
|
public PushConnection openPush() throws TransportException {
|
||||||
|
@ -138,8 +130,7 @@ Socket openConnection() throws TransportException {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void service(String name, PacketLineOut pckOut,
|
void service(String name, PacketLineOut pckOut)
|
||||||
TransferConfig.ProtocolVersion gitProtocol)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final StringBuilder cmd = new StringBuilder();
|
final StringBuilder cmd = new StringBuilder();
|
||||||
cmd.append(name);
|
cmd.append(name);
|
||||||
|
@ -153,11 +144,6 @@ void service(String name, PacketLineOut pckOut,
|
||||||
cmd.append(uri.getPort());
|
cmd.append(uri.getPort());
|
||||||
}
|
}
|
||||||
cmd.append('\0');
|
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.writeString(cmd.toString());
|
||||||
pckOut.flush();
|
pckOut.flush();
|
||||||
}
|
}
|
||||||
|
@ -166,11 +152,6 @@ class TcpFetchConnection extends BasePackFetchConnection {
|
||||||
private Socket sock;
|
private Socket sock;
|
||||||
|
|
||||||
TcpFetchConnection() throws TransportException {
|
TcpFetchConnection() throws TransportException {
|
||||||
this(Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
TcpFetchConnection(Collection<RefSpec> refSpecs,
|
|
||||||
String... additionalPatterns) throws TransportException {
|
|
||||||
super(TransportGitAnon.this);
|
super(TransportGitAnon.this);
|
||||||
sock = openConnection();
|
sock = openConnection();
|
||||||
try {
|
try {
|
||||||
|
@ -181,19 +162,13 @@ class TcpFetchConnection extends BasePackFetchConnection {
|
||||||
sOut = new BufferedOutputStream(sOut);
|
sOut = new BufferedOutputStream(sOut);
|
||||||
|
|
||||||
init(sIn, sOut);
|
init(sIn, sOut);
|
||||||
TransferConfig.ProtocolVersion gitProtocol = protocol;
|
service("git-upload-pack", pckOut); //$NON-NLS-1$
|
||||||
if (gitProtocol == null) {
|
|
||||||
gitProtocol = TransferConfig.ProtocolVersion.V2;
|
|
||||||
}
|
|
||||||
service("git-upload-pack", pckOut, gitProtocol); //$NON-NLS-1$
|
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
close();
|
close();
|
||||||
throw new TransportException(uri,
|
throw new TransportException(uri,
|
||||||
JGitText.get().remoteHungUpUnexpectedly, err);
|
JGitText.get().remoteHungUpUnexpectedly, err);
|
||||||
}
|
}
|
||||||
if (!readAdvertisedRefs()) {
|
readAdvertisedRefs();
|
||||||
lsRefs(refSpecs, additionalPatterns);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -226,7 +201,7 @@ class TcpPushConnection extends BasePackPushConnection {
|
||||||
sOut = new BufferedOutputStream(sOut);
|
sOut = new BufferedOutputStream(sOut);
|
||||||
|
|
||||||
init(sIn, sOut);
|
init(sIn, sOut);
|
||||||
service("git-receive-pack", pckOut, null); //$NON-NLS-1$
|
service("git-receive-pack", pckOut); //$NON-NLS-1$
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
close();
|
close();
|
||||||
throw new TransportException(uri,
|
throw new TransportException(uri,
|
||||||
|
|
|
@ -19,13 +19,11 @@
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
|
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
|
||||||
|
@ -146,13 +144,6 @@ public FetchConnection openFetch() throws TransportException {
|
||||||
return new SshFetchConnection();
|
return new SshFetchConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public FetchConnection openFetch(Collection<RefSpec> refSpecs,
|
|
||||||
String... additionalPatterns)
|
|
||||||
throws NotSupportedException, TransportException {
|
|
||||||
return new SshFetchConnection(refSpecs, additionalPatterns);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public PushConnection openPush() throws TransportException {
|
public PushConnection openPush() throws TransportException {
|
||||||
|
@ -205,38 +196,29 @@ private static boolean useExtSession() {
|
||||||
return SystemReader.getInstance().getenv("GIT_SSH") != null; //$NON-NLS-1$
|
return SystemReader.getInstance().getenv("GIT_SSH") != null; //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExtSession implements RemoteSession2 {
|
private class ExtSession implements RemoteSession {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Process exec(String command, int timeout)
|
public Process exec(String command, int timeout)
|
||||||
throws TransportException {
|
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$
|
String ssh = SystemReader.getInstance().getenv("GIT_SSH"); //$NON-NLS-1$
|
||||||
boolean putty = ssh.toLowerCase(Locale.ROOT).contains("plink"); //$NON-NLS-1$
|
boolean putty = ssh.toLowerCase(Locale.ROOT).contains("plink"); //$NON-NLS-1$
|
||||||
|
|
||||||
List<String> args = new ArrayList<>();
|
List<String> args = new ArrayList<>();
|
||||||
args.add(ssh);
|
args.add(ssh);
|
||||||
if (putty && !ssh.toLowerCase(Locale.ROOT)
|
if (putty
|
||||||
.contains("tortoiseplink")) {//$NON-NLS-1$
|
&& !ssh.toLowerCase(Locale.ROOT).contains("tortoiseplink")) //$NON-NLS-1$
|
||||||
args.add("-batch"); //$NON-NLS-1$
|
args.add("-batch"); //$NON-NLS-1$
|
||||||
}
|
|
||||||
if (0 < getURI().getPort()) {
|
if (0 < getURI().getPort()) {
|
||||||
args.add(putty ? "-P" : "-p"); //$NON-NLS-1$ //$NON-NLS-2$
|
args.add(putty ? "-P" : "-p"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
args.add(String.valueOf(getURI().getPort()));
|
args.add(String.valueOf(getURI().getPort()));
|
||||||
}
|
}
|
||||||
if (getURI().getUser() != null) {
|
if (getURI().getUser() != null)
|
||||||
args.add(getURI().getUser() + "@" + getURI().getHost()); //$NON-NLS-1$
|
args.add(getURI().getUser() + "@" + getURI().getHost()); //$NON-NLS-1$
|
||||||
} else {
|
else
|
||||||
args.add(getURI().getHost());
|
args.add(getURI().getHost());
|
||||||
}
|
|
||||||
args.add(command);
|
args.add(command);
|
||||||
|
|
||||||
ProcessBuilder pb = createProcess(args, environment);
|
ProcessBuilder pb = createProcess(args);
|
||||||
try {
|
try {
|
||||||
return pb.start();
|
return pb.start();
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
|
@ -244,13 +226,9 @@ public Process exec(String command, Map<String, String> environment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ProcessBuilder createProcess(List<String> args,
|
private ProcessBuilder createProcess(List<String> args) {
|
||||||
Map<String, String> environment) {
|
|
||||||
ProcessBuilder pb = new ProcessBuilder();
|
ProcessBuilder pb = new ProcessBuilder();
|
||||||
pb.command(args);
|
pb.command(args);
|
||||||
if (environment != null) {
|
|
||||||
pb.environment().putAll(environment);
|
|
||||||
}
|
|
||||||
File directory = local != null ? local.getDirectory() : null;
|
File directory = local != null ? local.getDirectory() : null;
|
||||||
if (directory != null) {
|
if (directory != null) {
|
||||||
pb.environment().put(Constants.GIT_DIR_KEY,
|
pb.environment().put(Constants.GIT_DIR_KEY,
|
||||||
|
@ -271,31 +249,10 @@ class SshFetchConnection extends BasePackFetchConnection {
|
||||||
private StreamCopyThread errorThread;
|
private StreamCopyThread errorThread;
|
||||||
|
|
||||||
SshFetchConnection() throws TransportException {
|
SshFetchConnection() throws TransportException {
|
||||||
this(Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
SshFetchConnection(Collection<RefSpec> refSpecs,
|
|
||||||
String... additionalPatterns) throws TransportException {
|
|
||||||
super(TransportGitSsh.this);
|
super(TransportGitSsh.this);
|
||||||
try {
|
try {
|
||||||
RemoteSession session = getSession();
|
process = getSession().exec(commandFor(getOptionUploadPack()),
|
||||||
TransferConfig.ProtocolVersion gitProtocol = protocol;
|
getTimeout());
|
||||||
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());
|
|
||||||
}
|
|
||||||
final MessageWriter msg = new MessageWriter();
|
final MessageWriter msg = new MessageWriter();
|
||||||
setMessageWriter(msg);
|
setMessageWriter(msg);
|
||||||
|
|
||||||
|
@ -315,9 +272,7 @@ class SshFetchConnection extends BasePackFetchConnection {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!readAdvertisedRefs()) {
|
readAdvertisedRefs();
|
||||||
lsRefs(refSpecs, additionalPatterns);
|
|
||||||
}
|
|
||||||
} catch (NoRemoteRepositoryException notFound) {
|
} catch (NoRemoteRepositoryException notFound) {
|
||||||
final String msgs = getMessages();
|
final String msgs = getMessages();
|
||||||
checkExecFailure(process.exitValue(), getOptionUploadPack(),
|
checkExecFailure(process.exitValue(), getOptionUploadPack(),
|
||||||
|
|
|
@ -33,8 +33,8 @@
|
||||||
import static org.eclipse.jgit.util.HttpSupport.METHOD_GET;
|
import static org.eclipse.jgit.util.HttpSupport.METHOD_GET;
|
||||||
import static org.eclipse.jgit.util.HttpSupport.METHOD_POST;
|
import static org.eclipse.jgit.util.HttpSupport.METHOD_POST;
|
||||||
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -339,15 +339,11 @@ public void setUseSmartHttp(boolean on) {
|
||||||
|
|
||||||
@SuppressWarnings("resource") // Closed by caller
|
@SuppressWarnings("resource") // Closed by caller
|
||||||
private FetchConnection getConnection(HttpConnection c, InputStream in,
|
private FetchConnection getConnection(HttpConnection c, InputStream in,
|
||||||
String service, Collection<RefSpec> refSpecs,
|
String service) throws IOException {
|
||||||
String... additionalPatterns) throws IOException {
|
|
||||||
BaseConnection f;
|
BaseConnection f;
|
||||||
if (isSmartHttp(c, service)) {
|
if (isSmartHttp(c, service)) {
|
||||||
InputStream withMark = in.markSupported() ? in
|
readSmartHeaders(in, service);
|
||||||
: new BufferedInputStream(in);
|
f = new SmartHttpFetchConnection(in);
|
||||||
readSmartHeaders(withMark, service);
|
|
||||||
f = new SmartHttpFetchConnection(withMark, refSpecs,
|
|
||||||
additionalPatterns);
|
|
||||||
} else {
|
} else {
|
||||||
// Assume this server doesn't support smart HTTP fetch
|
// Assume this server doesn't support smart HTTP fetch
|
||||||
// and fall back on dumb object walking.
|
// and fall back on dumb object walking.
|
||||||
|
@ -361,23 +357,11 @@ private FetchConnection getConnection(HttpConnection c, InputStream in,
|
||||||
@Override
|
@Override
|
||||||
public FetchConnection openFetch() throws TransportException,
|
public FetchConnection openFetch() throws TransportException,
|
||||||
NotSupportedException {
|
NotSupportedException {
|
||||||
return openFetch(Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FetchConnection openFetch(Collection<RefSpec> refSpecs,
|
|
||||||
String... additionalPatterns)
|
|
||||||
throws NotSupportedException, TransportException {
|
|
||||||
final String service = SVC_UPLOAD_PACK;
|
final String service = SVC_UPLOAD_PACK;
|
||||||
try {
|
try {
|
||||||
TransferConfig.ProtocolVersion gitProtocol = protocol;
|
final HttpConnection c = connect(service);
|
||||||
if (gitProtocol == null) {
|
|
||||||
gitProtocol = TransferConfig.ProtocolVersion.V2;
|
|
||||||
}
|
|
||||||
HttpConnection c = connect(service, gitProtocol);
|
|
||||||
try (InputStream in = openInputStream(c)) {
|
try (InputStream in = openInputStream(c)) {
|
||||||
return getConnection(c, in, service, refSpecs,
|
return getConnection(c, in, service);
|
||||||
additionalPatterns);
|
|
||||||
}
|
}
|
||||||
} catch (NotSupportedException | TransportException err) {
|
} catch (NotSupportedException | TransportException err) {
|
||||||
throw err;
|
throw err;
|
||||||
|
@ -472,9 +456,8 @@ public PushConnection openPush() throws NotSupportedException,
|
||||||
|
|
||||||
private PushConnection smartPush(String service, HttpConnection c,
|
private PushConnection smartPush(String service, HttpConnection c,
|
||||||
InputStream in) throws IOException, TransportException {
|
InputStream in) throws IOException, TransportException {
|
||||||
BufferedInputStream inBuf = new BufferedInputStream(in);
|
readSmartHeaders(in, service);
|
||||||
readSmartHeaders(inBuf, service);
|
SmartHttpPushConnection p = new SmartHttpPushConnection(in);
|
||||||
SmartHttpPushConnection p = new SmartHttpPushConnection(inBuf);
|
|
||||||
p.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER));
|
p.setPeerUserAgent(c.getHeaderField(HttpSupport.HDR_SERVER));
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -511,12 +494,6 @@ private NoRemoteRepositoryException createNotFoundException(URIish u,
|
||||||
|
|
||||||
private HttpConnection connect(String service)
|
private HttpConnection connect(String service)
|
||||||
throws TransportException, NotSupportedException {
|
throws TransportException, NotSupportedException {
|
||||||
return connect(service, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private HttpConnection connect(String service,
|
|
||||||
TransferConfig.ProtocolVersion protocolVersion)
|
|
||||||
throws TransportException, NotSupportedException {
|
|
||||||
URL u = getServiceURL(service);
|
URL u = getServiceURL(service);
|
||||||
int authAttempts = 1;
|
int authAttempts = 1;
|
||||||
int redirects = 0;
|
int redirects = 0;
|
||||||
|
@ -530,11 +507,6 @@ private HttpConnection connect(String service,
|
||||||
} else {
|
} else {
|
||||||
conn.setRequestProperty(HDR_ACCEPT, "*/*"); //$NON-NLS-1$
|
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);
|
final int status = HttpSupport.response(conn);
|
||||||
processResponseCookies(conn);
|
processResponseCookies(conn);
|
||||||
switch (status) {
|
switch (status) {
|
||||||
|
@ -1176,37 +1148,20 @@ private boolean isGzipContent(HttpConnection c) {
|
||||||
|
|
||||||
private void readSmartHeaders(InputStream in, String service)
|
private void readSmartHeaders(InputStream in, String service)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
// A smart protocol V0 reply will have a '#' after the first 4 bytes,
|
// A smart reply will have a '#' after the first 4 bytes, but
|
||||||
// but a dumb reply cannot contain a '#' until after byte 41. Do a
|
// a dumb reply cannot contain a '#' until after byte 41. Do a
|
||||||
// quick check to make sure its a smart reply before we parse
|
// quick check to make sure its a smart reply before we parse
|
||||||
// as a pkt-line stream.
|
// as a pkt-line stream.
|
||||||
//
|
//
|
||||||
// There appears to be a confusion about this in protocol V2. Github
|
final byte[] magic = new byte[5];
|
||||||
// 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);
|
|
||||||
IO.readFully(in, magic, 0, magic.length);
|
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] != '#') {
|
if (magic[4] != '#') {
|
||||||
throw new TransportException(uri, MessageFormat.format(
|
throw new TransportException(uri, MessageFormat.format(
|
||||||
JGitText.get().expectedPktLineWithService, RawParseUtils.decode(magic)));
|
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 exp = "# service=" + service; //$NON-NLS-1$
|
||||||
final String act = pckIn.readString();
|
final String act = pckIn.readString();
|
||||||
if (!exp.equals(act)) {
|
if (!exp.equals(act)) {
|
||||||
|
@ -1372,24 +1327,12 @@ class SmartHttpFetchConnection extends BasePackFetchConnection {
|
||||||
|
|
||||||
SmartHttpFetchConnection(InputStream advertisement)
|
SmartHttpFetchConnection(InputStream advertisement)
|
||||||
throws TransportException {
|
throws TransportException {
|
||||||
this(advertisement, Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
SmartHttpFetchConnection(InputStream advertisement,
|
|
||||||
Collection<RefSpec> refSpecs, String... additionalPatterns)
|
|
||||||
throws TransportException {
|
|
||||||
super(TransportHttp.this);
|
super(TransportHttp.this);
|
||||||
statelessRPC = true;
|
statelessRPC = true;
|
||||||
|
|
||||||
init(advertisement, DisabledOutputStream.INSTANCE);
|
init(advertisement, DisabledOutputStream.INSTANCE);
|
||||||
outNeedsEnd = false;
|
outNeedsEnd = false;
|
||||||
if (!readAdvertisedRefs()) {
|
readAdvertisedRefs();
|
||||||
// Must be protocol V2
|
|
||||||
LongPollService service = new LongPollService(SVC_UPLOAD_PACK,
|
|
||||||
getProtocolVersion());
|
|
||||||
init(service.getInputStream(), service.getOutputStream());
|
|
||||||
lsRefs(refSpecs, additionalPatterns);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1397,8 +1340,7 @@ protected void doFetch(final ProgressMonitor monitor,
|
||||||
final Collection<Ref> want, final Set<ObjectId> have,
|
final Collection<Ref> want, final Set<ObjectId> have,
|
||||||
final OutputStream outputStream) throws TransportException {
|
final OutputStream outputStream) throws TransportException {
|
||||||
try {
|
try {
|
||||||
svc = new MultiRequestService(SVC_UPLOAD_PACK,
|
svc = new MultiRequestService(SVC_UPLOAD_PACK);
|
||||||
getProtocolVersion());
|
|
||||||
init(svc.getInputStream(), svc.getOutputStream());
|
init(svc.getInputStream(), svc.getOutputStream());
|
||||||
super.doFetch(monitor, want, have, outputStream);
|
super.doFetch(monitor, want, have, outputStream);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -1427,8 +1369,7 @@ class SmartHttpPushConnection extends BasePackPushConnection {
|
||||||
protected void doPush(final ProgressMonitor monitor,
|
protected void doPush(final ProgressMonitor monitor,
|
||||||
final Map<String, RemoteRefUpdate> refUpdates,
|
final Map<String, RemoteRefUpdate> refUpdates,
|
||||||
OutputStream outputStream) throws TransportException {
|
OutputStream outputStream) throws TransportException {
|
||||||
final Service svc = new MultiRequestService(SVC_RECEIVE_PACK,
|
final Service svc = new MultiRequestService(SVC_RECEIVE_PACK);
|
||||||
getProtocolVersion());
|
|
||||||
init(svc.getInputStream(), svc.getOutputStream());
|
init(svc.getInputStream(), svc.getOutputStream());
|
||||||
super.doPush(monitor, refUpdates, outputStream);
|
super.doPush(monitor, refUpdates, outputStream);
|
||||||
}
|
}
|
||||||
|
@ -1448,14 +1389,10 @@ abstract class Service {
|
||||||
|
|
||||||
protected final HttpExecuteStream execute;
|
protected final HttpExecuteStream execute;
|
||||||
|
|
||||||
protected final TransferConfig.ProtocolVersion protocolVersion;
|
|
||||||
|
|
||||||
final UnionInputStream in;
|
final UnionInputStream in;
|
||||||
|
|
||||||
Service(String serviceName,
|
Service(String serviceName) {
|
||||||
TransferConfig.ProtocolVersion protocolVersion) {
|
|
||||||
this.serviceName = serviceName;
|
this.serviceName = serviceName;
|
||||||
this.protocolVersion = protocolVersion;
|
|
||||||
this.requestType = "application/x-" + serviceName + "-request"; //$NON-NLS-1$ //$NON-NLS-2$
|
this.requestType = "application/x-" + serviceName + "-request"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
this.responseType = "application/x-" + serviceName + "-result"; //$NON-NLS-1$ //$NON-NLS-2$
|
this.responseType = "application/x-" + serviceName + "-result"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
|
||||||
|
@ -1471,10 +1408,6 @@ void openStream() throws IOException {
|
||||||
conn.setDoOutput(true);
|
conn.setDoOutput(true);
|
||||||
conn.setRequestProperty(HDR_CONTENT_TYPE, requestType);
|
conn.setRequestProperty(HDR_CONTENT_TYPE, requestType);
|
||||||
conn.setRequestProperty(HDR_ACCEPT, responseType);
|
conn.setRequestProperty(HDR_ACCEPT, responseType);
|
||||||
if (TransferConfig.ProtocolVersion.V2.equals(protocolVersion)) {
|
|
||||||
conn.setRequestProperty(GitProtocolConstants.PROTOCOL_HEADER,
|
|
||||||
GitProtocolConstants.VERSION_2_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendRequest() throws IOException {
|
void sendRequest() throws IOException {
|
||||||
|
@ -1730,9 +1663,8 @@ protected OutputStream overflow() throws IOException {
|
||||||
class MultiRequestService extends Service {
|
class MultiRequestService extends Service {
|
||||||
boolean finalRequest;
|
boolean finalRequest;
|
||||||
|
|
||||||
MultiRequestService(String serviceName,
|
MultiRequestService(String serviceName) {
|
||||||
TransferConfig.ProtocolVersion protocolVersion) {
|
super(serviceName);
|
||||||
super(serviceName, protocolVersion);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Keep opening send-receive pairs to the given URI. */
|
/** Keep opening send-receive pairs to the given URI. */
|
||||||
|
@ -1769,10 +1701,11 @@ void execute() throws IOException {
|
||||||
|
|
||||||
/** Service for maintaining a single long-poll connection. */
|
/** Service for maintaining a single long-poll connection. */
|
||||||
class LongPollService extends Service {
|
class LongPollService extends Service {
|
||||||
|
/**
|
||||||
LongPollService(String serviceName,
|
* @param serviceName
|
||||||
TransferConfig.ProtocolVersion protocolVersion) {
|
*/
|
||||||
super(serviceName, protocolVersion);
|
LongPollService(String serviceName) {
|
||||||
|
super(serviceName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Only open one send-receive request. */
|
/** Only open one send-receive request. */
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -154,17 +153,11 @@ private Repository openRepo() throws TransportException {
|
||||||
/** {@inheritDoc} */
|
/** {@inheritDoc} */
|
||||||
@Override
|
@Override
|
||||||
public FetchConnection openFetch() throws TransportException {
|
public FetchConnection openFetch() throws TransportException {
|
||||||
return openFetch(Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public FetchConnection openFetch(Collection<RefSpec> refSpecs,
|
|
||||||
String... additionalPatterns) throws TransportException {
|
|
||||||
final String up = getOptionUploadPack();
|
final String up = getOptionUploadPack();
|
||||||
if (!"git-upload-pack".equals(up) //$NON-NLS-1$
|
if (!"git-upload-pack".equals(up) //$NON-NLS-1$
|
||||||
&& !"git upload-pack".equals(up)) {//$NON-NLS-1$
|
&& !"git upload-pack".equals(up)) //$NON-NLS-1$
|
||||||
return new ForkLocalFetchConnection(refSpecs, additionalPatterns);
|
return new ForkLocalFetchConnection();
|
||||||
}
|
|
||||||
UploadPackFactory<Void> upf = (Void req,
|
UploadPackFactory<Void> upf = (Void req,
|
||||||
Repository db) -> createUploadPack(db);
|
Repository db) -> createUploadPack(db);
|
||||||
return new InternalFetchConnection<>(this, upf, null, openRepo());
|
return new InternalFetchConnection<>(this, upf, null, openRepo());
|
||||||
|
@ -200,23 +193,6 @@ public void close() {
|
||||||
*/
|
*/
|
||||||
protected Process spawn(String cmd)
|
protected Process spawn(String cmd)
|
||||||
throws TransportException {
|
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 {
|
try {
|
||||||
String[] args = { "." }; //$NON-NLS-1$
|
String[] args = { "." }; //$NON-NLS-1$
|
||||||
ProcessBuilder proc = local.getFS().runInShell(cmd, args);
|
ProcessBuilder proc = local.getFS().runInShell(cmd, args);
|
||||||
|
@ -232,10 +208,7 @@ private Process spawn(String cmd,
|
||||||
env.remove("GIT_GRAFT_FILE"); //$NON-NLS-1$
|
env.remove("GIT_GRAFT_FILE"); //$NON-NLS-1$
|
||||||
env.remove("GIT_INDEX_FILE"); //$NON-NLS-1$
|
env.remove("GIT_INDEX_FILE"); //$NON-NLS-1$
|
||||||
env.remove("GIT_NO_REPLACE_OBJECTS"); //$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();
|
return proc.start();
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
throw new TransportException(uri, err.getMessage(), err);
|
throw new TransportException(uri, err.getMessage(), err);
|
||||||
|
@ -248,21 +221,12 @@ class ForkLocalFetchConnection extends BasePackFetchConnection {
|
||||||
private Thread errorReaderThread;
|
private Thread errorReaderThread;
|
||||||
|
|
||||||
ForkLocalFetchConnection() throws TransportException {
|
ForkLocalFetchConnection() throws TransportException {
|
||||||
this(Collections.emptyList());
|
|
||||||
}
|
|
||||||
|
|
||||||
ForkLocalFetchConnection(Collection<RefSpec> refSpecs,
|
|
||||||
String... additionalPatterns) throws TransportException {
|
|
||||||
super(TransportLocal.this);
|
super(TransportLocal.this);
|
||||||
|
|
||||||
final MessageWriter msg = new MessageWriter();
|
final MessageWriter msg = new MessageWriter();
|
||||||
setMessageWriter(msg);
|
setMessageWriter(msg);
|
||||||
|
|
||||||
TransferConfig.ProtocolVersion gitProtocol = protocol;
|
uploadPack = spawn(getOptionUploadPack());
|
||||||
if (gitProtocol == null) {
|
|
||||||
gitProtocol = TransferConfig.ProtocolVersion.V2;
|
|
||||||
}
|
|
||||||
uploadPack = spawn(getOptionUploadPack(), gitProtocol);
|
|
||||||
|
|
||||||
final InputStream upErr = uploadPack.getErrorStream();
|
final InputStream upErr = uploadPack.getErrorStream();
|
||||||
errorReaderThread = new StreamCopyThread(upErr, msg.getRawStream());
|
errorReaderThread = new StreamCopyThread(upErr, msg.getRawStream());
|
||||||
|
@ -275,9 +239,7 @@ class ForkLocalFetchConnection extends BasePackFetchConnection {
|
||||||
upOut = new BufferedOutputStream(upOut);
|
upOut = new BufferedOutputStream(upOut);
|
||||||
|
|
||||||
init(upIn, upOut);
|
init(upIn, upOut);
|
||||||
if (!readAdvertisedRefs()) {
|
readAdvertisedRefs();
|
||||||
lsRefs(refSpecs, additionalPatterns);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,7 +33,6 @@
|
||||||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND;
|
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_SIDE_BAND_64K;
|
||||||
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK;
|
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 static org.eclipse.jgit.util.RefMap.toRefMap;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
|
@ -710,7 +709,7 @@ public boolean isSideBand() throws RequestNotYetReadException {
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public void setExtraParameters(Collection<String> params) {
|
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 @@ private void fetchV2(PacketLineOut pckOut) throws IOException {
|
||||||
new PacketLineOut(NullOutputStream.INSTANCE),
|
new PacketLineOut(NullOutputStream.INSTANCE),
|
||||||
accumulator);
|
accumulator);
|
||||||
} else {
|
} else {
|
||||||
pckOut.writeString(
|
pckOut.writeString("acknowledgments\n"); //$NON-NLS-1$
|
||||||
GitProtocolConstants.SECTION_ACKNOWLEDGMENTS + '\n');
|
|
||||||
for (ObjectId id : req.getPeerHas()) {
|
for (ObjectId id : req.getPeerHas()) {
|
||||||
if (walk.getObjectReader().has(id)) {
|
if (walk.getObjectReader().has(id)) {
|
||||||
pckOut.writeString("ACK " + id.getName() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
pckOut.writeString("ACK " + id.getName() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||||
|
@ -1245,8 +1243,7 @@ private void fetchV2(PacketLineOut pckOut) throws IOException {
|
||||||
if (!pckOut.isUsingSideband()) {
|
if (!pckOut.isUsingSideband()) {
|
||||||
// sendPack will write "packfile\n" for us if sideband-all is used.
|
// 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.
|
// But sideband-all is not used, so we have to write it ourselves.
|
||||||
pckOut.writeString(
|
pckOut.writeString("packfile\n"); //$NON-NLS-1$
|
||||||
GitProtocolConstants.SECTION_PACKFILE + '\n');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
accumulator.timeNegotiating = Duration
|
accumulator.timeNegotiating = Duration
|
||||||
|
@ -2330,8 +2327,7 @@ else if (ref.getName().startsWith(Constants.R_HEADS))
|
||||||
// for us if provided a PackfileUriConfig. In this case, we
|
// for us if provided a PackfileUriConfig. In this case, we
|
||||||
// are not providing a PackfileUriConfig, so we have to
|
// are not providing a PackfileUriConfig, so we have to
|
||||||
// write this line ourselves.
|
// write this line ourselves.
|
||||||
pckOut.writeString(
|
pckOut.writeString("packfile\n"); //$NON-NLS-1$
|
||||||
GitProtocolConstants.SECTION_PACKFILE + '\n');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pw.writePack(pm, NullProgressMonitor.INSTANCE, packOut);
|
pw.writePack(pm, NullProgressMonitor.INSTANCE, packOut);
|
||||||
|
|
Loading…
Reference in New Issue