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