1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.transport;
11
12 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_DEEPEN_RELATIVE;
13 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_FILTER;
14 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
15 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_INCLUDE_TAG;
16 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_NO_PROGRESS;
17 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_OFS_DELTA;
18 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SERVER_OPTION;
19 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDEBAND_ALL;
20 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K;
21 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK;
22 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_WAIT_FOR_DONE;
23 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SESSION_ID;
24 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN;
25 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN_NOT;
26 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DEEPEN_SINCE;
27 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_DONE;
28 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_HAVE;
29 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_SHALLOW;
30 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_WANT;
31 import static org.eclipse.jgit.transport.GitProtocolConstants.PACKET_WANT_REF;
32
33 import java.io.IOException;
34 import java.text.MessageFormat;
35 import java.util.ArrayList;
36 import java.util.List;
37 import java.util.function.Consumer;
38
39 import org.eclipse.jgit.errors.InvalidObjectIdException;
40 import org.eclipse.jgit.errors.PackProtocolException;
41 import org.eclipse.jgit.internal.JGitText;
42 import org.eclipse.jgit.lib.ObjectId;
43
44
45
46
47
48
49
50
51 final class ProtocolV2Parser {
52
53 private final TransferConfig transferConfig;
54
55 ProtocolV2Parser(TransferConfig transferConfig) {
56 this.transferConfig = transferConfig;
57 }
58
59
60
61
62
63
64
65 private static String consumeCapabilities(PacketLineIn pckIn,
66 Consumer<String> serverOptionConsumer,
67 Consumer<String> agentConsumer,
68 Consumer<String> clientSIDConsumer) throws IOException {
69
70 String serverOptionPrefix = OPTION_SERVER_OPTION + '=';
71 String agentPrefix = OPTION_AGENT + '=';
72 String clientSIDPrefix = OPTION_SESSION_ID + '=';
73
74 String line = pckIn.readString();
75 while (!PacketLineIn.isDelimiter(line) && !PacketLineIn.isEnd(line)) {
76 if (line.startsWith(serverOptionPrefix)) {
77 serverOptionConsumer
78 .accept(line.substring(serverOptionPrefix.length()));
79 } else if (line.startsWith(agentPrefix)) {
80 agentConsumer.accept(line.substring(agentPrefix.length()));
81 } else if (line.startsWith(clientSIDPrefix)) {
82 clientSIDConsumer
83 .accept(line.substring(clientSIDPrefix.length()));
84 } else {
85
86 }
87 line = pckIn.readString();
88 }
89
90 return line;
91 }
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107 FetchV2Request parseFetchRequest(PacketLineIn pckIn)
108 throws PackProtocolException, IOException {
109 FetchV2Request.Builder reqBuilder = FetchV2Request.builder();
110
111
112
113 reqBuilder.addClientCapability(OPTION_SIDE_BAND_64K);
114
115 String line = consumeCapabilities(pckIn,
116 serverOption -> reqBuilder.addServerOption(serverOption),
117 agent -> reqBuilder.setAgent(agent),
118 clientSID -> reqBuilder.setClientSID(clientSID));
119
120 if (PacketLineIn.isEnd(line)) {
121 return reqBuilder.build();
122 }
123
124 if (!PacketLineIn.isDelimiter(line)) {
125 throw new PackProtocolException(
126 MessageFormat.format(JGitText.get().unexpectedPacketLine,
127 line));
128 }
129
130 boolean filterReceived = false;
131 for (String line2 : pckIn.readStrings()) {
132 if (line2.startsWith(PACKET_WANT)) {
133 reqBuilder.addWantId(ObjectId
134 .fromString(line2.substring(PACKET_WANT.length())));
135 } else if (transferConfig.isAllowRefInWant()
136 && line2.startsWith(PACKET_WANT_REF)) {
137 reqBuilder.addWantedRef(
138 line2.substring(PACKET_WANT_REF.length()));
139 } else if (line2.startsWith(PACKET_HAVE)) {
140 reqBuilder.addPeerHas(ObjectId
141 .fromString(line2.substring(PACKET_HAVE.length())));
142 } else if (line2.equals(PACKET_DONE)) {
143 reqBuilder.setDoneReceived();
144 } else if (line2.equals(OPTION_WAIT_FOR_DONE)) {
145 reqBuilder.setWaitForDone();
146 } else if (line2.equals(OPTION_THIN_PACK)) {
147 reqBuilder.addClientCapability(OPTION_THIN_PACK);
148 } else if (line2.equals(OPTION_NO_PROGRESS)) {
149 reqBuilder.addClientCapability(OPTION_NO_PROGRESS);
150 } else if (line2.equals(OPTION_INCLUDE_TAG)) {
151 reqBuilder.addClientCapability(OPTION_INCLUDE_TAG);
152 } else if (line2.equals(OPTION_OFS_DELTA)) {
153 reqBuilder.addClientCapability(OPTION_OFS_DELTA);
154 } else if (line2.startsWith(PACKET_SHALLOW)) {
155 reqBuilder.addClientShallowCommit(
156 ObjectId.fromString(
157 line2.substring(PACKET_SHALLOW.length())));
158 } else if (line2.startsWith(PACKET_DEEPEN)) {
159 int parsedDepth = Integer
160 .parseInt(line2.substring(PACKET_DEEPEN.length()));
161 if (parsedDepth <= 0) {
162 throw new PackProtocolException(
163 MessageFormat.format(JGitText.get().invalidDepth,
164 Integer.valueOf(parsedDepth)));
165 }
166 if (reqBuilder.getDeepenSince() != 0) {
167 throw new PackProtocolException(
168 JGitText.get().deepenSinceWithDeepen);
169 }
170 if (reqBuilder.hasDeepenNots()) {
171 throw new PackProtocolException(
172 JGitText.get().deepenNotWithDeepen);
173 }
174 reqBuilder.setDepth(parsedDepth);
175 } else if (line2.startsWith(PACKET_DEEPEN_NOT)) {
176 reqBuilder.addDeepenNot(
177 line2.substring(PACKET_DEEPEN_NOT.length()));
178 if (reqBuilder.getDepth() != 0) {
179 throw new PackProtocolException(
180 JGitText.get().deepenNotWithDeepen);
181 }
182 } else if (line2.equals(OPTION_DEEPEN_RELATIVE)) {
183 reqBuilder.addClientCapability(OPTION_DEEPEN_RELATIVE);
184 } else if (line2.startsWith(PACKET_DEEPEN_SINCE)) {
185 int ts = Integer.parseInt(
186 line2.substring(PACKET_DEEPEN_SINCE.length()));
187 if (ts <= 0) {
188 throw new PackProtocolException(MessageFormat
189 .format(JGitText.get().invalidTimestamp, line2));
190 }
191 if (reqBuilder.getDepth() != 0) {
192 throw new PackProtocolException(
193 JGitText.get().deepenSinceWithDeepen);
194 }
195 reqBuilder.setDeepenSince(ts);
196 } else if (transferConfig.isAllowFilter()
197 && line2.startsWith(OPTION_FILTER + ' ')) {
198 if (filterReceived) {
199 throw new PackProtocolException(
200 JGitText.get().tooManyFilters);
201 }
202 filterReceived = true;
203 reqBuilder.setFilterSpec(FilterSpec.fromFilterLine(
204 line2.substring(OPTION_FILTER.length() + 1)));
205 } else if (transferConfig.isAllowSidebandAll()
206 && line2.equals(OPTION_SIDEBAND_ALL)) {
207 reqBuilder.setSidebandAll(true);
208 } else if (line2.startsWith("packfile-uris ")) {
209 for (String s : line2.substring(14).split(",")) {
210 reqBuilder.addPackfileUriProtocol(s);
211 }
212 } else {
213 throw new PackProtocolException(MessageFormat
214 .format(JGitText.get().unexpectedPacketLine, line2));
215 }
216 }
217
218 return reqBuilder.build();
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238 LsRefsV2Request parseLsRefsRequest(PacketLineIn pckIn)
239 throws PackProtocolException, IOException {
240 LsRefsV2Request.Builder builder = LsRefsV2Request.builder();
241 List<String> prefixes = new ArrayList<>();
242
243 String line = consumeCapabilities(pckIn,
244 serverOption -> builder.addServerOption(serverOption),
245 agent -> builder.setAgent(agent),
246 clientSID -> builder.setClientSID(clientSID));
247
248 if (PacketLineIn.isEnd(line)) {
249 return builder.build();
250 }
251
252 if (!PacketLineIn.isDelimiter(line)) {
253 throw new PackProtocolException(MessageFormat
254 .format(JGitText.get().unexpectedPacketLine, line));
255 }
256
257 for (String line2 : pckIn.readStrings()) {
258 if (line2.equals("peel")) {
259 builder.setPeel(true);
260 } else if (line2.equals("symrefs")) {
261 builder.setSymrefs(true);
262 } else if (line2.startsWith("ref-prefix ")) {
263 prefixes.add(line2.substring("ref-prefix ".length()));
264 } else {
265 throw new PackProtocolException(MessageFormat
266 .format(JGitText.get().unexpectedPacketLine, line2));
267 }
268 }
269
270 return builder.setRefPrefixes(prefixes).build();
271 }
272
273 ObjectInfoRequest parseObjectInfoRequest(PacketLineIn pckIn)
274 throws PackProtocolException, IOException {
275 ObjectInfoRequest.Builder builder = ObjectInfoRequest.builder();
276 List<ObjectId> objectIDs = new ArrayList<>();
277
278 String line = pckIn.readString();
279
280 if (PacketLineIn.isEnd(line)) {
281 return builder.build();
282 }
283
284 if (!line.equals("size")) {
285 throw new PackProtocolException(MessageFormat
286 .format(JGitText.get().unexpectedPacketLine, line));
287 }
288
289 for (String line2 : pckIn.readStrings()) {
290 if (!line2.startsWith("oid ")) {
291 throw new PackProtocolException(MessageFormat
292 .format(JGitText.get().unexpectedPacketLine, line2));
293 }
294
295 String oidStr = line2.substring("oid ".length());
296
297 try {
298 objectIDs.add(ObjectId.fromString(oidStr));
299 } catch (InvalidObjectIdException e) {
300 throw new PackProtocolException(MessageFormat
301 .format(JGitText.get().invalidObject, oidStr), e);
302 }
303 }
304
305 return builder.setObjectIDs(objectIDs).build();
306 }
307 }