You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

BaseReceivePack.java 56KB

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