Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

ReceivePackAdvertiseRefsHookTest.java 21KB

Fix checkReferencedIsReachable to use correct base list When checkReferencedIsReachable is set in ReceivePack we are trying to prove that the push client is permitted to access an object that it did not send to us, but that the received objects link to either via a link inside of an object (e.g. commit parent pointer or tree member) or by a delta base reference. To do this check we are making a list of every potential delta base, and then ensuring that every delta base used appears on this list. If a delta base does not appear on this list, we abort with an error, letting the client know we are missing a particular object. Preventing spurious errors about missing delta base objects requires us to use the exact same list of potential delta bases as the remote push client used. This means we must use TOPO ordering, and we need to enable BOUNDARY sorting so that ObjectWalk will correctly include any trees found during the enumeration back to the common merge base between the interesting and uninteresting heads. To ensure JGit's own push client matches this same potential delta base list, we need to undo 60aae90d4d15 ("Disable topological sorting in PackWriter") and switch back to using the conventional TOPO ordering for commits in a pack file. This ensures that our own push client will use the same potential base object list as checkReferencedIsReachable uses on the receiving side. Change-Id: I14d0a326deb62a43f987b375cfe519711031e172 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
13 роки тому
Fix checkReferencedIsReachable to use correct base list When checkReferencedIsReachable is set in ReceivePack we are trying to prove that the push client is permitted to access an object that it did not send to us, but that the received objects link to either via a link inside of an object (e.g. commit parent pointer or tree member) or by a delta base reference. To do this check we are making a list of every potential delta base, and then ensuring that every delta base used appears on this list. If a delta base does not appear on this list, we abort with an error, letting the client know we are missing a particular object. Preventing spurious errors about missing delta base objects requires us to use the exact same list of potential delta bases as the remote push client used. This means we must use TOPO ordering, and we need to enable BOUNDARY sorting so that ObjectWalk will correctly include any trees found during the enumeration back to the common merge base between the interesting and uninteresting heads. To ensure JGit's own push client matches this same potential delta base list, we need to undo 60aae90d4d15 ("Disable topological sorting in PackWriter") and switch back to using the conventional TOPO ordering for commits in a pack file. This ensures that our own push client will use the same potential base object list as checkReferencedIsReachable uses on the receiving side. Change-Id: I14d0a326deb62a43f987b375cfe519711031e172 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
13 роки тому
Fix checkReferencedIsReachable to use correct base list When checkReferencedIsReachable is set in ReceivePack we are trying to prove that the push client is permitted to access an object that it did not send to us, but that the received objects link to either via a link inside of an object (e.g. commit parent pointer or tree member) or by a delta base reference. To do this check we are making a list of every potential delta base, and then ensuring that every delta base used appears on this list. If a delta base does not appear on this list, we abort with an error, letting the client know we are missing a particular object. Preventing spurious errors about missing delta base objects requires us to use the exact same list of potential delta bases as the remote push client used. This means we must use TOPO ordering, and we need to enable BOUNDARY sorting so that ObjectWalk will correctly include any trees found during the enumeration back to the common merge base between the interesting and uninteresting heads. To ensure JGit's own push client matches this same potential delta base list, we need to undo 60aae90d4d15 ("Disable topological sorting in PackWriter") and switch back to using the conventional TOPO ordering for commits in a pack file. This ensures that our own push client will use the same potential base object list as checkReferencedIsReachable uses on the receiving side. Change-Id: I14d0a326deb62a43f987b375cfe519711031e172 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
13 роки тому
Fix checkReferencedIsReachable to use correct base list When checkReferencedIsReachable is set in ReceivePack we are trying to prove that the push client is permitted to access an object that it did not send to us, but that the received objects link to either via a link inside of an object (e.g. commit parent pointer or tree member) or by a delta base reference. To do this check we are making a list of every potential delta base, and then ensuring that every delta base used appears on this list. If a delta base does not appear on this list, we abort with an error, letting the client know we are missing a particular object. Preventing spurious errors about missing delta base objects requires us to use the exact same list of potential delta bases as the remote push client used. This means we must use TOPO ordering, and we need to enable BOUNDARY sorting so that ObjectWalk will correctly include any trees found during the enumeration back to the common merge base between the interesting and uninteresting heads. To ensure JGit's own push client matches this same potential delta base list, we need to undo 60aae90d4d15 ("Disable topological sorting in PackWriter") and switch back to using the conventional TOPO ordering for commits in a pack file. This ensures that our own push client will use the same potential base object list as checkReferencedIsReachable uses on the receiving side. Change-Id: I14d0a326deb62a43f987b375cfe519711031e172 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
13 роки тому
Fix checkReferencedIsReachable to use correct base list When checkReferencedIsReachable is set in ReceivePack we are trying to prove that the push client is permitted to access an object that it did not send to us, but that the received objects link to either via a link inside of an object (e.g. commit parent pointer or tree member) or by a delta base reference. To do this check we are making a list of every potential delta base, and then ensuring that every delta base used appears on this list. If a delta base does not appear on this list, we abort with an error, letting the client know we are missing a particular object. Preventing spurious errors about missing delta base objects requires us to use the exact same list of potential delta bases as the remote push client used. This means we must use TOPO ordering, and we need to enable BOUNDARY sorting so that ObjectWalk will correctly include any trees found during the enumeration back to the common merge base between the interesting and uninteresting heads. To ensure JGit's own push client matches this same potential delta base list, we need to undo 60aae90d4d15 ("Disable topological sorting in PackWriter") and switch back to using the conventional TOPO ordering for commits in a pack file. This ensures that our own push client will use the same potential base object list as checkReferencedIsReachable uses on the receiving side. Change-Id: I14d0a326deb62a43f987b375cfe519711031e172 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
13 роки тому
Fix checkReferencedIsReachable to use correct base list When checkReferencedIsReachable is set in ReceivePack we are trying to prove that the push client is permitted to access an object that it did not send to us, but that the received objects link to either via a link inside of an object (e.g. commit parent pointer or tree member) or by a delta base reference. To do this check we are making a list of every potential delta base, and then ensuring that every delta base used appears on this list. If a delta base does not appear on this list, we abort with an error, letting the client know we are missing a particular object. Preventing spurious errors about missing delta base objects requires us to use the exact same list of potential delta bases as the remote push client used. This means we must use TOPO ordering, and we need to enable BOUNDARY sorting so that ObjectWalk will correctly include any trees found during the enumeration back to the common merge base between the interesting and uninteresting heads. To ensure JGit's own push client matches this same potential delta base list, we need to undo 60aae90d4d15 ("Disable topological sorting in PackWriter") and switch back to using the conventional TOPO ordering for commits in a pack file. This ensures that our own push client will use the same potential base object list as checkReferencedIsReachable uses on the receiving side. Change-Id: I14d0a326deb62a43f987b375cfe519711031e172 Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
13 роки тому
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625
  1. /*
  2. * Copyright (C) 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.junit.Assert.assertEquals;
  45. import static org.junit.Assert.assertFalse;
  46. import static org.junit.Assert.assertNotNull;
  47. import static org.junit.Assert.assertNull;
  48. import static org.junit.Assert.assertSame;
  49. import static org.junit.Assert.assertTrue;
  50. import static org.junit.Assert.fail;
  51. import java.io.ByteArrayInputStream;
  52. import java.io.IOException;
  53. import java.net.URISyntaxException;
  54. import java.security.MessageDigest;
  55. import java.util.Collections;
  56. import java.util.HashMap;
  57. import java.util.Map;
  58. import java.util.zip.Deflater;
  59. import org.eclipse.jgit.errors.MissingObjectException;
  60. import org.eclipse.jgit.errors.UnpackException;
  61. import org.eclipse.jgit.internal.storage.file.ObjectDirectory;
  62. import org.eclipse.jgit.internal.storage.pack.BinaryDelta;
  63. import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
  64. import org.eclipse.jgit.junit.TestRepository;
  65. import org.eclipse.jgit.lib.Constants;
  66. import org.eclipse.jgit.lib.NullProgressMonitor;
  67. import org.eclipse.jgit.lib.ObjectId;
  68. import org.eclipse.jgit.lib.ObjectInserter;
  69. import org.eclipse.jgit.lib.ObjectLoader;
  70. import org.eclipse.jgit.lib.Ref;
  71. import org.eclipse.jgit.lib.Repository;
  72. import org.eclipse.jgit.revwalk.RevBlob;
  73. import org.eclipse.jgit.revwalk.RevCommit;
  74. import org.eclipse.jgit.revwalk.RevTree;
  75. import org.eclipse.jgit.revwalk.RevWalk;
  76. import org.eclipse.jgit.util.NB;
  77. import org.eclipse.jgit.util.TemporaryBuffer;
  78. import org.junit.After;
  79. import org.junit.Before;
  80. import org.junit.Test;
  81. public class ReceivePackAdvertiseRefsHookTest extends LocalDiskRepositoryTestCase {
  82. private static final NullProgressMonitor PM = NullProgressMonitor.INSTANCE;
  83. private static final String R_MASTER = Constants.R_HEADS + Constants.MASTER;
  84. private static final String R_PRIVATE = Constants.R_HEADS + "private";
  85. private Repository src;
  86. private Repository dst;
  87. private RevCommit A, B, P;
  88. private RevBlob a, b;
  89. @Override
  90. @Before
  91. public void setUp() throws Exception {
  92. super.setUp();
  93. src = createBareRepository();
  94. dst = createBareRepository();
  95. // Fill dst with a some common history.
  96. //
  97. TestRepository<Repository> d = new TestRepository<>(dst);
  98. a = d.blob("a");
  99. A = d.commit(d.tree(d.file("a", a)));
  100. B = d.commit().parent(A).create();
  101. d.update(R_MASTER, B);
  102. // Clone from dst into src
  103. //
  104. try (Transport t = Transport.open(src, uriOf(dst))) {
  105. t.fetch(PM, Collections.singleton(new RefSpec("+refs/*:refs/*")));
  106. assertEquals(B, src.resolve(R_MASTER));
  107. }
  108. // Now put private stuff into dst.
  109. //
  110. b = d.blob("b");
  111. P = d.commit(d.tree(d.file("b", b)), A);
  112. d.update(R_PRIVATE, P);
  113. }
  114. @Test
  115. public void testFilterHidesPrivate() throws Exception {
  116. Map<String, Ref> refs;
  117. try (TransportLocal t = new TransportLocal(src, uriOf(dst),
  118. dst.getDirectory()) {
  119. @Override
  120. ReceivePack createReceivePack(final Repository db) {
  121. db.close();
  122. dst.incrementOpen();
  123. final ReceivePack rp = super.createReceivePack(dst);
  124. rp.setAdvertiseRefsHook(new HidePrivateHook());
  125. return rp;
  126. }
  127. }) {
  128. try (PushConnection c = t.openPush()) {
  129. refs = c.getRefsMap();
  130. }
  131. }
  132. assertNotNull(refs);
  133. assertNull("no private", refs.get(R_PRIVATE));
  134. assertNull("no HEAD", refs.get(Constants.HEAD));
  135. assertEquals(1, refs.size());
  136. Ref master = refs.get(R_MASTER);
  137. assertNotNull("has master", master);
  138. assertEquals(B, master.getObjectId());
  139. }
  140. @Test
  141. public void testSuccess() throws Exception {
  142. // Manually force a delta of an object so we reuse it later.
  143. //
  144. TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
  145. packHeader(pack, 2);
  146. pack.write((Constants.OBJ_BLOB) << 4 | 1);
  147. deflate(pack, new byte[] { 'a' });
  148. pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
  149. a.copyRawTo(pack);
  150. deflate(pack, new byte[] { 0x1, 0x1, 0x1, 'b' });
  151. digest(pack);
  152. openPack(pack);
  153. // Verify the only storage of b is our packed delta above.
  154. //
  155. ObjectDirectory od = (ObjectDirectory) src.getObjectDatabase();
  156. assertTrue("has b", src.hasObject(b));
  157. assertFalse("b not loose", od.fileFor(b).exists());
  158. // Now use b but in a different commit than what is hidden.
  159. //
  160. TestRepository<Repository> s = new TestRepository<>(src);
  161. RevCommit N = s.commit().parent(B).add("q", b).create();
  162. s.update(R_MASTER, N);
  163. // Push this new content to the remote, doing strict validation.
  164. //
  165. TransportLocal t = new TransportLocal(src, uriOf(dst), dst.getDirectory()) {
  166. @Override
  167. ReceivePack createReceivePack(final Repository db) {
  168. db.close();
  169. dst.incrementOpen();
  170. final ReceivePack rp = super.createReceivePack(dst);
  171. rp.setCheckReceivedObjects(true);
  172. rp.setCheckReferencedObjectsAreReachable(true);
  173. rp.setAdvertiseRefsHook(new HidePrivateHook());
  174. return rp;
  175. }
  176. };
  177. RemoteRefUpdate u = new RemoteRefUpdate( //
  178. src, //
  179. R_MASTER, // src name
  180. R_MASTER, // dst name
  181. false, // do not force update
  182. null, // local tracking branch
  183. null // expected id
  184. );
  185. PushResult r;
  186. try {
  187. t.setPushThin(true);
  188. r = t.push(PM, Collections.singleton(u));
  189. } finally {
  190. t.close();
  191. }
  192. assertNotNull("have result", r);
  193. assertNull("private not advertised", r.getAdvertisedRef(R_PRIVATE));
  194. assertSame("master updated", RemoteRefUpdate.Status.OK, u.getStatus());
  195. assertEquals(N, dst.resolve(R_MASTER));
  196. }
  197. @Test
  198. public void testCreateBranchAtHiddenCommitFails() throws Exception {
  199. final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64);
  200. packHeader(pack, 0);
  201. digest(pack);
  202. final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256);
  203. final PacketLineOut inPckLine = new PacketLineOut(inBuf);
  204. inPckLine.writeString(ObjectId.zeroId().name() + ' ' + P.name() + ' '
  205. + "refs/heads/s" + '\0'
  206. + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
  207. inPckLine.end();
  208. pack.writeTo(inBuf, PM);
  209. final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
  210. final ReceivePack rp = new ReceivePack(dst);
  211. rp.setCheckReceivedObjects(true);
  212. rp.setCheckReferencedObjectsAreReachable(true);
  213. rp.setAdvertiseRefsHook(new HidePrivateHook());
  214. try {
  215. receive(rp, inBuf, outBuf);
  216. fail("Expected UnpackException");
  217. } catch (UnpackException failed) {
  218. Throwable err = failed.getCause();
  219. assertTrue(err instanceof MissingObjectException);
  220. MissingObjectException moe = (MissingObjectException) err;
  221. assertEquals(P, moe.getObjectId());
  222. }
  223. final PacketLineIn r = asPacketLineIn(outBuf);
  224. String master = r.readString();
  225. int nul = master.indexOf('\0');
  226. assertTrue("has capability list", nul > 0);
  227. assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
  228. assertSame(PacketLineIn.END, r.readString());
  229. assertEquals("unpack error Missing commit " + P.name(), r.readString());
  230. assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
  231. assertSame(PacketLineIn.END, r.readString());
  232. }
  233. private static void receive(final ReceivePack rp,
  234. final TemporaryBuffer.Heap inBuf, final TemporaryBuffer.Heap outBuf)
  235. throws IOException {
  236. rp.receive(new ByteArrayInputStream(inBuf.toByteArray()), outBuf, null);
  237. }
  238. @Test
  239. public void testUsingHiddenDeltaBaseFails() throws Exception {
  240. byte[] delta = { 0x1, 0x1, 0x1, 'c' };
  241. TestRepository<Repository> s = new TestRepository<>(src);
  242. RevCommit N = s.commit().parent(B).add("q",
  243. s.blob(BinaryDelta.apply(dst.open(b).getCachedBytes(), delta)))
  244. .create();
  245. final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
  246. packHeader(pack, 3);
  247. copy(pack, src.open(N));
  248. copy(pack, src.open(s.parseBody(N).getTree()));
  249. pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
  250. b.copyRawTo(pack);
  251. deflate(pack, delta);
  252. digest(pack);
  253. final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
  254. final PacketLineOut inPckLine = new PacketLineOut(inBuf);
  255. inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
  256. + "refs/heads/s" + '\0'
  257. + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
  258. inPckLine.end();
  259. pack.writeTo(inBuf, PM);
  260. final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
  261. final ReceivePack rp = new ReceivePack(dst);
  262. rp.setCheckReceivedObjects(true);
  263. rp.setCheckReferencedObjectsAreReachable(true);
  264. rp.setAdvertiseRefsHook(new HidePrivateHook());
  265. try {
  266. receive(rp, inBuf, outBuf);
  267. fail("Expected UnpackException");
  268. } catch (UnpackException failed) {
  269. Throwable err = failed.getCause();
  270. assertTrue(err instanceof MissingObjectException);
  271. MissingObjectException moe = (MissingObjectException) err;
  272. assertEquals(b, moe.getObjectId());
  273. }
  274. final PacketLineIn r = asPacketLineIn(outBuf);
  275. String master = r.readString();
  276. int nul = master.indexOf('\0');
  277. assertTrue("has capability list", nul > 0);
  278. assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
  279. assertSame(PacketLineIn.END, r.readString());
  280. assertEquals("unpack error Missing blob " + b.name(), r.readString());
  281. assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
  282. assertSame(PacketLineIn.END, r.readString());
  283. }
  284. @Test
  285. public void testUsingHiddenCommonBlobFails() throws Exception {
  286. // Try to use the 'b' blob that is hidden.
  287. //
  288. TestRepository<Repository> s = new TestRepository<>(src);
  289. RevCommit N = s.commit().parent(B).add("q", s.blob("b")).create();
  290. // But don't include it in the pack.
  291. //
  292. final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
  293. packHeader(pack, 2);
  294. copy(pack, src.open(N));
  295. copy(pack,src.open(s.parseBody(N).getTree()));
  296. digest(pack);
  297. final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
  298. final PacketLineOut inPckLine = new PacketLineOut(inBuf);
  299. inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
  300. + "refs/heads/s" + '\0'
  301. + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
  302. inPckLine.end();
  303. pack.writeTo(inBuf, PM);
  304. final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
  305. final ReceivePack rp = new ReceivePack(dst);
  306. rp.setCheckReceivedObjects(true);
  307. rp.setCheckReferencedObjectsAreReachable(true);
  308. rp.setAdvertiseRefsHook(new HidePrivateHook());
  309. try {
  310. receive(rp, inBuf, outBuf);
  311. fail("Expected UnpackException");
  312. } catch (UnpackException failed) {
  313. Throwable err = failed.getCause();
  314. assertTrue(err instanceof MissingObjectException);
  315. MissingObjectException moe = (MissingObjectException) err;
  316. assertEquals(b, moe.getObjectId());
  317. }
  318. final PacketLineIn r = asPacketLineIn(outBuf);
  319. String master = r.readString();
  320. int nul = master.indexOf('\0');
  321. assertTrue("has capability list", nul > 0);
  322. assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
  323. assertSame(PacketLineIn.END, r.readString());
  324. assertEquals("unpack error Missing blob " + b.name(), r.readString());
  325. assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
  326. assertSame(PacketLineIn.END, r.readString());
  327. }
  328. @Test
  329. public void testUsingUnknownBlobFails() throws Exception {
  330. // Try to use the 'n' blob that is not on the server.
  331. //
  332. TestRepository<Repository> s = new TestRepository<>(src);
  333. RevBlob n = s.blob("n");
  334. RevCommit N = s.commit().parent(B).add("q", n).create();
  335. // But don't include it in the pack.
  336. //
  337. final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
  338. packHeader(pack, 2);
  339. copy(pack, src.open(N));
  340. copy(pack,src.open(s.parseBody(N).getTree()));
  341. digest(pack);
  342. final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
  343. final PacketLineOut inPckLine = new PacketLineOut(inBuf);
  344. inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
  345. + "refs/heads/s" + '\0'
  346. + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
  347. inPckLine.end();
  348. pack.writeTo(inBuf, PM);
  349. final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
  350. final ReceivePack rp = new ReceivePack(dst);
  351. rp.setCheckReceivedObjects(true);
  352. rp.setCheckReferencedObjectsAreReachable(true);
  353. rp.setAdvertiseRefsHook(new HidePrivateHook());
  354. try {
  355. receive(rp, inBuf, outBuf);
  356. fail("Expected UnpackException");
  357. } catch (UnpackException failed) {
  358. Throwable err = failed.getCause();
  359. assertTrue(err instanceof MissingObjectException);
  360. MissingObjectException moe = (MissingObjectException) err;
  361. assertEquals(n, moe.getObjectId());
  362. }
  363. final PacketLineIn r = asPacketLineIn(outBuf);
  364. String master = r.readString();
  365. int nul = master.indexOf('\0');
  366. assertTrue("has capability list", nul > 0);
  367. assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
  368. assertSame(PacketLineIn.END, r.readString());
  369. assertEquals("unpack error Missing blob " + n.name(), r.readString());
  370. assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
  371. assertSame(PacketLineIn.END, r.readString());
  372. }
  373. @Test
  374. public void testIncludesInvalidGitmodules() throws Exception {
  375. final TemporaryBuffer.Heap inBuf = setupSourceRepoInvalidGitmodules();
  376. final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
  377. final ReceivePack rp = new ReceivePack(dst);
  378. rp.setCheckReceivedObjects(true);
  379. rp.setCheckReferencedObjectsAreReachable(true);
  380. rp.setAdvertiseRefsHook(new HidePrivateHook());
  381. try {
  382. receive(rp, inBuf, outBuf);
  383. fail("Expected UnpackException");
  384. } catch (UnpackException failed) {
  385. Throwable err = failed.getCause();
  386. assertTrue(err instanceof IOException);
  387. }
  388. final PacketLineIn r = asPacketLineIn(outBuf);
  389. String master = r.readString();
  390. int nul = master.indexOf('\0');
  391. assertTrue("has capability list", nul > 0);
  392. assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
  393. assertSame(PacketLineIn.END, r.readString());
  394. String errorLine = r.readString();
  395. System.out.println(errorLine);
  396. assertTrue(errorLine.startsWith(
  397. "unpack error Invalid submodule URL '-"));
  398. assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
  399. assertSame(PacketLineIn.END, r.readString());
  400. }
  401. private TemporaryBuffer.Heap setupSourceRepoInvalidGitmodules()
  402. throws IOException, Exception, MissingObjectException {
  403. String fakeGitmodules = new StringBuilder()
  404. .append("[submodule \"test\"]\n")
  405. .append(" path = xlib\n")
  406. .append(" url = https://example.com/repo/xlib.git\n\n")
  407. .append("[submodule \"test2\"]\n")
  408. .append(" path = zlib\n")
  409. .append(" url = -upayload.sh\n")
  410. .toString();
  411. TestRepository<Repository> s = new TestRepository<>(src);
  412. RevBlob blob = s.blob(fakeGitmodules);
  413. RevCommit N = s.commit().parent(B)
  414. .add(".gitmodules", blob).create();
  415. RevTree t = s.parseBody(N).getTree();
  416. final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
  417. packHeader(pack, 3);
  418. copy(pack, src.open(N));
  419. copy(pack, src.open(t));
  420. copy(pack, src.open(blob));
  421. digest(pack);
  422. final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
  423. final PacketLineOut inPckLine = new PacketLineOut(inBuf);
  424. inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
  425. + "refs/heads/s" + '\0'
  426. + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
  427. inPckLine.end();
  428. pack.writeTo(inBuf, PM);
  429. return inBuf;
  430. }
  431. @Test
  432. public void testUsingUnknownTreeFails() throws Exception {
  433. TestRepository<Repository> s = new TestRepository<>(src);
  434. RevCommit N = s.commit().parent(B).add("q", s.blob("a")).create();
  435. RevTree t = s.parseBody(N).getTree();
  436. // Don't include the tree in the pack.
  437. //
  438. final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
  439. packHeader(pack, 1);
  440. copy(pack, src.open(N));
  441. digest(pack);
  442. final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
  443. final PacketLineOut inPckLine = new PacketLineOut(inBuf);
  444. inPckLine.writeString(ObjectId.zeroId().name() + ' ' + N.name() + ' '
  445. + "refs/heads/s" + '\0'
  446. + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
  447. inPckLine.end();
  448. pack.writeTo(inBuf, PM);
  449. final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
  450. final ReceivePack rp = new ReceivePack(dst);
  451. rp.setCheckReceivedObjects(true);
  452. rp.setCheckReferencedObjectsAreReachable(true);
  453. rp.setAdvertiseRefsHook(new HidePrivateHook());
  454. try {
  455. receive(rp, inBuf, outBuf);
  456. fail("Expected UnpackException");
  457. } catch (UnpackException failed) {
  458. Throwable err = failed.getCause();
  459. assertTrue(err instanceof MissingObjectException);
  460. MissingObjectException moe = (MissingObjectException) err;
  461. assertEquals(t, moe.getObjectId());
  462. }
  463. final PacketLineIn r = asPacketLineIn(outBuf);
  464. String master = r.readString();
  465. int nul = master.indexOf('\0');
  466. assertTrue("has capability list", nul > 0);
  467. assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
  468. assertSame(PacketLineIn.END, r.readString());
  469. assertEquals("unpack error Missing tree " + t.name(), r.readString());
  470. assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
  471. assertSame(PacketLineIn.END, r.readString());
  472. }
  473. private static void packHeader(TemporaryBuffer.Heap tinyPack, int cnt)
  474. throws IOException {
  475. final byte[] hdr = new byte[8];
  476. NB.encodeInt32(hdr, 0, 2);
  477. NB.encodeInt32(hdr, 4, cnt);
  478. tinyPack.write(Constants.PACK_SIGNATURE);
  479. tinyPack.write(hdr, 0, 8);
  480. }
  481. private static void copy(TemporaryBuffer.Heap tinyPack, ObjectLoader ldr)
  482. throws IOException {
  483. final byte[] buf = new byte[64];
  484. final byte[] content = ldr.getCachedBytes();
  485. int dataLength = content.length;
  486. int nextLength = dataLength >>> 4;
  487. int size = 0;
  488. buf[size++] = (byte) ((nextLength > 0 ? 0x80 : 0x00)
  489. | (ldr.getType() << 4) | (dataLength & 0x0F));
  490. dataLength = nextLength;
  491. while (dataLength > 0) {
  492. nextLength >>>= 7;
  493. buf[size++] = (byte) ((nextLength > 0 ? 0x80 : 0x00) | (dataLength & 0x7F));
  494. dataLength = nextLength;
  495. }
  496. tinyPack.write(buf, 0, size);
  497. deflate(tinyPack, content);
  498. }
  499. private static void deflate(TemporaryBuffer.Heap tinyPack,
  500. final byte[] content)
  501. throws IOException {
  502. final Deflater deflater = new Deflater();
  503. final byte[] buf = new byte[128];
  504. deflater.setInput(content, 0, content.length);
  505. deflater.finish();
  506. do {
  507. final int n = deflater.deflate(buf, 0, buf.length);
  508. if (n > 0)
  509. tinyPack.write(buf, 0, n);
  510. } while (!deflater.finished());
  511. }
  512. private static void digest(TemporaryBuffer.Heap buf) throws IOException {
  513. MessageDigest md = Constants.newMessageDigest();
  514. md.update(buf.toByteArray());
  515. buf.write(md.digest());
  516. }
  517. private ObjectInserter inserter;
  518. @After
  519. public void release() {
  520. if (inserter != null) {
  521. inserter.close();
  522. }
  523. }
  524. private void openPack(TemporaryBuffer.Heap buf) throws IOException {
  525. if (inserter == null)
  526. inserter = src.newObjectInserter();
  527. final byte[] raw = buf.toByteArray();
  528. PackParser p = inserter.newPackParser(new ByteArrayInputStream(raw));
  529. p.setAllowThin(true);
  530. p.parse(PM);
  531. }
  532. private static PacketLineIn asPacketLineIn(TemporaryBuffer.Heap buf)
  533. throws IOException {
  534. return new PacketLineIn(new ByteArrayInputStream(buf.toByteArray()));
  535. }
  536. private static final class HidePrivateHook extends AbstractAdvertiseRefsHook {
  537. @Override
  538. public Map<String, Ref> getAdvertisedRefs(Repository r, RevWalk revWalk) {
  539. Map<String, Ref> refs = new HashMap<>(r.getAllRefs());
  540. assertNotNull(refs.remove(R_PRIVATE));
  541. return refs;
  542. }
  543. }
  544. private static URIish uriOf(Repository r) throws URISyntaxException {
  545. return new URIish(r.getDirectory().getAbsolutePath());
  546. }
  547. }