/* * Copyright (C) 2015, christian.Halstrick <christian.halstrick@sap.com> * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available * under the terms of the Eclipse Distribution License v1.0 which * accompanies this distribution, is reproduced below, and is * available at http://www.eclipse.org/org/documents/edl-v10.php * * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Eclipse Foundation, Inc. nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.eclipse.jgit.http.test; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Collection; import java.util.Collections; import javax.servlet.http.HttpServletRequest; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jgit.errors.CorruptObjectException; import org.eclipse.jgit.errors.RepositoryNotFoundException; import org.eclipse.jgit.errors.TooLargePackException; import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.http.server.GitServlet; import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory; import org.eclipse.jgit.junit.TestRepository; import org.eclipse.jgit.junit.http.HttpTestCase; import org.eclipse.jgit.lib.AnyObjectId; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.NullProgressMonitor; import org.eclipse.jgit.lib.ObjectChecker; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevBlob; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.transport.PostReceiveHook; import org.eclipse.jgit.transport.PreReceiveHook; import org.eclipse.jgit.transport.ReceiveCommand; import org.eclipse.jgit.transport.ReceivePack; import org.eclipse.jgit.transport.RemoteRefUpdate; import org.eclipse.jgit.transport.Transport; import org.eclipse.jgit.transport.URIish; import org.eclipse.jgit.transport.resolver.RepositoryResolver; import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; import org.junit.Before; import org.junit.Test; /** * Tests for correct responses of {@link GitServlet}. Especially error * situations where the {@link GitServlet} faces exceptions during request * processing are tested */ public class GitServletResponseTests extends HttpTestCase { private Repository srvRepo; private URIish srvURI; private GitServlet gs; private long maxPackSize = 0; // the maximum pack file size used by // the server private PostReceiveHook postHook = null; private PreReceiveHook preHook = null; private ObjectChecker oc = null; /** * Setup a http server using {@link GitServlet}. Tests should be able to * configure the maximum pack file size, the object checker and custom hooks * just before they talk to the server. */ @Before public void setUp() throws Exception { super.setUp(); final TestRepository<Repository> srv = createTestRepository(); final String repoName = srv.getRepository().getDirectory().getName(); ServletContextHandler app = server.addContext("/git"); gs = new GitServlet(); gs.setRepositoryResolver(new RepositoryResolver<HttpServletRequest>() { public Repository open(HttpServletRequest req, String name) throws RepositoryNotFoundException, ServiceNotEnabledException { if (!name.equals(repoName)) throw new RepositoryNotFoundException(name); final Repository db = srv.getRepository(); db.incrementOpen(); return db; } }); gs.setReceivePackFactory(new DefaultReceivePackFactory() { public ReceivePack create(HttpServletRequest req, Repository db) throws ServiceNotEnabledException, ServiceNotAuthorizedException { ReceivePack recv = super.create(req, db); if (maxPackSize > 0) recv.setMaxPackSizeLimit(maxPackSize); if (postHook != null) recv.setPostReceiveHook(postHook); if (preHook != null) recv.setPreReceiveHook(preHook); if (oc != null) recv.setObjectChecker(oc); return recv; } }); app.addServlet(new ServletHolder(gs), "/*"); server.setUp(); srvRepo = srv.getRepository(); srvURI = toURIish(app, repoName); StoredConfig cfg = srvRepo.getConfig(); cfg.setBoolean("http", null, "receivepack", true); cfg.save(); } /** * Configure a {@link GitServlet} that faces a {@link IllegalStateException} * during executing preReceiveHooks. This used to lead to exceptions with a * description of "invalid channel 101" on the client side. Make sure * clients receive the correct response on the correct sideband. * * @throws Exception */ @Test public void testRuntimeExceptionInPreReceiveHook() throws Exception { final TestRepository client = createTestRepository(); final RevBlob Q_txt = client .blob("some blob content to measure pack size"); final RevCommit Q = client.commit().add("Q", Q_txt).create(); final Repository clientRepo = client.getRepository(); final String srvBranchName = Constants.R_HEADS + "new.branch"; Transport t; maxPackSize = 0; postHook = null; preHook = new PreReceiveHook() { @Override public void onPreReceive(ReceivePack rp, Collection<ReceiveCommand> commands) { throw new IllegalStateException(); } }; t = Transport.open(clientRepo, srvURI); try { RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(), srvBranchName, false, null, null); try { t.push(NullProgressMonitor.INSTANCE, Collections.singleton(update)); fail("should not reach this line"); } catch (Exception e) { assertTrue(e instanceof TransportException); } } finally { t.close(); } } /** * Configure a {@link GitServlet} that faces a {@link IllegalStateException} * during executing objectChecking. * * @throws Exception */ @Test public void testObjectCheckerException() throws Exception { final TestRepository client = createTestRepository(); final RevBlob Q_txt = client .blob("some blob content to measure pack size"); final RevCommit Q = client.commit().add("Q", Q_txt).create(); final Repository clientRepo = client.getRepository(); final String srvBranchName = Constants.R_HEADS + "new.branch"; Transport t; maxPackSize = 0; postHook = null; preHook = null; oc = new ObjectChecker() { @Override public void checkCommit(AnyObjectId id, byte[] raw) throws CorruptObjectException { throw new CorruptObjectException("refusing all commits"); } }; t = Transport.open(clientRepo, srvURI); try { RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(), srvBranchName, false, null, null); try { t.push(NullProgressMonitor.INSTANCE, Collections.singleton(update)); fail("should not reach this line"); } catch (Exception e) { assertTrue(e instanceof TransportException); } } finally { t.close(); } } /** * Configure a {@link GitServlet} that faces a {@link TooLargePackException} * during persisting the pack and a {@link IllegalStateException} during * executing postReceiveHooks. This used to lead to exceptions with a * description of "invalid channel 101" on the client side. Make sure * clients receive the correct response about the too large pack on the * correct sideband. * * @throws Exception */ @Test public void testUnpackErrorWithSubsequentExceptionInPostReceiveHook() throws Exception { final TestRepository client = createTestRepository(); final RevBlob Q_txt = client .blob("some blob content to measure pack size"); final RevCommit Q = client.commit().add("Q", Q_txt).create(); final Repository clientRepo = client.getRepository(); final String srvBranchName = Constants.R_HEADS + "new.branch"; Transport t; // this maxPackSize leads to an unPackError maxPackSize = 400; // this PostReceiveHook when called after an unsuccesfull unpack will // lead to an IllegalStateException postHook = new PostReceiveHook() { public void onPostReceive(ReceivePack rp, Collection<ReceiveCommand> commands) { // the maxPackSize setting caused that the packfile couldn't be // saved to disk. Calling getPackSize() now will lead to a // IllegalStateException. rp.getPackSize(); } }; t = Transport.open(clientRepo, srvURI); try { RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(), srvBranchName, false, null, null); try { t.push(NullProgressMonitor.INSTANCE, Collections.singleton(update)); fail("should not reach this line"); } catch (Exception e) { assertTrue(e instanceof TooLargePackException); } } finally { t.close(); } } }