View Javadoc
1   /*
2    * Copyright (C) 2008-2010, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.transport;
45  
46  import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
47  import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS;
48  import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA;
49  import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_QUIET;
50  import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
51  import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
52  import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
53  import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA;
54  import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
55  import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
56  
57  import java.io.EOFException;
58  import java.io.IOException;
59  import java.io.InputStream;
60  import java.io.OutputStream;
61  import java.text.MessageFormat;
62  import java.util.ArrayList;
63  import java.util.Collections;
64  import java.util.HashSet;
65  import java.util.List;
66  import java.util.Map;
67  import java.util.Set;
68  import java.util.concurrent.TimeUnit;
69  
70  import org.eclipse.jgit.errors.MissingObjectException;
71  import org.eclipse.jgit.errors.PackProtocolException;
72  import org.eclipse.jgit.errors.TooLargePackException;
73  import org.eclipse.jgit.internal.JGitText;
74  import org.eclipse.jgit.internal.storage.file.PackLock;
75  import org.eclipse.jgit.lib.BatchRefUpdate;
76  import org.eclipse.jgit.lib.Config;
77  import org.eclipse.jgit.lib.Config.SectionParser;
78  import org.eclipse.jgit.lib.Constants;
79  import org.eclipse.jgit.lib.NullProgressMonitor;
80  import org.eclipse.jgit.lib.ObjectChecker;
81  import org.eclipse.jgit.lib.ObjectId;
82  import org.eclipse.jgit.lib.ObjectIdSubclassMap;
83  import org.eclipse.jgit.lib.ObjectInserter;
84  import org.eclipse.jgit.lib.PersonIdent;
85  import org.eclipse.jgit.lib.ProgressMonitor;
86  import org.eclipse.jgit.lib.Ref;
87  import org.eclipse.jgit.lib.Repository;
88  import org.eclipse.jgit.revwalk.ObjectWalk;
89  import org.eclipse.jgit.revwalk.RevBlob;
90  import org.eclipse.jgit.revwalk.RevCommit;
91  import org.eclipse.jgit.revwalk.RevFlag;
92  import org.eclipse.jgit.revwalk.RevObject;
93  import org.eclipse.jgit.revwalk.RevSort;
94  import org.eclipse.jgit.revwalk.RevTree;
95  import org.eclipse.jgit.revwalk.RevWalk;
96  import org.eclipse.jgit.transport.ReceiveCommand.Result;
97  import org.eclipse.jgit.util.io.InterruptTimer;
98  import org.eclipse.jgit.util.io.LimitedInputStream;
99  import org.eclipse.jgit.util.io.TimeoutInputStream;
100 import org.eclipse.jgit.util.io.TimeoutOutputStream;
101 
102 /**
103  * Base implementation of the side of a push connection that receives objects.
104  * <p>
105  * Contains high-level operations for initializing and closing streams,
106  * advertising refs, reading commands, and receiving and applying a pack.
107  * Subclasses compose these operations into full service implementations.
108  */
109 public abstract class BaseReceivePack {
110 	/** Data in the first line of a request, the line itself plus capabilities. */
111 	public static class FirstLine {
112 		private final String line;
113 		private final Set<String> capabilities;
114 
115 		/**
116 		 * Parse the first line of a receive-pack request.
117 		 *
118 		 * @param line
119 		 *            line from the client.
120 		 */
121 		public FirstLine(String line) {
122 			final HashSet<String> caps = new HashSet<String>();
123 			final int nul = line.indexOf('\0');
124 			if (nul >= 0) {
125 				for (String c : line.substring(nul + 1).split(" ")) //$NON-NLS-1$
126 					caps.add(c);
127 				this.line = line.substring(0, nul);
128 			} else
129 				this.line = line;
130 			this.capabilities = Collections.unmodifiableSet(caps);
131 		}
132 
133 		/** @return non-capabilities part of the line. */
134 		public String getLine() {
135 			return line;
136 		}
137 
138 		/** @return capabilities parsed from the line. */
139 		public Set<String> getCapabilities() {
140 			return capabilities;
141 		}
142 	}
143 
144 	/** Database we write the stored objects into. */
145 	private final Repository db;
146 
147 	/** Revision traversal support over {@link #db}. */
148 	private final RevWalk walk;
149 
150 	/**
151 	 * Is the client connection a bi-directional socket or pipe?
152 	 * <p>
153 	 * If true, this class assumes it can perform multiple read and write cycles
154 	 * with the client over the input and output streams. This matches the
155 	 * functionality available with a standard TCP/IP connection, or a local
156 	 * operating system or in-memory pipe.
157 	 * <p>
158 	 * If false, this class runs in a read everything then output results mode,
159 	 * making it suitable for single round-trip systems RPCs such as HTTP.
160 	 */
161 	private boolean biDirectionalPipe = true;
162 
163 	/** Expecting data after the pack footer */
164 	private boolean expectDataAfterPackFooter;
165 
166 	/** Should an incoming transfer validate objects? */
167 	private ObjectChecker objectChecker;
168 
169 	/** Should an incoming transfer permit create requests? */
170 	private boolean allowCreates;
171 
172 	/** Should an incoming transfer permit delete requests? */
173 	private boolean allowAnyDeletes;
174 	private boolean allowBranchDeletes;
175 
176 	/** Should an incoming transfer permit non-fast-forward requests? */
177 	private boolean allowNonFastForwards;
178 
179 	private boolean allowOfsDelta;
180 	private boolean allowQuiet = true;
181 
182 	/** Identity to record action as within the reflog. */
183 	private PersonIdent refLogIdent;
184 
185 	/** Hook used while advertising the refs to the client. */
186 	private AdvertiseRefsHook advertiseRefsHook;
187 
188 	/** Filter used while advertising the refs to the client. */
189 	private RefFilter refFilter;
190 
191 	/** Timeout in seconds to wait for client interaction. */
192 	private int timeout;
193 
194 	/** Timer to manage {@link #timeout}. */
195 	private InterruptTimer timer;
196 
197 	private TimeoutInputStream timeoutIn;
198 
199 	// Original stream passed to init(), since rawOut may be wrapped in a
200 	// sideband.
201 	private OutputStream origOut;
202 
203 	/** Raw input stream. */
204 	protected InputStream rawIn;
205 
206 	/** Raw output stream. */
207 	protected OutputStream rawOut;
208 
209 	/** Optional message output stream. */
210 	protected OutputStream msgOut;
211 
212 	/** Packet line input stream around {@link #rawIn}. */
213 	protected PacketLineIn pckIn;
214 
215 	/** Packet line output stream around {@link #rawOut}. */
216 	protected PacketLineOut pckOut;
217 
218 	private final MessageOutputWrapper msgOutWrapper = new MessageOutputWrapper();
219 
220 	private PackParser parser;
221 
222 	/** The refs we advertised as existing at the start of the connection. */
223 	private Map<String, Ref> refs;
224 
225 	/** All SHA-1s shown to the client, which can be possible edges. */
226 	private Set<ObjectId> advertisedHaves;
227 
228 	/** Capabilities requested by the client. */
229 	private Set<String> enabledCapabilities;
230 	String userAgent;
231 	private Set<ObjectId> clientShallowCommits;
232 	private List<ReceiveCommand> commands;
233 
234 	private StringBuilder advertiseError;
235 
236 	/** If {@link BasePackPushConnection#CAPABILITY_SIDE_BAND_64K} is enabled. */
237 	private boolean sideBand;
238 
239 	private boolean quiet;
240 
241 	/** Lock around the received pack file, while updating refs. */
242 	private PackLock packLock;
243 
244 	private boolean checkReferencedIsReachable;
245 
246 	/** Git object size limit */
247 	private long maxObjectSizeLimit;
248 
249 	/** Total pack size limit */
250 	private long maxPackSizeLimit = -1;
251 
252 	/** The size of the received pack, including index size */
253 	private Long packSize;
254 
255 	private PushCertificateParser pushCertificateParser;
256 	private SignedPushConfig signedPushConfig;
257 	private PushCertificate pushCert;
258 
259 	/**
260 	 * Get the push certificate used to verify the pusher's identity.
261 	 * <p>
262 	 * Only valid after commands are read from the wire.
263 	 *
264 	 * @return the parsed certificate, or null if push certificates are disabled
265 	 *         or no cert was presented by the client.
266 	 * @since 4.1
267 	 */
268 	public PushCertificate getPushCertificate() {
269 		return pushCert;
270 	}
271 
272 	/**
273 	 * Set the push certificate used to verify the pusher's identity.
274 	 * <p>
275 	 * Should only be called if reconstructing an instance without going through
276 	 * the normal {@link #recvCommands()} flow.
277 	 *
278 	 * @param cert
279 	 *            the push certificate to set.
280 	 * @since 4.1
281 	 */
282 	public void setPushCertificate(PushCertificate cert) {
283 		pushCert = cert;
284 	}
285 
286 	/**
287 	 * Create a new pack receive for an open repository.
288 	 *
289 	 * @param into
290 	 *            the destination repository.
291 	 */
292 	protected BaseReceivePack(final Repository into) {
293 		db = into;
294 		walk = new RevWalk(db);
295 
296 		final ReceiveConfig cfg = db.getConfig().get(ReceiveConfig.KEY);
297 		objectChecker = cfg.newObjectChecker();
298 		allowCreates = cfg.allowCreates;
299 		allowAnyDeletes = true;
300 		allowBranchDeletes = cfg.allowDeletes;
301 		allowNonFastForwards = cfg.allowNonFastForwards;
302 		allowOfsDelta = cfg.allowOfsDelta;
303 		advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
304 		refFilter = RefFilter.DEFAULT;
305 		advertisedHaves = new HashSet<ObjectId>();
306 		clientShallowCommits = new HashSet<ObjectId>();
307 		signedPushConfig = cfg.signedPush;
308 	}
309 
310 	/** Configuration for receive operations. */
311 	protected static class ReceiveConfig {
312 		static final SectionParser<ReceiveConfig> KEY = new SectionParser<ReceiveConfig>() {
313 			public ReceiveConfig parse(final Config cfg) {
314 				return new ReceiveConfig(cfg);
315 			}
316 		};
317 
318 		final boolean checkReceivedObjects;
319 		final boolean allowLeadingZeroFileMode;
320 		final boolean allowInvalidPersonIdent;
321 		final boolean safeForWindows;
322 		final boolean safeForMacOS;
323 
324 		final boolean allowCreates;
325 		final boolean allowDeletes;
326 		final boolean allowNonFastForwards;
327 		final boolean allowOfsDelta;
328 
329 		final SignedPushConfig signedPush;
330 
331 		ReceiveConfig(final Config config) {
332 			checkReceivedObjects = config.getBoolean(
333 					"receive", "fsckobjects", //$NON-NLS-1$ //$NON-NLS-2$
334 					config.getBoolean("transfer", "fsckobjects", false)); //$NON-NLS-1$ //$NON-NLS-2$
335 			allowLeadingZeroFileMode = checkReceivedObjects
336 					&& config.getBoolean("fsck", "allowLeadingZeroFileMode", false); //$NON-NLS-1$ //$NON-NLS-2$
337 			allowInvalidPersonIdent = checkReceivedObjects
338 					&& config.getBoolean("fsck", "allowInvalidPersonIdent", false); //$NON-NLS-1$ //$NON-NLS-2$
339 			safeForWindows = checkReceivedObjects
340 					&& config.getBoolean("fsck", "safeForWindows", false); //$NON-NLS-1$ //$NON-NLS-2$
341 			safeForMacOS = checkReceivedObjects
342 					&& config.getBoolean("fsck", "safeForMacOS", false); //$NON-NLS-1$ //$NON-NLS-2$
343 
344 			allowCreates = true;
345 			allowDeletes = !config.getBoolean("receive", "denydeletes", false); //$NON-NLS-1$ //$NON-NLS-2$
346 			allowNonFastForwards = !config.getBoolean("receive", //$NON-NLS-1$
347 					"denynonfastforwards", false); //$NON-NLS-1$
348 			allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset", //$NON-NLS-1$ //$NON-NLS-2$
349 					true);
350 			signedPush = SignedPushConfig.KEY.parse(config);
351 		}
352 
353 		ObjectChecker newObjectChecker() {
354 			if (!checkReceivedObjects)
355 				return null;
356 			return new ObjectChecker()
357 				.setAllowLeadingZeroFileMode(allowLeadingZeroFileMode)
358 				.setAllowInvalidPersonIdent(allowInvalidPersonIdent)
359 				.setSafeForWindows(safeForWindows)
360 				.setSafeForMacOS(safeForMacOS);
361 		}
362 	}
363 
364 	/**
365 	 * Output stream that wraps the current {@link #msgOut}.
366 	 * <p>
367 	 * We don't want to expose {@link #msgOut} directly because it can change
368 	 * several times over the course of a session.
369 	 */
370 	class MessageOutputWrapper extends OutputStream {
371 		@Override
372 		public void write(int ch) {
373 			if (msgOut != null) {
374 				try {
375 					msgOut.write(ch);
376 				} catch (IOException e) {
377 					// Ignore write failures.
378 				}
379 			}
380 		}
381 
382 		@Override
383 		public void write(byte[] b, int off, int len) {
384 			if (msgOut != null) {
385 				try {
386 					msgOut.write(b, off, len);
387 				} catch (IOException e) {
388 					// Ignore write failures.
389 				}
390 			}
391 		}
392 
393 		@Override
394 		public void write(byte[] b) {
395 			write(b, 0, b.length);
396 		}
397 
398 		@Override
399 		public void flush() {
400 			if (msgOut != null) {
401 				try {
402 					msgOut.flush();
403 				} catch (IOException e) {
404 					// Ignore write failures.
405 				}
406 			}
407 		}
408 	}
409 
410 	/** @return the process name used for pack lock messages. */
411 	protected abstract String getLockMessageProcessName();
412 
413 	/** @return the repository this receive completes into. */
414 	public final Repository getRepository() {
415 		return db;
416 	}
417 
418 	/** @return the RevWalk instance used by this connection. */
419 	public final RevWalk getRevWalk() {
420 		return walk;
421 	}
422 
423 	/**
424 	 * Get refs which were advertised to the client.
425 	 *
426 	 * @return all refs which were advertised to the client, or null if
427 	 *         {@link #setAdvertisedRefs(Map, Set)} has not been called yet.
428 	 */
429 	public final Map<String, Ref> getAdvertisedRefs() {
430 		return refs;
431 	}
432 
433 	/**
434 	 * Set the refs advertised by this ReceivePack.
435 	 * <p>
436 	 * Intended to be called from a {@link PreReceiveHook}.
437 	 *
438 	 * @param allRefs
439 	 *            explicit set of references to claim as advertised by this
440 	 *            ReceivePack instance. This overrides any references that
441 	 *            may exist in the source repository. The map is passed
442 	 *            to the configured {@link #getRefFilter()}. If null, assumes
443 	 *            all refs were advertised.
444 	 * @param additionalHaves
445 	 *            explicit set of additional haves to claim as advertised. If
446 	 *            null, assumes the default set of additional haves from the
447 	 *            repository.
448 	 */
449 	public void setAdvertisedRefs(Map<String, Ref> allRefs, Set<ObjectId> additionalHaves) {
450 		refs = allRefs != null ? allRefs : db.getAllRefs();
451 		refs = refFilter.filter(refs);
452 
453 		Ref head = refs.get(Constants.HEAD);
454 		if (head != null && head.isSymbolic())
455 			refs.remove(Constants.HEAD);
456 
457 		for (Ref ref : refs.values()) {
458 			if (ref.getObjectId() != null)
459 				advertisedHaves.add(ref.getObjectId());
460 		}
461 		if (additionalHaves != null)
462 			advertisedHaves.addAll(additionalHaves);
463 		else
464 			advertisedHaves.addAll(db.getAdditionalHaves());
465 	}
466 
467 	/**
468 	 * Get objects advertised to the client.
469 	 *
470 	 * @return the set of objects advertised to the as present in this repository,
471 	 *         or null if {@link #setAdvertisedRefs(Map, Set)} has not been called
472 	 *         yet.
473 	 */
474 	public final Set<ObjectId> getAdvertisedObjects() {
475 		return advertisedHaves;
476 	}
477 
478 	/**
479 	 * @return true if this instance will validate all referenced, but not
480 	 *         supplied by the client, objects are reachable from another
481 	 *         reference.
482 	 */
483 	public boolean isCheckReferencedObjectsAreReachable() {
484 		return checkReferencedIsReachable;
485 	}
486 
487 	/**
488 	 * Validate all referenced but not supplied objects are reachable.
489 	 * <p>
490 	 * If enabled, this instance will verify that references to objects not
491 	 * contained within the received pack are already reachable through at least
492 	 * one other reference displayed as part of {@link #getAdvertisedRefs()}.
493 	 * <p>
494 	 * This feature is useful when the application doesn't trust the client to
495 	 * not provide a forged SHA-1 reference to an object, in an attempt to
496 	 * access parts of the DAG that they aren't allowed to see and which have
497 	 * been hidden from them via the configured {@link AdvertiseRefsHook} or
498 	 * {@link RefFilter}.
499 	 * <p>
500 	 * Enabling this feature may imply at least some, if not all, of the same
501 	 * functionality performed by {@link #setCheckReceivedObjects(boolean)}.
502 	 * Applications are encouraged to enable both features, if desired.
503 	 *
504 	 * @param b
505 	 *            {@code true} to enable the additional check.
506 	 */
507 	public void setCheckReferencedObjectsAreReachable(boolean b) {
508 		this.checkReferencedIsReachable = b;
509 	}
510 
511 	/**
512 	 * @return true if this class expects a bi-directional pipe opened between
513 	 *         the client and itself. The default is true.
514 	 */
515 	public boolean isBiDirectionalPipe() {
516 		return biDirectionalPipe;
517 	}
518 
519 	/**
520 	 * @param twoWay
521 	 *            if true, this class will assume the socket is a fully
522 	 *            bidirectional pipe between the two peers and takes advantage
523 	 *            of that by first transmitting the known refs, then waiting to
524 	 *            read commands. If false, this class assumes it must read the
525 	 *            commands before writing output and does not perform the
526 	 *            initial advertising.
527 	 */
528 	public void setBiDirectionalPipe(final boolean twoWay) {
529 		biDirectionalPipe = twoWay;
530 	}
531 
532 	/** @return true if there is data expected after the pack footer. */
533 	public boolean isExpectDataAfterPackFooter() {
534 		return expectDataAfterPackFooter;
535 	}
536 
537 	/**
538 	 * @param e
539 	 *            true if there is additional data in InputStream after pack.
540 	 */
541 	public void setExpectDataAfterPackFooter(boolean e) {
542 		expectDataAfterPackFooter = e;
543 	}
544 
545 	/**
546 	 * @return true if this instance will verify received objects are formatted
547 	 *         correctly. Validating objects requires more CPU time on this side
548 	 *         of the connection.
549 	 */
550 	public boolean isCheckReceivedObjects() {
551 		return objectChecker != null;
552 	}
553 
554 	/**
555 	 * @param check
556 	 *            true to enable checking received objects; false to assume all
557 	 *            received objects are valid.
558 	 * @see #setObjectChecker(ObjectChecker)
559 	 */
560 	public void setCheckReceivedObjects(final boolean check) {
561 		if (check && objectChecker == null)
562 			setObjectChecker(new ObjectChecker());
563 		else if (!check && objectChecker != null)
564 			setObjectChecker(null);
565 	}
566 
567 	/**
568 	 * @param impl if non-null the object checking instance to verify each
569 	 *        received object with; null to disable object checking.
570 	 * @since 3.4
571 	 */
572 	public void setObjectChecker(ObjectChecker impl) {
573 		objectChecker = impl;
574 	}
575 
576 	/** @return true if the client can request refs to be created. */
577 	public boolean isAllowCreates() {
578 		return allowCreates;
579 	}
580 
581 	/**
582 	 * @param canCreate
583 	 *            true to permit create ref commands to be processed.
584 	 */
585 	public void setAllowCreates(final boolean canCreate) {
586 		allowCreates = canCreate;
587 	}
588 
589 	/** @return true if the client can request refs to be deleted. */
590 	public boolean isAllowDeletes() {
591 		return allowAnyDeletes;
592 	}
593 
594 	/**
595 	 * @param canDelete
596 	 *            true to permit delete ref commands to be processed.
597 	 */
598 	public void setAllowDeletes(final boolean canDelete) {
599 		allowAnyDeletes = canDelete;
600 	}
601 
602 	/**
603 	 * @return true if the client can delete from {@code refs/heads/}.
604 	 * @since 3.6
605 	 */
606 	public boolean isAllowBranchDeletes() {
607 		return allowBranchDeletes;
608 	}
609 
610 	/**
611 	 * @param canDelete
612 	 *            true to permit deletion of branches from the
613 	 *            {@code refs/heads/} namespace.
614 	 * @since 3.6
615 	 */
616 	public void setAllowBranchDeletes(boolean canDelete) {
617 		allowBranchDeletes = canDelete;
618 	}
619 
620 	/**
621 	 * @return true if the client can request non-fast-forward updates of a ref,
622 	 *         possibly making objects unreachable.
623 	 */
624 	public boolean isAllowNonFastForwards() {
625 		return allowNonFastForwards;
626 	}
627 
628 	/**
629 	 * @param canRewind
630 	 *            true to permit the client to ask for non-fast-forward updates
631 	 *            of an existing ref.
632 	 */
633 	public void setAllowNonFastForwards(final boolean canRewind) {
634 		allowNonFastForwards = canRewind;
635 	}
636 
637 	/** @return identity of the user making the changes in the reflog. */
638 	public PersonIdent getRefLogIdent() {
639 		return refLogIdent;
640 	}
641 
642 	/**
643 	 * Set the identity of the user appearing in the affected reflogs.
644 	 * <p>
645 	 * The timestamp portion of the identity is ignored. A new identity with the
646 	 * current timestamp will be created automatically when the updates occur
647 	 * and the log records are written.
648 	 *
649 	 * @param pi
650 	 *            identity of the user. If null the identity will be
651 	 *            automatically determined based on the repository
652 	 *            configuration.
653 	 */
654 	public void setRefLogIdent(final PersonIdent pi) {
655 		refLogIdent = pi;
656 	}
657 
658 	/** @return the hook used while advertising the refs to the client */
659 	public AdvertiseRefsHook getAdvertiseRefsHook() {
660 		return advertiseRefsHook;
661 	}
662 
663 	/** @return the filter used while advertising the refs to the client */
664 	public RefFilter getRefFilter() {
665 		return refFilter;
666 	}
667 
668 	/**
669 	 * Set the hook used while advertising the refs to the client.
670 	 * <p>
671 	 * If the {@link AdvertiseRefsHook} chooses to call
672 	 * {@link #setAdvertisedRefs(Map,Set)}, only refs set by this hook
673 	 * <em>and</em> selected by the {@link RefFilter} will be shown to the client.
674 	 * Clients may still attempt to create or update a reference not advertised by
675 	 * the configured {@link AdvertiseRefsHook}. These attempts should be rejected
676 	 * by a matching {@link PreReceiveHook}.
677 	 *
678 	 * @param advertiseRefsHook
679 	 *            the hook; may be null to show all refs.
680 	 */
681 	public void setAdvertiseRefsHook(final AdvertiseRefsHook advertiseRefsHook) {
682 		if (advertiseRefsHook != null)
683 			this.advertiseRefsHook = advertiseRefsHook;
684 		else
685 			this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
686 	}
687 
688 	/**
689 	 * Set the filter used while advertising the refs to the client.
690 	 * <p>
691 	 * Only refs allowed by this filter will be shown to the client.
692 	 * The filter is run against the refs specified by the
693 	 * {@link AdvertiseRefsHook} (if applicable).
694 	 *
695 	 * @param refFilter
696 	 *            the filter; may be null to show all refs.
697 	 */
698 	public void setRefFilter(final RefFilter refFilter) {
699 		this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
700 	}
701 
702 	/** @return timeout (in seconds) before aborting an IO operation. */
703 	public int getTimeout() {
704 		return timeout;
705 	}
706 
707 	/**
708 	 * Set the timeout before willing to abort an IO call.
709 	 *
710 	 * @param seconds
711 	 *            number of seconds to wait (with no data transfer occurring)
712 	 *            before aborting an IO read or write operation with the
713 	 *            connected client.
714 	 */
715 	public void setTimeout(final int seconds) {
716 		timeout = seconds;
717 	}
718 
719 	/**
720 	 * Set the maximum allowed Git object size.
721 	 * <p>
722 	 * If an object is larger than the given size the pack-parsing will throw an
723 	 * exception aborting the receive-pack operation.
724 	 *
725 	 * @param limit
726 	 *            the Git object size limit. If zero then there is not limit.
727 	 */
728 	public void setMaxObjectSizeLimit(final long limit) {
729 		maxObjectSizeLimit = limit;
730 	}
731 
732 
733 	/**
734 	 * Set the maximum allowed pack size.
735 	 * <p>
736 	 * A pack exceeding this size will be rejected.
737 	 *
738 	 * @param limit
739 	 *            the pack size limit, in bytes
740 	 *
741 	 * @since 3.3
742 	 */
743 	public void setMaxPackSizeLimit(final long limit) {
744 		if (limit < 0)
745 			throw new IllegalArgumentException(MessageFormat.format(
746 					JGitText.get().receivePackInvalidLimit, Long.valueOf(limit)));
747 		maxPackSizeLimit = limit;
748 	}
749 
750 	/**
751 	 * Check whether the client expects a side-band stream.
752 	 *
753 	 * @return true if the client has advertised a side-band capability, false
754 	 *     otherwise.
755 	 * @throws RequestNotYetReadException
756 	 *             if the client's request has not yet been read from the wire, so
757 	 *             we do not know if they expect side-band. Note that the client
758 	 *             may have already written the request, it just has not been
759 	 *             read.
760 	 */
761 	public boolean isSideBand() throws RequestNotYetReadException {
762 		if (enabledCapabilities == null)
763 			throw new RequestNotYetReadException();
764 		return enabledCapabilities.contains(CAPABILITY_SIDE_BAND_64K);
765 	}
766 
767 	/**
768 	 * @return true if clients may request avoiding noisy progress messages.
769 	 * @since 4.0
770 	 */
771 	public boolean isAllowQuiet() {
772 		return allowQuiet;
773 	}
774 
775 	/**
776 	 * Configure if clients may request the server skip noisy messages.
777 	 *
778 	 * @param allow
779 	 *            true to allow clients to request quiet behavior; false to
780 	 *            refuse quiet behavior and send messages anyway. This may be
781 	 *            necessary if processing is slow and the client-server network
782 	 *            connection can timeout.
783 	 * @since 4.0
784 	 */
785 	public void setAllowQuiet(boolean allow) {
786 		allowQuiet = allow;
787 	}
788 
789 	/**
790 	 * True if the client wants less verbose output.
791 	 *
792 	 * @return true if the client has requested the server to be less verbose.
793 	 * @throws RequestNotYetReadException
794 	 *             if the client's request has not yet been read from the wire,
795 	 *             so we do not know if they expect side-band. Note that the
796 	 *             client may have already written the request, it just has not
797 	 *             been read.
798 	 * @since 4.0
799 	 */
800 	public boolean isQuiet() throws RequestNotYetReadException {
801 		if (enabledCapabilities == null)
802 			throw new RequestNotYetReadException();
803 		return quiet;
804 	}
805 
806 	/**
807 	 * Set the configuration for push certificate verification.
808 	 *
809 	 * @param cfg
810 	 *            new configuration; if this object is null or its {@link
811 	 *            SignedPushConfig#getCertNonceSeed()} is null, push certificate
812 	 *            verification will be disabled.
813 	 * @since 4.1
814 	 */
815 	public void setSignedPushConfig(SignedPushConfig cfg) {
816 		signedPushConfig = cfg;
817 	}
818 
819 	private PushCertificateParser getPushCertificateParser() {
820 		if (pushCertificateParser == null) {
821 			pushCertificateParser = new PushCertificateParser(db, signedPushConfig);
822 		}
823 		return pushCertificateParser;
824 	}
825 
826 	/**
827 	 * Get the user agent of the client.
828 	 * <p>
829 	 * If the client is new enough to use {@code agent=} capability that value
830 	 * will be returned. Older HTTP clients may also supply their version using
831 	 * the HTTP {@code User-Agent} header. The capability overrides the HTTP
832 	 * header if both are available.
833 	 * <p>
834 	 * When an HTTP request has been received this method returns the HTTP
835 	 * {@code User-Agent} header value until capabilities have been parsed.
836 	 *
837 	 * @return user agent supplied by the client. Available only if the client
838 	 *         is new enough to advertise its user agent.
839 	 * @since 4.0
840 	 */
841 	public String getPeerUserAgent() {
842 		return UserAgent.getAgent(enabledCapabilities, userAgent);
843 	}
844 
845 	/** @return all of the command received by the current request. */
846 	public List<ReceiveCommand> getAllCommands() {
847 		return Collections.unmodifiableList(commands);
848 	}
849 
850 	/**
851 	 * Send an error message to the client.
852 	 * <p>
853 	 * If any error messages are sent before the references are advertised to
854 	 * the client, the errors will be sent instead of the advertisement and the
855 	 * receive operation will be aborted. All clients should receive and display
856 	 * such early stage errors.
857 	 * <p>
858 	 * If the reference advertisements have already been sent, messages are sent
859 	 * in a side channel. If the client doesn't support receiving messages, the
860 	 * message will be discarded, with no other indication to the caller or to
861 	 * the client.
862 	 * <p>
863 	 * {@link PreReceiveHook}s should always try to use
864 	 * {@link ReceiveCommand#setResult(Result, String)} with a result status of
865 	 * {@link Result#REJECTED_OTHER_REASON} to indicate any reasons for
866 	 * rejecting an update. Messages attached to a command are much more likely
867 	 * to be returned to the client.
868 	 *
869 	 * @param what
870 	 *            string describing the problem identified by the hook. The
871 	 *            string must not end with an LF, and must not contain an LF.
872 	 */
873 	public void sendError(final String what) {
874 		if (refs == null) {
875 			if (advertiseError == null)
876 				advertiseError = new StringBuilder();
877 			advertiseError.append(what).append('\n');
878 		} else {
879 			msgOutWrapper.write(Constants.encode("error: " + what + "\n")); //$NON-NLS-1$ //$NON-NLS-2$
880 		}
881 	}
882 
883 	/**
884 	 * Send a message to the client, if it supports receiving them.
885 	 * <p>
886 	 * If the client doesn't support receiving messages, the message will be
887 	 * discarded, with no other indication to the caller or to the client.
888 	 *
889 	 * @param what
890 	 *            string describing the problem identified by the hook. The
891 	 *            string must not end with an LF, and must not contain an LF.
892 	 */
893 	public void sendMessage(final String what) {
894 		msgOutWrapper.write(Constants.encode(what + "\n")); //$NON-NLS-1$
895 	}
896 
897 	/** @return an underlying stream for sending messages to the client. */
898 	public OutputStream getMessageOutputStream() {
899 		return msgOutWrapper;
900 	}
901 
902 	/**
903 	 * Get the size of the received pack file including the index size.
904 	 *
905 	 * This can only be called if the pack is already received.
906 	 *
907 	 * @return the size of the received pack including index size
908 	 * @throws IllegalStateException
909 	 *             if called before the pack has been received
910 	 * @since 3.3
911 	 */
912 	public long getPackSize() {
913 		if (packSize != null)
914 			return packSize.longValue();
915 		throw new IllegalStateException(JGitText.get().packSizeNotSetYet);
916 	}
917 
918 	/**
919 	 * Get the commits from the client's shallow file.
920 	 *
921 	 * @return if the client is a shallow repository, the list of edge commits
922 	 *     that define the client's shallow boundary. Empty set if the client
923 	 *     is earlier than Git 1.9, or is a full clone.
924 	 * @since 3.5
925 	 */
926 	protected Set<ObjectId> getClientShallowCommits() {
927 		return clientShallowCommits;
928 	}
929 
930 	/** @return true if any commands to be executed have been read. */
931 	protected boolean hasCommands() {
932 		return !commands.isEmpty();
933 	}
934 
935 	/** @return true if an error occurred that should be advertised. */
936 	protected boolean hasError() {
937 		return advertiseError != null;
938 	}
939 
940 	/**
941 	 * Initialize the instance with the given streams.
942 	 *
943 	 * @param input
944 	 *            raw input to read client commands and pack data from. Caller
945 	 *            must ensure the input is buffered, otherwise read performance
946 	 *            may suffer.
947 	 * @param output
948 	 *            response back to the Git network client. Caller must ensure
949 	 *            the output is buffered, otherwise write performance may
950 	 *            suffer.
951 	 * @param messages
952 	 *            secondary "notice" channel to send additional messages out
953 	 *            through. When run over SSH this should be tied back to the
954 	 *            standard error channel of the command execution. For most
955 	 *            other network connections this should be null.
956 	 */
957 	protected void init(final InputStream input, final OutputStream output,
958 			final OutputStream messages) {
959 		origOut = output;
960 		rawIn = input;
961 		rawOut = output;
962 		msgOut = messages;
963 
964 		if (timeout > 0) {
965 			final Thread caller = Thread.currentThread();
966 			timer = new InterruptTimer(caller.getName() + "-Timer"); //$NON-NLS-1$
967 			timeoutIn = new TimeoutInputStream(rawIn, timer);
968 			TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer);
969 			timeoutIn.setTimeout(timeout * 1000);
970 			o.setTimeout(timeout * 1000);
971 			rawIn = timeoutIn;
972 			rawOut = o;
973 		}
974 
975 		if (maxPackSizeLimit >= 0)
976 			rawIn = new LimitedInputStream(rawIn, maxPackSizeLimit) {
977 				@Override
978 				protected void limitExceeded() throws TooLargePackException {
979 					throw new TooLargePackException(limit);
980 				}
981 			};
982 
983 		pckIn = new PacketLineIn(rawIn);
984 		pckOut = new PacketLineOut(rawOut);
985 		pckOut.setFlushOnEnd(false);
986 
987 		enabledCapabilities = new HashSet<String>();
988 		commands = new ArrayList<ReceiveCommand>();
989 	}
990 
991 	/** @return advertised refs, or the default if not explicitly advertised. */
992 	protected Map<String, Ref> getAdvertisedOrDefaultRefs() {
993 		if (refs == null)
994 			setAdvertisedRefs(null, null);
995 		return refs;
996 	}
997 
998 	/**
999 	 * Receive a pack from the stream and check connectivity if necessary.
1000 	 *
1001 	 * @throws IOException
1002 	 *             an error occurred during unpacking or connectivity checking.
1003 	 */
1004 	protected void receivePackAndCheckConnectivity() throws IOException {
1005 		receivePack();
1006 		if (needCheckConnectivity())
1007 			checkConnectivity();
1008 		parser = null;
1009 	}
1010 
1011 	/**
1012 	 * Unlock the pack written by this object.
1013 	 *
1014 	 * @throws IOException
1015 	 *             the pack could not be unlocked.
1016 	 */
1017 	protected void unlockPack() throws IOException {
1018 		if (packLock != null) {
1019 			packLock.unlock();
1020 			packLock = null;
1021 		}
1022 	}
1023 
1024 	/**
1025 	 * Generate an advertisement of available refs and capabilities.
1026 	 *
1027 	 * @param adv
1028 	 *            the advertisement formatter.
1029 	 * @throws IOException
1030 	 *             the formatter failed to write an advertisement.
1031 	 * @throws ServiceMayNotContinueException
1032 	 *             the hook denied advertisement.
1033 	 */
1034 	public void sendAdvertisedRefs(final RefAdvertiser adv)
1035 			throws IOException, ServiceMayNotContinueException {
1036 		if (advertiseError != null) {
1037 			adv.writeOne("ERR " + advertiseError); //$NON-NLS-1$
1038 			return;
1039 		}
1040 
1041 		try {
1042 			advertiseRefsHook.advertiseRefs(this);
1043 		} catch (ServiceMayNotContinueException fail) {
1044 			if (fail.getMessage() != null) {
1045 				adv.writeOne("ERR " + fail.getMessage()); //$NON-NLS-1$
1046 				fail.setOutput();
1047 			}
1048 			throw fail;
1049 		}
1050 
1051 		adv.init(db);
1052 		adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
1053 		adv.advertiseCapability(CAPABILITY_DELETE_REFS);
1054 		adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
1055 		if (allowQuiet)
1056 			adv.advertiseCapability(CAPABILITY_QUIET);
1057 		String nonce = getPushCertificateParser().getAdvertiseNonce();
1058 		if (nonce != null) {
1059 			adv.advertiseCapability(nonce);
1060 		}
1061 		if (db.getRefDatabase().performsAtomicTransactions())
1062 			adv.advertiseCapability(CAPABILITY_ATOMIC);
1063 		if (allowOfsDelta)
1064 			adv.advertiseCapability(CAPABILITY_OFS_DELTA);
1065 		adv.advertiseCapability(OPTION_AGENT, UserAgent.get());
1066 		adv.send(getAdvertisedOrDefaultRefs());
1067 		for (ObjectId obj : advertisedHaves)
1068 			adv.advertiseHave(obj);
1069 		if (adv.isEmpty())
1070 			adv.advertiseId(ObjectId.zeroId(), "capabilities^{}"); //$NON-NLS-1$
1071 		adv.end();
1072 	}
1073 
1074 	/**
1075 	 * Receive a list of commands from the input.
1076 	 *
1077 	 * @throws IOException
1078 	 */
1079 	protected void recvCommands() throws IOException {
1080 		PushCertificateParser certParser = getPushCertificateParser();
1081 		FirstLine firstLine = null;
1082 		try {
1083 			for (;;) {
1084 				String line;
1085 				try {
1086 					line = pckIn.readString();
1087 				} catch (EOFException eof) {
1088 					if (commands.isEmpty())
1089 						return;
1090 					throw eof;
1091 				}
1092 				if (line == PacketLineIn.END) {
1093 					break;
1094 				}
1095 
1096 				if (line.length() >= 48 && line.startsWith("shallow ")) { //$NON-NLS-1$
1097 					clientShallowCommits.add(ObjectId.fromString(line.substring(8, 48)));
1098 					continue;
1099 				}
1100 
1101 				if (firstLine == null) {
1102 					firstLine = new FirstLine(line);
1103 					enabledCapabilities = firstLine.getCapabilities();
1104 					line = firstLine.getLine();
1105 
1106 					if (line.equals(GitProtocolConstants.OPTION_PUSH_CERT)) {
1107 						certParser.receiveHeader(pckIn, !isBiDirectionalPipe());
1108 						continue;
1109 					}
1110 				}
1111 
1112 				if (line.equals(PushCertificateParser.BEGIN_SIGNATURE)) {
1113 					certParser.receiveSignature(pckIn);
1114 					continue;
1115 				}
1116 
1117 				ReceiveCommand cmd;
1118 				try {
1119 					cmd = parseCommand(line);
1120 				} catch (PackProtocolException e) {
1121 					sendError(e.getMessage());
1122 					throw e;
1123 				}
1124 				if (cmd.getRefName().equals(Constants.HEAD)) {
1125 					cmd.setResult(Result.REJECTED_CURRENT_BRANCH);
1126 				} else {
1127 					cmd.setRef(refs.get(cmd.getRefName()));
1128 				}
1129 				commands.add(cmd);
1130 				if (certParser.enabled()) {
1131 					certParser.addCommand(cmd);
1132 				}
1133 			}
1134 			pushCert = certParser.build();
1135 		} catch (PackProtocolException e) {
1136 			sendError(e.getMessage());
1137 			throw e;
1138 		}
1139 	}
1140 
1141 	static ReceiveCommand parseCommand(String line) throws PackProtocolException {
1142           if (line == null || line.length() < 83) {
1143 			throw new PackProtocolException(
1144 					JGitText.get().errorInvalidProtocolWantedOldNewRef);
1145 		}
1146 		String oldStr = line.substring(0, 40);
1147 		String newStr = line.substring(41, 81);
1148 		ObjectId oldId, newId;
1149 		try {
1150 			oldId = ObjectId.fromString(oldStr);
1151 			newId = ObjectId.fromString(newStr);
1152 		} catch (IllegalArgumentException e) {
1153 			throw new PackProtocolException(
1154 					JGitText.get().errorInvalidProtocolWantedOldNewRef, e);
1155 		}
1156 		String name = line.substring(82);
1157 		if (!Repository.isValidRefName(name)) {
1158 			throw new PackProtocolException(
1159 					JGitText.get().errorInvalidProtocolWantedOldNewRef);
1160 		}
1161 		return new ReceiveCommand(oldId, newId, name);
1162 	}
1163 
1164 	/** Enable capabilities based on a previously read capabilities line. */
1165 	protected void enableCapabilities() {
1166 		sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K);
1167 		quiet = allowQuiet && isCapabilityEnabled(CAPABILITY_QUIET);
1168 		if (sideBand) {
1169 			OutputStream out = rawOut;
1170 
1171 			rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out);
1172 			msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out);
1173 
1174 			pckOut = new PacketLineOut(rawOut);
1175 			pckOut.setFlushOnEnd(false);
1176 		}
1177 	}
1178 
1179 	/**
1180 	 * Check if the peer requested a capability.
1181 	 *
1182 	 * @param name
1183 	 *            protocol name identifying the capability.
1184 	 * @return true if the peer requested the capability to be enabled.
1185 	 */
1186 	protected boolean isCapabilityEnabled(String name) {
1187 		return enabledCapabilities.contains(name);
1188 	}
1189 
1190 	/** @return true if a pack is expected based on the list of commands. */
1191 	protected boolean needPack() {
1192 		for (final ReceiveCommand cmd : commands) {
1193 			if (cmd.getType() != ReceiveCommand.Type.DELETE)
1194 				return true;
1195 		}
1196 		return false;
1197 	}
1198 
1199 	/**
1200 	 * Receive a pack from the input and store it in the repository.
1201 	 *
1202 	 * @throws IOException
1203 	 *             an error occurred reading or indexing the pack.
1204 	 */
1205 	private void receivePack() throws IOException {
1206 		// It might take the client a while to pack the objects it needs
1207 		// to send to us.  We should increase our timeout so we don't
1208 		// abort while the client is computing.
1209 		//
1210 		if (timeoutIn != null)
1211 			timeoutIn.setTimeout(10 * timeout * 1000);
1212 
1213 		ProgressMonitor receiving = NullProgressMonitor.INSTANCE;
1214 		ProgressMonitor resolving = NullProgressMonitor.INSTANCE;
1215 		if (sideBand && !quiet)
1216 			resolving = new SideBandProgressMonitor(msgOut);
1217 
1218 		try (ObjectInserter ins = db.newObjectInserter()) {
1219 			String lockMsg = "jgit receive-pack"; //$NON-NLS-1$
1220 			if (getRefLogIdent() != null)
1221 				lockMsg += " from " + getRefLogIdent().toExternalString(); //$NON-NLS-1$
1222 
1223 			parser = ins.newPackParser(rawIn);
1224 			parser.setAllowThin(true);
1225 			parser.setNeedNewObjectIds(checkReferencedIsReachable);
1226 			parser.setNeedBaseObjectIds(checkReferencedIsReachable);
1227 			parser.setCheckEofAfterPackFooter(!biDirectionalPipe
1228 					&& !isExpectDataAfterPackFooter());
1229 			parser.setExpectDataAfterPackFooter(isExpectDataAfterPackFooter());
1230 			parser.setObjectChecker(objectChecker);
1231 			parser.setLockMessage(lockMsg);
1232 			parser.setMaxObjectSizeLimit(maxObjectSizeLimit);
1233 			packLock = parser.parse(receiving, resolving);
1234 			packSize = Long.valueOf(parser.getPackSize());
1235 			ins.flush();
1236 		}
1237 
1238 		if (timeoutIn != null)
1239 			timeoutIn.setTimeout(timeout * 1000);
1240 	}
1241 
1242 	private boolean needCheckConnectivity() {
1243 		return isCheckReceivedObjects()
1244 				|| isCheckReferencedObjectsAreReachable()
1245 				|| !getClientShallowCommits().isEmpty();
1246 	}
1247 
1248 	private void checkConnectivity() throws IOException {
1249 		ObjectIdSubclassMap<ObjectId> baseObjects = null;
1250 		ObjectIdSubclassMap<ObjectId> providedObjects = null;
1251 		ProgressMonitor checking = NullProgressMonitor.INSTANCE;
1252 		if (sideBand && !quiet) {
1253 			SideBandProgressMonitor m = new SideBandProgressMonitor(msgOut);
1254 			m.setDelayStart(750, TimeUnit.MILLISECONDS);
1255 			checking = m;
1256 		}
1257 
1258 		if (checkReferencedIsReachable) {
1259 			baseObjects = parser.getBaseObjectIds();
1260 			providedObjects = parser.getNewObjectIds();
1261 		}
1262 		parser = null;
1263 
1264 		try (final ObjectWalk ow = new ObjectWalk(db)) {
1265 			if (baseObjects != null) {
1266 				ow.sort(RevSort.TOPO);
1267 				if (!baseObjects.isEmpty())
1268 					ow.sort(RevSort.BOUNDARY, true);
1269 			}
1270 
1271 			for (final ReceiveCommand cmd : commands) {
1272 				if (cmd.getResult() != Result.NOT_ATTEMPTED)
1273 					continue;
1274 				if (cmd.getType() == ReceiveCommand.Type.DELETE)
1275 					continue;
1276 				ow.markStart(ow.parseAny(cmd.getNewId()));
1277 			}
1278 			for (final ObjectId have : advertisedHaves) {
1279 				RevObject o = ow.parseAny(have);
1280 				ow.markUninteresting(o);
1281 
1282 				if (baseObjects != null && !baseObjects.isEmpty()) {
1283 					o = ow.peel(o);
1284 					if (o instanceof RevCommit)
1285 						o = ((RevCommit) o).getTree();
1286 					if (o instanceof RevTree)
1287 						ow.markUninteresting(o);
1288 				}
1289 			}
1290 
1291 			checking.beginTask(JGitText.get().countingObjects,
1292 					ProgressMonitor.UNKNOWN);
1293 			RevCommit c;
1294 			while ((c = ow.next()) != null) {
1295 				checking.update(1);
1296 				if (providedObjects != null //
1297 						&& !c.has(RevFlag.UNINTERESTING) //
1298 						&& !providedObjects.contains(c))
1299 					throw new MissingObjectException(c, Constants.TYPE_COMMIT);
1300 			}
1301 
1302 			RevObject o;
1303 			while ((o = ow.nextObject()) != null) {
1304 				checking.update(1);
1305 				if (o.has(RevFlag.UNINTERESTING))
1306 					continue;
1307 
1308 				if (providedObjects != null) {
1309 					if (providedObjects.contains(o))
1310 						continue;
1311 					else
1312 						throw new MissingObjectException(o, o.getType());
1313 				}
1314 
1315 				if (o instanceof RevBlob && !db.hasObject(o))
1316 					throw new MissingObjectException(o, Constants.TYPE_BLOB);
1317 			}
1318 			checking.endTask();
1319 
1320 			if (baseObjects != null) {
1321 				for (ObjectId id : baseObjects) {
1322 					o = ow.parseAny(id);
1323 					if (!o.has(RevFlag.UNINTERESTING))
1324 						throw new MissingObjectException(o, o.getType());
1325 				}
1326 			}
1327 		}
1328 	}
1329 
1330 	/** Validate the command list. */
1331 	protected void validateCommands() {
1332 		for (final ReceiveCommand cmd : commands) {
1333 			final Ref ref = cmd.getRef();
1334 			if (cmd.getResult() != Result.NOT_ATTEMPTED)
1335 				continue;
1336 
1337 			if (cmd.getType() == ReceiveCommand.Type.DELETE) {
1338 				if (!isAllowDeletes()) {
1339 					// Deletes are not supported on this repository.
1340 					cmd.setResult(Result.REJECTED_NODELETE);
1341 					continue;
1342 				}
1343 				if (!isAllowBranchDeletes()
1344 						&& ref.getName().startsWith(Constants.R_HEADS)) {
1345 					// Branches cannot be deleted, but other refs can.
1346 					cmd.setResult(Result.REJECTED_NODELETE);
1347 					continue;
1348 				}
1349 			}
1350 
1351 			if (cmd.getType() == ReceiveCommand.Type.CREATE) {
1352 				if (!isAllowCreates()) {
1353 					cmd.setResult(Result.REJECTED_NOCREATE);
1354 					continue;
1355 				}
1356 
1357 				if (ref != null && !isAllowNonFastForwards()) {
1358 					// Creation over an existing ref is certainly not going
1359 					// to be a fast-forward update. We can reject it early.
1360 					//
1361 					cmd.setResult(Result.REJECTED_NONFASTFORWARD);
1362 					continue;
1363 				}
1364 
1365 				if (ref != null) {
1366 					// A well behaved client shouldn't have sent us a
1367 					// create command for a ref we advertised to it.
1368 					//
1369 					cmd.setResult(Result.REJECTED_OTHER_REASON,
1370 							JGitText.get().refAlreadyExists);
1371 					continue;
1372 				}
1373 			}
1374 
1375 			if (cmd.getType() == ReceiveCommand.Type.DELETE && ref != null
1376 					&& !ObjectId.zeroId().equals(cmd.getOldId())
1377 					&& !ref.getObjectId().equals(cmd.getOldId())) {
1378 				// Delete commands can be sent with the old id matching our
1379 				// advertised value, *OR* with the old id being 0{40}. Any
1380 				// other requested old id is invalid.
1381 				//
1382 				cmd.setResult(Result.REJECTED_OTHER_REASON,
1383 						JGitText.get().invalidOldIdSent);
1384 				continue;
1385 			}
1386 
1387 			if (cmd.getType() == ReceiveCommand.Type.UPDATE) {
1388 				if (ref == null) {
1389 					// The ref must have been advertised in order to be updated.
1390 					//
1391 					cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().noSuchRef);
1392 					continue;
1393 				}
1394 
1395 				if (!ref.getObjectId().equals(cmd.getOldId())) {
1396 					// A properly functioning client will send the same
1397 					// object id we advertised.
1398 					//
1399 					cmd.setResult(Result.REJECTED_OTHER_REASON,
1400 							JGitText.get().invalidOldIdSent);
1401 					continue;
1402 				}
1403 
1404 				// Is this possibly a non-fast-forward style update?
1405 				//
1406 				RevObject oldObj, newObj;
1407 				try {
1408 					oldObj = walk.parseAny(cmd.getOldId());
1409 				} catch (IOException e) {
1410 					cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd
1411 							.getOldId().name());
1412 					continue;
1413 				}
1414 
1415 				try {
1416 					newObj = walk.parseAny(cmd.getNewId());
1417 				} catch (IOException e) {
1418 					cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd
1419 							.getNewId().name());
1420 					continue;
1421 				}
1422 
1423 				if (oldObj instanceof RevCommit && newObj instanceof RevCommit) {
1424 					try {
1425 						if (walk.isMergedInto((RevCommit) oldObj,
1426 								(RevCommit) newObj))
1427 							cmd.setTypeFastForwardUpdate();
1428 						else
1429 							cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1430 					} catch (MissingObjectException e) {
1431 						cmd.setResult(Result.REJECTED_MISSING_OBJECT, e
1432 								.getMessage());
1433 					} catch (IOException e) {
1434 						cmd.setResult(Result.REJECTED_OTHER_REASON);
1435 					}
1436 				} else {
1437 					cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
1438 				}
1439 
1440 				if (cmd.getType() == ReceiveCommand.Type.UPDATE_NONFASTFORWARD
1441 						&& !isAllowNonFastForwards()) {
1442 					cmd.setResult(Result.REJECTED_NONFASTFORWARD);
1443 					continue;
1444 				}
1445 			}
1446 
1447 			if (!cmd.getRefName().startsWith(Constants.R_REFS)
1448 					|| !Repository.isValidRefName(cmd.getRefName())) {
1449 				cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().funnyRefname);
1450 			}
1451 		}
1452 	}
1453 
1454 	/**
1455 	 * @return if any commands have been rejected so far.
1456 	 * @since 3.6
1457 	 */
1458 	protected boolean anyRejects() {
1459 		for (ReceiveCommand cmd : commands) {
1460 			if (cmd.getResult() != Result.NOT_ATTEMPTED && cmd.getResult() != Result.OK)
1461 				return true;
1462 		}
1463 		return false;
1464 	}
1465 
1466 	/**
1467 	 * Set the result to fail for any command that was not processed yet.
1468 	 * @since 3.6
1469 	 */
1470 	protected void failPendingCommands() {
1471 		for (ReceiveCommand cmd : commands) {
1472 			if (cmd.getResult() == Result.NOT_ATTEMPTED)
1473 				cmd.setResult(Result.REJECTED_OTHER_REASON, JGitText.get().transactionAborted);
1474 		}
1475 	}
1476 
1477 	/**
1478 	 * Filter the list of commands according to result.
1479 	 *
1480 	 * @param want
1481 	 *            desired status to filter by.
1482 	 * @return a copy of the command list containing only those commands with the
1483 	 *         desired status.
1484 	 */
1485 	protected List<ReceiveCommand> filterCommands(final Result want) {
1486 		return ReceiveCommand.filter(commands, want);
1487 	}
1488 
1489 	/** Execute commands to update references. */
1490 	protected void executeCommands() {
1491 		List<ReceiveCommand> toApply = filterCommands(Result.NOT_ATTEMPTED);
1492 		if (toApply.isEmpty())
1493 			return;
1494 
1495 		ProgressMonitor updating = NullProgressMonitor.INSTANCE;
1496 		if (sideBand) {
1497 			SideBandProgressMonitor pm = new SideBandProgressMonitor(msgOut);
1498 			pm.setDelayStart(250, TimeUnit.MILLISECONDS);
1499 			updating = pm;
1500 		}
1501 
1502 		BatchRefUpdate batch = db.getRefDatabase().newBatchUpdate();
1503 		batch.setAllowNonFastForwards(isAllowNonFastForwards());
1504 		batch.setRefLogIdent(getRefLogIdent());
1505 		batch.setRefLogMessage("push", true); //$NON-NLS-1$
1506 		batch.addCommand(toApply);
1507 		try {
1508 			batch.setPushCertificate(getPushCertificate());
1509 			batch.execute(walk, updating);
1510 		} catch (IOException err) {
1511 			for (ReceiveCommand cmd : toApply) {
1512 				if (cmd.getResult() == Result.NOT_ATTEMPTED)
1513 					cmd.reject(err);
1514 			}
1515 		}
1516 	}
1517 
1518 	/**
1519 	 * Send a status report.
1520 	 *
1521 	 * @param forClient
1522 	 *            true if this report is for a Git client, false if it is for an
1523 	 *            end-user.
1524 	 * @param unpackError
1525 	 *            an error that occurred during unpacking, or {@code null}
1526 	 * @param out
1527 	 *            the reporter for sending the status strings.
1528 	 * @throws IOException
1529 	 *             an error occurred writing the status report.
1530 	 */
1531 	protected void sendStatusReport(final boolean forClient,
1532 			final Throwable unpackError, final Reporter out) throws IOException {
1533 		if (unpackError != null) {
1534 			out.sendString("unpack error " + unpackError.getMessage()); //$NON-NLS-1$
1535 			if (forClient) {
1536 				for (final ReceiveCommand cmd : commands) {
1537 					out.sendString("ng " + cmd.getRefName() //$NON-NLS-1$
1538 							+ " n/a (unpacker error)"); //$NON-NLS-1$
1539 				}
1540 			}
1541 			return;
1542 		}
1543 
1544 		if (forClient)
1545 			out.sendString("unpack ok"); //$NON-NLS-1$
1546 		for (final ReceiveCommand cmd : commands) {
1547 			if (cmd.getResult() == Result.OK) {
1548 				if (forClient)
1549 					out.sendString("ok " + cmd.getRefName()); //$NON-NLS-1$
1550 				continue;
1551 			}
1552 
1553 			final StringBuilder r = new StringBuilder();
1554 			if (forClient)
1555 				r.append("ng ").append(cmd.getRefName()).append(" "); //$NON-NLS-1$ //$NON-NLS-2$
1556 			else
1557 				r.append(" ! [rejected] ").append(cmd.getRefName()).append(" ("); //$NON-NLS-1$ //$NON-NLS-2$
1558 
1559 			switch (cmd.getResult()) {
1560 			case NOT_ATTEMPTED:
1561 				r.append("server bug; ref not processed"); //$NON-NLS-1$
1562 				break;
1563 
1564 			case REJECTED_NOCREATE:
1565 				r.append("creation prohibited"); //$NON-NLS-1$
1566 				break;
1567 
1568 			case REJECTED_NODELETE:
1569 				r.append("deletion prohibited"); //$NON-NLS-1$
1570 				break;
1571 
1572 			case REJECTED_NONFASTFORWARD:
1573 				r.append("non-fast forward"); //$NON-NLS-1$
1574 				break;
1575 
1576 			case REJECTED_CURRENT_BRANCH:
1577 				r.append("branch is currently checked out"); //$NON-NLS-1$
1578 				break;
1579 
1580 			case REJECTED_MISSING_OBJECT:
1581 				if (cmd.getMessage() == null)
1582 					r.append("missing object(s)"); //$NON-NLS-1$
1583 				else if (cmd.getMessage().length() == Constants.OBJECT_ID_STRING_LENGTH) {
1584 					r.append("object "); //$NON-NLS-1$
1585 					r.append(cmd.getMessage());
1586 					r.append(" missing"); //$NON-NLS-1$
1587 				} else
1588 					r.append(cmd.getMessage());
1589 				break;
1590 
1591 			case REJECTED_OTHER_REASON:
1592 				if (cmd.getMessage() == null)
1593 					r.append("unspecified reason"); //$NON-NLS-1$
1594 				else
1595 					r.append(cmd.getMessage());
1596 				break;
1597 
1598 			case LOCK_FAILURE:
1599 				r.append("failed to lock"); //$NON-NLS-1$
1600 				break;
1601 
1602 			case OK:
1603 				// We shouldn't have reached this case (see 'ok' case above).
1604 				continue;
1605 			}
1606 			if (!forClient)
1607 				r.append(")"); //$NON-NLS-1$
1608 			out.sendString(r.toString());
1609 		}
1610 	}
1611 
1612 	/**
1613 	 * Close and flush (if necessary) the underlying streams.
1614 	 *
1615 	 * @throws IOException
1616 	 */
1617 	protected void close() throws IOException {
1618 		if (sideBand) {
1619 			// If we are using side band, we need to send a final
1620 			// flush-pkt to tell the remote peer the side band is
1621 			// complete and it should stop decoding. We need to
1622 			// use the original output stream as rawOut is now the
1623 			// side band data channel.
1624 			//
1625 			((SideBandOutputStream) msgOut).flushBuffer();
1626 			((SideBandOutputStream) rawOut).flushBuffer();
1627 
1628 			PacketLineOut plo = new PacketLineOut(origOut);
1629 			plo.setFlushOnEnd(false);
1630 			plo.end();
1631 		}
1632 
1633 		if (biDirectionalPipe) {
1634 			// If this was a native git connection, flush the pipe for
1635 			// the caller. For smart HTTP we don't do this flush and
1636 			// instead let the higher level HTTP servlet code do it.
1637 			//
1638 			if (!sideBand && msgOut != null)
1639 				msgOut.flush();
1640 			rawOut.flush();
1641 		}
1642 	}
1643 
1644 	/**
1645 	 * Release any resources used by this object.
1646 	 *
1647 	 * @throws IOException
1648 	 *             the pack could not be unlocked.
1649 	 */
1650 	protected void release() throws IOException {
1651 		walk.close();
1652 		unlockPack();
1653 		timeoutIn = null;
1654 		rawIn = null;
1655 		rawOut = null;
1656 		msgOut = null;
1657 		pckIn = null;
1658 		pckOut = null;
1659 		refs = null;
1660 		// Keep the capabilities. If responses are sent after this release
1661 		// we need to remember at least whether sideband communication has to be
1662 		// used
1663 		commands = null;
1664 		if (timer != null) {
1665 			try {
1666 				timer.terminate();
1667 			} finally {
1668 				timer = null;
1669 			}
1670 		}
1671 	}
1672 
1673 	/** Interface for reporting status messages. */
1674 	static abstract class Reporter {
1675 			abstract void sendString(String s) throws IOException;
1676 	}
1677 }