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