"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.
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());
+ }
}
assertEquals(up.getPeerUserAgent(), "JGit-test/1.2.3");
}
+ @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,
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) {
@Nullable
final String agent;
+ @Nullable
+ final String clientSID;
+
/**
* Initialize the common fields of a fetch request.
*
* 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);
this.deepenSince = deepenSince;
this.deepenNots = requireNonNull(deepenNots);
this.agent = agent;
+ this.clientSID = clientSID;
}
/**
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;
+ }
}
@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 {
String agent;
+ String clientSID;
+
/**
* @param objectId
* object id received in a "want" line
return this;
}
+ /**
+ * @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
FetchV0Request build() {
return new FetchV0Request(wantIds, depth, clientShallowCommits,
- filterSpec, clientCaps, deepenSince, deepenNots, agent);
+ filterSpec, clientCaps, deepenSince, deepenNots, agent,
+ clientSID);
}
}
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;
@Nullable
String agent;
+ @Nullable
+ String clientSID;
+
final List<String> serverOptions = new ArrayList<>();
boolean sidebandAll;
return this;
}
+ /**
+ * @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
depth, filterSpec, doneReceived, waitForDone, clientCapabilities,
agent, Collections.unmodifiableList(serverOptions),
sidebandAll,
- Collections.unmodifiableList(packfileUriProtocols));
+ Collections.unmodifiableList(packfileUriProtocols),
+ clientSID);
}
}
}
@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. */
return agent;
}
+ /**
+ * @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.
private String agent;
+ private String clientSID;
+
private Builder() {
}
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);
}
}
}
FirstWant firstLine = FirstWant.fromLine(line);
reqBuilder.addClientCapabilities(firstLine.getCapabilities());
reqBuilder.setAgent(firstLine.getAgent());
+ reqBuilder.setClientSID(firstLine.getClientSID());
line = firstLine.getLine();
}
}
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;
*/
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)) {
.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.
}
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();
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();
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;
: "")
+ OPTION_SHALLOW);
caps.add(CAPABILITY_SERVER_OPTION);
+ if (transferConfig.isAllowReceiveClientSID()) {
+ caps.add(OPTION_SESSION_ID);
+ }
+
return caps;
}
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)