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.

SmartClientSmartServerTest.java 57KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607
  1. /*
  2. * Copyright (C) 2010, 2020 Google Inc. and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.http.test;
  11. import static java.nio.charset.StandardCharsets.UTF_8;
  12. import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING;
  13. import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_LENGTH;
  14. import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;
  15. import static org.junit.Assert.assertEquals;
  16. import static org.junit.Assert.assertFalse;
  17. import static org.junit.Assert.assertNotNull;
  18. import static org.junit.Assert.assertNull;
  19. import static org.junit.Assert.assertThrows;
  20. import static org.junit.Assert.assertTrue;
  21. import static org.junit.Assert.fail;
  22. import java.io.ByteArrayOutputStream;
  23. import java.io.IOException;
  24. import java.io.OutputStreamWriter;
  25. import java.io.PrintWriter;
  26. import java.io.Writer;
  27. import java.net.URI;
  28. import java.net.URISyntaxException;
  29. import java.nio.charset.StandardCharsets;
  30. import java.text.MessageFormat;
  31. import java.util.Collections;
  32. import java.util.EnumSet;
  33. import java.util.List;
  34. import java.util.Map;
  35. import java.util.regex.Matcher;
  36. import java.util.regex.Pattern;
  37. import javax.servlet.DispatcherType;
  38. import javax.servlet.Filter;
  39. import javax.servlet.FilterChain;
  40. import javax.servlet.FilterConfig;
  41. import javax.servlet.RequestDispatcher;
  42. import javax.servlet.ServletException;
  43. import javax.servlet.ServletRequest;
  44. import javax.servlet.ServletResponse;
  45. import javax.servlet.http.HttpServletRequest;
  46. import javax.servlet.http.HttpServletResponse;
  47. import org.eclipse.jetty.servlet.FilterHolder;
  48. import org.eclipse.jetty.servlet.ServletContextHandler;
  49. import org.eclipse.jetty.servlet.ServletHolder;
  50. import org.eclipse.jgit.errors.RemoteRepositoryException;
  51. import org.eclipse.jgit.errors.TransportException;
  52. import org.eclipse.jgit.errors.UnsupportedCredentialItem;
  53. import org.eclipse.jgit.http.server.GitServlet;
  54. import org.eclipse.jgit.http.server.resolver.DefaultUploadPackFactory;
  55. import org.eclipse.jgit.internal.JGitText;
  56. import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
  57. import org.eclipse.jgit.junit.TestRepository;
  58. import org.eclipse.jgit.junit.TestRng;
  59. import org.eclipse.jgit.junit.http.AccessEvent;
  60. import org.eclipse.jgit.junit.http.AppServer;
  61. import org.eclipse.jgit.lib.ConfigConstants;
  62. import org.eclipse.jgit.lib.Constants;
  63. import org.eclipse.jgit.lib.NullProgressMonitor;
  64. import org.eclipse.jgit.lib.ObjectId;
  65. import org.eclipse.jgit.lib.ObjectIdRef;
  66. import org.eclipse.jgit.lib.ObjectInserter;
  67. import org.eclipse.jgit.lib.Ref;
  68. import org.eclipse.jgit.lib.ReflogEntry;
  69. import org.eclipse.jgit.lib.ReflogReader;
  70. import org.eclipse.jgit.lib.Repository;
  71. import org.eclipse.jgit.lib.StoredConfig;
  72. import org.eclipse.jgit.lib.TextProgressMonitor;
  73. import org.eclipse.jgit.revwalk.RevBlob;
  74. import org.eclipse.jgit.revwalk.RevCommit;
  75. import org.eclipse.jgit.revwalk.RevWalk;
  76. import org.eclipse.jgit.transport.AbstractAdvertiseRefsHook;
  77. import org.eclipse.jgit.transport.AdvertiseRefsHook;
  78. import org.eclipse.jgit.transport.CredentialItem;
  79. import org.eclipse.jgit.transport.CredentialsProvider;
  80. import org.eclipse.jgit.transport.FetchConnection;
  81. import org.eclipse.jgit.transport.HttpTransport;
  82. import org.eclipse.jgit.transport.RefSpec;
  83. import org.eclipse.jgit.transport.RemoteRefUpdate;
  84. import org.eclipse.jgit.transport.Transport;
  85. import org.eclipse.jgit.transport.TransportHttp;
  86. import org.eclipse.jgit.transport.URIish;
  87. import org.eclipse.jgit.transport.UploadPack;
  88. import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
  89. import org.eclipse.jgit.util.HttpSupport;
  90. import org.eclipse.jgit.util.SystemReader;
  91. import org.junit.Before;
  92. import org.junit.Test;
  93. public class SmartClientSmartServerTest extends AllProtocolsHttpTestCase {
  94. private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding";
  95. private AdvertiseRefsHook advertiseRefsHook;
  96. private Repository remoteRepository;
  97. private CredentialsProvider testCredentials = new UsernamePasswordCredentialsProvider(
  98. AppServer.username, AppServer.password);
  99. private URIish remoteURI;
  100. private URIish brokenURI;
  101. private URIish redirectURI;
  102. private URIish authURI;
  103. private URIish authOnPostURI;
  104. private URIish slowURI;
  105. private URIish slowAuthURI;
  106. private RevBlob A_txt;
  107. private RevCommit A, B, unreachableCommit;
  108. public SmartClientSmartServerTest(TestParameters params) {
  109. super(params);
  110. }
  111. @Override
  112. @Before
  113. public void setUp() throws Exception {
  114. super.setUp();
  115. final TestRepository<Repository> src = createTestRepository();
  116. final String srcName = src.getRepository().getDirectory().getName();
  117. StoredConfig cfg = src.getRepository().getConfig();
  118. cfg.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
  119. ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
  120. cfg.setInt("protocol", null, "version", enableProtocolV2 ? 2 : 0);
  121. cfg.save();
  122. GitServlet gs = new GitServlet();
  123. gs.setUploadPackFactory((HttpServletRequest req, Repository db) -> {
  124. DefaultUploadPackFactory f = new DefaultUploadPackFactory();
  125. UploadPack up = f.create(req, db);
  126. if (advertiseRefsHook != null) {
  127. up.setAdvertiseRefsHook(advertiseRefsHook);
  128. }
  129. return up;
  130. });
  131. ServletContextHandler app = addNormalContext(gs, src, srcName);
  132. ServletContextHandler broken = addBrokenContext(gs, srcName);
  133. ServletContextHandler redirect = addRedirectContext(gs);
  134. ServletContextHandler auth = addAuthContext(gs, "auth");
  135. ServletContextHandler authOnPost = addAuthContext(gs, "pauth", "POST");
  136. ServletContextHandler slow = addSlowContext(gs, "slow", false);
  137. ServletContextHandler slowAuth = addSlowContext(gs, "slowAuth", true);
  138. server.setUp();
  139. remoteRepository = src.getRepository();
  140. remoteURI = toURIish(app, srcName);
  141. brokenURI = toURIish(broken, srcName);
  142. redirectURI = toURIish(redirect, srcName);
  143. authURI = toURIish(auth, srcName);
  144. authOnPostURI = toURIish(authOnPost, srcName);
  145. slowURI = toURIish(slow, srcName);
  146. slowAuthURI = toURIish(slowAuth, srcName);
  147. A_txt = src.blob("A");
  148. A = src.commit().add("A_txt", A_txt).create();
  149. B = src.commit().parent(A).add("A_txt", "C").add("B", "B").create();
  150. src.update(master, B);
  151. unreachableCommit = src.commit().add("A_txt", A_txt).create();
  152. src.update("refs/garbage/a/very/long/ref/name/to/compress", B);
  153. }
  154. private ServletContextHandler addNormalContext(GitServlet gs, TestRepository<Repository> src, String srcName) {
  155. ServletContextHandler app = server.addContext("/git");
  156. app.addFilter(new FilterHolder(new Filter() {
  157. @Override
  158. public void init(FilterConfig filterConfig)
  159. throws ServletException {
  160. // empty
  161. }
  162. // Does an internal forward for GET requests containing "/post/",
  163. // and issues a 301 redirect on POST requests for such URLs. Used
  164. // in the POST redirect tests.
  165. @Override
  166. public void doFilter(ServletRequest request,
  167. ServletResponse response, FilterChain chain)
  168. throws IOException, ServletException {
  169. final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
  170. final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
  171. final StringBuffer fullUrl = httpServletRequest.getRequestURL();
  172. if (httpServletRequest.getQueryString() != null) {
  173. fullUrl.append("?")
  174. .append(httpServletRequest.getQueryString());
  175. }
  176. String urlString = fullUrl.toString();
  177. if ("POST".equalsIgnoreCase(httpServletRequest.getMethod())) {
  178. httpServletResponse.setStatus(
  179. HttpServletResponse.SC_MOVED_PERMANENTLY);
  180. httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
  181. urlString.replace("/post/", "/"));
  182. } else {
  183. String path = httpServletRequest.getPathInfo();
  184. path = path.replace("/post/", "/");
  185. if (httpServletRequest.getQueryString() != null) {
  186. path += '?' + httpServletRequest.getQueryString();
  187. }
  188. RequestDispatcher dispatcher = httpServletRequest
  189. .getRequestDispatcher(path);
  190. dispatcher.forward(httpServletRequest, httpServletResponse);
  191. }
  192. }
  193. @Override
  194. public void destroy() {
  195. // empty
  196. }
  197. }), "/post/*", EnumSet.of(DispatcherType.REQUEST));
  198. gs.setRepositoryResolver(new TestRepositoryResolver(src, srcName));
  199. app.addServlet(new ServletHolder(gs), "/*");
  200. return app;
  201. }
  202. private ServletContextHandler addBrokenContext(GitServlet gs,
  203. String srcName) {
  204. ServletContextHandler broken = server.addContext("/bad");
  205. broken.addFilter(new FilterHolder(new Filter() {
  206. @Override
  207. public void doFilter(ServletRequest request,
  208. ServletResponse response, FilterChain chain)
  209. throws IOException, ServletException {
  210. final HttpServletResponse r = (HttpServletResponse) response;
  211. r.setContentType("text/plain");
  212. r.setCharacterEncoding(UTF_8.name());
  213. try (PrintWriter w = r.getWriter()) {
  214. w.print("OK");
  215. }
  216. }
  217. @Override
  218. public void init(FilterConfig filterConfig)
  219. throws ServletException {
  220. // empty
  221. }
  222. @Override
  223. public void destroy() {
  224. // empty
  225. }
  226. }), "/" + srcName + "/git-upload-pack",
  227. EnumSet.of(DispatcherType.REQUEST));
  228. broken.addServlet(new ServletHolder(gs), "/*");
  229. return broken;
  230. }
  231. private ServletContextHandler addAuthContext(GitServlet gs,
  232. String contextPath, String... methods) {
  233. ServletContextHandler auth = server.addContext('/' + contextPath);
  234. auth.addServlet(new ServletHolder(gs), "/*");
  235. return server.authBasic(auth, methods);
  236. }
  237. private ServletContextHandler addRedirectContext(GitServlet gs) {
  238. ServletContextHandler redirect = server.addContext("/redirect");
  239. redirect.addFilter(new FilterHolder(new Filter() {
  240. // Enables tests for different codes, and for multiple redirects.
  241. // First parameter is the number of redirects, second one is the
  242. // redirect status code that should be used
  243. private Pattern responsePattern = Pattern
  244. .compile("/response/(\\d+)/(30[1237])/");
  245. // Enables tests to specify the context that the request should be
  246. // redirected to in the end. If not present, redirects got to the
  247. // normal /git context.
  248. private Pattern targetPattern = Pattern.compile("/target(/\\w+)/");
  249. @Override
  250. public void init(FilterConfig filterConfig)
  251. throws ServletException {
  252. // empty
  253. }
  254. private String local(String url, boolean toLocal) {
  255. if (!toLocal) {
  256. return url;
  257. }
  258. try {
  259. URI u = new URI(url);
  260. String fragment = u.getRawFragment();
  261. if (fragment != null) {
  262. return u.getRawPath() + '#' + fragment;
  263. }
  264. return u.getRawPath();
  265. } catch (URISyntaxException e) {
  266. return url;
  267. }
  268. }
  269. @Override
  270. public void doFilter(ServletRequest request,
  271. ServletResponse response, FilterChain chain)
  272. throws IOException, ServletException {
  273. final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
  274. final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
  275. final StringBuffer fullUrl = httpServletRequest.getRequestURL();
  276. if (httpServletRequest.getQueryString() != null) {
  277. fullUrl.append("?")
  278. .append(httpServletRequest.getQueryString());
  279. }
  280. String urlString = fullUrl.toString();
  281. boolean localRedirect = false;
  282. if (urlString.contains("/local")) {
  283. urlString = urlString.replace("/local", "");
  284. localRedirect = true;
  285. }
  286. if (urlString.contains("/loop/")) {
  287. urlString = urlString.replace("/loop/", "/loop/x/");
  288. if (urlString.contains("/loop/x/x/x/x/x/x/x/x/")) {
  289. // Go back to initial.
  290. urlString = urlString.replace("/loop/x/x/x/x/x/x/x/x/",
  291. "/loop/");
  292. }
  293. httpServletResponse.setStatus(
  294. HttpServletResponse.SC_MOVED_TEMPORARILY);
  295. httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
  296. local(urlString, localRedirect));
  297. return;
  298. }
  299. int responseCode = HttpServletResponse.SC_MOVED_PERMANENTLY;
  300. int nofRedirects = 0;
  301. Matcher matcher = responsePattern.matcher(urlString);
  302. if (matcher.find()) {
  303. nofRedirects = Integer
  304. .parseUnsignedInt(matcher.group(1));
  305. responseCode = Integer.parseUnsignedInt(matcher.group(2));
  306. if (--nofRedirects <= 0) {
  307. urlString = urlString.substring(0, matcher.start())
  308. + '/' + urlString.substring(matcher.end());
  309. } else {
  310. urlString = urlString.substring(0, matcher.start())
  311. + "/response/" + nofRedirects + "/"
  312. + responseCode + '/'
  313. + urlString.substring(matcher.end());
  314. }
  315. }
  316. httpServletResponse.setStatus(responseCode);
  317. if (nofRedirects <= 0) {
  318. String targetContext = "/git";
  319. matcher = targetPattern.matcher(urlString);
  320. if (matcher.find()) {
  321. urlString = urlString.substring(0, matcher.start())
  322. + '/' + urlString.substring(matcher.end());
  323. targetContext = matcher.group(1);
  324. }
  325. urlString = urlString.replace("/redirect", targetContext);
  326. }
  327. httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
  328. local(urlString, localRedirect));
  329. }
  330. @Override
  331. public void destroy() {
  332. // empty
  333. }
  334. }), "/*", EnumSet.of(DispatcherType.REQUEST));
  335. redirect.addServlet(new ServletHolder(gs), "/*");
  336. return redirect;
  337. }
  338. private ServletContextHandler addSlowContext(GitServlet gs, String path,
  339. boolean auth) {
  340. ServletContextHandler slow = server.addContext('/' + path);
  341. slow.addFilter(new FilterHolder(new Filter() {
  342. @Override
  343. public void init(FilterConfig filterConfig)
  344. throws ServletException {
  345. // empty
  346. }
  347. // Simply delays the servlet for two seconds. Used for timeout
  348. // tests, which use a one-second timeout.
  349. @Override
  350. public void doFilter(ServletRequest request,
  351. ServletResponse response, FilterChain chain)
  352. throws IOException, ServletException {
  353. try {
  354. Thread.sleep(2000);
  355. } catch (InterruptedException e) {
  356. throw new IOException(e);
  357. }
  358. chain.doFilter(request, response);
  359. }
  360. @Override
  361. public void destroy() {
  362. // empty
  363. }
  364. }), "/*", EnumSet.of(DispatcherType.REQUEST));
  365. slow.addServlet(new ServletHolder(gs), "/*");
  366. if (auth) {
  367. return server.authBasic(slow);
  368. }
  369. return slow;
  370. }
  371. @Test
  372. public void testListRemote() throws IOException {
  373. assertEquals("http", remoteURI.getScheme());
  374. Map<String, Ref> map;
  375. try (Repository dst = createBareRepository();
  376. Transport t = Transport.open(dst, remoteURI)) {
  377. // I didn't make up these public interface names, I just
  378. // approved them for inclusion into the code base. Sorry.
  379. // --spearce
  380. //
  381. assertTrue("isa TransportHttp", t instanceof TransportHttp);
  382. assertTrue("isa HttpTransport", t instanceof HttpTransport);
  383. try (FetchConnection c = t.openFetch()) {
  384. map = c.getRefsMap();
  385. }
  386. }
  387. assertNotNull("have map of refs", map);
  388. assertEquals(3, map.size());
  389. assertNotNull("has " + master, map.get(master));
  390. assertEquals(B, map.get(master).getObjectId());
  391. assertNotNull("has " + Constants.HEAD, map.get(Constants.HEAD));
  392. assertEquals(B, map.get(Constants.HEAD).getObjectId());
  393. List<AccessEvent> requests = getRequests();
  394. assertEquals(enableProtocolV2 ? 2 : 1, requests.size());
  395. AccessEvent info = requests.get(0);
  396. assertEquals("GET", info.getMethod());
  397. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  398. assertEquals(1, info.getParameters().size());
  399. assertEquals("git-upload-pack", info.getParameter("service"));
  400. assertEquals(200, info.getStatus());
  401. assertEquals("application/x-git-upload-pack-advertisement", info
  402. .getResponseHeader(HDR_CONTENT_TYPE));
  403. if (!enableProtocolV2) {
  404. assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
  405. } else {
  406. AccessEvent lsRefs = requests.get(1);
  407. assertEquals("POST", lsRefs.getMethod());
  408. assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
  409. assertEquals(0, lsRefs.getParameters().size());
  410. assertNotNull("has content-length",
  411. lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
  412. assertNull("not chunked",
  413. lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
  414. assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
  415. assertEquals(200, lsRefs.getStatus());
  416. assertEquals("application/x-git-upload-pack-result",
  417. lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
  418. }
  419. }
  420. @Test
  421. public void testListRemote_BadName() throws IOException, URISyntaxException {
  422. URIish uri = new URIish(this.remoteURI.toString() + ".invalid");
  423. try (Repository dst = createBareRepository();
  424. Transport t = Transport.open(dst, uri)) {
  425. try {
  426. t.openFetch();
  427. fail("fetch connection opened");
  428. } catch (RemoteRepositoryException notFound) {
  429. assertEquals(uri + ": Git repository not found",
  430. notFound.getMessage());
  431. }
  432. }
  433. List<AccessEvent> requests = getRequests();
  434. assertEquals(1, requests.size());
  435. AccessEvent info = requests.get(0);
  436. assertEquals("GET", info.getMethod());
  437. assertEquals(join(uri, "info/refs"), info.getPath());
  438. assertEquals(1, info.getParameters().size());
  439. assertEquals("git-upload-pack", info.getParameter("service"));
  440. assertEquals(200, info.getStatus());
  441. assertEquals("application/x-git-upload-pack-advertisement",
  442. info.getResponseHeader(HDR_CONTENT_TYPE));
  443. }
  444. @Test
  445. public void testFetchBySHA1() throws Exception {
  446. try (Repository dst = createBareRepository();
  447. Transport t = Transport.open(dst, remoteURI)) {
  448. assertFalse(dst.getObjectDatabase().has(A_txt));
  449. t.fetch(NullProgressMonitor.INSTANCE,
  450. Collections.singletonList(new RefSpec(B.name())));
  451. assertTrue(dst.getObjectDatabase().has(A_txt));
  452. }
  453. }
  454. @Test
  455. public void testFetchBySHA1Unreachable() throws Exception {
  456. try (Repository dst = createBareRepository();
  457. Transport t = Transport.open(dst, remoteURI)) {
  458. assertFalse(dst.getObjectDatabase().has(A_txt));
  459. Exception e = assertThrows(TransportException.class,
  460. () -> t.fetch(NullProgressMonitor.INSTANCE,
  461. Collections.singletonList(
  462. new RefSpec(unreachableCommit.name()))));
  463. assertTrue(e.getMessage().contains(
  464. "want " + unreachableCommit.name() + " not valid"));
  465. }
  466. }
  467. @Test
  468. public void testFetchBySHA1UnreachableByAdvertiseRefsHook()
  469. throws Exception {
  470. advertiseRefsHook = new AbstractAdvertiseRefsHook() {
  471. @Override
  472. protected Map<String, Ref> getAdvertisedRefs(Repository repository,
  473. RevWalk revWalk) {
  474. return Collections.emptyMap();
  475. }
  476. };
  477. try (Repository dst = createBareRepository();
  478. Transport t = Transport.open(dst, remoteURI)) {
  479. assertFalse(dst.getObjectDatabase().has(A_txt));
  480. Exception e = assertThrows(TransportException.class,
  481. () -> t.fetch(NullProgressMonitor.INSTANCE,
  482. Collections.singletonList(new RefSpec(A.name()))));
  483. assertTrue(
  484. e.getMessage().contains("want " + A.name() + " not valid"));
  485. }
  486. }
  487. @Test
  488. public void testTimeoutExpired() throws Exception {
  489. try (Repository dst = createBareRepository();
  490. Transport t = Transport.open(dst, slowURI)) {
  491. t.setTimeout(1);
  492. TransportException expected = assertThrows(TransportException.class,
  493. () -> t.fetch(NullProgressMonitor.INSTANCE,
  494. mirror(master)));
  495. assertTrue("Unexpected exception message: " + expected.toString(),
  496. expected.getMessage().contains("time"));
  497. }
  498. }
  499. @Test
  500. public void testTimeoutExpiredWithAuth() throws Exception {
  501. try (Repository dst = createBareRepository();
  502. Transport t = Transport.open(dst, slowAuthURI)) {
  503. t.setTimeout(1);
  504. t.setCredentialsProvider(testCredentials);
  505. TransportException expected = assertThrows(TransportException.class,
  506. () -> t.fetch(NullProgressMonitor.INSTANCE,
  507. mirror(master)));
  508. assertTrue("Unexpected exception message: " + expected.toString(),
  509. expected.getMessage().contains("time"));
  510. assertFalse("Unexpected exception message: " + expected.toString(),
  511. expected.getMessage().contains("auth"));
  512. }
  513. }
  514. @Test
  515. public void testInitialClone_Small() throws Exception {
  516. try (Repository dst = createBareRepository();
  517. Transport t = Transport.open(dst, remoteURI)) {
  518. assertFalse(dst.getObjectDatabase().has(A_txt));
  519. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  520. assertTrue(dst.getObjectDatabase().has(A_txt));
  521. assertEquals(B, dst.exactRef(master).getObjectId());
  522. fsck(dst, B);
  523. }
  524. List<AccessEvent> requests = getRequests();
  525. assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
  526. int requestNumber = 0;
  527. AccessEvent info = requests.get(requestNumber++);
  528. assertEquals("GET", info.getMethod());
  529. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  530. assertEquals(1, info.getParameters().size());
  531. assertEquals("git-upload-pack", info.getParameter("service"));
  532. assertEquals(200, info.getStatus());
  533. assertEquals("application/x-git-upload-pack-advertisement", info
  534. .getResponseHeader(HDR_CONTENT_TYPE));
  535. if (!enableProtocolV2) {
  536. assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
  537. } else {
  538. AccessEvent lsRefs = requests.get(requestNumber++);
  539. assertEquals("POST", lsRefs.getMethod());
  540. assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
  541. assertEquals(0, lsRefs.getParameters().size());
  542. assertNotNull("has content-length",
  543. lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
  544. assertNull("not chunked",
  545. lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
  546. assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
  547. assertEquals(200, lsRefs.getStatus());
  548. assertEquals("application/x-git-upload-pack-result",
  549. lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
  550. }
  551. AccessEvent service = requests.get(requestNumber);
  552. assertEquals("POST", service.getMethod());
  553. assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
  554. assertEquals(0, service.getParameters().size());
  555. assertNotNull("has content-length", service
  556. .getRequestHeader(HDR_CONTENT_LENGTH));
  557. assertNull("not chunked", service
  558. .getRequestHeader(HDR_TRANSFER_ENCODING));
  559. assertEquals(200, service.getStatus());
  560. assertEquals("application/x-git-upload-pack-result", service
  561. .getResponseHeader(HDR_CONTENT_TYPE));
  562. }
  563. private void initialClone_Redirect(int nofRedirects, int code)
  564. throws Exception {
  565. initialClone_Redirect(nofRedirects, code, false);
  566. }
  567. private void initialClone_Redirect(int nofRedirects, int code,
  568. boolean localRedirect) throws Exception {
  569. URIish cloneFrom = redirectURI;
  570. if (localRedirect) {
  571. cloneFrom = extendPath(cloneFrom, "/local");
  572. }
  573. if (code != 301 || nofRedirects > 1) {
  574. cloneFrom = extendPath(cloneFrom,
  575. "/response/" + nofRedirects + "/" + code);
  576. }
  577. try (Repository dst = createBareRepository();
  578. Transport t = Transport.open(dst, cloneFrom)) {
  579. assertFalse(dst.getObjectDatabase().has(A_txt));
  580. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  581. assertTrue(dst.getObjectDatabase().has(A_txt));
  582. assertEquals(B, dst.exactRef(master).getObjectId());
  583. fsck(dst, B);
  584. }
  585. List<AccessEvent> requests = getRequests();
  586. assertEquals((enableProtocolV2 ? 3 : 2) + nofRedirects,
  587. requests.size());
  588. int n = 0;
  589. while (n < nofRedirects) {
  590. AccessEvent redirect = requests.get(n++);
  591. assertEquals(code, redirect.getStatus());
  592. }
  593. AccessEvent info = requests.get(n++);
  594. assertEquals("GET", info.getMethod());
  595. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  596. assertEquals(1, info.getParameters().size());
  597. assertEquals("git-upload-pack", info.getParameter("service"));
  598. assertEquals(200, info.getStatus());
  599. assertEquals("application/x-git-upload-pack-advertisement",
  600. info.getResponseHeader(HDR_CONTENT_TYPE));
  601. if (!enableProtocolV2) {
  602. assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
  603. } else {
  604. AccessEvent lsRefs = requests.get(n++);
  605. assertEquals("POST", lsRefs.getMethod());
  606. assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
  607. assertEquals(0, lsRefs.getParameters().size());
  608. assertNotNull("has content-length",
  609. lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
  610. assertNull("not chunked",
  611. lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
  612. assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
  613. assertEquals(200, lsRefs.getStatus());
  614. assertEquals("application/x-git-upload-pack-result",
  615. lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
  616. }
  617. AccessEvent service = requests.get(n++);
  618. assertEquals("POST", service.getMethod());
  619. assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
  620. assertEquals(0, service.getParameters().size());
  621. assertNotNull("has content-length",
  622. service.getRequestHeader(HDR_CONTENT_LENGTH));
  623. assertNull("not chunked",
  624. service.getRequestHeader(HDR_TRANSFER_ENCODING));
  625. assertEquals(200, service.getStatus());
  626. assertEquals("application/x-git-upload-pack-result",
  627. service.getResponseHeader(HDR_CONTENT_TYPE));
  628. }
  629. @Test
  630. public void testInitialClone_Redirect301Small() throws Exception {
  631. initialClone_Redirect(1, 301);
  632. }
  633. @Test
  634. public void testInitialClone_Redirect301Local() throws Exception {
  635. initialClone_Redirect(1, 301, true);
  636. }
  637. @Test
  638. public void testInitialClone_Redirect302Small() throws Exception {
  639. initialClone_Redirect(1, 302);
  640. }
  641. @Test
  642. public void testInitialClone_Redirect303Small() throws Exception {
  643. initialClone_Redirect(1, 303);
  644. }
  645. @Test
  646. public void testInitialClone_Redirect307Small() throws Exception {
  647. initialClone_Redirect(1, 307);
  648. }
  649. @Test
  650. public void testInitialClone_RedirectMultiple() throws Exception {
  651. initialClone_Redirect(4, 302);
  652. }
  653. @Test
  654. public void testInitialClone_RedirectMax() throws Exception {
  655. StoredConfig userConfig = SystemReader.getInstance()
  656. .getUserConfig();
  657. userConfig.setInt("http", null, "maxRedirects", 4);
  658. userConfig.save();
  659. initialClone_Redirect(4, 302);
  660. }
  661. @Test
  662. public void testInitialClone_RedirectTooOften() throws Exception {
  663. StoredConfig userConfig = SystemReader.getInstance()
  664. .getUserConfig();
  665. userConfig.setInt("http", null, "maxRedirects", 3);
  666. userConfig.save();
  667. URIish cloneFrom = extendPath(redirectURI, "/response/4/302");
  668. String remoteUri = cloneFrom.toString();
  669. try (Repository dst = createBareRepository();
  670. Transport t = Transport.open(dst, cloneFrom)) {
  671. assertFalse(dst.getObjectDatabase().has(A_txt));
  672. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  673. fail("Should have failed (too many redirects)");
  674. } catch (TransportException e) {
  675. String expectedMessageBegin = remoteUri.toString() + ": "
  676. + MessageFormat.format(JGitText.get().redirectLimitExceeded,
  677. "3", remoteUri.replace("/4/", "/1/") + '/', "");
  678. String message = e.getMessage();
  679. if (message.length() > expectedMessageBegin.length()) {
  680. message = message.substring(0, expectedMessageBegin.length());
  681. }
  682. assertEquals(expectedMessageBegin, message);
  683. }
  684. }
  685. @Test
  686. public void testInitialClone_RedirectLoop() throws Exception {
  687. URIish cloneFrom = extendPath(redirectURI, "/loop");
  688. try (Repository dst = createBareRepository();
  689. Transport t = Transport.open(dst, cloneFrom)) {
  690. assertFalse(dst.getObjectDatabase().has(A_txt));
  691. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  692. fail("Should have failed (redirect loop)");
  693. } catch (TransportException e) {
  694. assertTrue(e.getMessage().contains("Redirected more than"));
  695. }
  696. }
  697. @Test
  698. public void testInitialClone_RedirectOnPostAllowed() throws Exception {
  699. StoredConfig userConfig = SystemReader.getInstance()
  700. .getUserConfig();
  701. userConfig.setString("http", null, "followRedirects", "true");
  702. userConfig.save();
  703. URIish cloneFrom = extendPath(remoteURI, "/post");
  704. try (Repository dst = createBareRepository();
  705. Transport t = Transport.open(dst, cloneFrom)) {
  706. assertFalse(dst.getObjectDatabase().has(A_txt));
  707. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  708. assertTrue(dst.getObjectDatabase().has(A_txt));
  709. assertEquals(B, dst.exactRef(master).getObjectId());
  710. fsck(dst, B);
  711. }
  712. List<AccessEvent> requests = getRequests();
  713. assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
  714. AccessEvent info = requests.get(0);
  715. assertEquals("GET", info.getMethod());
  716. assertEquals(join(cloneFrom, "info/refs"), info.getPath());
  717. assertEquals(1, info.getParameters().size());
  718. assertEquals("git-upload-pack", info.getParameter("service"));
  719. assertEquals(200, info.getStatus());
  720. assertEquals("application/x-git-upload-pack-advertisement",
  721. info.getResponseHeader(HDR_CONTENT_TYPE));
  722. if (!enableProtocolV2) {
  723. assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
  724. }
  725. AccessEvent redirect = requests.get(1);
  726. assertEquals("POST", redirect.getMethod());
  727. assertEquals(301, redirect.getStatus());
  728. for (int i = 2; i < requests.size(); i++) {
  729. AccessEvent service = requests.get(i);
  730. assertEquals("POST", service.getMethod());
  731. assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
  732. assertEquals(0, service.getParameters().size());
  733. assertNotNull("has content-length",
  734. service.getRequestHeader(HDR_CONTENT_LENGTH));
  735. assertNull("not chunked",
  736. service.getRequestHeader(HDR_TRANSFER_ENCODING));
  737. assertEquals(200, service.getStatus());
  738. assertEquals("application/x-git-upload-pack-result",
  739. service.getResponseHeader(HDR_CONTENT_TYPE));
  740. }
  741. }
  742. @Test
  743. public void testInitialClone_RedirectOnPostForbidden() throws Exception {
  744. URIish cloneFrom = extendPath(remoteURI, "/post");
  745. try (Repository dst = createBareRepository();
  746. Transport t = Transport.open(dst, cloneFrom)) {
  747. assertFalse(dst.getObjectDatabase().has(A_txt));
  748. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  749. fail("Should have failed (redirect on POST)");
  750. } catch (TransportException e) {
  751. assertTrue(e.getMessage().contains("301"));
  752. }
  753. }
  754. @Test
  755. public void testInitialClone_RedirectForbidden() throws Exception {
  756. StoredConfig userConfig = SystemReader.getInstance()
  757. .getUserConfig();
  758. userConfig.setString("http", null, "followRedirects", "false");
  759. userConfig.save();
  760. try (Repository dst = createBareRepository();
  761. Transport t = Transport.open(dst, redirectURI)) {
  762. assertFalse(dst.getObjectDatabase().has(A_txt));
  763. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  764. fail("Should have failed (redirects forbidden)");
  765. } catch (TransportException e) {
  766. assertTrue(
  767. e.getMessage().contains("http.followRedirects is false"));
  768. }
  769. }
  770. @Test
  771. public void testInitialClone_WithAuthentication() throws Exception {
  772. try (Repository dst = createBareRepository();
  773. Transport t = Transport.open(dst, authURI)) {
  774. assertFalse(dst.getObjectDatabase().has(A_txt));
  775. t.setCredentialsProvider(testCredentials);
  776. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  777. assertTrue(dst.getObjectDatabase().has(A_txt));
  778. assertEquals(B, dst.exactRef(master).getObjectId());
  779. fsck(dst, B);
  780. }
  781. List<AccessEvent> requests = getRequests();
  782. assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
  783. AccessEvent info = requests.get(0);
  784. assertEquals("GET", info.getMethod());
  785. assertEquals(401, info.getStatus());
  786. info = requests.get(1);
  787. assertEquals("GET", info.getMethod());
  788. assertEquals(join(authURI, "info/refs"), info.getPath());
  789. assertEquals(1, info.getParameters().size());
  790. assertEquals("git-upload-pack", info.getParameter("service"));
  791. assertEquals(200, info.getStatus());
  792. assertEquals("application/x-git-upload-pack-advertisement",
  793. info.getResponseHeader(HDR_CONTENT_TYPE));
  794. if (!enableProtocolV2) {
  795. assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
  796. }
  797. for (int i = 2; i < requests.size(); i++) {
  798. AccessEvent service = requests.get(i);
  799. assertEquals("POST", service.getMethod());
  800. assertEquals(join(authURI, "git-upload-pack"), service.getPath());
  801. assertEquals(0, service.getParameters().size());
  802. assertNotNull("has content-length",
  803. service.getRequestHeader(HDR_CONTENT_LENGTH));
  804. assertNull("not chunked",
  805. service.getRequestHeader(HDR_TRANSFER_ENCODING));
  806. assertEquals(200, service.getStatus());
  807. assertEquals("application/x-git-upload-pack-result",
  808. service.getResponseHeader(HDR_CONTENT_TYPE));
  809. }
  810. }
  811. @Test
  812. public void testInitialClone_WithAuthenticationNoCredentials()
  813. throws Exception {
  814. try (Repository dst = createBareRepository();
  815. Transport t = Transport.open(dst, authURI)) {
  816. assertFalse(dst.getObjectDatabase().has(A_txt));
  817. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  818. fail("Should not have succeeded -- no authentication");
  819. } catch (TransportException e) {
  820. String msg = e.getMessage();
  821. assertTrue("Unexpected exception message: " + msg,
  822. msg.contains("no CredentialsProvider"));
  823. }
  824. List<AccessEvent> requests = getRequests();
  825. assertEquals(1, requests.size());
  826. AccessEvent info = requests.get(0);
  827. assertEquals("GET", info.getMethod());
  828. assertEquals(401, info.getStatus());
  829. }
  830. @Test
  831. public void testInitialClone_WithAuthenticationWrongCredentials()
  832. throws Exception {
  833. try (Repository dst = createBareRepository();
  834. Transport t = Transport.open(dst, authURI)) {
  835. assertFalse(dst.getObjectDatabase().has(A_txt));
  836. t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
  837. AppServer.username, "wrongpassword"));
  838. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  839. fail("Should not have succeeded -- wrong password");
  840. } catch (TransportException e) {
  841. String msg = e.getMessage();
  842. assertTrue("Unexpected exception message: " + msg,
  843. msg.contains("auth"));
  844. }
  845. List<AccessEvent> requests = getRequests();
  846. // Once without authentication plus three re-tries with authentication
  847. assertEquals(4, requests.size());
  848. for (AccessEvent event : requests) {
  849. assertEquals("GET", event.getMethod());
  850. assertEquals(401, event.getStatus());
  851. }
  852. }
  853. @Test
  854. public void testInitialClone_WithAuthenticationAfterRedirect()
  855. throws Exception {
  856. URIish cloneFrom = extendPath(redirectURI, "/target/auth");
  857. CredentialsProvider uriSpecificCredentialsProvider = new UsernamePasswordCredentialsProvider(
  858. "unknown", "none") {
  859. @Override
  860. public boolean get(URIish uri, CredentialItem... items)
  861. throws UnsupportedCredentialItem {
  862. // Only return the true credentials if the uri path starts with
  863. // /auth. This ensures that we do provide the correct
  864. // credentials only for the URi after the redirect, making the
  865. // test fail if we should be asked for the credentials for the
  866. // original URI.
  867. if (uri.getPath().startsWith("/auth")) {
  868. return testCredentials.get(uri, items);
  869. }
  870. return super.get(uri, items);
  871. }
  872. };
  873. try (Repository dst = createBareRepository();
  874. Transport t = Transport.open(dst, cloneFrom)) {
  875. assertFalse(dst.getObjectDatabase().has(A_txt));
  876. t.setCredentialsProvider(uriSpecificCredentialsProvider);
  877. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  878. assertTrue(dst.getObjectDatabase().has(A_txt));
  879. assertEquals(B, dst.exactRef(master).getObjectId());
  880. fsck(dst, B);
  881. }
  882. List<AccessEvent> requests = getRequests();
  883. assertEquals(enableProtocolV2 ? 5 : 4, requests.size());
  884. int requestNumber = 0;
  885. AccessEvent redirect = requests.get(requestNumber++);
  886. assertEquals("GET", redirect.getMethod());
  887. assertEquals(join(cloneFrom, "info/refs"), redirect.getPath());
  888. assertEquals(301, redirect.getStatus());
  889. AccessEvent info = requests.get(requestNumber++);
  890. assertEquals("GET", info.getMethod());
  891. assertEquals(join(authURI, "info/refs"), info.getPath());
  892. assertEquals(401, info.getStatus());
  893. info = requests.get(requestNumber++);
  894. assertEquals("GET", info.getMethod());
  895. assertEquals(join(authURI, "info/refs"), info.getPath());
  896. assertEquals(1, info.getParameters().size());
  897. assertEquals("git-upload-pack", info.getParameter("service"));
  898. assertEquals(200, info.getStatus());
  899. assertEquals("application/x-git-upload-pack-advertisement",
  900. info.getResponseHeader(HDR_CONTENT_TYPE));
  901. if (!enableProtocolV2) {
  902. assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
  903. } else {
  904. AccessEvent lsRefs = requests.get(requestNumber++);
  905. assertEquals("POST", lsRefs.getMethod());
  906. assertEquals(join(authURI, "git-upload-pack"), lsRefs.getPath());
  907. assertEquals(0, lsRefs.getParameters().size());
  908. assertNotNull("has content-length",
  909. lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
  910. assertNull("not chunked",
  911. lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
  912. assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
  913. assertEquals(200, lsRefs.getStatus());
  914. assertEquals("application/x-git-upload-pack-result",
  915. lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
  916. }
  917. AccessEvent service = requests.get(requestNumber);
  918. assertEquals("POST", service.getMethod());
  919. assertEquals(join(authURI, "git-upload-pack"), service.getPath());
  920. assertEquals(0, service.getParameters().size());
  921. assertNotNull("has content-length",
  922. service.getRequestHeader(HDR_CONTENT_LENGTH));
  923. assertNull("not chunked",
  924. service.getRequestHeader(HDR_TRANSFER_ENCODING));
  925. assertEquals(200, service.getStatus());
  926. assertEquals("application/x-git-upload-pack-result",
  927. service.getResponseHeader(HDR_CONTENT_TYPE));
  928. }
  929. @Test
  930. public void testInitialClone_WithAuthenticationOnPostOnly()
  931. throws Exception {
  932. try (Repository dst = createBareRepository();
  933. Transport t = Transport.open(dst, authOnPostURI)) {
  934. assertFalse(dst.getObjectDatabase().has(A_txt));
  935. t.setCredentialsProvider(testCredentials);
  936. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  937. assertTrue(dst.getObjectDatabase().has(A_txt));
  938. assertEquals(B, dst.exactRef(master).getObjectId());
  939. fsck(dst, B);
  940. }
  941. List<AccessEvent> requests = getRequests();
  942. assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
  943. AccessEvent info = requests.get(0);
  944. assertEquals("GET", info.getMethod());
  945. assertEquals(join(authOnPostURI, "info/refs"), info.getPath());
  946. assertEquals(1, info.getParameters().size());
  947. assertEquals("git-upload-pack", info.getParameter("service"));
  948. assertEquals(200, info.getStatus());
  949. assertEquals("application/x-git-upload-pack-advertisement",
  950. info.getResponseHeader(HDR_CONTENT_TYPE));
  951. if (!enableProtocolV2) {
  952. assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
  953. }
  954. AccessEvent service = requests.get(1);
  955. assertEquals("POST", service.getMethod());
  956. assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
  957. assertEquals(401, service.getStatus());
  958. for (int i = 2; i < requests.size(); i++) {
  959. service = requests.get(i);
  960. assertEquals("POST", service.getMethod());
  961. assertEquals(join(authOnPostURI, "git-upload-pack"),
  962. service.getPath());
  963. assertEquals(0, service.getParameters().size());
  964. assertNotNull("has content-length",
  965. service.getRequestHeader(HDR_CONTENT_LENGTH));
  966. assertNull("not chunked",
  967. service.getRequestHeader(HDR_TRANSFER_ENCODING));
  968. assertEquals(200, service.getStatus());
  969. assertEquals("application/x-git-upload-pack-result",
  970. service.getResponseHeader(HDR_CONTENT_TYPE));
  971. }
  972. }
  973. @Test
  974. public void testFetch_FewLocalCommits() throws Exception {
  975. // Bootstrap by doing the clone.
  976. //
  977. TestRepository dst = createTestRepository();
  978. try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
  979. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  980. }
  981. assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
  982. List<AccessEvent> cloneRequests = getRequests();
  983. // Only create a few new commits.
  984. TestRepository.BranchBuilder b = dst.branch(master);
  985. for (int i = 0; i < 4; i++)
  986. b.commit().tick(3600 /* 1 hour */).message("c" + i).create();
  987. // Create a new commit on the remote.
  988. //
  989. RevCommit Z;
  990. try (TestRepository<Repository> tr = new TestRepository<>(
  991. remoteRepository)) {
  992. b = tr.branch(master);
  993. Z = b.commit().message("Z").create();
  994. }
  995. // Now incrementally update.
  996. //
  997. try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
  998. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  999. }
  1000. assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
  1001. List<AccessEvent> requests = getRequests();
  1002. requests.removeAll(cloneRequests);
  1003. assertEquals(enableProtocolV2 ? 3 : 2, requests.size());
  1004. int requestNumber = 0;
  1005. AccessEvent info = requests.get(requestNumber++);
  1006. assertEquals("GET", info.getMethod());
  1007. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  1008. assertEquals(1, info.getParameters().size());
  1009. assertEquals("git-upload-pack", info.getParameter("service"));
  1010. assertEquals(200, info.getStatus());
  1011. assertEquals("application/x-git-upload-pack-advertisement",
  1012. info.getResponseHeader(HDR_CONTENT_TYPE));
  1013. if (enableProtocolV2) {
  1014. AccessEvent lsRefs = requests.get(requestNumber++);
  1015. assertEquals("POST", lsRefs.getMethod());
  1016. assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
  1017. assertEquals(0, lsRefs.getParameters().size());
  1018. assertNotNull("has content-length",
  1019. lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
  1020. assertNull("not chunked",
  1021. lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
  1022. assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
  1023. assertEquals(200, lsRefs.getStatus());
  1024. assertEquals("application/x-git-upload-pack-result",
  1025. lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
  1026. }
  1027. // We should have needed one request to perform the fetch.
  1028. //
  1029. AccessEvent service = requests.get(requestNumber);
  1030. assertEquals("POST", service.getMethod());
  1031. assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
  1032. assertEquals(0, service.getParameters().size());
  1033. assertNotNull("has content-length",
  1034. service.getRequestHeader(HDR_CONTENT_LENGTH));
  1035. assertNull("not chunked",
  1036. service.getRequestHeader(HDR_TRANSFER_ENCODING));
  1037. assertEquals(200, service.getStatus());
  1038. assertEquals("application/x-git-upload-pack-result",
  1039. service.getResponseHeader(HDR_CONTENT_TYPE));
  1040. }
  1041. @Test
  1042. public void testFetch_TooManyLocalCommits() throws Exception {
  1043. // Bootstrap by doing the clone.
  1044. //
  1045. TestRepository dst = createTestRepository();
  1046. try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
  1047. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  1048. }
  1049. assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
  1050. List<AccessEvent> cloneRequests = getRequests();
  1051. // Force enough into the local client that enumeration will
  1052. // need multiple packets, but not too many to overflow and
  1053. // not pick up the ACK_COMMON message.
  1054. //
  1055. TestRepository.BranchBuilder b = dst.branch(master);
  1056. for (int i = 0; i < 32 - 1; i++)
  1057. b.commit().tick(3600 /* 1 hour */).message("c" + i).create();
  1058. // Create a new commit on the remote.
  1059. //
  1060. RevCommit Z;
  1061. try (TestRepository<Repository> tr = new TestRepository<>(
  1062. remoteRepository)) {
  1063. b = tr.branch(master);
  1064. Z = b.commit().message("Z").create();
  1065. }
  1066. // Now incrementally update.
  1067. //
  1068. try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
  1069. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  1070. }
  1071. assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
  1072. List<AccessEvent> requests = getRequests();
  1073. requests.removeAll(cloneRequests);
  1074. assertEquals(enableProtocolV2 ? 4 : 3, requests.size());
  1075. int requestNumber = 0;
  1076. AccessEvent info = requests.get(requestNumber++);
  1077. assertEquals("GET", info.getMethod());
  1078. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  1079. assertEquals(1, info.getParameters().size());
  1080. assertEquals("git-upload-pack", info.getParameter("service"));
  1081. assertEquals(200, info.getStatus());
  1082. assertEquals("application/x-git-upload-pack-advertisement", info
  1083. .getResponseHeader(HDR_CONTENT_TYPE));
  1084. if (enableProtocolV2) {
  1085. AccessEvent lsRefs = requests.get(requestNumber++);
  1086. assertEquals("POST", lsRefs.getMethod());
  1087. assertEquals(join(remoteURI, "git-upload-pack"), lsRefs.getPath());
  1088. assertEquals(0, lsRefs.getParameters().size());
  1089. assertNotNull("has content-length",
  1090. lsRefs.getRequestHeader(HDR_CONTENT_LENGTH));
  1091. assertNull("not chunked",
  1092. lsRefs.getRequestHeader(HDR_TRANSFER_ENCODING));
  1093. assertEquals("version=2", lsRefs.getRequestHeader("Git-Protocol"));
  1094. assertEquals(200, lsRefs.getStatus());
  1095. assertEquals("application/x-git-upload-pack-result",
  1096. lsRefs.getResponseHeader(HDR_CONTENT_TYPE));
  1097. }
  1098. // We should have needed two requests to perform the fetch
  1099. // due to the high number of local unknown commits.
  1100. //
  1101. AccessEvent service = requests.get(requestNumber++);
  1102. assertEquals("POST", service.getMethod());
  1103. assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
  1104. assertEquals(0, service.getParameters().size());
  1105. assertNotNull("has content-length", service
  1106. .getRequestHeader(HDR_CONTENT_LENGTH));
  1107. assertNull("not chunked", service
  1108. .getRequestHeader(HDR_TRANSFER_ENCODING));
  1109. assertEquals(200, service.getStatus());
  1110. assertEquals("application/x-git-upload-pack-result", service
  1111. .getResponseHeader(HDR_CONTENT_TYPE));
  1112. service = requests.get(requestNumber);
  1113. assertEquals("POST", service.getMethod());
  1114. assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
  1115. assertEquals(0, service.getParameters().size());
  1116. assertNotNull("has content-length", service
  1117. .getRequestHeader(HDR_CONTENT_LENGTH));
  1118. assertNull("not chunked", service
  1119. .getRequestHeader(HDR_TRANSFER_ENCODING));
  1120. assertEquals(200, service.getStatus());
  1121. assertEquals("application/x-git-upload-pack-result", service
  1122. .getResponseHeader(HDR_CONTENT_TYPE));
  1123. }
  1124. @Test
  1125. public void testFetch_MaxHavesCutoffAfterAckOnly() throws Exception {
  1126. // Bootstrap by doing the clone.
  1127. //
  1128. TestRepository dst = createTestRepository();
  1129. try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
  1130. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  1131. }
  1132. assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
  1133. // Force enough into the local client that enumeration will
  1134. // need more than MAX_HAVES (256) haves to be sent. The server
  1135. // doesn't know any of these, so it will never ACK. The client
  1136. // should keep going.
  1137. //
  1138. // If it does, client and server will find a common commit, and
  1139. // the pack file will contain exactly the one commit object Z
  1140. // we create on the remote, which we can test for via the progress
  1141. // monitor, which should have something like
  1142. // "Receiving objects: 100% (1/1)". If the client sends a "done"
  1143. // too early, the server will send more objects, and we'll have
  1144. // a line like "Receiving objects: 100% (8/8)".
  1145. TestRepository.BranchBuilder b = dst.branch(master);
  1146. // The client will send 32 + 64 + 128 + 256 + 512 haves. Only the
  1147. // last one will be a common commit. If the cutoff kicks in too
  1148. // early (after 480), we'll get too many objects in the fetch.
  1149. for (int i = 0; i < 992; i++)
  1150. b.commit().tick(3600 /* 1 hour */).message("c" + i).create();
  1151. // Create a new commit on the remote.
  1152. //
  1153. RevCommit Z;
  1154. try (TestRepository<Repository> tr = new TestRepository<>(
  1155. remoteRepository)) {
  1156. b = tr.branch(master);
  1157. Z = b.commit().message("Z").create();
  1158. }
  1159. // Now incrementally update.
  1160. //
  1161. ByteArrayOutputStream buffer = new ByteArrayOutputStream();
  1162. Writer writer = new OutputStreamWriter(buffer, StandardCharsets.UTF_8);
  1163. TextProgressMonitor monitor = new TextProgressMonitor(writer);
  1164. try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
  1165. t.fetch(monitor, mirror(master));
  1166. }
  1167. assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
  1168. String progressMessages = new String(buffer.toByteArray(),
  1169. StandardCharsets.UTF_8);
  1170. Pattern expected = Pattern
  1171. .compile("Receiving objects:\\s+100% \\(1/1\\)\n");
  1172. if (!expected.matcher(progressMessages).find()) {
  1173. System.out.println(progressMessages);
  1174. fail("Expected only one object to be sent");
  1175. }
  1176. }
  1177. @Test
  1178. public void testInitialClone_BrokenServer() throws Exception {
  1179. try (Repository dst = createBareRepository();
  1180. Transport t = Transport.open(dst, brokenURI)) {
  1181. assertFalse(dst.getObjectDatabase().has(A_txt));
  1182. try {
  1183. t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
  1184. fail("fetch completed despite upload-pack being broken");
  1185. } catch (TransportException err) {
  1186. String exp = brokenURI + ": expected"
  1187. + " Content-Type application/x-git-upload-pack-result;"
  1188. + " received Content-Type text/plain;charset=utf-8";
  1189. assertEquals(exp, err.getMessage());
  1190. }
  1191. }
  1192. List<AccessEvent> requests = getRequests();
  1193. assertEquals(2, requests.size());
  1194. AccessEvent info = requests.get(0);
  1195. assertEquals("GET", info.getMethod());
  1196. assertEquals(join(brokenURI, "info/refs"), info.getPath());
  1197. assertEquals(1, info.getParameters().size());
  1198. assertEquals("git-upload-pack", info.getParameter("service"));
  1199. assertEquals(200, info.getStatus());
  1200. assertEquals("application/x-git-upload-pack-advertisement", info
  1201. .getResponseHeader(HDR_CONTENT_TYPE));
  1202. AccessEvent service = requests.get(1);
  1203. assertEquals("POST", service.getMethod());
  1204. assertEquals(join(brokenURI, "git-upload-pack"), service.getPath());
  1205. assertEquals(0, service.getParameters().size());
  1206. assertEquals(200, service.getStatus());
  1207. assertEquals("text/plain;charset=utf-8",
  1208. service.getResponseHeader(HDR_CONTENT_TYPE));
  1209. }
  1210. @Test
  1211. public void testInvalidWant() throws Exception {
  1212. ObjectId id;
  1213. try (ObjectInserter.Formatter formatter = new ObjectInserter.Formatter()) {
  1214. id = formatter.idFor(Constants.OBJ_BLOB,
  1215. "testInvalidWant".getBytes(UTF_8));
  1216. }
  1217. try (Repository dst = createBareRepository();
  1218. Transport t = Transport.open(dst, remoteURI);
  1219. FetchConnection c = t.openFetch()) {
  1220. Ref want = new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, id.name(),
  1221. id);
  1222. c.fetch(NullProgressMonitor.INSTANCE, Collections.singleton(want),
  1223. Collections.<ObjectId> emptySet());
  1224. fail("Server accepted want " + id.name());
  1225. } catch (TransportException err) {
  1226. assertTrue(err.getMessage()
  1227. .contains("want " + id.name() + " not valid"));
  1228. }
  1229. }
  1230. @Test
  1231. public void testFetch_RefsUnreadableOnUpload() throws Exception {
  1232. AppServer noRefServer = new AppServer();
  1233. try {
  1234. final String repoName = "refs-unreadable";
  1235. RefsUnreadableInMemoryRepository badRefsRepo = new RefsUnreadableInMemoryRepository(
  1236. new DfsRepositoryDescription(repoName));
  1237. final TestRepository<Repository> repo = new TestRepository<>(
  1238. badRefsRepo);
  1239. badRefsRepo.getConfig().setInt("protocol", null, "version",
  1240. enableProtocolV2 ? 2 : 0);
  1241. ServletContextHandler app = noRefServer.addContext("/git");
  1242. GitServlet gs = new GitServlet();
  1243. gs.setRepositoryResolver(new TestRepositoryResolver(repo, repoName));
  1244. app.addServlet(new ServletHolder(gs), "/*");
  1245. noRefServer.setUp();
  1246. RevBlob A2_txt = repo.blob("A2");
  1247. RevCommit A2 = repo.commit().add("A2_txt", A2_txt).create();
  1248. RevCommit B2 = repo.commit().parent(A2).add("A2_txt", "C2")
  1249. .add("B2", "B2").create();
  1250. repo.update(master, B2);
  1251. URIish badRefsURI = new URIish(noRefServer.getURI()
  1252. .resolve(app.getContextPath() + "/" + repoName).toString());
  1253. try (Repository dst = createBareRepository();
  1254. Transport t = Transport.open(dst, badRefsURI);
  1255. FetchConnection c = t.openFetch()) {
  1256. // We start failing here to exercise the post-advertisement
  1257. // upload pack handler.
  1258. badRefsRepo.startFailing();
  1259. // Need to flush caches because ref advertisement populated them.
  1260. badRefsRepo.getRefDatabase().refresh();
  1261. c.fetch(NullProgressMonitor.INSTANCE,
  1262. Collections.singleton(c.getRef(master)),
  1263. Collections.<ObjectId> emptySet());
  1264. fail("Successfully served ref with value " + c.getRef(master));
  1265. } catch (TransportException err) {
  1266. assertTrue("Unexpected exception message " + err.getMessage(),
  1267. err.getMessage().contains("Internal server error"));
  1268. }
  1269. } finally {
  1270. noRefServer.tearDown();
  1271. }
  1272. }
  1273. @Test
  1274. public void testPush_NotAuthorized() throws Exception {
  1275. final TestRepository src = createTestRepository();
  1276. final RevBlob Q_txt = src.blob("new text");
  1277. final RevCommit Q = src.commit().add("Q", Q_txt).create();
  1278. final Repository db = src.getRepository();
  1279. final String dstName = Constants.R_HEADS + "new.branch";
  1280. // push anonymous shouldn't be allowed.
  1281. //
  1282. try (Transport t = Transport.open(db, remoteURI)) {
  1283. final String srcExpr = Q.name();
  1284. final boolean forceUpdate = false;
  1285. final String localName = null;
  1286. final ObjectId oldId = null;
  1287. RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
  1288. srcExpr, dstName, forceUpdate, localName, oldId);
  1289. try {
  1290. t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
  1291. fail("anonymous push incorrectly accepted without error");
  1292. } catch (TransportException e) {
  1293. final String exp = remoteURI + ": "
  1294. + JGitText.get().authenticationNotSupported;
  1295. assertEquals(exp, e.getMessage());
  1296. }
  1297. }
  1298. List<AccessEvent> requests = getRequests();
  1299. assertEquals(1, requests.size());
  1300. AccessEvent info = requests.get(0);
  1301. assertEquals("GET", info.getMethod());
  1302. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  1303. assertEquals(1, info.getParameters().size());
  1304. assertEquals("git-receive-pack", info.getParameter("service"));
  1305. assertEquals(401, info.getStatus());
  1306. }
  1307. @Test
  1308. public void testPush_CreateBranch() throws Exception {
  1309. final TestRepository src = createTestRepository();
  1310. final RevBlob Q_txt = src.blob("new text");
  1311. final RevCommit Q = src.commit().add("Q", Q_txt).create();
  1312. final Repository db = src.getRepository();
  1313. final String dstName = Constants.R_HEADS + "new.branch";
  1314. enableReceivePack();
  1315. try (Transport t = Transport.open(db, remoteURI)) {
  1316. final String srcExpr = Q.name();
  1317. final boolean forceUpdate = false;
  1318. final String localName = null;
  1319. final ObjectId oldId = null;
  1320. RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
  1321. srcExpr, dstName, forceUpdate, localName, oldId);
  1322. t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
  1323. }
  1324. assertTrue(remoteRepository.getObjectDatabase().has(Q_txt));
  1325. assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
  1326. assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
  1327. fsck(remoteRepository, Q);
  1328. final ReflogReader log = remoteRepository.getReflogReader(dstName);
  1329. assertNotNull("has log for " + dstName, log);
  1330. final ReflogEntry last = log.getLastEntry();
  1331. assertNotNull("has last entry", last);
  1332. assertEquals(ObjectId.zeroId(), last.getOldId());
  1333. assertEquals(Q, last.getNewId());
  1334. assertEquals("anonymous", last.getWho().getName());
  1335. // Assumption: The host name we use to contact the server should
  1336. // be the server's own host name, because it should be the loopback
  1337. // network interface.
  1338. //
  1339. final String clientHost = remoteURI.getHost();
  1340. assertEquals("anonymous@" + clientHost, last.getWho().getEmailAddress());
  1341. assertEquals("push: created", last.getComment());
  1342. List<AccessEvent> requests = getRequests();
  1343. assertEquals(2, requests.size());
  1344. AccessEvent info = requests.get(0);
  1345. assertEquals("GET", info.getMethod());
  1346. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  1347. assertEquals(1, info.getParameters().size());
  1348. assertEquals("git-receive-pack", info.getParameter("service"));
  1349. assertEquals(200, info.getStatus());
  1350. assertEquals("application/x-git-receive-pack-advertisement", info
  1351. .getResponseHeader(HDR_CONTENT_TYPE));
  1352. AccessEvent service = requests.get(1);
  1353. assertEquals("POST", service.getMethod());
  1354. assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
  1355. assertEquals(0, service.getParameters().size());
  1356. assertNotNull("has content-length", service
  1357. .getRequestHeader(HDR_CONTENT_LENGTH));
  1358. assertNull("not chunked", service
  1359. .getRequestHeader(HDR_TRANSFER_ENCODING));
  1360. assertEquals(200, service.getStatus());
  1361. assertEquals("application/x-git-receive-pack-result", service
  1362. .getResponseHeader(HDR_CONTENT_TYPE));
  1363. }
  1364. @Test
  1365. public void testPush_ChunkedEncoding() throws Exception {
  1366. final TestRepository<Repository> src = createTestRepository();
  1367. final RevBlob Q_bin = src.blob(new TestRng("Q").nextBytes(128 * 1024));
  1368. final RevCommit Q = src.commit().add("Q", Q_bin).create();
  1369. final Repository db = src.getRepository();
  1370. final String dstName = Constants.R_HEADS + "new.branch";
  1371. enableReceivePack();
  1372. final StoredConfig cfg = db.getConfig();
  1373. cfg.setInt("core", null, "compression", 0);
  1374. cfg.setInt("http", null, "postbuffer", 8 * 1024);
  1375. cfg.save();
  1376. try (Transport t = Transport.open(db, remoteURI)) {
  1377. final String srcExpr = Q.name();
  1378. final boolean forceUpdate = false;
  1379. final String localName = null;
  1380. final ObjectId oldId = null;
  1381. RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
  1382. srcExpr, dstName, forceUpdate, localName, oldId);
  1383. t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
  1384. }
  1385. assertTrue(remoteRepository.getObjectDatabase().has(Q_bin));
  1386. assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
  1387. assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
  1388. fsck(remoteRepository, Q);
  1389. List<AccessEvent> requests = getRequests();
  1390. assertEquals(2, requests.size());
  1391. AccessEvent info = requests.get(0);
  1392. assertEquals("GET", info.getMethod());
  1393. assertEquals(join(remoteURI, "info/refs"), info.getPath());
  1394. assertEquals(1, info.getParameters().size());
  1395. assertEquals("git-receive-pack", info.getParameter("service"));
  1396. assertEquals(200, info.getStatus());
  1397. assertEquals("application/x-git-receive-pack-advertisement", info
  1398. .getResponseHeader(HDR_CONTENT_TYPE));
  1399. AccessEvent service = requests.get(1);
  1400. assertEquals("POST", service.getMethod());
  1401. assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
  1402. assertEquals(0, service.getParameters().size());
  1403. assertNull("no content-length", service
  1404. .getRequestHeader(HDR_CONTENT_LENGTH));
  1405. assertEquals("chunked", service.getRequestHeader(HDR_TRANSFER_ENCODING));
  1406. assertEquals(200, service.getStatus());
  1407. assertEquals("application/x-git-receive-pack-result", service
  1408. .getResponseHeader(HDR_CONTENT_TYPE));
  1409. }
  1410. private void enableReceivePack() throws IOException {
  1411. final StoredConfig cfg = remoteRepository.getConfig();
  1412. cfg.setBoolean("http", null, "receivepack", true);
  1413. cfg.save();
  1414. }
  1415. }