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.parser.FirstCommand;
52 import org.eclipse.jgit.lib.AnyObjectId;
53 import org.eclipse.jgit.lib.BatchRefUpdate;
54 import org.eclipse.jgit.lib.Config;
55 import org.eclipse.jgit.lib.ConfigConstants;
56 import org.eclipse.jgit.lib.Constants;
57 import org.eclipse.jgit.lib.GitmoduleEntry;
58 import org.eclipse.jgit.lib.NullProgressMonitor;
59 import org.eclipse.jgit.lib.ObjectChecker;
60 import org.eclipse.jgit.lib.ObjectDatabase;
61 import org.eclipse.jgit.lib.ObjectId;
62 import org.eclipse.jgit.lib.ObjectInserter;
63 import org.eclipse.jgit.lib.ObjectLoader;
64 import org.eclipse.jgit.lib.PersonIdent;
65 import org.eclipse.jgit.lib.ProgressMonitor;
66 import org.eclipse.jgit.lib.Ref;
67 import org.eclipse.jgit.lib.Repository;
68 import org.eclipse.jgit.revwalk.RevCommit;
69 import org.eclipse.jgit.revwalk.RevObject;
70 import org.eclipse.jgit.revwalk.RevWalk;
71 import org.eclipse.jgit.transport.ConnectivityChecker.ConnectivityCheckInfo;
72 import org.eclipse.jgit.transport.PacketLineIn.InputOverLimitIOException;
73 import org.eclipse.jgit.transport.ReceiveCommand.Result;
74 import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
75 import org.eclipse.jgit.transport.internal.FullConnectivityChecker;
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 switch (cmd.getResult()) {
1818 case NOT_ATTEMPTED:
1819 r.append("server bug; ref not processed");
1820 break;
1821
1822 case REJECTED_NOCREATE:
1823 r.append("creation prohibited");
1824 break;
1825
1826 case REJECTED_NODELETE:
1827 r.append("deletion prohibited");
1828 break;
1829
1830 case REJECTED_NONFASTFORWARD:
1831 r.append("non-fast forward");
1832 break;
1833
1834 case REJECTED_CURRENT_BRANCH:
1835 r.append("branch is currently checked out");
1836 break;
1837
1838 case REJECTED_MISSING_OBJECT:
1839 if (cmd.getMessage() == null)
1840 r.append("missing object(s)");
1841 else if (cmd.getMessage()
1842 .length() == Constants.OBJECT_ID_STRING_LENGTH) {
1843 r.append("object ");
1844 r.append(cmd.getMessage());
1845 r.append(" missing");
1846 } else
1847 r.append(cmd.getMessage());
1848 break;
1849
1850 case REJECTED_OTHER_REASON:
1851 if (cmd.getMessage() == null)
1852 r.append("unspecified reason");
1853 else
1854 r.append(cmd.getMessage());
1855 break;
1856
1857 case LOCK_FAILURE:
1858 r.append("failed to lock");
1859 break;
1860
1861 case OK:
1862
1863
1864 continue;
1865 }
1866 if (!reportStatus) {
1867 r.append(")");
1868 }
1869 out.sendString(r.toString());
1870 }
1871 } finally {
1872 if (reportStatus) {
1873 pckOut.end();
1874 }
1875 }
1876 }
1877
1878
1879
1880
1881
1882
1883 private void close() throws IOException {
1884 if (sideBand) {
1885
1886
1887
1888
1889
1890
1891 ((SideBandOutputStream) msgOut).flushBuffer();
1892 ((SideBandOutputStream) rawOut).flushBuffer();
1893
1894 PacketLineOut plo = new PacketLineOut(origOut);
1895 plo.setFlushOnEnd(false);
1896 plo.end();
1897 }
1898
1899 if (biDirectionalPipe) {
1900
1901
1902
1903
1904 if (!sideBand && msgOut != null)
1905 msgOut.flush();
1906 rawOut.flush();
1907 }
1908 }
1909
1910
1911
1912
1913
1914
1915
1916 private void release() throws IOException {
1917 walk.close();
1918 unlockPack();
1919 timeoutIn = null;
1920 rawIn = null;
1921 rawOut = null;
1922 msgOut = null;
1923 pckIn = null;
1924 pckOut = null;
1925 refs = null;
1926
1927
1928
1929 commands = null;
1930 if (timer != null) {
1931 try {
1932 timer.terminate();
1933 } finally {
1934 timer = null;
1935 }
1936 }
1937 }
1938
1939
1940 abstract static class Reporter {
1941 abstract void sendString(String s) throws IOException;
1942 }
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953 public PushCertificate getPushCertificate() {
1954 return pushCert;
1955 }
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967 public void setPushCertificate(PushCertificate cert) {
1968 pushCert = cert;
1969 }
1970
1971
1972
1973
1974
1975
1976
1977 @Nullable
1978 public List<String> getPushOptions() {
1979 if (isAllowPushOptions() && usePushOptions) {
1980 return Collections.unmodifiableList(pushOptions);
1981 }
1982
1983
1984
1985
1986 return null;
1987 }
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002 public void setPushOptions(@Nullable List<String> options) {
2003 usePushOptions = options != null;
2004 pushOptions = options;
2005 }
2006
2007
2008
2009
2010
2011
2012 public PreReceiveHook getPreReceiveHook() {
2013 return preReceive;
2014 }
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031 public void setPreReceiveHook(PreReceiveHook h) {
2032 preReceive = h != null ? h : PreReceiveHook.NULL;
2033 }
2034
2035
2036
2037
2038
2039
2040 public PostReceiveHook getPostReceiveHook() {
2041 return postReceive;
2042 }
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055 public void setPostReceiveHook(PostReceiveHook h) {
2056 postReceive = h != null ? h : PostReceiveHook.NULL;
2057 }
2058
2059
2060
2061
2062
2063
2064 public void setUnpackErrorHandler(UnpackErrorHandler unpackErrorHandler) {
2065 this.unpackErrorHandler = unpackErrorHandler;
2066 }
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079 @Deprecated
2080 public void setEchoCommandFailures(boolean echo) {
2081
2082 }
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102 public void receive(final InputStream input, final OutputStream output,
2103 final OutputStream messages) throws IOException {
2104 init(input, output, messages);
2105 try {
2106 service();
2107 } catch (PackProtocolException e) {
2108 fatalError(e.getMessage());
2109 throw e;
2110 } catch (InputOverLimitIOException e) {
2111 String msg = JGitText.get().tooManyCommands;
2112 fatalError(msg);
2113 throw new PackProtocolException(msg, e);
2114 } finally {
2115 try {
2116 close();
2117 } finally {
2118 release();
2119 }
2120 }
2121 }
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146 public void receiveWithExceptionPropagation(InputStream input,
2147 OutputStream output, OutputStream messages) throws IOException {
2148 init(input, output, messages);
2149 try {
2150 service();
2151 } finally {
2152 try {
2153 close();
2154 } finally {
2155 release();
2156 }
2157 }
2158 }
2159
2160 private void service() throws IOException {
2161 if (isBiDirectionalPipe()) {
2162 sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
2163 pckOut.flush();
2164 } else
2165 getAdvertisedOrDefaultRefs();
2166 if (hasError())
2167 return;
2168
2169 recvCommands();
2170
2171 if (hasCommands()) {
2172 try (PostReceiveExecutor e = new PostReceiveExecutor()) {
2173 if (needPack()) {
2174 try {
2175 receivePackAndCheckConnectivity();
2176 } catch (IOException | RuntimeException
2177 | SubmoduleValidationException | Error err) {
2178 unlockPack();
2179 unpackErrorHandler.handleUnpackException(err);
2180 throw new UnpackException(err);
2181 }
2182 }
2183
2184 try {
2185 setAtomic(isCapabilityEnabled(CAPABILITY_ATOMIC));
2186
2187 validateCommands();
2188 if (atomic && anyRejects()) {
2189 failPendingCommands();
2190 }
2191
2192 preReceive.onPreReceive(
2193 this, filterCommands(Result.NOT_ATTEMPTED));
2194 if (atomic && anyRejects()) {
2195 failPendingCommands();
2196 }
2197 executeCommands();
2198 } finally {
2199 unlockPack();
2200 }
2201
2202 sendStatusReport(null);
2203 }
2204 autoGc();
2205 }
2206 }
2207
2208 private void autoGc() {
2209 Repository repo = getRepository();
2210 if (!repo.getConfig().getBoolean(ConfigConstants.CONFIG_RECEIVE_SECTION,
2211 ConfigConstants.CONFIG_KEY_AUTOGC, true)) {
2212 return;
2213 }
2214 repo.autoGC(NullProgressMonitor.INSTANCE);
2215 }
2216
2217 static ReceiveCommand parseCommand(String line)
2218 throws PackProtocolException {
2219 if (line == null || line.length() < 83) {
2220 throw new PackProtocolException(
2221 JGitText.get().errorInvalidProtocolWantedOldNewRef);
2222 }
2223 String oldStr = line.substring(0, 40);
2224 String newStr = line.substring(41, 81);
2225 ObjectId oldId, newId;
2226 try {
2227 oldId = ObjectId.fromString(oldStr);
2228 newId = ObjectId.fromString(newStr);
2229 } catch (InvalidObjectIdException e) {
2230 throw new PackProtocolException(
2231 JGitText.get().errorInvalidProtocolWantedOldNewRef, e);
2232 }
2233 String name = line.substring(82);
2234 if (!Repository.isValidRefName(name)) {
2235 throw new PackProtocolException(
2236 JGitText.get().errorInvalidProtocolWantedOldNewRef);
2237 }
2238 return new ReceiveCommand(oldId, newId, name);
2239 }
2240
2241 private class PostReceiveExecutor implements AutoCloseable {
2242 @Override
2243 public void close() {
2244 postReceive.onPostReceive(ReceivePack.this,
2245 filterCommands(Result.OK));
2246 }
2247 }
2248
2249 private class DefaultUnpackErrorHandler implements UnpackErrorHandler {
2250 @Override
2251 public void handleUnpackException(Throwable t) throws IOException {
2252 sendStatusReport(t);
2253 }
2254 }
2255 }