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 51KB

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