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