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, src, 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 @SuppressWarnings("unused")
289 private ServletContextHandler addBrokenContext(GitServlet gs, TestRepository<Repository> src, 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 Repository dst = createBareRepository();
418
419 assertEquals("http", remoteURI.getScheme());
420
421 Map<String, Ref> map;
422 try (Transport t = Transport.open(dst, remoteURI)) {
423
424
425
426
427 assertTrue("isa TransportHttp", t instanceof TransportHttp);
428 assertTrue("isa HttpTransport", t instanceof HttpTransport);
429
430 try (FetchConnection c = t.openFetch()) {
431 map = c.getRefsMap();
432 }
433 }
434
435 assertNotNull("have map of refs", map);
436 assertEquals(3, map.size());
437
438 assertNotNull("has " + master, map.get(master));
439 assertEquals(B, map.get(master).getObjectId());
440
441 assertNotNull("has " + Constants.HEAD, map.get(Constants.HEAD));
442 assertEquals(B, map.get(Constants.HEAD).getObjectId());
443
444 List<AccessEvent> requests = getRequests();
445 assertEquals(1, requests.size());
446
447 AccessEvent info = requests.get(0);
448 assertEquals("GET", info.getMethod());
449 assertEquals(join(remoteURI, "info/refs"), info.getPath());
450 assertEquals(1, info.getParameters().size());
451 assertEquals("git-upload-pack", info.getParameter("service"));
452 assertEquals(200, info.getStatus());
453 assertEquals("application/x-git-upload-pack-advertisement", info
454 .getResponseHeader(HDR_CONTENT_TYPE));
455 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
456 }
457
458 @Test
459 public void testListRemote_BadName() throws IOException, URISyntaxException {
460 Repository dst = createBareRepository();
461 URIish uri = new URIish(this.remoteURI.toString() + ".invalid");
462 try (Transport t = Transport.open(dst, uri)) {
463 try {
464 t.openFetch();
465 fail("fetch connection opened");
466 } catch (RemoteRepositoryException notFound) {
467 assertEquals(uri + ": Git repository not found",
468 notFound.getMessage());
469 }
470 }
471
472 List<AccessEvent> requests = getRequests();
473 assertEquals(1, requests.size());
474
475 AccessEvent info = requests.get(0);
476 assertEquals("GET", info.getMethod());
477 assertEquals(join(uri, "info/refs"), info.getPath());
478 assertEquals(1, info.getParameters().size());
479 assertEquals("git-upload-pack", info.getParameter("service"));
480 assertEquals(200, info.getStatus());
481 assertEquals("application/x-git-upload-pack-advertisement",
482 info.getResponseHeader(HDR_CONTENT_TYPE));
483 }
484
485 @Test
486 public void testFetchBySHA1() throws Exception {
487 Repository dst = createBareRepository();
488 assertFalse(dst.hasObject(A_txt));
489
490 try (Transport t = Transport.open(dst, remoteURI)) {
491 t.fetch(NullProgressMonitor.INSTANCE,
492 Collections.singletonList(new RefSpec(B.name())));
493 }
494
495 assertTrue(dst.hasObject(A_txt));
496 }
497
498 @Test
499 public void testFetchBySHA1Unreachable() throws Exception {
500 Repository dst = createBareRepository();
501 assertFalse(dst.hasObject(A_txt));
502
503 try (Transport t = Transport.open(dst, remoteURI)) {
504 thrown.expect(TransportException.class);
505 thrown.expectMessage(Matchers.containsString(
506 "want " + unreachableCommit.name() + " not valid"));
507 t.fetch(NullProgressMonitor.INSTANCE, Collections
508 .singletonList(new RefSpec(unreachableCommit.name())));
509 }
510 }
511
512 @Test
513 public void testFetchBySHA1UnreachableByAdvertiseRefsHook()
514 throws Exception {
515 Repository dst = createBareRepository();
516 assertFalse(dst.hasObject(A_txt));
517
518 advertiseRefsHook = new AbstractAdvertiseRefsHook() {
519 @Override
520 protected Map<String, Ref> getAdvertisedRefs(Repository repository,
521 RevWalk revWalk) {
522 return Collections.emptyMap();
523 }
524 };
525
526 try (Transport t = Transport.open(dst, remoteURI)) {
527 thrown.expect(TransportException.class);
528 thrown.expectMessage(Matchers.containsString(
529 "want " + A.name() + " not valid"));
530 t.fetch(NullProgressMonitor.INSTANCE, Collections
531 .singletonList(new RefSpec(A.name())));
532 }
533 }
534
535 @Test
536 public void testInitialClone_Small() throws Exception {
537 Repository dst = createBareRepository();
538 assertFalse(dst.hasObject(A_txt));
539
540 try (Transport t = Transport.open(dst, remoteURI)) {
541 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
542 }
543
544 assertTrue(dst.hasObject(A_txt));
545 assertEquals(B, dst.exactRef(master).getObjectId());
546 fsck(dst, B);
547
548 List<AccessEvent> requests = getRequests();
549 assertEquals(2, requests.size());
550
551 AccessEvent info = requests.get(0);
552 assertEquals("GET", info.getMethod());
553 assertEquals(join(remoteURI, "info/refs"), info.getPath());
554 assertEquals(1, info.getParameters().size());
555 assertEquals("git-upload-pack", info.getParameter("service"));
556 assertEquals(200, info.getStatus());
557 assertEquals("application/x-git-upload-pack-advertisement", info
558 .getResponseHeader(HDR_CONTENT_TYPE));
559 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
560
561 AccessEvent service = requests.get(1);
562 assertEquals("POST", service.getMethod());
563 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
564 assertEquals(0, service.getParameters().size());
565 assertNotNull("has content-length", service
566 .getRequestHeader(HDR_CONTENT_LENGTH));
567 assertNull("not chunked", service
568 .getRequestHeader(HDR_TRANSFER_ENCODING));
569
570 assertEquals(200, service.getStatus());
571 assertEquals("application/x-git-upload-pack-result", service
572 .getResponseHeader(HDR_CONTENT_TYPE));
573 }
574
575 private void initialClone_Redirect(int nofRedirects, int code)
576 throws Exception {
577 Repository dst = createBareRepository();
578 assertFalse(dst.hasObject(A_txt));
579
580 URIish cloneFrom = redirectURI;
581 if (code != 301 || nofRedirects > 1) {
582 cloneFrom = extendPath(cloneFrom,
583 "/response/" + nofRedirects + "/" + code);
584 }
585 try (Transport t = Transport.open(dst, cloneFrom)) {
586 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
587 }
588
589 assertTrue(dst.hasObject(A_txt));
590 assertEquals(B, dst.exactRef(master).getObjectId());
591 fsck(dst, B);
592
593 List<AccessEvent> requests = getRequests();
594 assertEquals(2 + nofRedirects, requests.size());
595
596 int n = 0;
597 while (n < nofRedirects) {
598 AccessEvent redirect = requests.get(n++);
599 assertEquals(code, redirect.getStatus());
600 }
601
602 AccessEvent info = requests.get(n++);
603 assertEquals("GET", info.getMethod());
604 assertEquals(join(remoteURI, "info/refs"), info.getPath());
605 assertEquals(1, info.getParameters().size());
606 assertEquals("git-upload-pack", info.getParameter("service"));
607 assertEquals(200, info.getStatus());
608 assertEquals("application/x-git-upload-pack-advertisement",
609 info.getResponseHeader(HDR_CONTENT_TYPE));
610 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
611
612 AccessEvent service = requests.get(n++);
613 assertEquals("POST", service.getMethod());
614 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
615 assertEquals(0, service.getParameters().size());
616 assertNotNull("has content-length",
617 service.getRequestHeader(HDR_CONTENT_LENGTH));
618 assertNull("not chunked",
619 service.getRequestHeader(HDR_TRANSFER_ENCODING));
620
621 assertEquals(200, service.getStatus());
622 assertEquals("application/x-git-upload-pack-result",
623 service.getResponseHeader(HDR_CONTENT_TYPE));
624 }
625
626 @Test
627 public void testInitialClone_Redirect301Small() throws Exception {
628 initialClone_Redirect(1, 301);
629 }
630
631 @Test
632 public void testInitialClone_Redirect302Small() throws Exception {
633 initialClone_Redirect(1, 302);
634 }
635
636 @Test
637 public void testInitialClone_Redirect303Small() throws Exception {
638 initialClone_Redirect(1, 303);
639 }
640
641 @Test
642 public void testInitialClone_Redirect307Small() throws Exception {
643 initialClone_Redirect(1, 307);
644 }
645
646 @Test
647 public void testInitialClone_RedirectMultiple() throws Exception {
648 initialClone_Redirect(4, 302);
649 }
650
651 @Test
652 public void testInitialClone_RedirectMax() throws Exception {
653 StoredConfig userConfig = SystemReader.getInstance()
654 .getUserConfig();
655 userConfig.setInt("http", null, "maxRedirects", 4);
656 userConfig.save();
657 initialClone_Redirect(4, 302);
658 }
659
660 @Test
661 public void testInitialClone_RedirectTooOften() throws Exception {
662 StoredConfig userConfig = SystemReader.getInstance()
663 .getUserConfig();
664 userConfig.setInt("http", null, "maxRedirects", 3);
665 userConfig.save();
666 Repository dst = createBareRepository();
667 assertFalse(dst.hasObject(A_txt));
668
669 URIish cloneFrom = extendPath(redirectURI, "/response/4/302");
670 String remoteUri = cloneFrom.toString();
671 try (Transport t = Transport.open(dst, cloneFrom)) {
672 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
673 fail("Should have failed (too many redirects)");
674 } catch (TransportException e) {
675 String expectedMessageBegin = remoteUri.toString() + ": "
676 + MessageFormat.format(JGitText.get().redirectLimitExceeded,
677 "3", remoteUri.replace("/4/", "/1/") + '/', "");
678 String message = e.getMessage();
679 if (message.length() > expectedMessageBegin.length()) {
680 message = message.substring(0, expectedMessageBegin.length());
681 }
682 assertEquals(expectedMessageBegin, message);
683 }
684 }
685
686 @Test
687 public void testInitialClone_RedirectLoop() throws Exception {
688 Repository dst = createBareRepository();
689 assertFalse(dst.hasObject(A_txt));
690
691 URIish cloneFrom = extendPath(redirectURI, "/loop");
692 try (Transport t = Transport.open(dst, cloneFrom)) {
693 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
694 fail("Should have failed (redirect loop)");
695 } catch (TransportException e) {
696 assertTrue(e.getMessage().contains("Redirected more than"));
697 }
698 }
699
700 @Test
701 public void testInitialClone_RedirectOnPostAllowed() throws Exception {
702 StoredConfig userConfig = SystemReader.getInstance()
703 .getUserConfig();
704 userConfig.setString("http", null, "followRedirects", "true");
705 userConfig.save();
706 Repository dst = createBareRepository();
707 assertFalse(dst.hasObject(A_txt));
708
709 URIish cloneFrom = extendPath(remoteURI, "/post");
710 try (Transport t = Transport.open(dst, cloneFrom)) {
711 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
712 }
713
714 assertTrue(dst.hasObject(A_txt));
715 assertEquals(B, dst.exactRef(master).getObjectId());
716 fsck(dst, B);
717
718 List<AccessEvent> requests = getRequests();
719 assertEquals(3, requests.size());
720
721 AccessEvent info = requests.get(0);
722 assertEquals("GET", info.getMethod());
723 assertEquals(join(cloneFrom, "info/refs"), info.getPath());
724 assertEquals(1, info.getParameters().size());
725 assertEquals("git-upload-pack", info.getParameter("service"));
726 assertEquals(200, info.getStatus());
727 assertEquals("application/x-git-upload-pack-advertisement",
728 info.getResponseHeader(HDR_CONTENT_TYPE));
729 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
730
731 AccessEvent redirect = requests.get(1);
732 assertEquals("POST", redirect.getMethod());
733 assertEquals(301, redirect.getStatus());
734
735 AccessEvent service = requests.get(2);
736 assertEquals("POST", service.getMethod());
737 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
738 assertEquals(0, service.getParameters().size());
739 assertNotNull("has content-length",
740 service.getRequestHeader(HDR_CONTENT_LENGTH));
741 assertNull("not chunked",
742 service.getRequestHeader(HDR_TRANSFER_ENCODING));
743
744 assertEquals(200, service.getStatus());
745 assertEquals("application/x-git-upload-pack-result",
746 service.getResponseHeader(HDR_CONTENT_TYPE));
747 }
748
749 @Test
750 public void testInitialClone_RedirectOnPostForbidden() throws Exception {
751 Repository dst = createBareRepository();
752 assertFalse(dst.hasObject(A_txt));
753
754 URIish cloneFrom = extendPath(remoteURI, "/post");
755 try (Transport t = Transport.open(dst, cloneFrom)) {
756 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
757 fail("Should have failed (redirect on POST)");
758 } catch (TransportException e) {
759 assertTrue(e.getMessage().contains("301"));
760 }
761 }
762
763 @Test
764 public void testInitialClone_RedirectForbidden() throws Exception {
765 StoredConfig userConfig = SystemReader.getInstance()
766 .getUserConfig();
767 userConfig.setString("http", null, "followRedirects", "false");
768 userConfig.save();
769
770 Repository dst = createBareRepository();
771 assertFalse(dst.hasObject(A_txt));
772
773 try (Transport t = Transport.open(dst, redirectURI)) {
774 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
775 fail("Should have failed (redirects forbidden)");
776 } catch (TransportException e) {
777 assertTrue(
778 e.getMessage().contains("http.followRedirects is false"));
779 }
780 }
781
782 @Test
783 public void testInitialClone_WithAuthentication() throws Exception {
784 Repository dst = createBareRepository();
785 assertFalse(dst.hasObject(A_txt));
786
787 try (Transport t = Transport.open(dst, authURI)) {
788 t.setCredentialsProvider(testCredentials);
789 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
790 }
791
792 assertTrue(dst.hasObject(A_txt));
793 assertEquals(B, dst.exactRef(master).getObjectId());
794 fsck(dst, B);
795
796 List<AccessEvent> requests = getRequests();
797 assertEquals(3, requests.size());
798
799 AccessEvent info = requests.get(0);
800 assertEquals("GET", info.getMethod());
801 assertEquals(401, info.getStatus());
802
803 info = requests.get(1);
804 assertEquals("GET", info.getMethod());
805 assertEquals(join(authURI, "info/refs"), info.getPath());
806 assertEquals(1, info.getParameters().size());
807 assertEquals("git-upload-pack", info.getParameter("service"));
808 assertEquals(200, info.getStatus());
809 assertEquals("application/x-git-upload-pack-advertisement",
810 info.getResponseHeader(HDR_CONTENT_TYPE));
811 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
812
813 AccessEvent service = requests.get(2);
814 assertEquals("POST", service.getMethod());
815 assertEquals(join(authURI, "git-upload-pack"), service.getPath());
816 assertEquals(0, service.getParameters().size());
817 assertNotNull("has content-length",
818 service.getRequestHeader(HDR_CONTENT_LENGTH));
819 assertNull("not chunked",
820 service.getRequestHeader(HDR_TRANSFER_ENCODING));
821
822 assertEquals(200, service.getStatus());
823 assertEquals("application/x-git-upload-pack-result",
824 service.getResponseHeader(HDR_CONTENT_TYPE));
825 }
826
827 @Test
828 public void testInitialClone_WithAuthenticationNoCredentials()
829 throws Exception {
830 Repository dst = createBareRepository();
831 assertFalse(dst.hasObject(A_txt));
832
833 try (Transport t = Transport.open(dst, authURI)) {
834 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
835 fail("Should not have succeeded -- no authentication");
836 } catch (TransportException e) {
837 String msg = e.getMessage();
838 assertTrue("Unexpected exception message: " + msg,
839 msg.contains("no CredentialsProvider"));
840 }
841 List<AccessEvent> requests = getRequests();
842 assertEquals(1, requests.size());
843
844 AccessEvent info = requests.get(0);
845 assertEquals("GET", info.getMethod());
846 assertEquals(401, info.getStatus());
847 }
848
849 @Test
850 public void testInitialClone_WithAuthenticationWrongCredentials()
851 throws Exception {
852 Repository dst = createBareRepository();
853 assertFalse(dst.hasObject(A_txt));
854
855 try (Transport t = Transport.open(dst, authURI)) {
856 t.setCredentialsProvider(new UsernamePasswordCredentialsProvider(
857 AppServer.username, "wrongpassword"));
858 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
859 fail("Should not have succeeded -- wrong password");
860 } catch (TransportException e) {
861 String msg = e.getMessage();
862 assertTrue("Unexpected exception message: " + msg,
863 msg.contains("auth"));
864 }
865 List<AccessEvent> requests = getRequests();
866
867 assertEquals(4, requests.size());
868
869 for (AccessEvent event : requests) {
870 assertEquals("GET", event.getMethod());
871 assertEquals(401, event.getStatus());
872 }
873 }
874
875 @Test
876 public void testInitialClone_WithAuthenticationAfterRedirect()
877 throws Exception {
878 Repository dst = createBareRepository();
879 assertFalse(dst.hasObject(A_txt));
880
881 URIish cloneFrom = extendPath(redirectURI, "/target/auth");
882 CredentialsProvider uriSpecificCredentialsProvider = new UsernamePasswordCredentialsProvider(
883 "unknown", "none") {
884 @Override
885 public boolean get(URIish uri, CredentialItem... items)
886 throws UnsupportedCredentialItem {
887
888
889
890
891
892 if (uri.getPath().startsWith("/auth")) {
893 return testCredentials.get(uri, items);
894 }
895 return super.get(uri, items);
896 }
897 };
898 try (Transport t = Transport.open(dst, cloneFrom)) {
899 t.setCredentialsProvider(uriSpecificCredentialsProvider);
900 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
901 }
902
903 assertTrue(dst.hasObject(A_txt));
904 assertEquals(B, dst.exactRef(master).getObjectId());
905 fsck(dst, B);
906
907 List<AccessEvent> requests = getRequests();
908 assertEquals(4, requests.size());
909
910 AccessEvent redirect = requests.get(0);
911 assertEquals("GET", redirect.getMethod());
912 assertEquals(join(cloneFrom, "info/refs"), redirect.getPath());
913 assertEquals(301, redirect.getStatus());
914
915 AccessEvent info = requests.get(1);
916 assertEquals("GET", info.getMethod());
917 assertEquals(join(authURI, "info/refs"), info.getPath());
918 assertEquals(401, info.getStatus());
919
920 info = requests.get(2);
921 assertEquals("GET", info.getMethod());
922 assertEquals(join(authURI, "info/refs"), info.getPath());
923 assertEquals(1, info.getParameters().size());
924 assertEquals("git-upload-pack", info.getParameter("service"));
925 assertEquals(200, info.getStatus());
926 assertEquals("application/x-git-upload-pack-advertisement",
927 info.getResponseHeader(HDR_CONTENT_TYPE));
928 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
929
930 AccessEvent service = requests.get(3);
931 assertEquals("POST", service.getMethod());
932 assertEquals(join(authURI, "git-upload-pack"), service.getPath());
933 assertEquals(0, service.getParameters().size());
934 assertNotNull("has content-length",
935 service.getRequestHeader(HDR_CONTENT_LENGTH));
936 assertNull("not chunked",
937 service.getRequestHeader(HDR_TRANSFER_ENCODING));
938
939 assertEquals(200, service.getStatus());
940 assertEquals("application/x-git-upload-pack-result",
941 service.getResponseHeader(HDR_CONTENT_TYPE));
942 }
943
944 @Test
945 public void testInitialClone_WithAuthenticationOnPostOnly()
946 throws Exception {
947 Repository dst = createBareRepository();
948 assertFalse(dst.hasObject(A_txt));
949
950 try (Transport t = Transport.open(dst, authOnPostURI)) {
951 t.setCredentialsProvider(testCredentials);
952 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
953 }
954
955 assertTrue(dst.hasObject(A_txt));
956 assertEquals(B, dst.exactRef(master).getObjectId());
957 fsck(dst, B);
958
959 List<AccessEvent> requests = getRequests();
960 assertEquals(3, requests.size());
961
962 AccessEvent info = requests.get(0);
963 assertEquals("GET", info.getMethod());
964 assertEquals(join(authOnPostURI, "info/refs"), info.getPath());
965 assertEquals(1, info.getParameters().size());
966 assertEquals("git-upload-pack", info.getParameter("service"));
967 assertEquals(200, info.getStatus());
968 assertEquals("application/x-git-upload-pack-advertisement",
969 info.getResponseHeader(HDR_CONTENT_TYPE));
970 assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
971
972 AccessEvent service = requests.get(1);
973 assertEquals("POST", service.getMethod());
974 assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
975 assertEquals(401, service.getStatus());
976
977 service = requests.get(2);
978 assertEquals("POST", service.getMethod());
979 assertEquals(join(authOnPostURI, "git-upload-pack"), service.getPath());
980 assertEquals(0, service.getParameters().size());
981 assertNotNull("has content-length",
982 service.getRequestHeader(HDR_CONTENT_LENGTH));
983 assertNull("not chunked",
984 service.getRequestHeader(HDR_TRANSFER_ENCODING));
985
986 assertEquals(200, service.getStatus());
987 assertEquals("application/x-git-upload-pack-result",
988 service.getResponseHeader(HDR_CONTENT_TYPE));
989 }
990
991 @Test
992 public void testFetch_FewLocalCommits() throws Exception {
993
994
995 TestRepository dst = createTestRepository();
996 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
997 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
998 }
999 assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
1000 List<AccessEvent> cloneRequests = getRequests();
1001
1002
1003 TestRepository.BranchBuilder b = dst.branch(master);
1004 for (int i = 0; i < 4; i++)
1005 b.commit().tick(3600 ).message("c" + i).create();
1006
1007
1008
1009 b = new TestRepository<>(remoteRepository).branch(master);
1010 RevCommit Z = b.commit().message("Z").create();
1011
1012
1013
1014 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
1015 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
1016 }
1017 assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
1018
1019 List<AccessEvent> requests = getRequests();
1020 requests.removeAll(cloneRequests);
1021 assertEquals(2, requests.size());
1022
1023 AccessEvent info = requests.get(0);
1024 assertEquals("GET", info.getMethod());
1025 assertEquals(join(remoteURI, "info/refs"), info.getPath());
1026 assertEquals(1, info.getParameters().size());
1027 assertEquals("git-upload-pack", info.getParameter("service"));
1028 assertEquals(200, info.getStatus());
1029 assertEquals("application/x-git-upload-pack-advertisement",
1030 info.getResponseHeader(HDR_CONTENT_TYPE));
1031
1032
1033
1034 AccessEvent service = requests.get(1);
1035 assertEquals("POST", service.getMethod());
1036 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
1037 assertEquals(0, service.getParameters().size());
1038 assertNotNull("has content-length",
1039 service.getRequestHeader(HDR_CONTENT_LENGTH));
1040 assertNull("not chunked",
1041 service.getRequestHeader(HDR_TRANSFER_ENCODING));
1042
1043 assertEquals(200, service.getStatus());
1044 assertEquals("application/x-git-upload-pack-result",
1045 service.getResponseHeader(HDR_CONTENT_TYPE));
1046 }
1047
1048 @Test
1049 public void testFetch_TooManyLocalCommits() throws Exception {
1050
1051
1052 TestRepository dst = createTestRepository();
1053 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
1054 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
1055 }
1056 assertEquals(B, dst.getRepository().exactRef(master).getObjectId());
1057 List<AccessEvent> cloneRequests = getRequests();
1058
1059
1060
1061
1062
1063 TestRepository.BranchBuilder b = dst.branch(master);
1064 for (int i = 0; i < 32 - 1; i++)
1065 b.commit().tick(3600 ).message("c" + i).create();
1066
1067
1068
1069 b = new TestRepository<>(remoteRepository).branch(master);
1070 RevCommit Z = b.commit().message("Z").create();
1071
1072
1073
1074 try (Transport t = Transport.open(dst.getRepository(), remoteURI)) {
1075 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
1076 }
1077 assertEquals(Z, dst.getRepository().exactRef(master).getObjectId());
1078
1079 List<AccessEvent> requests = getRequests();
1080 requests.removeAll(cloneRequests);
1081 assertEquals(3, requests.size());
1082
1083 AccessEvent info = requests.get(0);
1084 assertEquals("GET", info.getMethod());
1085 assertEquals(join(remoteURI, "info/refs"), info.getPath());
1086 assertEquals(1, info.getParameters().size());
1087 assertEquals("git-upload-pack", info.getParameter("service"));
1088 assertEquals(200, info.getStatus());
1089 assertEquals("application/x-git-upload-pack-advertisement", info
1090 .getResponseHeader(HDR_CONTENT_TYPE));
1091
1092
1093
1094
1095 AccessEvent service = requests.get(1);
1096 assertEquals("POST", service.getMethod());
1097 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
1098 assertEquals(0, service.getParameters().size());
1099 assertNotNull("has content-length", service
1100 .getRequestHeader(HDR_CONTENT_LENGTH));
1101 assertNull("not chunked", service
1102 .getRequestHeader(HDR_TRANSFER_ENCODING));
1103
1104 assertEquals(200, service.getStatus());
1105 assertEquals("application/x-git-upload-pack-result", service
1106 .getResponseHeader(HDR_CONTENT_TYPE));
1107
1108 service = requests.get(2);
1109 assertEquals("POST", service.getMethod());
1110 assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
1111 assertEquals(0, service.getParameters().size());
1112 assertNotNull("has content-length", service
1113 .getRequestHeader(HDR_CONTENT_LENGTH));
1114 assertNull("not chunked", service
1115 .getRequestHeader(HDR_TRANSFER_ENCODING));
1116
1117 assertEquals(200, service.getStatus());
1118 assertEquals("application/x-git-upload-pack-result", service
1119 .getResponseHeader(HDR_CONTENT_TYPE));
1120 }
1121
1122 @Test
1123 public void testInitialClone_BrokenServer() throws Exception {
1124 Repository dst = createBareRepository();
1125 assertFalse(dst.hasObject(A_txt));
1126
1127 try (Transport t = Transport.open(dst, brokenURI)) {
1128 try {
1129 t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
1130 fail("fetch completed despite upload-pack being broken");
1131 } catch (TransportException err) {
1132 String exp = brokenURI + ": expected"
1133 + " Content-Type application/x-git-upload-pack-result;"
1134 + " received Content-Type text/plain;charset=utf-8";
1135 assertEquals(exp, err.getMessage());
1136 }
1137 }
1138
1139 List<AccessEvent> requests = getRequests();
1140 assertEquals(2, requests.size());
1141
1142 AccessEvent info = requests.get(0);
1143 assertEquals("GET", info.getMethod());
1144 assertEquals(join(brokenURI, "info/refs"), info.getPath());
1145 assertEquals(1, info.getParameters().size());
1146 assertEquals("git-upload-pack", info.getParameter("service"));
1147 assertEquals(200, info.getStatus());
1148 assertEquals("application/x-git-upload-pack-advertisement", info
1149 .getResponseHeader(HDR_CONTENT_TYPE));
1150
1151 AccessEvent service = requests.get(1);
1152 assertEquals("POST", service.getMethod());
1153 assertEquals(join(brokenURI, "git-upload-pack"), service.getPath());
1154 assertEquals(0, service.getParameters().size());
1155 assertEquals(200, service.getStatus());
1156 assertEquals("text/plain;charset=utf-8",
1157 service.getResponseHeader(HDR_CONTENT_TYPE));
1158 }
1159
1160 @Test
1161 public void testInvalidWant() throws Exception {
1162 @SuppressWarnings("resource")
1163 ObjectId id = new ObjectInserter.Formatter().idFor(Constants.OBJ_BLOB,
1164 "testInvalidWant".getBytes(UTF_8));
1165
1166 Repository dst = createBareRepository();
1167 try (Transport t = Transport.open(dst, remoteURI);
1168 FetchConnection c = t.openFetch()) {
1169 Ref want = new ObjectIdRef.Unpeeled(Ref.Storage.NETWORK, id.name(),
1170 id);
1171 c.fetch(NullProgressMonitor.INSTANCE, Collections.singleton(want),
1172 Collections.<ObjectId> emptySet());
1173 fail("Server accepted want " + id.name());
1174 } catch (TransportException err) {
1175 assertEquals("want " + id.name() + " not valid", err.getMessage());
1176 }
1177 }
1178
1179 @Test
1180 public void testFetch_RefsUnreadableOnUpload() throws Exception {
1181 AppServer noRefServer = new AppServer();
1182 try {
1183 final String repoName = "refs-unreadable";
1184 RefsUnreadableInMemoryRepository badRefsRepo = new RefsUnreadableInMemoryRepository(
1185 new DfsRepositoryDescription(repoName));
1186 final TestRepository<Repository> repo = new TestRepository<>(
1187 badRefsRepo);
1188
1189 ServletContextHandler app = noRefServer.addContext("/git");
1190 GitServlet gs = new GitServlet();
1191 gs.setRepositoryResolver(new TestRepositoryResolver(repo, repoName));
1192 app.addServlet(new ServletHolder(gs), "/*");
1193 noRefServer.setUp();
1194
1195 RevBlob A2_txt = repo.blob("A2");
1196 RevCommit A2 = repo.commit().add("A2_txt", A2_txt).create();
1197 RevCommit B2 = repo.commit().parent(A2).add("A2_txt", "C2")
1198 .add("B2", "B2").create();
1199 repo.update(master, B2);
1200
1201 URIish badRefsURI = new URIish(noRefServer.getURI()
1202 .resolve(app.getContextPath() + "/" + repoName).toString());
1203
1204 Repository dst = createBareRepository();
1205 try (Transport t = Transport.open(dst, badRefsURI);
1206 FetchConnection c = t.openFetch()) {
1207
1208
1209 badRefsRepo.startFailing();
1210
1211 badRefsRepo.getRefDatabase().refresh();
1212 c.fetch(NullProgressMonitor.INSTANCE,
1213 Collections.singleton(c.getRef(master)),
1214 Collections.<ObjectId> emptySet());
1215 fail("Successfully served ref with value " + c.getRef(master));
1216 } catch (TransportException err) {
1217 assertEquals("internal server error", err.getMessage());
1218 }
1219 } finally {
1220 noRefServer.tearDown();
1221 }
1222 }
1223
1224 @Test
1225 public void testPush_NotAuthorized() throws Exception {
1226 final TestRepository src = createTestRepository();
1227 final RevBlob Q_txt = src.blob("new text");
1228 final RevCommit Q = src.commit().add("Q", Q_txt).create();
1229 final Repository db = src.getRepository();
1230 final String dstName = Constants.R_HEADS + "new.branch";
1231
1232
1233
1234 try (Transport t = Transport.open(db, remoteURI)) {
1235 final String srcExpr = Q.name();
1236 final boolean forceUpdate = false;
1237 final String localName = null;
1238 final ObjectId oldId = null;
1239
1240 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
1241 srcExpr, dstName, forceUpdate, localName, oldId);
1242 try {
1243 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
1244 fail("anonymous push incorrectly accepted without error");
1245 } catch (TransportException e) {
1246 final String exp = remoteURI + ": "
1247 + JGitText.get().authenticationNotSupported;
1248 assertEquals(exp, e.getMessage());
1249 }
1250 }
1251
1252 List<AccessEvent> requests = getRequests();
1253 assertEquals(1, requests.size());
1254
1255 AccessEvent info = requests.get(0);
1256 assertEquals("GET", info.getMethod());
1257 assertEquals(join(remoteURI, "info/refs"), info.getPath());
1258 assertEquals(1, info.getParameters().size());
1259 assertEquals("git-receive-pack", info.getParameter("service"));
1260 assertEquals(401, info.getStatus());
1261 }
1262
1263 @Test
1264 public void testPush_CreateBranch() throws Exception {
1265 final TestRepository src = createTestRepository();
1266 final RevBlob Q_txt = src.blob("new text");
1267 final RevCommit Q = src.commit().add("Q", Q_txt).create();
1268 final Repository db = src.getRepository();
1269 final String dstName = Constants.R_HEADS + "new.branch";
1270
1271 enableReceivePack();
1272
1273 try (Transport t = Transport.open(db, remoteURI)) {
1274 final String srcExpr = Q.name();
1275 final boolean forceUpdate = false;
1276 final String localName = null;
1277 final ObjectId oldId = null;
1278
1279 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
1280 srcExpr, dstName, forceUpdate, localName, oldId);
1281 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
1282 }
1283
1284 assertTrue(remoteRepository.hasObject(Q_txt));
1285 assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
1286 assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
1287 fsck(remoteRepository, Q);
1288
1289 final ReflogReader log = remoteRepository.getReflogReader(dstName);
1290 assertNotNull("has log for " + dstName, log);
1291
1292 final ReflogEntry last = log.getLastEntry();
1293 assertNotNull("has last entry", last);
1294 assertEquals(ObjectId.zeroId(), last.getOldId());
1295 assertEquals(Q, last.getNewId());
1296 assertEquals("anonymous", last.getWho().getName());
1297
1298
1299
1300
1301
1302 final String clientHost = remoteURI.getHost();
1303 assertEquals("anonymous@" + clientHost, last.getWho().getEmailAddress());
1304 assertEquals("push: created", last.getComment());
1305
1306 List<AccessEvent> requests = getRequests();
1307 assertEquals(2, requests.size());
1308
1309 AccessEvent info = requests.get(0);
1310 assertEquals("GET", info.getMethod());
1311 assertEquals(join(remoteURI, "info/refs"), info.getPath());
1312 assertEquals(1, info.getParameters().size());
1313 assertEquals("git-receive-pack", info.getParameter("service"));
1314 assertEquals(200, info.getStatus());
1315 assertEquals("application/x-git-receive-pack-advertisement", info
1316 .getResponseHeader(HDR_CONTENT_TYPE));
1317
1318 AccessEvent service = requests.get(1);
1319 assertEquals("POST", service.getMethod());
1320 assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
1321 assertEquals(0, service.getParameters().size());
1322 assertNotNull("has content-length", service
1323 .getRequestHeader(HDR_CONTENT_LENGTH));
1324 assertNull("not chunked", service
1325 .getRequestHeader(HDR_TRANSFER_ENCODING));
1326
1327 assertEquals(200, service.getStatus());
1328 assertEquals("application/x-git-receive-pack-result", service
1329 .getResponseHeader(HDR_CONTENT_TYPE));
1330 }
1331
1332 @Test
1333 public void testPush_ChunkedEncoding() throws Exception {
1334 final TestRepository<Repository> src = createTestRepository();
1335 final RevBlob Q_bin = src.blob(new TestRng("Q").nextBytes(128 * 1024));
1336 final RevCommit Q = src.commit().add("Q", Q_bin).create();
1337 final Repository db = src.getRepository();
1338 final String dstName = Constants.R_HEADS + "new.branch";
1339
1340 enableReceivePack();
1341
1342 final StoredConfig cfg = db.getConfig();
1343 cfg.setInt("core", null, "compression", 0);
1344 cfg.setInt("http", null, "postbuffer", 8 * 1024);
1345 cfg.save();
1346
1347 try (Transport t = Transport.open(db, remoteURI)) {
1348 final String srcExpr = Q.name();
1349 final boolean forceUpdate = false;
1350 final String localName = null;
1351 final ObjectId oldId = null;
1352
1353 RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
1354 srcExpr, dstName, forceUpdate, localName, oldId);
1355 t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
1356 }
1357
1358 assertTrue(remoteRepository.hasObject(Q_bin));
1359 assertNotNull("has " + dstName, remoteRepository.exactRef(dstName));
1360 assertEquals(Q, remoteRepository.exactRef(dstName).getObjectId());
1361 fsck(remoteRepository, Q);
1362
1363 List<AccessEvent> requests = getRequests();
1364 assertEquals(2, requests.size());
1365
1366 AccessEvent info = requests.get(0);
1367 assertEquals("GET", info.getMethod());
1368 assertEquals(join(remoteURI, "info/refs"), info.getPath());
1369 assertEquals(1, info.getParameters().size());
1370 assertEquals("git-receive-pack", info.getParameter("service"));
1371 assertEquals(200, info.getStatus());
1372 assertEquals("application/x-git-receive-pack-advertisement", info
1373 .getResponseHeader(HDR_CONTENT_TYPE));
1374
1375 AccessEvent service = requests.get(1);
1376 assertEquals("POST", service.getMethod());
1377 assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
1378 assertEquals(0, service.getParameters().size());
1379 assertNull("no content-length", service
1380 .getRequestHeader(HDR_CONTENT_LENGTH));
1381 assertEquals("chunked", service.getRequestHeader(HDR_TRANSFER_ENCODING));
1382
1383 assertEquals(200, service.getStatus());
1384 assertEquals("application/x-git-receive-pack-result", service
1385 .getResponseHeader(HDR_CONTENT_TYPE));
1386 }
1387
1388 private void enableReceivePack() throws IOException {
1389 final StoredConfig cfg = remoteRepository.getConfig();
1390 cfg.setBoolean("http", null, "receivepack", true);
1391 cfg.save();
1392 }
1393
1394 }