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