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