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.

ReceivePack.java 31KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  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.BasePackPushConnection.CAPABILITY_DELETE_REFS;
  45. import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_OFS_DELTA;
  46. import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_REPORT_STATUS;
  47. import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K;
  48. import static org.eclipse.jgit.transport.SideBandOutputStream.CH_DATA;
  49. import static org.eclipse.jgit.transport.SideBandOutputStream.CH_PROGRESS;
  50. import static org.eclipse.jgit.transport.SideBandOutputStream.MAX_BUF;
  51. import java.io.EOFException;
  52. import java.io.IOException;
  53. import java.io.InputStream;
  54. import java.io.OutputStream;
  55. import java.io.OutputStreamWriter;
  56. import java.io.Writer;
  57. import java.util.ArrayList;
  58. import java.util.Collections;
  59. import java.util.HashSet;
  60. import java.util.List;
  61. import java.util.Map;
  62. import java.util.Set;
  63. import org.eclipse.jgit.errors.MissingObjectException;
  64. import org.eclipse.jgit.errors.PackProtocolException;
  65. import org.eclipse.jgit.lib.Config;
  66. import org.eclipse.jgit.lib.Constants;
  67. import org.eclipse.jgit.lib.NullProgressMonitor;
  68. import org.eclipse.jgit.lib.ObjectId;
  69. import org.eclipse.jgit.lib.PackLock;
  70. import org.eclipse.jgit.lib.PersonIdent;
  71. import org.eclipse.jgit.lib.Ref;
  72. import org.eclipse.jgit.lib.RefUpdate;
  73. import org.eclipse.jgit.lib.Repository;
  74. import org.eclipse.jgit.lib.Config.SectionParser;
  75. import org.eclipse.jgit.revwalk.ObjectWalk;
  76. import org.eclipse.jgit.revwalk.RevCommit;
  77. import org.eclipse.jgit.revwalk.RevFlag;
  78. import org.eclipse.jgit.revwalk.RevObject;
  79. import org.eclipse.jgit.revwalk.RevWalk;
  80. import org.eclipse.jgit.transport.ReceiveCommand.Result;
  81. import org.eclipse.jgit.transport.RefAdvertiser.PacketLineOutRefAdvertiser;
  82. import org.eclipse.jgit.util.io.InterruptTimer;
  83. import org.eclipse.jgit.util.io.TimeoutInputStream;
  84. import org.eclipse.jgit.util.io.TimeoutOutputStream;
  85. /**
  86. * Implements the server side of a push connection, receiving objects.
  87. */
  88. public class ReceivePack {
  89. /** Database we write the stored objects into. */
  90. private final Repository db;
  91. /** Revision traversal support over {@link #db}. */
  92. private final RevWalk walk;
  93. /**
  94. * Is the client connection a bi-directional socket or pipe?
  95. * <p>
  96. * If true, this class assumes it can perform multiple read and write cycles
  97. * with the client over the input and output streams. This matches the
  98. * functionality available with a standard TCP/IP connection, or a local
  99. * operating system or in-memory pipe.
  100. * <p>
  101. * If false, this class runs in a read everything then output results mode,
  102. * making it suitable for single round-trip systems RPCs such as HTTP.
  103. */
  104. private boolean biDirectionalPipe = true;
  105. /** Should an incoming transfer validate objects? */
  106. private boolean checkReceivedObjects;
  107. /** Should an incoming transfer permit create requests? */
  108. private boolean allowCreates;
  109. /** Should an incoming transfer permit delete requests? */
  110. private boolean allowDeletes;
  111. /** Should an incoming transfer permit non-fast-forward requests? */
  112. private boolean allowNonFastForwards;
  113. private boolean allowOfsDelta;
  114. /** Identity to record action as within the reflog. */
  115. private PersonIdent refLogIdent;
  116. /** Filter used while advertising the refs to the client. */
  117. private RefFilter refFilter;
  118. /** Hook to validate the update commands before execution. */
  119. private PreReceiveHook preReceive;
  120. /** Hook to report on the commands after execution. */
  121. private PostReceiveHook postReceive;
  122. /** Timeout in seconds to wait for client interaction. */
  123. private int timeout;
  124. /** Timer to manage {@link #timeout}. */
  125. private InterruptTimer timer;
  126. private TimeoutInputStream timeoutIn;
  127. private InputStream rawIn;
  128. private OutputStream rawOut;
  129. private PacketLineIn pckIn;
  130. private PacketLineOut pckOut;
  131. private Writer msgs;
  132. private IndexPack ip;
  133. /** The refs we advertised as existing at the start of the connection. */
  134. private Map<String, Ref> refs;
  135. /** Capabilities requested by the client. */
  136. private Set<String> enabledCapablities;
  137. /** Commands to execute, as received by the client. */
  138. private List<ReceiveCommand> commands;
  139. /** Error to display instead of advertising the references. */
  140. private StringBuilder advertiseError;
  141. /** An exception caught while unpacking and fsck'ing the objects. */
  142. private Throwable unpackError;
  143. /** If {@link BasePackPushConnection#CAPABILITY_REPORT_STATUS} is enabled. */
  144. private boolean reportStatus;
  145. /** If {@link BasePackPushConnection#CAPABILITY_SIDE_BAND_64K} is enabled. */
  146. private boolean sideBand;
  147. /** Lock around the received pack file, while updating refs. */
  148. private PackLock packLock;
  149. private boolean needNewObjectIds;
  150. private boolean needBaseObjectIds;
  151. /**
  152. * Create a new pack receive for an open repository.
  153. *
  154. * @param into
  155. * the destination repository.
  156. */
  157. public ReceivePack(final Repository into) {
  158. db = into;
  159. walk = new RevWalk(db);
  160. final ReceiveConfig cfg = db.getConfig().get(ReceiveConfig.KEY);
  161. checkReceivedObjects = cfg.checkReceivedObjects;
  162. allowCreates = cfg.allowCreates;
  163. allowDeletes = cfg.allowDeletes;
  164. allowNonFastForwards = cfg.allowNonFastForwards;
  165. allowOfsDelta = cfg.allowOfsDelta;
  166. refFilter = RefFilter.DEFAULT;
  167. preReceive = PreReceiveHook.NULL;
  168. postReceive = PostReceiveHook.NULL;
  169. }
  170. private static class ReceiveConfig {
  171. static final SectionParser<ReceiveConfig> KEY = new SectionParser<ReceiveConfig>() {
  172. public ReceiveConfig parse(final Config cfg) {
  173. return new ReceiveConfig(cfg);
  174. }
  175. };
  176. final boolean checkReceivedObjects;
  177. final boolean allowCreates;
  178. final boolean allowDeletes;
  179. final boolean allowNonFastForwards;
  180. final boolean allowOfsDelta;
  181. ReceiveConfig(final Config config) {
  182. checkReceivedObjects = config.getBoolean("receive", "fsckobjects",
  183. false);
  184. allowCreates = true;
  185. allowDeletes = !config.getBoolean("receive", "denydeletes", false);
  186. allowNonFastForwards = !config.getBoolean("receive",
  187. "denynonfastforwards", false);
  188. allowOfsDelta = config.getBoolean("repack", "usedeltabaseoffset",
  189. true);
  190. }
  191. }
  192. /** @return the repository this receive completes into. */
  193. public final Repository getRepository() {
  194. return db;
  195. }
  196. /** @return the RevWalk instance used by this connection. */
  197. public final RevWalk getRevWalk() {
  198. return walk;
  199. }
  200. /** @return all refs which were advertised to the client. */
  201. public final Map<String, Ref> getAdvertisedRefs() {
  202. return refs;
  203. }
  204. /**
  205. * Configure this receive pack instance to keep track of the objects assumed
  206. * for delta bases.
  207. * <p>
  208. * By default a receive pack doesn't save the objects that were used as
  209. * delta bases. Setting this flag to {@code true} will allow the caller to
  210. * use {@link #getBaseObjectIds()} to retrieve that list.
  211. *
  212. * @param b {@code true} to enable keeping track of delta bases.
  213. */
  214. public void setNeedBaseObjectIds(boolean b) {
  215. this.needBaseObjectIds = b;
  216. }
  217. /**
  218. * @return the set of objects the incoming pack assumed for delta purposes
  219. */
  220. public final Set<ObjectId> getBaseObjectIds() {
  221. return ip.getBaseObjectIds();
  222. }
  223. /**
  224. * Configure this receive pack instance to keep track of new objects.
  225. * <p>
  226. * By default a receive pack doesn't save the new objects that were created
  227. * when it was instantiated. Setting this flag to {@code true} allows the
  228. * caller to use {@link #getNewObjectIds()} to retrieve that list.
  229. *
  230. * @param b {@code true} to enable keeping track of new objects.
  231. */
  232. public void setNeedNewObjectIds(boolean b) {
  233. this.needNewObjectIds = b;
  234. }
  235. /** @return the new objects that were sent by the user */
  236. public final Set<ObjectId> getNewObjectIds() {
  237. return ip.getNewObjectIds();
  238. }
  239. /**
  240. * @return true if this class expects a bi-directional pipe opened between
  241. * the client and itself. The default is true.
  242. */
  243. public boolean isBiDirectionalPipe() {
  244. return biDirectionalPipe;
  245. }
  246. /**
  247. * @param twoWay
  248. * if true, this class will assume the socket is a fully
  249. * bidirectional pipe between the two peers and takes advantage
  250. * of that by first transmitting the known refs, then waiting to
  251. * read commands. If false, this class assumes it must read the
  252. * commands before writing output and does not perform the
  253. * initial advertising.
  254. */
  255. public void setBiDirectionalPipe(final boolean twoWay) {
  256. biDirectionalPipe = twoWay;
  257. }
  258. /**
  259. * @return true if this instance will verify received objects are formatted
  260. * correctly. Validating objects requires more CPU time on this side
  261. * of the connection.
  262. */
  263. public boolean isCheckReceivedObjects() {
  264. return checkReceivedObjects;
  265. }
  266. /**
  267. * @param check
  268. * true to enable checking received objects; false to assume all
  269. * received objects are valid.
  270. */
  271. public void setCheckReceivedObjects(final boolean check) {
  272. checkReceivedObjects = check;
  273. }
  274. /** @return true if the client can request refs to be created. */
  275. public boolean isAllowCreates() {
  276. return allowCreates;
  277. }
  278. /**
  279. * @param canCreate
  280. * true to permit create ref commands to be processed.
  281. */
  282. public void setAllowCreates(final boolean canCreate) {
  283. allowCreates = canCreate;
  284. }
  285. /** @return true if the client can request refs to be deleted. */
  286. public boolean isAllowDeletes() {
  287. return allowDeletes;
  288. }
  289. /**
  290. * @param canDelete
  291. * true to permit delete ref commands to be processed.
  292. */
  293. public void setAllowDeletes(final boolean canDelete) {
  294. allowDeletes = canDelete;
  295. }
  296. /**
  297. * @return true if the client can request non-fast-forward updates of a ref,
  298. * possibly making objects unreachable.
  299. */
  300. public boolean isAllowNonFastForwards() {
  301. return allowNonFastForwards;
  302. }
  303. /**
  304. * @param canRewind
  305. * true to permit the client to ask for non-fast-forward updates
  306. * of an existing ref.
  307. */
  308. public void setAllowNonFastForwards(final boolean canRewind) {
  309. allowNonFastForwards = canRewind;
  310. }
  311. /** @return identity of the user making the changes in the reflog. */
  312. public PersonIdent getRefLogIdent() {
  313. return refLogIdent;
  314. }
  315. /**
  316. * Set the identity of the user appearing in the affected reflogs.
  317. * <p>
  318. * The timestamp portion of the identity is ignored. A new identity with the
  319. * current timestamp will be created automatically when the updates occur
  320. * and the log records are written.
  321. *
  322. * @param pi
  323. * identity of the user. If null the identity will be
  324. * automatically determined based on the repository
  325. * configuration.
  326. */
  327. public void setRefLogIdent(final PersonIdent pi) {
  328. refLogIdent = pi;
  329. }
  330. /** @return the filter used while advertising the refs to the client */
  331. public RefFilter getRefFilter() {
  332. return refFilter;
  333. }
  334. /**
  335. * Set the filter used while advertising the refs to the client.
  336. * <p>
  337. * Only refs allowed by this filter will be shown to the client.
  338. * Clients may still attempt to create or update a reference hidden
  339. * by the configured {@link RefFilter}. These attempts should be
  340. * rejected by a matching {@link PreReceiveHook}.
  341. *
  342. * @param refFilter
  343. * the filter; may be null to show all refs.
  344. */
  345. public void setRefFilter(final RefFilter refFilter) {
  346. this.refFilter = refFilter != null ? refFilter : RefFilter.DEFAULT;
  347. }
  348. /** @return get the hook invoked before updates occur. */
  349. public PreReceiveHook getPreReceiveHook() {
  350. return preReceive;
  351. }
  352. /**
  353. * Set the hook which is invoked prior to commands being executed.
  354. * <p>
  355. * Only valid commands (those which have no obvious errors according to the
  356. * received input and this instance's configuration) are passed into the
  357. * hook. The hook may mark a command with a result of any value other than
  358. * {@link Result#NOT_ATTEMPTED} to block its execution.
  359. * <p>
  360. * The hook may be called with an empty command collection if the current
  361. * set is completely invalid.
  362. *
  363. * @param h
  364. * the hook instance; may be null to disable the hook.
  365. */
  366. public void setPreReceiveHook(final PreReceiveHook h) {
  367. preReceive = h != null ? h : PreReceiveHook.NULL;
  368. }
  369. /** @return get the hook invoked after updates occur. */
  370. public PostReceiveHook getPostReceiveHook() {
  371. return postReceive;
  372. }
  373. /**
  374. * Set the hook which is invoked after commands are executed.
  375. * <p>
  376. * Only successful commands (type is {@link Result#OK}) are passed into the
  377. * hook. The hook may be called with an empty command collection if the
  378. * current set all resulted in an error.
  379. *
  380. * @param h
  381. * the hook instance; may be null to disable the hook.
  382. */
  383. public void setPostReceiveHook(final PostReceiveHook h) {
  384. postReceive = h != null ? h : PostReceiveHook.NULL;
  385. }
  386. /** @return timeout (in seconds) before aborting an IO operation. */
  387. public int getTimeout() {
  388. return timeout;
  389. }
  390. /**
  391. * Set the timeout before willing to abort an IO call.
  392. *
  393. * @param seconds
  394. * number of seconds to wait (with no data transfer occurring)
  395. * before aborting an IO read or write operation with the
  396. * connected client.
  397. */
  398. public void setTimeout(final int seconds) {
  399. timeout = seconds;
  400. }
  401. /** @return all of the command received by the current request. */
  402. public List<ReceiveCommand> getAllCommands() {
  403. return Collections.unmodifiableList(commands);
  404. }
  405. /**
  406. * Send an error message to the client.
  407. * <p>
  408. * If any error messages are sent before the references are advertised to
  409. * the client, the errors will be sent instead of the advertisement and the
  410. * receive operation will be aborted. All clients should receive and display
  411. * such early stage errors.
  412. * <p>
  413. * If the reference advertisements have already been sent, messages are sent
  414. * in a side channel. If the client doesn't support receiving messages, the
  415. * message will be discarded, with no other indication to the caller or to
  416. * the client.
  417. * <p>
  418. * {@link PreReceiveHook}s should always try to use
  419. * {@link ReceiveCommand#setResult(Result, String)} with a result status of
  420. * {@link Result#REJECTED_OTHER_REASON} to indicate any reasons for
  421. * rejecting an update. Messages attached to a command are much more likely
  422. * to be returned to the client.
  423. *
  424. * @param what
  425. * string describing the problem identified by the hook. The
  426. * string must not end with an LF, and must not contain an LF.
  427. */
  428. public void sendError(final String what) {
  429. if (refs == null) {
  430. if (advertiseError == null)
  431. advertiseError = new StringBuilder();
  432. advertiseError.append(what).append('\n');
  433. } else {
  434. try {
  435. if (msgs != null)
  436. msgs.write("error: " + what + "\n");
  437. } catch (IOException e) {
  438. // Ignore write failures.
  439. }
  440. }
  441. }
  442. /**
  443. * Send a message to the client, if it supports receiving them.
  444. * <p>
  445. * If the client doesn't support receiving messages, the message will be
  446. * discarded, with no other indication to the caller or to the client.
  447. *
  448. * @param what
  449. * string describing the problem identified by the hook. The
  450. * string must not end with an LF, and must not contain an LF.
  451. */
  452. public void sendMessage(final String what) {
  453. try {
  454. if (msgs != null)
  455. msgs.write(what + "\n");
  456. } catch (IOException e) {
  457. // Ignore write failures.
  458. }
  459. }
  460. /**
  461. * Execute the receive task on the socket.
  462. *
  463. * @param input
  464. * raw input to read client commands and pack data from. Caller
  465. * must ensure the input is buffered, otherwise read performance
  466. * may suffer.
  467. * @param output
  468. * response back to the Git network client. Caller must ensure
  469. * the output is buffered, otherwise write performance may
  470. * suffer.
  471. * @param messages
  472. * secondary "notice" channel to send additional messages out
  473. * through. When run over SSH this should be tied back to the
  474. * standard error channel of the command execution. For most
  475. * other network connections this should be null.
  476. * @throws IOException
  477. */
  478. public void receive(final InputStream input, final OutputStream output,
  479. final OutputStream messages) throws IOException {
  480. try {
  481. rawIn = input;
  482. rawOut = output;
  483. if (timeout > 0) {
  484. final Thread caller = Thread.currentThread();
  485. timer = new InterruptTimer(caller.getName() + "-Timer");
  486. timeoutIn = new TimeoutInputStream(rawIn, timer);
  487. TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer);
  488. timeoutIn.setTimeout(timeout * 1000);
  489. o.setTimeout(timeout * 1000);
  490. rawIn = timeoutIn;
  491. rawOut = o;
  492. }
  493. pckIn = new PacketLineIn(rawIn);
  494. pckOut = new PacketLineOut(rawOut);
  495. if (messages != null)
  496. msgs = new OutputStreamWriter(messages, Constants.CHARSET);
  497. enabledCapablities = new HashSet<String>();
  498. commands = new ArrayList<ReceiveCommand>();
  499. service();
  500. } finally {
  501. try {
  502. if (pckOut != null)
  503. pckOut.flush();
  504. if (msgs != null)
  505. msgs.flush();
  506. if (sideBand) {
  507. // If we are using side band, we need to send a final
  508. // flush-pkt to tell the remote peer the side band is
  509. // complete and it should stop decoding. We need to
  510. // use the original output stream as rawOut is now the
  511. // side band data channel.
  512. //
  513. new PacketLineOut(output).end();
  514. }
  515. } finally {
  516. unlockPack();
  517. timeoutIn = null;
  518. rawIn = null;
  519. rawOut = null;
  520. pckIn = null;
  521. pckOut = null;
  522. msgs = null;
  523. refs = null;
  524. enabledCapablities = null;
  525. commands = null;
  526. if (timer != null) {
  527. try {
  528. timer.terminate();
  529. } finally {
  530. timer = null;
  531. }
  532. }
  533. }
  534. }
  535. }
  536. private void service() throws IOException {
  537. if (biDirectionalPipe)
  538. sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
  539. else
  540. refs = refFilter.filter(db.getAllRefs());
  541. if (advertiseError != null)
  542. return;
  543. recvCommands();
  544. if (!commands.isEmpty()) {
  545. enableCapabilities();
  546. if (needPack()) {
  547. try {
  548. receivePack();
  549. if (isCheckReceivedObjects())
  550. checkConnectivity();
  551. unpackError = null;
  552. } catch (IOException err) {
  553. unpackError = err;
  554. } catch (RuntimeException err) {
  555. unpackError = err;
  556. } catch (Error err) {
  557. unpackError = err;
  558. }
  559. }
  560. if (unpackError == null) {
  561. validateCommands();
  562. executeCommands();
  563. }
  564. unlockPack();
  565. if (reportStatus) {
  566. sendStatusReport(true, new Reporter() {
  567. void sendString(final String s) throws IOException {
  568. pckOut.writeString(s + "\n");
  569. }
  570. });
  571. pckOut.end();
  572. } else if (msgs != null) {
  573. sendStatusReport(false, new Reporter() {
  574. void sendString(final String s) throws IOException {
  575. msgs.write(s + "\n");
  576. }
  577. });
  578. }
  579. postReceive.onPostReceive(this, filterCommands(Result.OK));
  580. }
  581. }
  582. private void unlockPack() {
  583. if (packLock != null) {
  584. packLock.unlock();
  585. packLock = null;
  586. }
  587. }
  588. /**
  589. * Generate an advertisement of available refs and capabilities.
  590. *
  591. * @param adv
  592. * the advertisement formatter.
  593. * @throws IOException
  594. * the formatter failed to write an advertisement.
  595. */
  596. public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException {
  597. if (advertiseError != null) {
  598. adv.writeOne("ERR " + advertiseError);
  599. return;
  600. }
  601. final RevFlag advertised = walk.newFlag("ADVERTISED");
  602. adv.init(walk, advertised);
  603. adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
  604. adv.advertiseCapability(CAPABILITY_DELETE_REFS);
  605. adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
  606. if (allowOfsDelta)
  607. adv.advertiseCapability(CAPABILITY_OFS_DELTA);
  608. refs = refFilter.filter(db.getAllRefs());
  609. final Ref head = refs.remove(Constants.HEAD);
  610. adv.send(refs);
  611. if (head != null && !head.isSymbolic())
  612. adv.advertiseHave(head.getObjectId());
  613. adv.includeAdditionalHaves();
  614. if (adv.isEmpty())
  615. adv.advertiseId(ObjectId.zeroId(), "capabilities^{}");
  616. adv.end();
  617. }
  618. private void recvCommands() throws IOException {
  619. for (;;) {
  620. String line;
  621. try {
  622. line = pckIn.readStringRaw();
  623. } catch (EOFException eof) {
  624. if (commands.isEmpty())
  625. return;
  626. throw eof;
  627. }
  628. if (line == PacketLineIn.END)
  629. break;
  630. if (commands.isEmpty()) {
  631. final int nul = line.indexOf('\0');
  632. if (nul >= 0) {
  633. for (String c : line.substring(nul + 1).split(" "))
  634. enabledCapablities.add(c);
  635. line = line.substring(0, nul);
  636. }
  637. }
  638. if (line.length() < 83) {
  639. final String m = "error: invalid protocol: wanted 'old new ref'";
  640. sendError(m);
  641. throw new PackProtocolException(m);
  642. }
  643. final ObjectId oldId = ObjectId.fromString(line.substring(0, 40));
  644. final ObjectId newId = ObjectId.fromString(line.substring(41, 81));
  645. final String name = line.substring(82);
  646. final ReceiveCommand cmd = new ReceiveCommand(oldId, newId, name);
  647. if (name.equals(Constants.HEAD)) {
  648. cmd.setResult(Result.REJECTED_CURRENT_BRANCH);
  649. } else {
  650. cmd.setRef(refs.get(cmd.getRefName()));
  651. }
  652. commands.add(cmd);
  653. }
  654. }
  655. private void enableCapabilities() {
  656. reportStatus = enabledCapablities.contains(CAPABILITY_REPORT_STATUS);
  657. sideBand = enabledCapablities.contains(CAPABILITY_SIDE_BAND_64K);
  658. if (sideBand) {
  659. OutputStream out = rawOut;
  660. rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out);
  661. pckOut = new PacketLineOut(rawOut);
  662. msgs = new OutputStreamWriter(new SideBandOutputStream(CH_PROGRESS,
  663. MAX_BUF, out), Constants.CHARSET);
  664. }
  665. }
  666. private boolean needPack() {
  667. for (final ReceiveCommand cmd : commands) {
  668. if (cmd.getType() != ReceiveCommand.Type.DELETE)
  669. return true;
  670. }
  671. return false;
  672. }
  673. private void receivePack() throws IOException {
  674. // It might take the client a while to pack the objects it needs
  675. // to send to us. We should increase our timeout so we don't
  676. // abort while the client is computing.
  677. //
  678. if (timeoutIn != null)
  679. timeoutIn.setTimeout(10 * timeout * 1000);
  680. ip = IndexPack.create(db, rawIn);
  681. ip.setFixThin(true);
  682. ip.setNeedNewObjectIds(needNewObjectIds);
  683. ip.setNeedBaseObjectIds(needBaseObjectIds);
  684. ip.setObjectChecking(isCheckReceivedObjects());
  685. ip.index(NullProgressMonitor.INSTANCE);
  686. String lockMsg = "jgit receive-pack";
  687. if (getRefLogIdent() != null)
  688. lockMsg += " from " + getRefLogIdent().toExternalString();
  689. packLock = ip.renameAndOpenPack(lockMsg);
  690. if (timeoutIn != null)
  691. timeoutIn.setTimeout(timeout * 1000);
  692. }
  693. private void checkConnectivity() throws IOException {
  694. final ObjectWalk ow = new ObjectWalk(db);
  695. for (final ReceiveCommand cmd : commands) {
  696. if (cmd.getResult() != Result.NOT_ATTEMPTED)
  697. continue;
  698. if (cmd.getType() == ReceiveCommand.Type.DELETE)
  699. continue;
  700. ow.markStart(ow.parseAny(cmd.getNewId()));
  701. }
  702. for (final Ref ref : refs.values())
  703. ow.markUninteresting(ow.parseAny(ref.getObjectId()));
  704. ow.checkConnectivity();
  705. }
  706. private void validateCommands() {
  707. for (final ReceiveCommand cmd : commands) {
  708. final Ref ref = cmd.getRef();
  709. if (cmd.getResult() != Result.NOT_ATTEMPTED)
  710. continue;
  711. if (cmd.getType() == ReceiveCommand.Type.DELETE
  712. && !isAllowDeletes()) {
  713. // Deletes are not supported on this repository.
  714. //
  715. cmd.setResult(Result.REJECTED_NODELETE);
  716. continue;
  717. }
  718. if (cmd.getType() == ReceiveCommand.Type.CREATE) {
  719. if (!isAllowCreates()) {
  720. cmd.setResult(Result.REJECTED_NOCREATE);
  721. continue;
  722. }
  723. if (ref != null && !isAllowNonFastForwards()) {
  724. // Creation over an existing ref is certainly not going
  725. // to be a fast-forward update. We can reject it early.
  726. //
  727. cmd.setResult(Result.REJECTED_NONFASTFORWARD);
  728. continue;
  729. }
  730. if (ref != null) {
  731. // A well behaved client shouldn't have sent us a
  732. // create command for a ref we advertised to it.
  733. //
  734. cmd.setResult(Result.REJECTED_OTHER_REASON, "ref exists");
  735. continue;
  736. }
  737. }
  738. if (cmd.getType() == ReceiveCommand.Type.DELETE && ref != null
  739. && !ObjectId.zeroId().equals(cmd.getOldId())
  740. && !ref.getObjectId().equals(cmd.getOldId())) {
  741. // Delete commands can be sent with the old id matching our
  742. // advertised value, *OR* with the old id being 0{40}. Any
  743. // other requested old id is invalid.
  744. //
  745. cmd.setResult(Result.REJECTED_OTHER_REASON,
  746. "invalid old id sent");
  747. continue;
  748. }
  749. if (cmd.getType() == ReceiveCommand.Type.UPDATE) {
  750. if (ref == null) {
  751. // The ref must have been advertised in order to be updated.
  752. //
  753. cmd.setResult(Result.REJECTED_OTHER_REASON, "no such ref");
  754. continue;
  755. }
  756. if (!ref.getObjectId().equals(cmd.getOldId())) {
  757. // A properly functioning client will send the same
  758. // object id we advertised.
  759. //
  760. cmd.setResult(Result.REJECTED_OTHER_REASON,
  761. "invalid old id sent");
  762. continue;
  763. }
  764. // Is this possibly a non-fast-forward style update?
  765. //
  766. RevObject oldObj, newObj;
  767. try {
  768. oldObj = walk.parseAny(cmd.getOldId());
  769. } catch (IOException e) {
  770. cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd
  771. .getOldId().name());
  772. continue;
  773. }
  774. try {
  775. newObj = walk.parseAny(cmd.getNewId());
  776. } catch (IOException e) {
  777. cmd.setResult(Result.REJECTED_MISSING_OBJECT, cmd
  778. .getNewId().name());
  779. continue;
  780. }
  781. if (oldObj instanceof RevCommit && newObj instanceof RevCommit) {
  782. try {
  783. if (!walk.isMergedInto((RevCommit) oldObj,
  784. (RevCommit) newObj)) {
  785. cmd
  786. .setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
  787. }
  788. } catch (MissingObjectException e) {
  789. cmd.setResult(Result.REJECTED_MISSING_OBJECT, e
  790. .getMessage());
  791. } catch (IOException e) {
  792. cmd.setResult(Result.REJECTED_OTHER_REASON);
  793. }
  794. } else {
  795. cmd.setType(ReceiveCommand.Type.UPDATE_NONFASTFORWARD);
  796. }
  797. }
  798. if (!cmd.getRefName().startsWith(Constants.R_REFS)
  799. || !Repository.isValidRefName(cmd.getRefName())) {
  800. cmd.setResult(Result.REJECTED_OTHER_REASON, "funny refname");
  801. }
  802. }
  803. }
  804. private void executeCommands() {
  805. preReceive.onPreReceive(this, filterCommands(Result.NOT_ATTEMPTED));
  806. for (final ReceiveCommand cmd : filterCommands(Result.NOT_ATTEMPTED))
  807. execute(cmd);
  808. }
  809. private void execute(final ReceiveCommand cmd) {
  810. try {
  811. final RefUpdate ru = db.updateRef(cmd.getRefName());
  812. ru.setRefLogIdent(getRefLogIdent());
  813. switch (cmd.getType()) {
  814. case DELETE:
  815. if (!ObjectId.zeroId().equals(cmd.getOldId())) {
  816. // We can only do a CAS style delete if the client
  817. // didn't bork its delete request by sending the
  818. // wrong zero id rather than the advertised one.
  819. //
  820. ru.setExpectedOldObjectId(cmd.getOldId());
  821. }
  822. ru.setForceUpdate(true);
  823. status(cmd, ru.delete(walk));
  824. break;
  825. case CREATE:
  826. case UPDATE:
  827. case UPDATE_NONFASTFORWARD:
  828. ru.setForceUpdate(isAllowNonFastForwards());
  829. ru.setExpectedOldObjectId(cmd.getOldId());
  830. ru.setNewObjectId(cmd.getNewId());
  831. ru.setRefLogMessage("push", true);
  832. status(cmd, ru.update(walk));
  833. break;
  834. }
  835. } catch (IOException err) {
  836. cmd.setResult(Result.REJECTED_OTHER_REASON, "lock error: "
  837. + err.getMessage());
  838. }
  839. }
  840. private void status(final ReceiveCommand cmd, final RefUpdate.Result result) {
  841. switch (result) {
  842. case NOT_ATTEMPTED:
  843. cmd.setResult(Result.NOT_ATTEMPTED);
  844. break;
  845. case LOCK_FAILURE:
  846. case IO_FAILURE:
  847. cmd.setResult(Result.LOCK_FAILURE);
  848. break;
  849. case NO_CHANGE:
  850. case NEW:
  851. case FORCED:
  852. case FAST_FORWARD:
  853. cmd.setResult(Result.OK);
  854. break;
  855. case REJECTED:
  856. cmd.setResult(Result.REJECTED_NONFASTFORWARD);
  857. break;
  858. case REJECTED_CURRENT_BRANCH:
  859. cmd.setResult(Result.REJECTED_CURRENT_BRANCH);
  860. break;
  861. default:
  862. cmd.setResult(Result.REJECTED_OTHER_REASON, result.name());
  863. break;
  864. }
  865. }
  866. private List<ReceiveCommand> filterCommands(final Result want) {
  867. final List<ReceiveCommand> r = new ArrayList<ReceiveCommand>(commands
  868. .size());
  869. for (final ReceiveCommand cmd : commands) {
  870. if (cmd.getResult() == want)
  871. r.add(cmd);
  872. }
  873. return r;
  874. }
  875. private void sendStatusReport(final boolean forClient, final Reporter out)
  876. throws IOException {
  877. if (unpackError != null) {
  878. out.sendString("unpack error " + unpackError.getMessage());
  879. if (forClient) {
  880. for (final ReceiveCommand cmd : commands) {
  881. out.sendString("ng " + cmd.getRefName()
  882. + " n/a (unpacker error)");
  883. }
  884. }
  885. return;
  886. }
  887. if (forClient)
  888. out.sendString("unpack ok");
  889. for (final ReceiveCommand cmd : commands) {
  890. if (cmd.getResult() == Result.OK) {
  891. if (forClient)
  892. out.sendString("ok " + cmd.getRefName());
  893. continue;
  894. }
  895. final StringBuilder r = new StringBuilder();
  896. r.append("ng ");
  897. r.append(cmd.getRefName());
  898. r.append(" ");
  899. switch (cmd.getResult()) {
  900. case NOT_ATTEMPTED:
  901. r.append("server bug; ref not processed");
  902. break;
  903. case REJECTED_NOCREATE:
  904. r.append("creation prohibited");
  905. break;
  906. case REJECTED_NODELETE:
  907. r.append("deletion prohibited");
  908. break;
  909. case REJECTED_NONFASTFORWARD:
  910. r.append("non-fast forward");
  911. break;
  912. case REJECTED_CURRENT_BRANCH:
  913. r.append("branch is currently checked out");
  914. break;
  915. case REJECTED_MISSING_OBJECT:
  916. if (cmd.getMessage() == null)
  917. r.append("missing object(s)");
  918. else if (cmd.getMessage().length() == Constants.OBJECT_ID_STRING_LENGTH)
  919. r.append("object " + cmd.getMessage() + " missing");
  920. else
  921. r.append(cmd.getMessage());
  922. break;
  923. case REJECTED_OTHER_REASON:
  924. if (cmd.getMessage() == null)
  925. r.append("unspecified reason");
  926. else
  927. r.append(cmd.getMessage());
  928. break;
  929. case LOCK_FAILURE:
  930. r.append("failed to lock");
  931. break;
  932. case OK:
  933. // We shouldn't have reached this case (see 'ok' case above).
  934. continue;
  935. }
  936. out.sendString(r.toString());
  937. }
  938. }
  939. static abstract class Reporter {
  940. abstract void sendString(String s) throws IOException;
  941. }
  942. }