1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.http.test;
45
46 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING;
47 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_LENGTH;
48 import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;
49 import static org.junit.Assert.assertEquals;
50 import static org.junit.Assert.assertFalse;
51 import static org.junit.Assert.assertNotNull;
52 import static org.junit.Assert.assertNull;
53 import static org.junit.Assert.assertTrue;
54 import static org.junit.Assert.fail;
55
56 import java.io.IOException;
57 import java.io.PrintWriter;
58 import java.net.URISyntaxException;
59 import java.nio.charset.StandardCharsets;
60 import java.util.Arrays;
61 import java.util.Collection;
62 import java.util.Collections;
63 import java.util.EnumSet;
64 import java.util.List;
65 import java.util.Map;
66
67 import javax.servlet.DispatcherType;
68 import javax.servlet.Filter;
69 import javax.servlet.FilterChain;
70 import javax.servlet.FilterConfig;
71 import javax.servlet.ServletException;
72 import javax.servlet.ServletRequest;
73 import javax.servlet.ServletResponse;
74 import javax.servlet.http.HttpServletRequest;
75 import javax.servlet.http.HttpServletResponse;
76
77 import org.eclipse.jetty.servlet.FilterHolder;
78 import org.eclipse.jetty.servlet.ServletContextHandler;
79 import org.eclipse.jetty.servlet.ServletHolder;
80 import org.eclipse.jgit.errors.RemoteRepositoryException;
81 import org.eclipse.jgit.errors.RepositoryNotFoundException;
82 import org.eclipse.jgit.errors.TransportException;
83 import org.eclipse.jgit.http.server.GitServlet;
84 import org.eclipse.jgit.internal.JGitText;
85 import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
86 import org.eclipse.jgit.junit.TestRepository;
87 import org.eclipse.jgit.junit.TestRng;
88 import org.eclipse.jgit.junit.http.AccessEvent;
89 import org.eclipse.jgit.junit.http.AppServer;
90 import org.eclipse.jgit.junit.http.HttpTestCase;
91 import org.eclipse.jgit.lib.ConfigConstants;
92 import org.eclipse.jgit.lib.Constants;
93 import org.eclipse.jgit.lib.NullProgressMonitor;
94 import org.eclipse.jgit.lib.ObjectId;
95 import org.eclipse.jgit.lib.ObjectIdRef;
96 import org.eclipse.jgit.lib.ObjectInserter;
97 import org.eclipse.jgit.lib.Ref;
98 import org.eclipse.jgit.lib.ReflogEntry;
99 import org.eclipse.jgit.lib.ReflogReader;
100 import org.eclipse.jgit.lib.Repository;
101 import org.eclipse.jgit.lib.StoredConfig;
102 import org.eclipse.jgit.revwalk.RevBlob;
103 import org.eclipse.jgit.revwalk.RevCommit;
104 import org.eclipse.jgit.transport.FetchConnection;
105 import org.eclipse.jgit.transport.HttpTransport;
106 import org.eclipse.jgit.transport.RemoteRefUpdate;
107 import org.eclipse.jgit.transport.Transport;
108 import org.eclipse.jgit.transport.TransportHttp;
109 import org.eclipse.jgit.transport.URIish;
110 import org.eclipse.jgit.transport.http.HttpConnectionFactory;
111 import org.eclipse.jgit.transport.http.JDKHttpConnectionFactory;
112 import org.eclipse.jgit.transport.http.apache.HttpClientConnectionFactory;
113 import org.eclipse.jgit.transport.resolver.RepositoryResolver;
114 import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
115 import org.eclipse.jgit.util.HttpSupport;
116 import org.junit.Before;
117 import org.junit.Test;
118 import org.junit.runner.RunWith;
119 import org.junit.runners.Parameterized;
120 import org.junit.runners.Parameterized.Parameters;
121
122 @RunWith(Parameterized.class)
123 public class SmartClientSmartServerTest extends HttpTestCase {
124 private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding";
125
126 private Repository remoteRepository;
127
128 private URIish remoteURI;
129
130 private URIish brokenURI;
131
132 private URIish redirectURI;
133
134 private RevBlob A_txt;
135
136 private RevCommit A, B;
137
138 @Parameters
139 public static Collection<Object[]> data() {
140
141 return Arrays.asList(new Object[][] {
142 { new JDKHttpConnectionFactory() },
143 { new HttpClientConnectionFactory() } });
144 }
145
146 public SmartClientSmartServerTest(HttpConnectionFactory cf) {
147 HttpTransport.setConnectionFactory(cf);
148 }
149
150 @Override
151 @Before
152 public void setUp() throws Exception {
153 super.setUp();
154
155 final TestRepository<Repository> src = createTestRepository();
156 final String srcName = src.getRepository().getDirectory().getName();
157 src.getRepository()
158 .getConfig()
159 .setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
160 ConfigConstants.CONFIG_KEY_LOGALLREFUPDATES, true);
161
162 GitServlet gs = new GitServlet();
163
164 ServletContextHandler app = addNormalContext(gs, src, srcName);
165
166 ServletContextHandler broken = addBrokenContext(gs, src, srcName);
167
168 ServletContextHandler redirect = addRedirectContext(gs, src, srcName);
169
170 server.setUp();
171
172 remoteRepository = src.getRepository();
173 remoteURI = toURIish(app, srcName);
174 brokenURI = toURIish(broken, srcName);
175 redirectURI = toURIish(redirect, srcName);
176
177 A_txt = src.blob("A");
178 A = src.commit().add("A_txt", A_txt).create();
179 B = src.commit().parent(A).add("A_txt", "C").add("B", "B").create();
180 src.update(master, B);
181
182 src.update("refs/garbage/a/very/long/ref/name/to/compress", B);
183 }
184
185 private ServletContextHandler addNormalContext(GitServlet gs, TestRepository<Repository> src, String srcName) {
186 ServletContextHandler app = server.addContext("/git");
187 gs.setRepositoryResolver(new TestRepoResolver(src, srcName));
188 app.addServlet(new ServletHolder(gs), "/*");
189 return app;
190 }
191
192 @SuppressWarnings("unused")
193 private ServletContextHandler addBrokenContext(GitServlet gs, TestRepository<Repository> src, String srcName) {
194 ServletContextHandler broken = server.addContext("/bad");
195 broken.addFilter(new FilterHolder(new Filter() {
196
197 @Override
198 public void doFilter(ServletRequest request,
199 ServletResponse response, FilterChain chain)
200 throws IOException, ServletException {
201 final HttpServletResponse r = (HttpServletResponse) response;
202 r.setContentType("text/plain");
203 r.setCharacterEncoding("UTF-8");
204 PrintWriter w = r.getWriter();
205 w.print("OK");
206 w.close();
207 }
208
209 @Override
210 public void init(FilterConfig filterConfig)
211 throws ServletException {
212
213 }
214
215 @Override
216 public void destroy() {
217
218 }
219 }), "/" + srcName + "/git-upload-pack",
220 EnumSet.of(DispatcherType.REQUEST));
221 broken.addServlet(new ServletHolder(gs), "/*");
222 return broken;
223 }
224
225 @SuppressWarnings("unused")
226 private ServletContextHandler addRedirectContext(GitServlet gs,
227 TestRepository<Repository> src, String srcName) {
228 ServletContextHandler redirect = server.addContext("/redirect");
229 redirect.addFilter(new FilterHolder(new Filter() {
230
231 @Override
232 public void init(FilterConfig filterConfig)
233 throws ServletException {
234
235 }
236
237 @Override
238 public void doFilter(ServletRequest request,
239 ServletResponse response, FilterChain chain)
240 throws IOException, ServletException {
241 final HttpServletResponse httpServletResponse = (HttpServletResponse) response;
242 final HttpServletRequest httpServletRequest = (HttpServletRequest) request;
243 final StringBuffer fullUrl = httpServletRequest.getRequestURL();
244 if (httpServletRequest.getQueryString() != null) {
245 fullUrl.append("?")
246 .append(httpServletRequest.getQueryString());
247 }
248 httpServletResponse
249 .setStatus(HttpServletResponse.SC_MOVED_PERMANENTLY);
250 httpServletResponse.setHeader(HttpSupport.HDR_LOCATION,
251 fullUrl.toString().replace("/redirect", "/git"));
252 }
253
254 @Override
255 public void destroy() {
256
257 }
258 }), "/*", EnumSet.of(DispatcherType.REQUEST));
259 redirect.addServlet(new ServletHolder(gs), "/*");
260 return redirect;
261 }
262
263 @Test
264 public void testListRemote() throws IOException {
265 Repository dst = createBareRepository();
266
267 assertEquals("http", remoteURI.getScheme());
268
269 Map<String, Ref> map;
270 try (Transport t = Transport.open(dst, remoteURI)) {
271
272
273
274
275 assertTrue("isa TransportHttp", t instanceof TransportHttp);
276 assertTrue("isa HttpTransport", t instanceof HttpTransport);
277
278 FetchConnection c = t.openFetch();
279 try {
280 map = c.getRefsMap();
281 } finally {
282 c.close();
283 }
284 }
285
286 assertNotNull("have map of refs", map);
287 assertEquals(3, map.size());
288
289 assertNotNull("has " + master, map.get(master));
290 assertEquals(B, map.get(master).getObjectId());
291
292 assertNotNull("has " + Constants.HEAD, map.get(Constants.HEAD));
293 assertEquals(B, map.get(Constants.HEAD).getObjectId());
294
295 List<AccessEvent> requests = getRequests();
296 assertEquals(1, requests.size());
297
298 AccessEvent info = requests.get(0);
299 assertEquals("GET", info.getMethod());
300 assertEquals(join(remoteURI, "info/refs"), info.getPath());
301 assertEquals(1, info.getParameters().size());
302 assertEquals("git-upload-pack", info.getParameter("service"));
303 assertEquals(200, info.getStatus());
304 assertEquals("application/x-git-upload-pack-advertisement", info
305 .getResponseHeader(HDR_CONTENT_TYPE));
306 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
307 }
308
309 @Test
310 public void testListRemote_BadName() throws IOException, URISyntaxException {
311 Repository dst = createBareRepository();
312 URIish uri = new URIish(this.remoteURI.toString() + ".invalid");
313 try (Transport t = Transport.open(dst, uri)) {
314 try {
315 t.openFetch();
316 fail("fetch connection opened");
317 } catch (RemoteRepositoryException notFound) {
318 assertEquals(uri + ": Git repository not found",
319 notFound.getMessage());
320 }
321 }
322
323 List<AccessEvent> requests = getRequests();
324 assertEquals(1, requests.size());
325
326 AccessEvent info = requests.get(0);
327 assertEquals("GET", info.getMethod());
328 assertEquals(join(uri, "info/refs"), info.getPath());
329 assertEquals(1, info.getParameters().size());
330 assertEquals("git-upload-pack", info.getParameter("service"));
331 assertEquals(200, info.getStatus());
332 assertEquals("application/x-git-upload-pack-advertisement",
333 info.getResponseHeader(HDR_CONTENT_TYPE));
334 }
335
336 @Test
337 public void testInitialClone_Small() throws Exception {
338 Repository dst = createBareRepository();
339 assertFalse(dst.hasObject(A_txt));
340
341 try (Transport t = Transport.open(dst, remoteURI)) {
342 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
343 }
344
345 assertTrue(dst.hasObject(A_txt));
346 assertEquals(B, dst.exactRef(master).getObjectId());
347 fsck(dst, B);
348
349 List<AccessEvent> requests = getRequests();
350 assertEquals(2, requests.size());
351
352 AccessEvent info = requests.get(0);
353 assertEquals("GET", info.getMethod());
354 assertEquals(join(remoteURI, "info/refs"), info.getPath());
355 assertEquals(1, info.getParameters().size());
356 assertEquals("git-upload-pack", info.getParameter("service"));
357 assertEquals(200, info.getStatus());
358 assertEquals("application/x-git-upload-pack-advertisement", info
359 .getResponseHeader(HDR_CONTENT_TYPE));
360 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
361
362 AccessEvent service = requests.get(1);
363 assertEquals("POST", service.getMethod());
364 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
365 assertEquals(0, service.getParameters().size());
366 assertNotNull("has content-length", service
367 .getRequestHeader(HDR_CONTENT_LENGTH));
368 assertNull("not chunked", service
369 .getRequestHeader(HDR_TRANSFER_ENCODING));
370
371 assertEquals(200, service.getStatus());
372 assertEquals("application/x-git-upload-pack-result", service
373 .getResponseHeader(HDR_CONTENT_TYPE));
374 }
375
376 @Test
377 public void testInitialClone_RedirectSmall() throws Exception {
378 Repository dst = createBareRepository();
379 assertFalse(dst.hasObject(A_txt));
380
381 try (Transport t = Transport.open(dst, redirectURI)) {
382 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
383 }
384
385 assertTrue(dst.hasObject(A_txt));
386 assertEquals(B, dst.exactRef(master).getObjectId());
387 fsck(dst, B);
388
389 List<AccessEvent> requests = getRequests();
390 assertEquals(4, requests.size());
391
392 AccessEvent firstRedirect = requests.get(0);
393 assertEquals(301, firstRedirect.getStatus());
394
395 AccessEvent info = requests.get(1);
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",
402 info.getResponseHeader(HDR_CONTENT_TYPE));
403 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
404
405 AccessEvent secondRedirect = requests.get(2);
406 assertEquals(301, secondRedirect.getStatus());
407
408 AccessEvent service = requests.get(3);
409 assertEquals("POST", service.getMethod());
410 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
411 assertEquals(0, service.getParameters().size());
412 assertNotNull("has content-length",
413 service.getRequestHeader(HDR_CONTENT_LENGTH));
414 assertNull("not chunked",
415 service.getRequestHeader(HDR_TRANSFER_ENCODING));
416
417 assertEquals(200, service.getStatus());
418 assertEquals("application/x-git-upload-pack-result",
419 service.getResponseHeader(HDR_CONTENT_TYPE));
420 }
421
422 @Test
423 public void testFetch_FewLocalCommits() throws Exception {
424
425
426 TestRepository dst = createTestRepository();
427 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
428 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
429 }
430 assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
431 List<AccessEvent> cloneRequests = getRequests();
432
433
434 TestRepository.BranchBuilder b = dst.branch(master);
435 for (int i = 0; i < 4; i++)
436 b.commit().tick(3600 ).message("c" + i).create();
437
438
439
440 b = new TestRepository<>(remoteRepository).branch(master);
441 RevCommit Z = b.commit().message("Z").create();
442
443
444
445 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
446 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
447 }
448 assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
449
450 List<AccessEvent> requests = getRequests();
451 requests.removeAll(cloneRequests);
452 assertEquals(2, requests.size());
453
454 AccessEvent info = requests.get(0);
455 assertEquals("GET", info.getMethod());
456 assertEquals(join(remoteURI, "info/refs"), info.getPath());
457 assertEquals(1, info.getParameters().size());
458 assertEquals("git-upload-pack", info.getParameter("service"));
459 assertEquals(200, info.getStatus());
460 assertEquals("application/x-git-upload-pack-advertisement",
461 info.getResponseHeader(HDR_CONTENT_TYPE));
462
463
464
465 AccessEvent service = requests.get(1);
466 assertEquals("POST", service.getMethod());
467 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
468 assertEquals(0, service.getParameters().size());
469 assertNotNull("has content-length",
470 service.getRequestHeader(HDR_CONTENT_LENGTH));
471 assertNull("not chunked",
472 service.getRequestHeader(HDR_TRANSFER_ENCODING));
473
474 assertEquals(200, service.getStatus());
475 assertEquals("application/x-git-upload-pack-result",
476 service.getResponseHeader(HDR_CONTENT_TYPE));
477 }
478
479 @Test
480 public void testFetch_TooManyLocalCommits() throws Exception {
481
482
483 TestRepository dst = createTestRepository();
484 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
485 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
486 }
487 assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
488 List<AccessEvent> cloneRequests = getRequests();
489
490
491
492
493
494 TestRepository.BranchBuilder b = dst.branch(master);
495 for (int i = 0; i < 32 - 1; i++)
496 b.commit().tick(3600 ).message("c" + i).create();
497
498
499
500 b = new TestRepository<>(remoteRepository).branch(master);
501 RevCommit Z = b.commit().message("Z").create();
502
503
504
505 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
506 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
507 }
508 assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
509
510 List<AccessEvent> requests = getRequests();
511 requests.removeAll(cloneRequests);
512 assertEquals(3, requests.size());
513
514 AccessEvent info = requests.get(0);
515 assertEquals("GET", info.getMethod());
516 assertEquals(join(remoteURI, "info/refs"), info.getPath());
517 assertEquals(1, info.getParameters().size());
518 assertEquals("git-upload-pack", info.getParameter("service"));
519 assertEquals(200, info.getStatus());
520 assertEquals("application/x-git-upload-pack-advertisement", info
521 .getResponseHeader(HDR_CONTENT_TYPE));
522
523
524
525
526 AccessEvent service = requests.get(1);
527 assertEquals("POST", service.getMethod());
528 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
529 assertEquals(0, service.getParameters().size());
530 assertNotNull("has content-length", service
531 .getRequestHeader(HDR_CONTENT_LENGTH));
532 assertNull("not chunked", service
533 .getRequestHeader(HDR_TRANSFER_ENCODING));
534
535 assertEquals(200, service.getStatus());
536 assertEquals("application/x-git-upload-pack-result", service
537 .getResponseHeader(HDR_CONTENT_TYPE));
538
539 service = requests.get(2);
540 assertEquals("POST", service.getMethod());
541 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
542 assertEquals(0, service.getParameters().size());
543 assertNotNull("has content-length", service
544 .getRequestHeader(HDR_CONTENT_LENGTH));
545 assertNull("not chunked", service
546 .getRequestHeader(HDR_TRANSFER_ENCODING));
547
548 assertEquals(200, service.getStatus());
549 assertEquals("application/x-git-upload-pack-result", service
550 .getResponseHeader(HDR_CONTENT_TYPE));
551 }
552
553 @Test
554 public void testInitialClone_BrokenServer() throws Exception {
555 Repository dst = createBareRepository();
556 assertFalse(dst.hasObject(A_txt));
557
558 try (Transport t = Transport.open(dst, brokenURI)) {
559 try {
560 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
561 fail("fetch completed despite upload-pack being broken");
562 } catch (TransportException err) {
563 String exp = brokenURI + ": expected"
564 + " Content-Type application/x-git-upload-pack-result;"
565 + " received Content-Type text/plain;charset=utf-8";
566 assertEquals(exp, err.getMessage());
567 }
568 }
569
570 List<AccessEvent> requests = getRequests();
571 assertEquals(2, requests.size());
572
573 AccessEvent info = requests.get(0);
574 assertEquals("GET", info.getMethod());
575 assertEquals(join(brokenURI, "info/refs"), info.getPath());
576 assertEquals(1, info.getParameters().size());
577 assertEquals("git-upload-pack", info.getParameter("service"));
578 assertEquals(200, info.getStatus());
579 assertEquals("application/x-git-upload-pack-advertisement", info
580 .getResponseHeader(HDR_CONTENT_TYPE));
581
582 AccessEvent service = requests.get(1);
583 assertEquals("POST", service.getMethod());
584 assertEquals(join(brokenURI, "git-upload-pack"), service.getPath());
585 assertEquals(0, service.getParameters().size());
586 assertEquals(200, service.getStatus());
587 assertEquals("text/plain;charset=utf-8",
588 service.getResponseHeader(HDR_CONTENT_TYPE));
589 }
590
591 @Test
592 public void testInvalidWant() throws Exception {
593 @SuppressWarnings("resource")
594 ObjectId id = new ObjectInserter.Formatter().idFor(Constants.OBJ_BLOB,
595 "testInvalidWant".getBytes(StandardCharsets.UTF_8));
596
597 Repository dst = createBareRepository();
598 try (Transport t = Transport.open(dst, remoteURI);
599 FetchConnection c = t.openFetch()) {
600 Ref want = new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, id.name(),
601 id);
602 c.fetch(NullProgressMonitor.INSTANCE, Collections.singleton(want),
603 Collections.<ObjectId> emptySet());
604 fail("Server accepted want " + id.name());
605 } catch (TransportException err) {
606 assertEquals("want " + id.name() + " not valid", err.getMessage());
607 }
608 }
609
610 @Test
611 public void testFetch_RefsUnreadableOnUpload() throws Exception {
612 AppServer noRefServer = new AppServer();
613 try {
614 final String repoName = "refs-unreadable";
615 RefsUnreadableInMemoryRepository badRefsRepo = new RefsUnreadableInMemoryRepository(
616 new DfsRepositoryDescription(repoName));
617 final TestRepository<Repository> repo = new TestRepository<>(
618 badRefsRepo);
619
620 ServletContextHandler app = noRefServer.addContext("/git");
621 GitServlet gs = new GitServlet();
622 gs.setRepositoryResolver(new TestRepoResolver(repo, repoName));
623 app.addServlet(new ServletHolder(gs), "/*");
624 noRefServer.setUp();
625
626 RevBlob A2_txt = repo.blob("A2");
627 RevCommit A2 = repo.commit().add("A2_txt", A2_txt).create();
628 RevCommit B2 = repo.commit().parent(A2).add("A2_txt", "C2")
629 .add("B2", "B2").create();
630 repo.update(master, B2);
631
632 URIish badRefsURI = new URIish(noRefServer.getURI()
633 .resolve(app.getContextPath() + "/" + repoName).toString());
634
635 Repository dst = createBareRepository();
636 try (Transport t = Transport.open(dst, badRefsURI);
637 FetchConnection c = t.openFetch()) {
638
639
640 badRefsRepo.startFailing();
641
642 badRefsRepo.getRefDatabase().refresh();
643 c.fetch(NullProgressMonitor.INSTANCE,
644 Collections.singleton(c.getRef(master)),
645 Collections.<ObjectId> emptySet());
646 fail("Successfully served ref with value " + c.getRef(master));
647 } catch (TransportException err) {
648 assertEquals("internal server error", err.getMessage());
649 }
650 } finally {
651 noRefServer.tearDown();
652 }
653 }
654
655 @Test
656 public void testPush_NotAuthorized() throws Exception {
657 final TestRepository src = createTestRepository();
658 final RevBlob Q_txt = src.blob("new text");
659 final RevCommit Q = src.commit().add("Q", Q_txt).create();
660 final Repository db = src.getRepository();
661 final String dstName = Constants.R_HEADS + "new.branch";
662
663
664
665 try (Transport t = Transport.open(db, remoteURI)) {
666 final String srcExpr = Q.name();
667 final boolean forceUpdate = false;
668 final String localName = null;
669 final ObjectId oldId = null;
670
671 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
672 srcExpr, dstName, forceUpdate, localName, oldId);
673 try {
674 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
675 fail("anonymous push incorrectly accepted without error");
676 } catch (TransportException e) {
677 final String exp = remoteURI + ": "
678 + JGitText.get().authenticationNotSupported;
679 assertEquals(exp, e.getMessage());
680 }
681 }
682
683 List<AccessEvent> requests = getRequests();
684 assertEquals(1, requests.size());
685
686 AccessEvent info = requests.get(0);
687 assertEquals("GET", info.getMethod());
688 assertEquals(join(remoteURI, "info/refs"), info.getPath());
689 assertEquals(1, info.getParameters().size());
690 assertEquals("git-receive-pack", info.getParameter("service"));
691 assertEquals(401, info.getStatus());
692 }
693
694 @Test
695 public void testPush_CreateBranch() throws Exception {
696 final TestRepository src = createTestRepository();
697 final RevBlob Q_txt = src.blob("new text");
698 final RevCommit Q = src.commit().add("Q", Q_txt).create();
699 final Repository db = src.getRepository();
700 final String dstName = Constants.R_HEADS + "new.branch";
701
702 enableReceivePack();
703
704 try (Transport t = Transport.open(db, remoteURI)) {
705 final String srcExpr = Q.name();
706 final boolean forceUpdate = false;
707 final String localName = null;
708 final ObjectId oldId = null;
709
710 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
711 srcExpr, dstName, forceUpdate, localName, oldId);
712 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
713 }
714
715 assertTrue(remoteRepository.hasObject(Q_txt));
716 assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
717 assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
718 fsck(remoteRepository, Q);
719
720 final ReflogReader log = remoteRepository.getReflogReader(dstName);
721 assertNotNull("has log for " + dstName, log);
722
723 final ReflogEntry last = log.getLastEntry();
724 assertNotNull("has last entry", last);
725 assertEquals(ObjectId.zeroId(), last.getOldId());
726 assertEquals(Q, last.getNewId());
727 assertEquals("anonymous", last.getWho().getName());
728
729
730
731
732
733 final String clientHost = remoteURI.getHost();
734 assertEquals("anonymous@" + clientHost, last.getWho().getEmailAddress());
735 assertEquals("push: created", last.getComment());
736
737 List<AccessEvent> requests = getRequests();
738 assertEquals(2, requests.size());
739
740 AccessEvent info = requests.get(0);
741 assertEquals("GET", info.getMethod());
742 assertEquals(join(remoteURI, "info/refs"), info.getPath());
743 assertEquals(1, info.getParameters().size());
744 assertEquals("git-receive-pack", info.getParameter("service"));
745 assertEquals(200, info.getStatus());
746 assertEquals("application/x-git-receive-pack-advertisement", info
747 .getResponseHeader(HDR_CONTENT_TYPE));
748
749 AccessEvent service = requests.get(1);
750 assertEquals("POST", service.getMethod());
751 assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
752 assertEquals(0, service.getParameters().size());
753 assertNotNull("has content-length", service
754 .getRequestHeader(HDR_CONTENT_LENGTH));
755 assertNull("not chunked", service
756 .getRequestHeader(HDR_TRANSFER_ENCODING));
757
758 assertEquals(200, service.getStatus());
759 assertEquals("application/x-git-receive-pack-result", service
760 .getResponseHeader(HDR_CONTENT_TYPE));
761 }
762
763 @Test
764 public void testPush_ChunkedEncoding() throws Exception {
765 final TestRepository<Repository> src = createTestRepository();
766 final RevBlob Q_bin = src.blob(new TestRng("Q").nextBytes(128 * 1024));
767 final RevCommit Q = src.commit().add("Q", Q_bin).create();
768 final Repository db = src.getRepository();
769 final String dstName = Constants.R_HEADS + "new.branch";
770
771 enableReceivePack();
772
773 final StoredConfig cfg = db.getConfig();
774 cfg.setInt("core", null, "compression", 0);
775 cfg.setInt("http", null, "postbuffer", 8 * 1024);
776 cfg.save();
777
778 try (Transport t = Transport.open(db, remoteURI)) {
779 final String srcExpr = Q.name();
780 final boolean forceUpdate = false;
781 final String localName = null;
782 final ObjectId oldId = null;
783
784 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
785 srcExpr, dstName, forceUpdate, localName, oldId);
786 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
787 }
788
789 assertTrue(remoteRepository.hasObject(Q_bin));
790 assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
791 assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
792 fsck(remoteRepository, Q);
793
794 List<AccessEvent> requests = getRequests();
795 assertEquals(2, requests.size());
796
797 AccessEvent info = requests.get(0);
798 assertEquals("GET", info.getMethod());
799 assertEquals(join(remoteURI, "info/refs"), info.getPath());
800 assertEquals(1, info.getParameters().size());
801 assertEquals("git-receive-pack", info.getParameter("service"));
802 assertEquals(200, info.getStatus());
803 assertEquals("application/x-git-receive-pack-advertisement", info
804 .getResponseHeader(HDR_CONTENT_TYPE));
805
806 AccessEvent service = requests.get(1);
807 assertEquals("POST", service.getMethod());
808 assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
809 assertEquals(0, service.getParameters().size());
810 assertNull("no content-length", service
811 .getRequestHeader(HDR_CONTENT_LENGTH));
812 assertEquals("chunked", service.getRequestHeader(HDR_TRANSFER_ENCODING));
813
814 assertEquals(200, service.getStatus());
815 assertEquals("application/x-git-receive-pack-result", service
816 .getResponseHeader(HDR_CONTENT_TYPE));
817 }
818
819 private void enableReceivePack() throws IOException {
820 final StoredConfig cfg = remoteRepository.getConfig();
821 cfg.setBoolean("http", null, "receivepack", true);
822 cfg.save();
823 }
824
825 private final class TestRepoResolver
826 implements RepositoryResolver<HttpServletRequest> {
827
828 private final TestRepository<Repository> repo;
829
830 private final String repoName;
831
832 private TestRepoResolver(TestRepository<Repository> repo,
833 String repoName) {
834 this.repo = repo;
835 this.repoName = repoName;
836 }
837
838 @Override
839 public Repository open(HttpServletRequest req, String name)
840 throws RepositoryNotFoundException, ServiceNotEnabledException {
841 if (!name.equals(repoName))
842 throw new RepositoryNotFoundException(name);
843
844 Repository db = repo.getRepository();
845 db.incrementOpen();
846 return db;
847 }
848 }
849 }