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
44 package org.eclipse.jgit.transport;
45
46 import static java.nio.charset.StandardCharsets.UTF_8;
47 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
48 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS;
49 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA;
50 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_PUSH_OPTIONS;
51 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_QUIET;
52 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
53 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
54 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
55 import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA;
56 import static org.eclipse.jgit.transport.SideBandOutputStream.CH_ERROR;
57 import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
58 import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
59
60 import java.io.EOFException;
61 import java.io.IOException;
62 import java.io.InputStream;
63 import java.io.OutputStream;
64 import java.text.MessageFormat;
65 import java.util.ArrayList;
66 import java.util.Collections;
67 import java.util.HashSet;
68 import java.util.List;
69 import java.util.Map;
70 import java.util.Set;
71 import java.util.concurrent.TimeUnit;
72
73 import org.eclipse.jgit.annotations.Nullable;
74 import org.eclipse.jgit.errors.InvalidObjectIdException;
75 import org.eclipse.jgit.errors.LargeObjectException;
76 import org.eclipse.jgit.errors.MissingObjectException;
77 import org.eclipse.jgit.errors.PackProtocolException;
78 import org.eclipse.jgit.errors.TooLargePackException;
79 import org.eclipse.jgit.internal.JGitText;
80 import org.eclipse.jgit.internal.storage.file.PackLock;
81 import org.eclipse.jgit.internal.submodule.SubmoduleValidator;
82 import org.eclipse.jgit.internal.submodule.SubmoduleValidator.SubmoduleValidationException;
83 import org.eclipse.jgit.internal.transport.parser.FirstCommand;
84 import org.eclipse.jgit.lib.AnyObjectId;
85 import org.eclipse.jgit.lib.BatchRefUpdate;
86 import org.eclipse.jgit.lib.Config;
87 import org.eclipse.jgit.lib.Constants;
88 import org.eclipse.jgit.lib.GitmoduleEntry;
89 import org.eclipse.jgit.lib.NullProgressMonitor;
90 import org.eclipse.jgit.lib.ObjectChecker;
91 import org.eclipse.jgit.lib.ObjectDatabase;
92 import org.eclipse.jgit.lib.ObjectId;
93 import org.eclipse.jgit.lib.ObjectIdSubclassMap;
94 import org.eclipse.jgit.lib.ObjectInserter;
95 import org.eclipse.jgit.lib.ObjectLoader;
96 import org.eclipse.jgit.lib.PersonIdent;
97 import org.eclipse.jgit.lib.ProgressMonitor;
98 import org.eclipse.jgit.lib.Ref;
99 import org.eclipse.jgit.lib.Repository;
100 import org.eclipse.jgit.revwalk.ObjectWalk;
101 import org.eclipse.jgit.revwalk.RevBlob;
102 import org.eclipse.jgit.revwalk.RevCommit;
103 import org.eclipse.jgit.revwalk.RevFlag;
104 import org.eclipse.jgit.revwalk.RevObject;
105 import org.eclipse.jgit.revwalk.RevSort;
106 import org.eclipse.jgit.revwalk.RevTree;
107 import org.eclipse.jgit.revwalk.RevWalk;
108 import org.eclipse.jgit.transport.PacketLineIn.InputOverLimitIOException;
109 import org.eclipse.jgit.transport.ReceiveCommand.Result;
110 import org.eclipse.jgit.util.io.InterruptTimer;
111 import org.eclipse.jgit.util.io.LimitedInputStream;
112 import org.eclipse.jgit.util.io.TimeoutInputStream;
113 import org.eclipse.jgit.util.io.TimeoutOutputStream;
114
115
116
117
118
119
120
121
122 public abstract class BaseReceivePack {
123
124
125
126
127
128 @Deprecated
129 public static class FirstLine {
130 private final FirstCommand command;
131
132
133
134
135
136
137
138 public FirstLine(String line) {
139 command = FirstCommand.fromLine(line);
140 }
141
142
143 public String getLine() {
144 return command.getLine();
145 }
146
147
148 public Set<String> getCapabilities() {
149 return command.getCapabilities();
150 }
151 }
152
153
154 final Repository db;
155
156
157 final RevWalk walk;
158
159
160
161
162
163
164
165
166
167
168
169
170 private boolean biDirectionalPipe = true;
171
172
173 private boolean expectDataAfterPackFooter;
174
175
176 private ObjectChecker objectChecker;
177
178
179 private boolean allowCreates;
180
181
182 private boolean allowAnyDeletes;
183 private boolean allowBranchDeletes;
184
185
186 private boolean allowNonFastForwards;
187
188
189 private boolean allowPushOptions;
190
191
192
193
194
195 private boolean atomic;
196
197 private boolean allowOfsDelta;
198 private boolean allowQuiet = true;
199
200
201 private PersonIdent refLogIdent;
202
203
204 private AdvertiseRefsHook advertiseRefsHook;
205
206
207 RefFilter refFilter;
208
209
210 private int timeout;
211
212
213 private InterruptTimer timer;
214
215 private TimeoutInputStream timeoutIn;
216
217
218
219 private OutputStream origOut;
220
221
222 protected InputStream rawIn;
223
224
225 protected OutputStream rawOut;
226
227
228 protected OutputStream msgOut;
229 private SideBandOutputStream errOut;
230
231
232 protected PacketLineIn pckIn;
233
234
235 protected PacketLineOut pckOut;
236
237 private final MessageOutputWrapper msgOutWrapper = new MessageOutputWrapper();
238
239 private PackParser parser;
240
241
242 Map<String, Ref> refs;
243
244
245 Set<ObjectId> advertisedHaves;
246
247
248 private Set<String> enabledCapabilities;
249 String userAgent;
250 private Set<ObjectId> clientShallowCommits;
251 private List<ReceiveCommand> commands;
252 private long maxCommandBytes;
253 private long maxDiscardBytes;
254
255 private StringBuilder advertiseError;
256
257
258 private boolean sideBand;
259
260 private boolean quiet;
261
262
263 private PackLock packLock;
264
265 private boolean checkReferencedIsReachable;
266
267
268 private long maxObjectSizeLimit;
269
270
271 private long maxPackSizeLimit = -1;
272
273
274 private Long packSize;
275
276 private PushCertificateParser pushCertificateParser;
277 private SignedPushConfig signedPushConfig;
278 PushCertificate pushCert;
279 private ReceivedPackStatistics stats;
280
281
282
283
284
285
286
287
288
289
290
291 @Deprecated
292 public abstract PushCertificate getPushCertificate();
293
294
295
296
297
298
299
300
301
302
303
304
305 @Deprecated
306 public abstract void setPushCertificate(PushCertificate cert);
307
308
309
310
311
312
313
314 protected BaseReceivePack(Repository into) {
315 db = into;
316 walk = new RevWalk(db);
317 walk.setRetainBody(false);
318
319 TransferConfig tc = db.getConfig().get(TransferConfig.KEY);
320 objectChecker = tc.newReceiveObjectChecker();
321
322 ReceiveConfig rc = db.getConfig().get(ReceiveConfig::new);
323 allowCreates = rc.allowCreates;
324 allowAnyDeletes = true;
325 allowBranchDeletes = rc.allowDeletes;
326 allowNonFastForwards = rc.allowNonFastForwards;
327 allowOfsDelta = rc.allowOfsDelta;
328 allowPushOptions = rc.allowPushOptions;
329 maxCommandBytes = rc.maxCommandBytes;
330 maxDiscardBytes = rc.maxDiscardBytes;
331 advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
332 refFilter = RefFilter.DEFAULT;
333 advertisedHaves = new HashSet<>();
334 clientShallowCommits = new HashSet<>();
335 signedPushConfig = rc.signedPush;
336 }
337
338
339 protected static class ReceiveConfig {
340 final boolean allowCreates;
341 final boolean allowDeletes;
342 final boolean allowNonFastForwards;
343 final boolean allowOfsDelta;
344 final boolean allowPushOptions;
345 final long maxCommandBytes;
346 final long maxDiscardBytes;
347 final SignedPushConfig signedPush;
348
349 ReceiveConfig(Config config) {
350 allowCreates = true;
351 allowDeletes = !config.getBoolean("receive", "denydeletes", false);
352 allowNonFastForwards = !config.getBoolean("receive",
353 "denynonfastforwards", false);
354 allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset",
355 true);
356 allowPushOptions = config.getBoolean("receive", "pushoptions",
357 false);
358 maxCommandBytes = config.getLong("receive",
359 "maxCommandBytes",
360 3 << 20);
361 maxDiscardBytes = config.getLong("receive",
362 "maxCommandDiscardBytes",
363 -1);
364 signedPush = SignedPushConfig.KEY.parse(config);
365 }
366 }
367
368
369
370
371
372
373
374 class MessageOutputWrapper extends OutputStream {
375 @Override
376 public void write(int ch) {
377 if (msgOut != null) {
378 try {
379 msgOut.write(ch);
380 } catch (IOException e) {
381
382 }
383 }
384 }
385
386 @Override
387 public void write(byte[] b, int off, int len) {
388 if (msgOut != null) {
389 try {
390 msgOut.write(b, off, len);
391 } catch (IOException e) {
392
393 }
394 }
395 }
396
397 @Override
398 public void write(byte[] b) {
399 write(b, 0, b.length);
400 }
401
402 @Override
403 public void flush() {
404 if (msgOut != null) {
405 try {
406 msgOut.flush();
407 } catch (IOException e) {
408
409 }
410 }
411 }
412 }
413
414
415
416
417
418
419 protected abstract String getLockMessageProcessName();
420
421
422
423
424
425
426
427 @Deprecated
428 public abstract Repository getRepository();
429
430
431
432
433
434
435
436 @Deprecated
437 public abstract RevWalk getRevWalk();
438
439
440
441
442
443
444
445
446 @Deprecated
447 public abstract Map<String, Ref> getAdvertisedRefs();
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467 @Deprecated
468 public abstract void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves);
469
470
471
472
473
474
475
476
477 public final Set<ObjectId> getAdvertisedObjects() {
478 return advertisedHaves;
479 }
480
481
482
483
484
485
486
487
488
489 public boolean isCheckReferencedObjectsAreReachable() {
490 return checkReferencedIsReachable;
491 }
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514 public void setCheckReferencedObjectsAreReachable(boolean b) {
515 this.checkReferencedIsReachable = b;
516 }
517
518
519
520
521
522
523
524
525 public boolean isBiDirectionalPipe() {
526 return biDirectionalPipe;
527 }
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 public void setBiDirectionalPipe(boolean twoWay) {
543 biDirectionalPipe = twoWay;
544 }
545
546
547
548
549
550
551 public boolean isExpectDataAfterPackFooter() {
552 return expectDataAfterPackFooter;
553 }
554
555
556
557
558
559
560
561
562 public void setExpectDataAfterPackFooter(boolean e) {
563 expectDataAfterPackFooter = e;
564 }
565
566
567
568
569
570
571
572
573
574 public boolean isCheckReceivedObjects() {
575 return objectChecker != null;
576 }
577
578
579
580
581
582
583
584
585
586 public void setCheckReceivedObjects(boolean check) {
587 if (check && objectChecker == null)
588 setObjectChecker(new ObjectChecker());
589 else if (!check && objectChecker != null)
590 setObjectChecker(null);
591 }
592
593
594
595
596
597
598
599
600
601 public void setObjectChecker(ObjectChecker impl) {
602 objectChecker = impl;
603 }
604
605
606
607
608
609
610 public boolean isAllowCreates() {
611 return allowCreates;
612 }
613
614
615
616
617
618
619
620 public void setAllowCreates(boolean canCreate) {
621 allowCreates = canCreate;
622 }
623
624
625
626
627
628
629 public boolean isAllowDeletes() {
630 return allowAnyDeletes;
631 }
632
633
634
635
636
637
638
639 public void setAllowDeletes(boolean canDelete) {
640 allowAnyDeletes = canDelete;
641 }
642
643
644
645
646
647
648
649 public boolean isAllowBranchDeletes() {
650 return allowBranchDeletes;
651 }
652
653
654
655
656
657
658
659
660
661
662 public void setAllowBranchDeletes(boolean canDelete) {
663 allowBranchDeletes = canDelete;
664 }
665
666
667
668
669
670
671
672
673 public boolean isAllowNonFastForwards() {
674 return allowNonFastForwards;
675 }
676
677
678
679
680
681
682
683
684
685 public void setAllowNonFastForwards(boolean canRewind) {
686 allowNonFastForwards = canRewind;
687 }
688
689
690
691
692
693
694
695
696
697 public boolean isAtomic() {
698 return atomic;
699 }
700
701
702
703
704
705
706
707
708
709
710 public void setAtomic(boolean atomic) {
711 this.atomic = atomic;
712 }
713
714
715
716
717
718
719 public PersonIdent getRefLogIdent() {
720 return refLogIdent;
721 }
722
723
724
725
726
727
728
729
730
731
732
733
734
735 public void setRefLogIdent(PersonIdent pi) {
736 refLogIdent = pi;
737 }
738
739
740
741
742
743
744 public AdvertiseRefsHook getAdvertiseRefsHook() {
745 return advertiseRefsHook;
746 }
747
748
749
750
751
752
753 public RefFilter getRefFilter() {
754 return refFilter;
755 }
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772 public void setAdvertiseRefsHook(AdvertiseRefsHook advertiseRefsHook) {
773 if (advertiseRefsHook != null)
774 this.advertiseRefsHook = advertiseRefsHook;
775 else
776 this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
777 }
778
779
780
781
782
783
784
785
786
787
788
789 public void setRefFilter(RefFilter refFilter) {
790 this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
791 }
792
793
794
795
796
797
798 public int getTimeout() {
799 return timeout;
800 }
801
802
803
804
805
806
807
808
809
810 public void setTimeout(int seconds) {
811 timeout = seconds;
812 }
813
814
815
816
817
818
819
820
821 public void setMaxCommandBytes(long limit) {
822 maxCommandBytes = limit;
823 }
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842 public void setMaxCommandDiscardBytes(long limit) {
843 maxDiscardBytes = limit;
844 }
845
846
847
848
849
850
851
852
853
854
855 public void setMaxObjectSizeLimit(long limit) {
856 maxObjectSizeLimit = limit;
857 }
858
859
860
861
862
863
864
865
866
867
868 public void setMaxPackSizeLimit(long limit) {
869 if (limit < 0)
870 throw new IllegalArgumentException(MessageFormat.format(
871 JGitText.get().receivePackInvalidLimit, Long.valueOf(limit)));
872 maxPackSizeLimit = limit;
873 }
874
875
876
877
878
879
880
881
882
883
884
885
886 public boolean isSideBand() throws RequestNotYetReadException {
887 checkRequestWasRead();
888 return enabledCapabilities.contains(CAPABILITY_SIDE_BAND_64K);
889 }
890
891
892
893
894
895
896
897 public boolean isAllowQuiet() {
898 return allowQuiet;
899 }
900
901
902
903
904
905
906
907
908
909
910
911 public void setAllowQuiet(boolean allow) {
912 allowQuiet = allow;
913 }
914
915
916
917
918
919
920
921 public boolean isAllowPushOptions() {
922 return allowPushOptions;
923 }
924
925
926
927
928
929
930
931
932 public void setAllowPushOptions(boolean allow) {
933 allowPushOptions = allow;
934 }
935
936
937
938
939
940
941
942
943
944
945
946
947 public boolean isQuiet() throws RequestNotYetReadException {
948 checkRequestWasRead();
949 return quiet;
950 }
951
952
953
954
955
956
957
958
959
960
961 public void setSignedPushConfig(SignedPushConfig cfg) {
962 signedPushConfig = cfg;
963 }
964
965 private PushCertificateParser getPushCertificateParser() {
966 if (pushCertificateParser == null) {
967 pushCertificateParser = new PushCertificateParser(db, signedPushConfig);
968 }
969 return pushCertificateParser;
970 }
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987 public String getPeerUserAgent() {
988 return UserAgent.getAgent(enabledCapabilities, userAgent);
989 }
990
991
992
993
994
995
996 public List<ReceiveCommand> getAllCommands() {
997 return Collections.unmodifiableList(commands);
998 }
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025 public void sendError(String what) {
1026 if (refs == null) {
1027 if (advertiseError == null)
1028 advertiseError = new StringBuilder();
1029 advertiseError.append(what).append('\n');
1030 } else {
1031 msgOutWrapper.write(Constants.encode("error: " + what + "\n"));
1032 }
1033 }
1034
1035 private void fatalError(String msg) {
1036 if (errOut != null) {
1037 try {
1038 errOut.write(Constants.encode(msg));
1039 errOut.flush();
1040 } catch (IOException e) {
1041
1042 }
1043 } else {
1044 sendError(msg);
1045 }
1046 }
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058 public void sendMessage(String what) {
1059 msgOutWrapper.write(Constants.encode(what + "\n"));
1060 }
1061
1062
1063
1064
1065
1066
1067 public OutputStream getMessageOutputStream() {
1068 return msgOutWrapper;
1069 }
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081 public long getPackSize() {
1082 if (packSize != null)
1083 return packSize.longValue();
1084 throw new IllegalStateException(JGitText.get().packSizeNotSetYet);
1085 }
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095 protected Set<ObjectId> getClientShallowCommits() {
1096 return clientShallowCommits;
1097 }
1098
1099
1100
1101
1102
1103
1104 protected boolean hasCommands() {
1105 return !commands.isEmpty();
1106 }
1107
1108
1109
1110
1111
1112
1113 protected boolean hasError() {
1114 return advertiseError != null;
1115 }
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134 protected void init(final InputStream input, final OutputStream output,
1135 final OutputStream messages) {
1136 origOut = output;
1137 rawIn = input;
1138 rawOut = output;
1139 msgOut = messages;
1140
1141 if (timeout > 0) {
1142 final Thread caller = Thread.currentThread();
1143 timer = new InterruptTimer(caller.getName() + "-Timer");
1144 timeoutIn = new TimeoutInputStream(rawIn, timer);
1145 TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer);
1146 timeoutIn.setTimeout(timeout * 1000);
1147 o.setTimeout(timeout * 1000);
1148 rawIn = timeoutIn;
1149 rawOut = o;
1150 }
1151
1152 pckIn = new PacketLineIn(rawIn);
1153 pckOut = new PacketLineOut(rawOut);
1154 pckOut.setFlushOnEnd(false);
1155
1156 enabledCapabilities = new HashSet<>();
1157 commands = new ArrayList<>();
1158 }
1159
1160
1161
1162
1163
1164
1165 protected Map<String, Ref> getAdvertisedOrDefaultRefs() {
1166 if (refs == null)
1167 setAdvertisedRefs(null, null);
1168 return refs;
1169 }
1170
1171
1172
1173
1174
1175
1176
1177 protected void receivePackAndCheckConnectivity() throws IOException {
1178 receivePack();
1179 if (needCheckConnectivity()) {
1180 checkSubmodules();
1181 checkConnectivity();
1182 }
1183 parser = null;
1184 }
1185
1186
1187
1188
1189
1190
1191
1192 protected void unlockPack() throws IOException {
1193 if (packLock != null) {
1194 packLock.unlock();
1195 packLock = null;
1196 }
1197 }
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209 public void sendAdvertisedRefs(RefAdvertiser adv)
1210 throws IOException, ServiceMayNotContinueException {
1211 if (advertiseError != null) {
1212 adv.writeOne("ERR " + advertiseError);
1213 return;
1214 }
1215
1216 try {
1217 advertiseRefsHook.advertiseRefs(this);
1218 } catch (ServiceMayNotContinueException fail) {
1219 if (fail.getMessage() != null) {
1220 adv.writeOne("ERR " + fail.getMessage());
1221 fail.setOutput();
1222 }
1223 throw fail;
1224 }
1225
1226 adv.init(db);
1227 adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
1228 adv.advertiseCapability(CAPABILITY_DELETE_REFS);
1229 adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
1230 if (allowQuiet)
1231 adv.advertiseCapability(CAPABILITY_QUIET);
1232 String nonce = getPushCertificateParser().getAdvertiseNonce();
1233 if (nonce != null) {
1234 adv.advertiseCapability(nonce);
1235 }
1236 if (db.getRefDatabase().performsAtomicTransactions())
1237 adv.advertiseCapability(CAPABILITY_ATOMIC);
1238 if (allowOfsDelta)
1239 adv.advertiseCapability(CAPABILITY_OFS_DELTA);
1240 if (allowPushOptions) {
1241 adv.advertiseCapability(CAPABILITY_PUSH_OPTIONS);
1242 }
1243 adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
1244 adv.send(getAdvertisedOrDefaultRefs().values());
1245 for (ObjectId obj : advertisedHaves)
1246 adv.advertiseHave(obj);
1247 if (adv.isEmpty())
1248 adv.advertiseId(ObjectId.zeroId(), "capabilities^{}");
1249 adv.end();
1250 }
1251
1252
1253
1254
1255
1256
1257
1258
1259 @Nullable
1260 public ReceivedPackStatistics getReceivedPackStatistics() {
1261 return stats;
1262 }
1263
1264
1265
1266
1267
1268
1269 protected void recvCommands() throws IOException {
1270 PacketLineIn pck = maxCommandBytes > 0
1271 ? new PacketLineIn(rawIn, maxCommandBytes)
1272 : pckIn;
1273 PushCertificateParser certParser = getPushCertificateParser();
1274 boolean firstPkt = true;
1275 try {
1276 for (;;) {
1277 String line;
1278 try {
1279 line = pck.readString();
1280 } catch (EOFException eof) {
1281 if (commands.isEmpty())
1282 return;
1283 throw eof;
1284 }
1285 if (PacketLineIn.isEnd(line)) {
1286 break;
1287 }
1288
1289 if (line.length() >= 48 && line.startsWith("shallow ")) {
1290 parseShallow(line.substring(8, 48));
1291 continue;
1292 }
1293
1294 if (firstPkt) {
1295 firstPkt = false;
1296 FirstCommand firstLine = FirstCommand.fromLine(line);
1297 enabledCapabilities = firstLine.getCapabilities();
1298 line = firstLine.getLine();
1299 enableCapabilities();
1300
1301 if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT)) {
1302 certParser.receiveHeader(pck, !isBiDirectionalPipe());
1303 continue;
1304 }
1305 }
1306
1307 if (line.equals(PushCertificateParser.BEGIN_SIGNATURE)) {
1308 certParser.receiveSignature(pck);
1309 continue;
1310 }
1311
1312 ReceiveCommand cmd = parseCommand(line);
1313 if (cmd.getRefName().equals(Constants.HEAD)) {
1314 cmd.setResult(Result.REJECTED_CURRENT_BRANCH);
1315 } else {
1316 cmd.setRef(refs.get(cmd.getRefName()));
1317 }
1318 commands.add(cmd);
1319 if (certParser.enabled()) {
1320 certParser.addCommand(cmd);
1321 }
1322 }
1323 pushCert = certParser.build();
1324 if (hasCommands()) {
1325 readPostCommands(pck);
1326 }
1327 } catch (PackProtocolException e) {
1328 discardCommands();
1329 fatalError(e.getMessage());
1330 throw e;
1331 } catch (InputOverLimitIOException e) {
1332 String msg = JGitText.get().tooManyCommands;
1333 discardCommands();
1334 fatalError(msg);
1335 throw new PackProtocolException(msg);
1336 }
1337 }
1338
1339 private void discardCommands() {
1340 if (sideBand) {
1341 long max = maxDiscardBytes;
1342 if (max < 0) {
1343 max = Math.max(3 * maxCommandBytes, 3L << 20);
1344 }
1345 try {
1346 new PacketLineIn(rawIn, max).discardUntilEnd();
1347 } catch (IOException e) {
1348
1349 }
1350 }
1351 }
1352
1353 private void parseShallow(String idStr) throws PackProtocolException {
1354 ObjectId id;
1355 try {
1356 id = ObjectId.fromString(idStr);
1357 } catch (InvalidObjectIdException e) {
1358 throw new PackProtocolException(e.getMessage(), e);
1359 }
1360 clientShallowCommits.add(id);
1361 }
1362
1363 static ReceiveCommand parseCommand(String line) throws PackProtocolException {
1364 if (line == null || line.length() < 83) {
1365 throw new PackProtocolException(
1366 JGitText.get().errorInvalidProtocolWantedOldNewRef);
1367 }
1368 String oldStr = line.substring(0, 40);
1369 String newStr = line.substring(41, 81);
1370 ObjectId oldId, newId;
1371 try {
1372 oldId = ObjectId.fromString(oldStr);
1373 newId = ObjectId.fromString(newStr);
1374 } catch (InvalidObjectIdException e) {
1375 throw new PackProtocolException(
1376 JGitText.get().errorInvalidProtocolWantedOldNewRef, e);
1377 }
1378 String name = line.substring(82);
1379 if (!Repository.isValidRefName(name)) {
1380 throw new PackProtocolException(
1381 JGitText.get().errorInvalidProtocolWantedOldNewRef);
1382 }
1383 return new ReceiveCommand(oldId, newId, name);
1384 }
1385
1386
1387
1388
1389
1390
1391
1392 void readPostCommands(PacketLineIn in) throws IOException {
1393
1394 }
1395
1396
1397
1398
1399 protected void enableCapabilities() {
1400 sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K);
1401 quiet = allowQuiet && isCapabilityEnabled(CAPABILITY_QUIET);
1402 if (sideBand) {
1403 OutputStream out = rawOut;
1404
1405 rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out);
1406 msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out);
1407 errOut = new SideBandOutputStream(CH_ERROR, MAX_BUF, out);
1408
1409 pckOut = new PacketLineOut(rawOut);
1410 pckOut.setFlushOnEnd(false);
1411 }
1412 }
1413
1414
1415
1416
1417
1418
1419
1420
1421 protected boolean isCapabilityEnabled(String name) {
1422 return enabledCapabilities.contains(name);
1423 }
1424
1425 void checkRequestWasRead() {
1426 if (enabledCapabilities == null)
1427 throw new RequestNotYetReadException();
1428 }
1429
1430
1431
1432
1433
1434
1435 protected boolean needPack() {
1436 for (ReceiveCommand cmd : commands) {
1437 if (cmd.getType() != ReceiveCommand.Type.DELETE)
1438 return true;
1439 }
1440 return false;
1441 }
1442
1443
1444
1445
1446
1447
1448
1449 private void receivePack() throws IOException {
1450
1451
1452
1453
1454 if (timeoutIn != null)
1455 timeoutIn.setTimeout(10 * timeout * 1000);
1456
1457 ProgressMonitor receiving = NullProgressMonitor.INSTANCE;
1458 ProgressMonitor resolving = NullProgressMonitor.INSTANCE;
1459 if (sideBand && !quiet)
1460 resolving = new SideBandProgressMonitor(msgOut);
1461
1462 try (ObjectInserter ins = db.newObjectInserter()) {
1463 String lockMsg = "jgit receive-pack";
1464 if (getRefLogIdent() != null)
1465 lockMsg += " from " + getRefLogIdent().toExternalString();
1466
1467 parser = ins.newPackParser(packInputStream());
1468 parser.setAllowThin(true);
1469 parser.setNeedNewObjectIds(checkReferencedIsReachable);
1470 parser.setNeedBaseObjectIds(checkReferencedIsReachable);
1471 parser.setCheckEofAfterPackFooter(!biDirectionalPipe
1472 && !isExpectDataAfterPackFooter());
1473 parser.setExpectDataAfterPackFooter(isExpectDataAfterPackFooter());
1474 parser.setObjectChecker(objectChecker);
1475 parser.setLockMessage(lockMsg);
1476 parser.setMaxObjectSizeLimit(maxObjectSizeLimit);
1477 packLock = parser.parse(receiving, resolving);
1478 packSize = Long.valueOf(parser.getPackSize());
1479 stats = parser.getReceivedPackStatistics();
1480 ins.flush();
1481 }
1482
1483 if (timeoutIn != null)
1484 timeoutIn.setTimeout(timeout * 1000);
1485 }
1486
1487 private InputStream packInputStream() {
1488 InputStream packIn = rawIn;
1489 if (maxPackSizeLimit >= 0) {
1490 packIn = new LimitedInputStream(packIn, maxPackSizeLimit) {
1491 @Override
1492 protected void limitExceeded() throws TooLargePackException {
1493 throw new TooLargePackException(limit);
1494 }
1495 };
1496 }
1497 return packIn;
1498 }
1499
1500 private boolean needCheckConnectivity() {
1501 return isCheckReceivedObjects()
1502 || isCheckReferencedObjectsAreReachable()
1503 || !getClientShallowCommits().isEmpty();
1504 }
1505
1506 private void checkSubmodules()
1507 throws IOException {
1508 ObjectDatabase odb = db.getObjectDatabase();
1509 if (objectChecker == null) {
1510 return;
1511 }
1512 for (GitmoduleEntry entry : objectChecker.getGitsubmodules()) {
1513 AnyObjectId blobId = entry.getBlobId();
1514 ObjectLoader blob = odb.open(blobId, Constants.OBJ_BLOB);
1515
1516 try {
1517 SubmoduleValidator.assertValidGitModulesFile(
1518 new String(blob.getBytes(), UTF_8));
1519 } catch (LargeObjectException | SubmoduleValidationException e) {
1520 throw new IOException(e);
1521 }
1522 }
1523 }
1524
1525 private void checkConnectivity() throws IOException {
1526 ObjectIdSubclassMap<ObjectId> baseObjects = null;
1527 ObjectIdSubclassMap<ObjectId> providedObjects = null;
1528 ProgressMonitor checking = NullProgressMonitor.INSTANCE;
1529 if (sideBand && !quiet) {
1530 SideBandProgressMonitor m = new SideBandProgressMonitor(msgOut);
1531 m.setDelayStart(750, TimeUnit.MILLISECONDS);
1532 checking = m;
1533 }
1534
1535 if (checkReferencedIsReachable) {
1536 baseObjects = parser.getBaseObjectIds();
1537 providedObjects = parser.getNewObjectIds();
1538 }
1539 parser = null;
1540
1541 try (ObjectWalkectWalk.html#ObjectWalk">ObjectWalk ow = new ObjectWalk(db)) {
1542 if (baseObjects != null) {
1543 ow.sort(RevSort.TOPO);
1544 if (!baseObjects.isEmpty())
1545 ow.sort(RevSort.BOUNDARY, true);
1546 }
1547
1548 for (ReceiveCommand cmd : commands) {
1549 if (cmd.getResult() != Result.NOT_ATTEMPTED)
1550 continue;
1551 if (cmd.getType() == ReceiveCommand.Type.DELETE)
1552 continue;
1553 ow.markStart(ow.parseAny(cmd.getNewId()));
1554 }
1555 for (ObjectId have : advertisedHaves) {
1556 RevObject o = ow.parseAny(have);
1557 ow.markUninteresting(o);
1558
1559 if (baseObjects != null && !baseObjects.isEmpty()) {
1560 o = ow.peel(o);
1561 if (o instanceof RevCommit)
1562 o = ((RevCommit) o).getTree();
1563 if (o instanceof RevTree)
1564 ow.markUninteresting(o);
1565 }
1566 }
1567
1568 checking.beginTask(JGitText.get().countingObjects,
1569 ProgressMonitor.UNKNOWN);
1570 RevCommit c;
1571 while ((c = ow.next()) != null) {
1572 checking.update(1);
1573 if (providedObjects != null
1574 && !c.has(RevFlag.UNINTERESTING)
1575 && !providedObjects.contains(c))
1576 throw new MissingObjectException(c, Constants.TYPE_COMMIT);
1577 }
1578
1579 RevObject o;
1580 while ((o = ow.nextObject()) != null) {
1581 checking.update(1);
1582 if (o.has(RevFlag.UNINTERESTING))
1583 continue;
1584
1585 if (providedObjects != null) {
1586 if (providedObjects.contains(o))
1587 continue;
1588 else
1589 throw new MissingObjectException(o, o.getType());
1590 }
1591
1592 if (o instanceof RevBlob && !db.getObjectDatabase().has(o))
1593 throw new MissingObjectException(o, Constants.TYPE_BLOB);
1594 }
1595 checking.endTask();
1596
1597 if (baseObjects != null) {
1598 for (ObjectId id : baseObjects) {
1599 o = ow.parseAny(id);
1600 if (!o.has(RevFlag.UNINTERESTING))
1601 throw new MissingObjectException(o, o.getType());
1602 }
1603 }
1604 }
1605 }
1606
1607
1608
1609
1610 protected void validateCommands() {
1611 for (ReceiveCommand cmd : commands) {
1612 final Ref ref = cmd.getRef();
1613 if (cmd.getResult() != Result.NOT_ATTEMPTED)
1614 continue;
1615
1616 if (cmd.getType() == ReceiveCommand.Type.DELETE) {
1617 if (!isAllowDeletes()) {
1618
1619 cmd.setResult(Result.REJECTED_NODELETE);
1620 continue;
1621 }
1622 if (!isAllowBranchDeletes()
1623 && ref.getName().startsWith(Constants.R_HEADS)) {
1624
1625 cmd.setResult(Result.REJECTED_NODELETE);
1626 continue;
1627 }
1628 }
1629
1630 if (cmd.getType() == ReceiveCommand.Type.CREATE) {
1631 if (!isAllowCreates()) {
1632 cmd.setResult(Result.REJECTED_NOCREATE);
1633 continue;
1634 }
1635
1636 if (ref != null && !isAllowNonFastForwards()) {
1637
1638
1639
1640 cmd.setResult(Result.REJECTED_NONFASTFORWARD);
1641 continue;
1642 }
1643
1644 if (ref != null) {
1645
1646
1647
1648 cmd.setResult(Result.REJECTED_OTHER_REASON,
1649 JGitText.get().refAlreadyExists);
1650 continue;
1651 }
1652 }
1653
1654 if (cmd.getType() == ReceiveCommand.Type.DELETE && ref != null) {
1655 ObjectId id = ref.getObjectId();
1656 if (id == null) {
1657 id = ObjectId.zeroId();
1658 }
1659 if (!ObjectId.zeroId().equals(cmd.getOldId())
1660 && !id.equals(cmd.getOldId())) {
1661
1662
1663
1664
1665 cmd.setResult(Result.REJECTED_OTHER_REASON,
1666 JGitText.get().invalidOldIdSent);
1667 continue;
1668 }
1669 }
1670
1671 if (cmd.getType() == ReceiveCommand.Type.UPDATE) {
1672 if (ref == null) {
1673
1674
1675 cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().noSuchRef);
1676 continue;
1677 }
1678 ObjectId id = ref.getObjectId();
1679 if (id == null) {
1680
1681 cmd.setResult(Result.REJECTED_OTHER_REASON,
1682 JGitText.get().cannotUpdateUnbornBranch);
1683 continue;
1684 }
1685
1686 if (!id.equals(cmd.getOldId())) {
1687
1688
1689
1690 cmd.setResult(Result.REJECTED_OTHER_REASON,
1691 JGitText.get().invalidOldIdSent);
1692 continue;
1693 }
1694
1695
1696
1697 RevObject oldObj, newObj;
1698 try {
1699 oldObj = walk.parseAny(cmd.getOldId());
1700 } catch (IOException e) {
1701 cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd
1702 .getOldId().name());
1703 continue;
1704 }
1705
1706 try {
1707 newObj = walk.parseAny(cmd.getNewId());
1708 } catch (IOException e) {
1709 cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd
1710 .getNewId().name());
1711 continue;
1712 }
1713
1714 if (oldObj instanceof RevCommite/jgit/revwalk/RevCommit.html#RevCommit">RevCommit && newObj instanceof RevCommit) {
1715 try {
1716 if (walk.isMergedInto((RevCommit) oldObj,
1717 (RevCommit) newObj))
1718 cmd.setTypeFastForwardUpdate();
1719 else
1720 cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1721 } catch (MissingObjectException e) {
1722 cmd.setResult(Result.REJECTED_MISSING_OBJECT, e
1723 .getMessage());
1724 } catch (IOException e) {
1725 cmd.setResult(Result.REJECTED_OTHER_REASON);
1726 }
1727 } else {
1728 cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1729 }
1730
1731 if (cmd.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD
1732 && !isAllowNonFastForwards()) {
1733 cmd.setResult(Result.REJECTED_NONFASTFORWARD);
1734 continue;
1735 }
1736 }
1737
1738 if (!cmd.getRefName().startsWith(Constants.R_REFS)
1739 || !Repository.isValidRefName(cmd.getRefName())) {
1740 cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().funnyRefname);
1741 }
1742 }
1743 }
1744
1745
1746
1747
1748
1749
1750
1751 protected boolean anyRejects() {
1752 for (ReceiveCommand cmd : commands) {
1753 if (cmd.getResult() != Result.NOT_ATTEMPTED && cmd.getResult() != Result.OK)
1754 return true;
1755 }
1756 return false;
1757 }
1758
1759
1760
1761
1762
1763
1764 protected void failPendingCommands() {
1765 ReceiveCommand.abort(commands);
1766 }
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776 protected List<ReceiveCommand> filterCommands(Result want) {
1777 return ReceiveCommand.filter(commands, want);
1778 }
1779
1780
1781
1782
1783 protected void executeCommands() {
1784 List<ReceiveCommand> toApply = filterCommands(Result.NOT_ATTEMPTED);
1785 if (toApply.isEmpty())
1786 return;
1787
1788 ProgressMonitor updating = NullProgressMonitor.INSTANCE;
1789 if (sideBand) {
1790 SideBandProgressMonitor pm = new SideBandProgressMonitor(msgOut);
1791 pm.setDelayStart(250, TimeUnit.MILLISECONDS);
1792 updating = pm;
1793 }
1794
1795 BatchRefUpdate batch = db.getRefDatabase().newBatchUpdate();
1796 batch.setAllowNonFastForwards(isAllowNonFastForwards());
1797 batch.setAtomic(isAtomic());
1798 batch.setRefLogIdent(getRefLogIdent());
1799 batch.setRefLogMessage("push", true);
1800 batch.addCommand(toApply);
1801 try {
1802 batch.setPushCertificate(getPushCertificate());
1803 batch.execute(walk, updating);
1804 } catch (IOException err) {
1805 for (ReceiveCommand cmd : toApply) {
1806 if (cmd.getResult() == Result.NOT_ATTEMPTED)
1807 cmd.reject(err);
1808 }
1809 }
1810 }
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825 protected void sendStatusReport(final boolean forClient,
1826 final Throwable unpackError, final Reporter out) throws IOException {
1827 if (unpackError != null) {
1828 out.sendString("unpack error " + unpackError.getMessage());
1829 if (forClient) {
1830 for (ReceiveCommand cmd : commands) {
1831 out.sendString("ng " + cmd.getRefName()
1832 + " n/a (unpacker error)");
1833 }
1834 }
1835 return;
1836 }
1837
1838 if (forClient)
1839 out.sendString("unpack ok");
1840 for (ReceiveCommand cmd : commands) {
1841 if (cmd.getResult() == Result.OK) {
1842 if (forClient)
1843 out.sendString("ok " + cmd.getRefName());
1844 continue;
1845 }
1846
1847 final StringBuilder r = new StringBuilder();
1848 if (forClient)
1849 r.append("ng ").append(cmd.getRefName()).append(" ");
1850 else
1851 r.append(" ! [rejected] ").append(cmd.getRefName()).append(" (");
1852
1853 switch (cmd.getResult()) {
1854 case NOT_ATTEMPTED:
1855 r.append("server bug; ref not processed");
1856 break;
1857
1858 case REJECTED_NOCREATE:
1859 r.append("creation prohibited");
1860 break;
1861
1862 case REJECTED_NODELETE:
1863 r.append("deletion prohibited");
1864 break;
1865
1866 case REJECTED_NONFASTFORWARD:
1867 r.append("non-fast forward");
1868 break;
1869
1870 case REJECTED_CURRENT_BRANCH:
1871 r.append("branch is currently checked out");
1872 break;
1873
1874 case REJECTED_MISSING_OBJECT:
1875 if (cmd.getMessage() == null)
1876 r.append("missing object(s)");
1877 else if (cmd.getMessage().length() == Constants.OBJECT_ID_STRING_LENGTH) {
1878 r.append("object ");
1879 r.append(cmd.getMessage());
1880 r.append(" missing");
1881 } else
1882 r.append(cmd.getMessage());
1883 break;
1884
1885 case REJECTED_OTHER_REASON:
1886 if (cmd.getMessage() == null)
1887 r.append("unspecified reason");
1888 else
1889 r.append(cmd.getMessage());
1890 break;
1891
1892 case LOCK_FAILURE:
1893 r.append("failed to lock");
1894 break;
1895
1896 case OK:
1897
1898 continue;
1899 }
1900 if (!forClient)
1901 r.append(")");
1902 out.sendString(r.toString());
1903 }
1904 }
1905
1906
1907
1908
1909
1910
1911 protected void close() throws IOException {
1912 if (sideBand) {
1913
1914
1915
1916
1917
1918
1919 ((SideBandOutputStream) msgOut).flushBuffer();
1920 ((SideBandOutputStream) rawOut).flushBuffer();
1921
1922 PacketLineOut plo = new PacketLineOut(origOut);
1923 plo.setFlushOnEnd(false);
1924 plo.end();
1925 }
1926
1927 if (biDirectionalPipe) {
1928
1929
1930
1931
1932 if (!sideBand && msgOut != null)
1933 msgOut.flush();
1934 rawOut.flush();
1935 }
1936 }
1937
1938
1939
1940
1941
1942
1943
1944 protected void release() throws IOException {
1945 walk.close();
1946 unlockPack();
1947 timeoutIn = null;
1948 rawIn = null;
1949 rawOut = null;
1950 msgOut = null;
1951 pckIn = null;
1952 pckOut = null;
1953 refs = null;
1954
1955
1956
1957 commands = null;
1958 if (timer != null) {
1959 try {
1960 timer.terminate();
1961 } finally {
1962 timer = null;
1963 }
1964 }
1965 }
1966
1967
1968 static abstract class Reporter {
1969 abstract void sendString(String s) throws IOException;
1970 }
1971 }