aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Brown <sjoshbrown@google.com>2022-11-01 20:51:48 +0000
committerJosh Brown <sjoshbrown@google.com>2022-11-02 16:13:22 -0400
commitfe9aeb02e616863bf0f19a4beb03c0916ca57c5d (patch)
tree649a1f295d25d081f70ecae9eb21ccd8c661f001
parent7b0a71a5e9916f0782eb24056a35b376373fdf59 (diff)
downloadjgit-fe9aeb02e616863bf0f19a4beb03c0916ca57c5d.tar.gz
jgit-fe9aeb02e616863bf0f19a4beb03c0916ca57c5d.zip
UploadPack: Receive and parse client session-id
Before this change JGit did not support the session-id capability implemented by native Git in UploadPack. This change implements advertising the capability from the server and parsing the session-id received from the client during an UploadPack operation. Enable the transfer.advertisesid config setting to advertise the capability from the server. The client may send a session-id capability in response. If received, the value from this is parsed and available via the getClientSID method on the UploadPack object. This change does not add the capability to send a session-id from the JGit client. https://git-scm.com/docs/gitprotocol-capabilities#_session_idsession_id Change-Id: Ib1b6929ff1b3a4528e767925b5e5c44b5d18182f Signed-off-by: Josh Brown <sjoshbrown@google.com>
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java19
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java24
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java42
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchRequest.java18
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV0Request.java21
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java22
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/LsRefsV2Request.java37
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java14
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java20
10 files changed, 206 insertions, 12 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java
index b2a4af30ab..61b7fb619a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV0ParserTest.java
@@ -98,6 +98,25 @@ public class ProtocolV0ParserTest {
"f900c8326a43303685c46b279b9f70411bff1a4b"));
}
+ @Test
+ public void testRecvWantsWithSessionID()
+ throws PackProtocolException, IOException {
+ PacketLineIn pckIn = formatAsPacketLine(String.join(" ", "want",
+ "4624442d68ee402a94364191085b77137618633e", "thin-pack",
+ "agent=JGit.test/0.0.1", "session-id=client-session-id", "\n"),
+ "want f900c8326a43303685c46b279b9f70411bff1a4b\n",
+ PacketLineIn.end());
+ ProtocolV0Parser parser = new ProtocolV0Parser(defaultConfig());
+ FetchV0Request request = parser.recvWants(pckIn);
+ assertTrue(request.getClientCapabilities()
+ .contains(GitProtocolConstants.OPTION_THIN_PACK));
+ assertEquals(1, request.getClientCapabilities().size());
+ assertEquals("client-session-id", request.getClientSID());
+ assertThat(request.getWantIds(),
+ hasOnlyObjectIds("4624442d68ee402a94364191085b77137618633e",
+ "f900c8326a43303685c46b279b9f70411bff1a4b"));
+ }
+
/*
* First round of protocol v0 negotiation. Client send wants, no
* capabilities.
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java
index 167b5b72c6..bab4a36cc4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ProtocolV2ParserTest.java
@@ -361,4 +361,28 @@ public class ProtocolV2ParserTest {
assertEquals(2, req.getRefPrefixes().size());
assertThat(req.getRefPrefixes(), hasItems("refs/for", "refs/heads"));
}
+
+ @Test
+ public void testFetchWithSessionID() throws IOException {
+ PacketLineIn pckIn = formatAsPacketLine("session-id=the.client.sid",
+ PacketLineIn.end());
+
+ ProtocolV2Parser parser = new ProtocolV2Parser(
+ ConfigBuilder.start().allowFilter().done());
+ FetchV2Request request = parser.parseFetchRequest(pckIn);
+
+ assertEquals("the.client.sid", request.getClientSID());
+ }
+
+ @Test
+ public void testLsRefsWithSessionID() throws IOException {
+ PacketLineIn pckIn = formatAsPacketLine("session-id=the.client.sid",
+ PacketLineIn.delimiter(), PacketLineIn.end());
+
+ ProtocolV2Parser parser = new ProtocolV2Parser(
+ ConfigBuilder.getDefault());
+ LsRefsV2Request req = parser.parseLsRefsRequest(pckIn);
+
+ assertEquals("the.client.sid", req.getClientSID());
+ }
}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index 7131905850..df48afef35 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -2429,6 +2429,24 @@ public class UploadPackTest {
}
@Test
+ public void testGetSessionIDValueProtocolV0() throws Exception {
+ RevCommit one = remote.commit().message("1").create();
+ remote.update("one", one);
+
+ UploadPack up = new UploadPack(server);
+ ByteArrayInputStream send = linesAsInputStream(
+ "want " + one.getName() + " agent=JGit-test/1.2.3"
+ + " session-id=client-session-id\n",
+ PacketLineIn.end(),
+ "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n");
+
+ ByteArrayOutputStream recv = new ByteArrayOutputStream();
+ up.upload(send, recv, null);
+
+ assertEquals(up.getClientSID(), "client-session-id");
+ }
+
+ @Test
public void testGetPeerAgentProtocolV2() throws Exception {
server.getConfig().setString(ConfigConstants.CONFIG_PROTOCOL_SECTION,
null, ConfigConstants.CONFIG_KEY_VERSION,
@@ -2452,6 +2470,30 @@ public class UploadPackTest {
assertEquals(up.getPeerUserAgent(), "JGit-test/1.2.4");
}
+ @Test
+ public void testGetSessionIDValueProtocolV2() throws Exception {
+ server.getConfig().setString(ConfigConstants.CONFIG_PROTOCOL_SECTION,
+ null, ConfigConstants.CONFIG_KEY_VERSION,
+ TransferConfig.ProtocolVersion.V2.version());
+
+ RevCommit one = remote.commit().message("1").create();
+ remote.update("one", one);
+
+ UploadPack up = new UploadPack(server);
+ up.setExtraParameters(Sets.of("version=2"));
+
+ ByteArrayInputStream send = linesAsInputStream("command=fetch\n",
+ "agent=JGit-test/1.2.4\n", "session-id=client-session-id\n",
+ PacketLineIn.delimiter(), "want " + one.getName() + "\n",
+ "have 11cedf1b796d44207da702f7d420684022fc0f09\n", "done\n",
+ PacketLineIn.end());
+
+ ByteArrayOutputStream recv = new ByteArrayOutputStream();
+ up.upload(send, recv, null);
+
+ assertEquals(up.getClientSID(), "client-session-id");
+ }
+
private static class RejectAllRefFilter implements RefFilter {
@Override
public Map<String, Ref> filter(Map<String, Ref> refs) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchRequest.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchRequest.java
index 0663c5141c..009a70b7b3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchRequest.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchRequest.java
@@ -40,6 +40,9 @@ abstract class FetchRequest {
@Nullable
final String agent;
+ @Nullable
+ final String clientSID;
+
/**
* Initialize the common fields of a fetch request.
*
@@ -61,12 +64,15 @@ abstract class FetchRequest {
* specific time, instead of depth
* @param agent
* agent as reported by the client in the request body
+ * @param clientSID
+ * agent as reported by the client in the request body
*/
FetchRequest(@NonNull Set<ObjectId> wantIds, int depth,
@NonNull Set<ObjectId> clientShallowCommits,
@NonNull FilterSpec filterSpec,
@NonNull Set<String> clientCapabilities, int deepenSince,
- @NonNull List<String> deepenNots, @Nullable String agent) {
+ @NonNull List<String> deepenNots, @Nullable String agent,
+ @Nullable String clientSID) {
this.wantIds = requireNonNull(wantIds);
this.depth = depth;
this.clientShallowCommits = requireNonNull(clientShallowCommits);
@@ -75,6 +81,7 @@ abstract class FetchRequest {
this.deepenSince = deepenSince;
this.deepenNots = requireNonNull(deepenNots);
this.agent = agent;
+ this.clientSID = clientSID;
}
/**
@@ -160,4 +167,13 @@ abstract class FetchRequest {
String getAgent() {
return agent;
}
+
+ /**
+ * @return string identifying the client session ID (as sent in the request body by the
+ * client)
+ */
+ @Nullable
+ String getClientSID() {
+ return clientSID;
+ }
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV0Request.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV0Request.java
index 4decb79513..ca3639d03c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV0Request.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV0Request.java
@@ -30,9 +30,11 @@ final class FetchV0Request extends FetchRequest {
@NonNull Set<ObjectId> clientShallowCommits,
@NonNull FilterSpec filterSpec,
@NonNull Set<String> clientCapabilities, int deepenSince,
- @NonNull List<String> deepenNotRefs, @Nullable String agent) {
+ @NonNull List<String> deepenNotRefs, @Nullable String agent,
+ @Nullable String clientSID) {
super(wantIds, depth, clientShallowCommits, filterSpec,
- clientCapabilities, deepenSince, deepenNotRefs, agent);
+ clientCapabilities, deepenSince, deepenNotRefs, agent,
+ clientSID);
}
static final class Builder {
@@ -53,6 +55,8 @@ final class FetchV0Request extends FetchRequest {
String agent;
+ String clientSID;
+
/**
* @param objectId
* object id received in a "want" line
@@ -149,6 +153,16 @@ final class FetchV0Request extends FetchRequest {
}
/**
+ * @param clientSID
+ * session-id line sent by the client in the request body
+ * @return this builder
+ */
+ Builder setClientSID(String clientSID) {
+ this.clientSID = clientSID;
+ return this;
+ }
+
+ /**
* @param filter
* the filter set in a filter line
* @return this builder
@@ -160,7 +174,8 @@ final class FetchV0Request extends FetchRequest {
FetchV0Request build() {
return new FetchV0Request(wantIds, depth, clientShallowCommits,
- filterSpec, clientCaps, deepenSince, deepenNots, agent);
+ filterSpec, clientCaps, deepenSince, deepenNots, agent,
+ clientSID);
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java
index 401744f6dd..3d4f38131c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchV2Request.java
@@ -55,10 +55,11 @@ public final class FetchV2Request extends FetchRequest {
boolean doneReceived, boolean waitForDone,
@NonNull Set<String> clientCapabilities,
@Nullable String agent, @NonNull List<String> serverOptions,
- boolean sidebandAll, @NonNull List<String> packfileUriProtocols) {
+ boolean sidebandAll, @NonNull List<String> packfileUriProtocols,
+ @Nullable String clientSID) {
super(wantIds, depth, clientShallowCommits, filterSpec,
clientCapabilities, deepenSince,
- deepenNots, agent);
+ deepenNots, agent, clientSID);
this.peerHas = requireNonNull(peerHas);
this.wantedRefs = requireNonNull(wantedRefs);
this.doneReceived = doneReceived;
@@ -157,6 +158,9 @@ public final class FetchV2Request extends FetchRequest {
@Nullable
String agent;
+ @Nullable
+ String clientSID;
+
final List<String> serverOptions = new ArrayList<>();
boolean sidebandAll;
@@ -317,6 +321,17 @@ public final class FetchV2Request extends FetchRequest {
}
/**
+ * @param clientSIDValue
+ * the client-supplied session capability, without the
+ * leading "session-id="
+ * @return this builder
+ */
+ Builder setClientSID(@Nullable String clientSIDValue) {
+ clientSID = clientSIDValue;
+ return this;
+ }
+
+ /**
* Records an application-specific option supplied in a server-option
* line, for later retrieval with
* {@link FetchV2Request#getServerOptions}.
@@ -354,7 +369,8 @@ public final class FetchV2Request extends FetchRequest {
depth, filterSpec, doneReceived, waitForDone, clientCapabilities,
agent, Collections.unmodifiableList(serverOptions),
sidebandAll,
- Collections.unmodifiableList(packfileUriProtocols));
+ Collections.unmodifiableList(packfileUriProtocols),
+ clientSID);
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/LsRefsV2Request.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/LsRefsV2Request.java
index f68d9c8135..856047ee19 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/LsRefsV2Request.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/LsRefsV2Request.java
@@ -36,17 +36,21 @@ public final class LsRefsV2Request {
@Nullable
private final String agent;
+ private final String clientSID;
+
@NonNull
private final List<String> serverOptions;
private LsRefsV2Request(List<String> refPrefixes, boolean symrefs,
boolean peel, @Nullable String agent,
- @NonNull List<String> serverOptions) {
+ @NonNull List<String> serverOptions,
+ @Nullable String clientSID) {
this.refPrefixes = refPrefixes;
this.symrefs = symrefs;
this.peel = peel;
this.agent = agent;
this.serverOptions = requireNonNull(serverOptions);
+ this.clientSID = clientSID;
}
/** @return ref prefixes that the client requested. */
@@ -75,6 +79,16 @@ public final class LsRefsV2Request {
}
/**
+ * @return session-id as reported by the client
+ *
+ * @since 6.4
+ */
+ @Nullable
+ public String getClientSID() {
+ return clientSID;
+ }
+
+ /**
* Get application-specific options provided by the client using
* --server-option.
* <p>
@@ -109,6 +123,8 @@ public final class LsRefsV2Request {
private String agent;
+ private String clientSID;
+
private Builder() {
}
@@ -171,11 +187,28 @@ public final class LsRefsV2Request {
return this;
}
+ /**
+ * Value of a session-id line received after the command and before the
+ * arguments. E.g. "session-id=a.b.c" should set "a.b.c".
+ *
+ * @param value
+ * the client-supplied session-id capability, without leading
+ * "session-id="
+ * @return this builder
+ *
+ * @since 6.4
+ */
+ public Builder setClientSID(@Nullable String value) {
+ clientSID = value;
+ return this;
+ }
+
/** @return LsRefsV2Request */
public LsRefsV2Request build() {
return new LsRefsV2Request(
Collections.unmodifiableList(refPrefixes), symrefs, peel,
- agent, Collections.unmodifiableList(serverOptions));
+ agent, Collections.unmodifiableList(serverOptions),
+ clientSID);
}
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java
index 21a492577f..9d055519a5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV0Parser.java
@@ -152,6 +152,7 @@ final class ProtocolV0Parser {
FirstWant firstLine = FirstWant.fromLine(line);
reqBuilder.addClientCapabilities(firstLine.getCapabilities());
reqBuilder.setAgent(firstLine.getAgent());
+ reqBuilder.setClientSID(firstLine.getClientSID());
line = firstLine.getLine();
}
}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
index b38deb69c0..c4129ff4d0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ProtocolV2Parser.java
@@ -20,6 +20,7 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDEBAND_AL
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_WAIT_FOR_DONE;
+import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SESSION_ID;
import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN;
import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN_NOT;
import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN_SINCE;
@@ -63,10 +64,12 @@ final class ProtocolV2Parser {
*/
private static String consumeCapabilities(PacketLineIn pckIn,
Consumer<String> serverOptionConsumer,
- Consumer<String> agentConsumer) throws IOException {
+ Consumer<String> agentConsumer,
+ Consumer<String> clientSIDConsumer) throws IOException {
String serverOptionPrefix = OPTION_SERVER_OPTION + '=';
String agentPrefix = OPTION_AGENT + '=';
+ String clientSIDPrefix = OPTION_SESSION_ID + '=';
String line = pckIn.readString();
while (!PacketLineIn.isDelimiter(line) && !PacketLineIn.isEnd(line)) {
@@ -75,6 +78,9 @@ final class ProtocolV2Parser {
.accept(line.substring(serverOptionPrefix.length()));
} else if (line.startsWith(agentPrefix)) {
agentConsumer.accept(line.substring(agentPrefix.length()));
+ } else if (line.startsWith(clientSIDPrefix)) {
+ clientSIDConsumer
+ .accept(line.substring(clientSIDPrefix.length()));
} else {
// Unrecognized capability. Ignore it.
}
@@ -108,7 +114,8 @@ final class ProtocolV2Parser {
String line = consumeCapabilities(pckIn,
serverOption -> reqBuilder.addServerOption(serverOption),
- agent -> reqBuilder.setAgent(agent));
+ agent -> reqBuilder.setAgent(agent),
+ clientSID -> reqBuilder.setClientSID(clientSID));
if (PacketLineIn.isEnd(line)) {
return reqBuilder.build();
@@ -235,7 +242,8 @@ final class ProtocolV2Parser {
String line = consumeCapabilities(pckIn,
serverOption -> builder.addServerOption(serverOption),
- agent -> builder.setAgent(agent));
+ agent -> builder.setAgent(agent),
+ clientSID -> builder.setClientSID(clientSID));
if (PacketLineIn.isEnd(line)) {
return builder.build();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index 65dbf12b2f..a7ce1d7c21 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -34,6 +34,7 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SHALLOW;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDEBAND_ALL;
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_SESSION_ID;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_WAIT_FOR_DONE;
import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_ACK;
@@ -1382,6 +1383,10 @@ public class UploadPack implements Closeable {
: "")
+ OPTION_SHALLOW);
caps.add(CAPABILITY_SERVER_OPTION);
+ if (transferConfig.isAllowReceiveClientSID()) {
+ caps.add(OPTION_SESSION_ID);
+ }
+
return caps;
}
@@ -1700,6 +1705,21 @@ public class UploadPack implements Closeable {
return userAgent;
}
+ /**
+ * Get the session ID if received from the client.
+ *
+ * @return The session ID if it has been received from the client.
+ * @since 6.4
+ */
+ @Nullable
+ public String getClientSID() {
+ if (currentRequest == null) {
+ return null;
+ }
+
+ return currentRequest.getClientSID();
+ }
+
private boolean negotiate(FetchRequest req,
PackStatistics.Accumulator accumulator,
PacketLineOut pckOut)