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