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.

HttpClientTests.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  1. /*
  2. * Copyright (C) 2009-2010, 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 org.hamcrest.Matchers.is;
  12. import static org.junit.Assert.assertEquals;
  13. import static org.junit.Assert.assertFalse;
  14. import static org.junit.Assert.assertNotNull;
  15. import static org.junit.Assert.assertNull;
  16. import static org.junit.Assert.assertThat;
  17. import static org.junit.Assert.assertTrue;
  18. import static org.junit.Assert.fail;
  19. import java.io.File;
  20. import java.io.OutputStream;
  21. import java.net.URI;
  22. import java.net.URL;
  23. import java.util.List;
  24. import javax.servlet.http.HttpServletRequest;
  25. import org.eclipse.jetty.servlet.DefaultServlet;
  26. import org.eclipse.jetty.servlet.ServletContextHandler;
  27. import org.eclipse.jetty.servlet.ServletHolder;
  28. import org.eclipse.jgit.errors.NoRemoteRepositoryException;
  29. import org.eclipse.jgit.errors.RepositoryNotFoundException;
  30. import org.eclipse.jgit.errors.TransportException;
  31. import org.eclipse.jgit.http.server.GitServlet;
  32. import org.eclipse.jgit.internal.JGitText;
  33. import org.eclipse.jgit.junit.TestRepository;
  34. import org.eclipse.jgit.junit.http.AccessEvent;
  35. import org.eclipse.jgit.junit.http.AppServer;
  36. import org.eclipse.jgit.lib.Constants;
  37. import org.eclipse.jgit.lib.Ref;
  38. import org.eclipse.jgit.lib.RefUpdate;
  39. import org.eclipse.jgit.lib.Repository;
  40. import org.eclipse.jgit.lib.StoredConfig;
  41. import org.eclipse.jgit.revwalk.RevCommit;
  42. import org.eclipse.jgit.transport.FetchConnection;
  43. import org.eclipse.jgit.transport.HttpTransport;
  44. import org.eclipse.jgit.transport.PacketLineIn;
  45. import org.eclipse.jgit.transport.PacketLineOut;
  46. import org.eclipse.jgit.transport.Transport;
  47. import org.eclipse.jgit.transport.URIish;
  48. import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
  49. import org.eclipse.jgit.transport.http.HttpConnection;
  50. import org.eclipse.jgit.transport.http.HttpConnectionFactory;
  51. import org.junit.Before;
  52. import org.junit.Test;
  53. public class HttpClientTests extends AllFactoriesHttpTestCase {
  54. private TestRepository<Repository> remoteRepository;
  55. private URIish dumbAuthNoneURI;
  56. private URIish dumbAuthBasicURI;
  57. private URIish smartAuthNoneURI;
  58. private URIish smartAuthBasicURI;
  59. public HttpClientTests(HttpConnectionFactory cf) {
  60. super(cf);
  61. }
  62. @Override
  63. @Before
  64. public void setUp() throws Exception {
  65. super.setUp();
  66. remoteRepository = createTestRepository();
  67. remoteRepository.update(master, remoteRepository.commit().create());
  68. ServletContextHandler dNone = dumb("/dnone");
  69. ServletContextHandler dBasic = server.authBasic(dumb("/dbasic"));
  70. ServletContextHandler sNone = smart("/snone");
  71. ServletContextHandler sBasic = server.authBasic(smart("/sbasic"));
  72. server.setUp();
  73. final String srcName = nameOf(remoteRepository.getRepository());
  74. dumbAuthNoneURI = toURIish(dNone, srcName);
  75. dumbAuthBasicURI = toURIish(dBasic, srcName);
  76. smartAuthNoneURI = toURIish(sNone, srcName);
  77. smartAuthBasicURI = toURIish(sBasic, srcName);
  78. }
  79. private ServletContextHandler dumb(String path) {
  80. final File srcGit = remoteRepository.getRepository().getDirectory();
  81. final URI base = srcGit.getParentFile().toURI();
  82. ServletContextHandler ctx = server.addContext(path);
  83. ctx.setResourceBase(base.toString());
  84. ServletHolder holder = ctx.addServlet(DefaultServlet.class, "/");
  85. // The tmp directory is symlinked on OS X
  86. holder.setInitParameter("aliases", "true");
  87. return ctx;
  88. }
  89. private ServletContextHandler smart(String path) {
  90. GitServlet gs = new GitServlet();
  91. gs.setRepositoryResolver((HttpServletRequest req, String name) -> {
  92. final Repository db = remoteRepository.getRepository();
  93. if (!name.equals(nameOf(db))) {
  94. throw new RepositoryNotFoundException(name);
  95. }
  96. db.incrementOpen();
  97. return db;
  98. });
  99. ServletContextHandler ctx = server.addContext(path);
  100. ctx.addServlet(new ServletHolder(gs), "/*");
  101. return ctx;
  102. }
  103. private static String nameOf(Repository db) {
  104. return db.getDirectory().getName();
  105. }
  106. @Test
  107. public void testRepositoryNotFound_Dumb() throws Exception {
  108. URIish uri = toURIish("/dumb.none/not-found");
  109. Repository dst = createBareRepository();
  110. try (Transport t = Transport.open(dst, uri)) {
  111. try {
  112. t.openFetch();
  113. fail("connection opened to not found repository");
  114. } catch (NoRemoteRepositoryException err) {
  115. String exp = uri + ": " + uri
  116. + "/info/refs?service=git-upload-pack not found";
  117. assertNotNull(err.getMessage());
  118. assertTrue("Unexpected error message",
  119. err.getMessage().startsWith(exp));
  120. }
  121. }
  122. }
  123. @Test
  124. public void testRepositoryNotFound_Smart() throws Exception {
  125. URIish uri = toURIish("/smart.none/not-found");
  126. Repository dst = createBareRepository();
  127. try (Transport t = Transport.open(dst, uri)) {
  128. try {
  129. t.openFetch();
  130. fail("connection opened to not found repository");
  131. } catch (NoRemoteRepositoryException err) {
  132. String exp = uri + ": " + uri
  133. + "/info/refs?service=git-upload-pack not found";
  134. assertNotNull(err.getMessage());
  135. assertTrue("Unexpected error message",
  136. err.getMessage().startsWith(exp));
  137. }
  138. }
  139. }
  140. @Test
  141. public void testListRemote_Dumb_DetachedHEAD() throws Exception {
  142. Repository src = remoteRepository.getRepository();
  143. RefUpdate u = src.updateRef(Constants.HEAD, true);
  144. RevCommit Q = remoteRepository.commit().message("Q").create();
  145. u.setNewObjectId(Q);
  146. assertEquals(RefUpdate.Result.FORCED, u.forceUpdate());
  147. Repository dst = createBareRepository();
  148. Ref head;
  149. try (Transport t = Transport.open(dst, dumbAuthNoneURI);
  150. FetchConnection c = t.openFetch()) {
  151. head = c.getRef(Constants.HEAD);
  152. }
  153. assertNotNull("has " + Constants.HEAD, head);
  154. assertEquals(Q, head.getObjectId());
  155. }
  156. @Test
  157. public void testListRemote_Dumb_NoHEAD() throws Exception {
  158. Repository src = remoteRepository.getRepository();
  159. File headref = new File(src.getDirectory(), Constants.HEAD);
  160. assertTrue("HEAD used to be present", headref.delete());
  161. assertFalse("HEAD is gone", headref.exists());
  162. Repository dst = createBareRepository();
  163. Ref head;
  164. try (Transport t = Transport.open(dst, dumbAuthNoneURI);
  165. FetchConnection c = t.openFetch()) {
  166. head = c.getRef(Constants.HEAD);
  167. }
  168. assertNull("has no " + Constants.HEAD, head);
  169. }
  170. @Test
  171. public void testListRemote_Smart_DetachedHEAD() throws Exception {
  172. Repository src = remoteRepository.getRepository();
  173. RefUpdate u = src.updateRef(Constants.HEAD, true);
  174. RevCommit Q = remoteRepository.commit().message("Q").create();
  175. u.setNewObjectId(Q);
  176. assertEquals(RefUpdate.Result.FORCED, u.forceUpdate());
  177. Repository dst = createBareRepository();
  178. Ref head;
  179. try (Transport t = Transport.open(dst, smartAuthNoneURI);
  180. FetchConnection c = t.openFetch()) {
  181. head = c.getRef(Constants.HEAD);
  182. }
  183. assertNotNull("has " + Constants.HEAD, head);
  184. assertEquals(Q, head.getObjectId());
  185. }
  186. @Test
  187. public void testListRemote_Smart_WithQueryParameters() throws Exception {
  188. URIish myURI = toURIish("/snone/do?r=1&p=test.git");
  189. Repository dst = createBareRepository();
  190. try (Transport t = Transport.open(dst, myURI)) {
  191. try {
  192. t.openFetch();
  193. fail("test did not fail to find repository as expected");
  194. } catch (NoRemoteRepositoryException err) {
  195. // expected
  196. }
  197. }
  198. List<AccessEvent> requests = getRequests();
  199. assertEquals(1, requests.size());
  200. AccessEvent info = requests.get(0);
  201. assertEquals("GET", info.getMethod());
  202. assertEquals("/snone/do", info.getPath());
  203. assertEquals(3, info.getParameters().size());
  204. assertEquals("1", info.getParameter("r"));
  205. assertEquals("test.git/info/refs", info.getParameter("p"));
  206. assertEquals("git-upload-pack", info.getParameter("service"));
  207. assertEquals(404, info.getStatus());
  208. }
  209. @Test
  210. public void testListRemote_Dumb_NeedsAuth() throws Exception {
  211. Repository dst = createBareRepository();
  212. try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
  213. try {
  214. t.openFetch();
  215. fail("connection opened even info/refs needs auth basic");
  216. } catch (TransportException err) {
  217. String exp = dumbAuthBasicURI + ": "
  218. + JGitText.get().noCredentialsProvider;
  219. assertEquals(exp, err.getMessage());
  220. }
  221. }
  222. }
  223. @Test
  224. public void testListRemote_Dumb_Auth() throws Exception {
  225. Repository dst = createBareRepository();
  226. try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
  227. t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
  228. AppServer.username, AppServer.password));
  229. t.openFetch().close();
  230. }
  231. try (Transport t = Transport.open(dst, dumbAuthBasicURI)) {
  232. t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
  233. AppServer.username, ""));
  234. try {
  235. t.openFetch();
  236. fail("connection opened even info/refs needs auth basic and we provide wrong password");
  237. } catch (TransportException err) {
  238. String exp = dumbAuthBasicURI + ": "
  239. + JGitText.get().notAuthorized;
  240. assertEquals(exp, err.getMessage());
  241. }
  242. }
  243. }
  244. @Test
  245. public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception {
  246. Repository dst = createBareRepository();
  247. try (Transport t = Transport.open(dst, smartAuthBasicURI)) {
  248. try {
  249. t.openFetch();
  250. fail("connection opened even though service disabled");
  251. } catch (TransportException err) {
  252. String exp = smartAuthBasicURI + ": "
  253. + JGitText.get().noCredentialsProvider;
  254. assertEquals(exp, err.getMessage());
  255. }
  256. }
  257. }
  258. @Test
  259. public void testListRemote_Smart_UploadPackDisabled() throws Exception {
  260. Repository src = remoteRepository.getRepository();
  261. final StoredConfig cfg = src.getConfig();
  262. cfg.setBoolean("http", null, "uploadpack", false);
  263. cfg.save();
  264. Repository dst = createBareRepository();
  265. try (Transport t = Transport.open(dst, smartAuthNoneURI)) {
  266. try {
  267. t.openFetch();
  268. fail("connection opened even though service disabled");
  269. } catch (TransportException err) {
  270. String exp = smartAuthNoneURI + ": "
  271. + JGitText.get().serviceNotEnabledNoName;
  272. assertEquals(exp, err.getMessage());
  273. }
  274. }
  275. }
  276. @Test
  277. public void testListRemoteWithoutLocalRepository() throws Exception {
  278. try (Transport t = Transport.open(smartAuthNoneURI);
  279. FetchConnection c = t.openFetch()) {
  280. Ref head = c.getRef(Constants.HEAD);
  281. assertNotNull(head);
  282. }
  283. }
  284. @Test
  285. public void testHttpClientWantsV2ButServerNotConfigured() throws Exception {
  286. String url = smartAuthNoneURI.toString() + "/info/refs?service=git-upload-pack";
  287. HttpConnection c = HttpTransport.getConnectionFactory()
  288. .create(new URL(url));
  289. c.setRequestMethod("GET");
  290. c.setRequestProperty("Git-Protocol", "version=2");
  291. assertEquals(200, c.getResponseCode());
  292. PacketLineIn pckIn = new PacketLineIn(c.getInputStream());
  293. // Check that we get a v0 response.
  294. assertThat(pckIn.readString(), is("# service=git-upload-pack"));
  295. assertTrue(PacketLineIn.isEnd(pckIn.readString()));
  296. assertTrue(pckIn.readString().matches("[0-9a-f]{40} HEAD.*"));
  297. }
  298. @Test
  299. public void testV2HttpFirstResponse() throws Exception {
  300. remoteRepository.getRepository().getConfig().setInt(
  301. "protocol", null, "version", 2);
  302. String url = smartAuthNoneURI.toString() + "/info/refs?service=git-upload-pack";
  303. HttpConnection c = HttpTransport.getConnectionFactory()
  304. .create(new URL(url));
  305. c.setRequestMethod("GET");
  306. c.setRequestProperty("Git-Protocol", "version=2");
  307. assertEquals(200, c.getResponseCode());
  308. PacketLineIn pckIn = new PacketLineIn(c.getInputStream());
  309. assertThat(pckIn.readString(), is("version 2"));
  310. // What remains are capabilities - ensure that all of them are
  311. // non-empty strings, and that we see END at the end.
  312. for (String s : pckIn.readStrings()) {
  313. assertTrue(!s.isEmpty());
  314. }
  315. }
  316. @Test
  317. public void testV2HttpSubsequentResponse() throws Exception {
  318. remoteRepository.getRepository().getConfig().setInt(
  319. "protocol", null, "version", 2);
  320. String url = smartAuthNoneURI.toString() + "/git-upload-pack";
  321. HttpConnection c = HttpTransport.getConnectionFactory()
  322. .create(new URL(url));
  323. c.setRequestMethod("POST");
  324. c.setRequestProperty("Content-Type", "application/x-git-upload-pack-request");
  325. c.setRequestProperty("Git-Protocol", "version=2");
  326. c.setDoOutput(true);
  327. // Test ls-refs to verify that everything is connected
  328. // properly. Tests for other commands go in
  329. // UploadPackTest.java.
  330. try (OutputStream os = c.getOutputStream()) {
  331. PacketLineOut pckOut = new PacketLineOut(os);
  332. pckOut.writeString("command=ls-refs");
  333. pckOut.writeDelim();
  334. pckOut.end();
  335. }
  336. PacketLineIn pckIn = new PacketLineIn(c.getInputStream());
  337. // Just check that we get what looks like a ref advertisement.
  338. for (String s : pckIn.readStrings()) {
  339. assertTrue(s.matches("[0-9a-f]{40} [A-Za-z/]*"));
  340. }
  341. assertEquals(200, c.getResponseCode());
  342. }
  343. }