View Javadoc
1   /*
2    * Copyright (C) 2015, christian.Halstrick <christian.halstrick@sap.com> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  package org.eclipse.jgit.http.test;
11  
12  import static org.junit.Assert.assertTrue;
13  import static org.junit.Assert.fail;
14  
15  import java.util.Collection;
16  import java.util.Collections;
17  
18  import javax.servlet.http.HttpServletRequest;
19  
20  import org.eclipse.jetty.servlet.ServletContextHandler;
21  import org.eclipse.jetty.servlet.ServletHolder;
22  import org.eclipse.jgit.errors.CorruptObjectException;
23  import org.eclipse.jgit.errors.RepositoryNotFoundException;
24  import org.eclipse.jgit.errors.TooLargePackException;
25  import org.eclipse.jgit.errors.TransportException;
26  import org.eclipse.jgit.http.server.GitServlet;
27  import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
28  import org.eclipse.jgit.junit.TestRepository;
29  import org.eclipse.jgit.junit.http.HttpTestCase;
30  import org.eclipse.jgit.lib.AnyObjectId;
31  import org.eclipse.jgit.lib.Constants;
32  import org.eclipse.jgit.lib.NullProgressMonitor;
33  import org.eclipse.jgit.lib.ObjectChecker;
34  import org.eclipse.jgit.lib.Repository;
35  import org.eclipse.jgit.lib.StoredConfig;
36  import org.eclipse.jgit.revwalk.RevBlob;
37  import org.eclipse.jgit.revwalk.RevCommit;
38  import org.eclipse.jgit.transport.PostReceiveHook;
39  import org.eclipse.jgit.transport.PreReceiveHook;
40  import org.eclipse.jgit.transport.ReceiveCommand;
41  import org.eclipse.jgit.transport.ReceivePack;
42  import org.eclipse.jgit.transport.RemoteRefUpdate;
43  import org.eclipse.jgit.transport.Transport;
44  import org.eclipse.jgit.transport.URIish;
45  import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
46  import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
47  import org.junit.Before;
48  import org.junit.Test;
49  
50  /**
51   * Tests for correct responses of {@link GitServlet}. Especially error
52   * situations where the {@link GitServlet} faces exceptions during request
53   * processing are tested
54   */
55  public class GitServletResponseTests extends HttpTestCase {
56  	private Repository srvRepo;
57  
58  	private URIish srvURI;
59  
60  	private GitServlet gs;
61  
62  	private long maxPackSize = 0; // the maximum pack file size used by
63  									// the server
64  
65  	private PostReceiveHook postHook = null;
66  
67  	private PreReceiveHook preHook = null;
68  
69  	private ObjectChecker oc = null;
70  
71  	/**
72  	 * Setup a http server using {@link GitServlet}. Tests should be able to
73  	 * configure the maximum pack file size, the object checker and custom hooks
74  	 * just before they talk to the server.
75  	 */
76  	@Override
77  	@Before
78  	public void setUp() throws Exception {
79  		super.setUp();
80  
81  		final TestRepository<Repository> srv = createTestRepository();
82  		final String repoName = srv.getRepository().getDirectory().getName();
83  
84  		ServletContextHandler app = server.addContext("/git");
85  		gs = new GitServlet();
86  		gs.setRepositoryResolver((HttpServletRequest req, String name) -> {
87  			if (!name.equals(repoName)) {
88  				throw new RepositoryNotFoundException(name);
89  			}
90  			final Repository db = srv.getRepository();
91  			db.incrementOpen();
92  			return db;
93  		});
94  		gs.setReceivePackFactory(new DefaultReceivePackFactory() {
95  			@Override
96  			public ReceivePack create(HttpServletRequest req, Repository db)
97  					throws ServiceNotEnabledException,
98  					ServiceNotAuthorizedException {
99  				ReceivePack recv = super.create(req, db);
100 				if (maxPackSize > 0)
101 					recv.setMaxPackSizeLimit(maxPackSize);
102 				if (postHook != null)
103 					recv.setPostReceiveHook(postHook);
104 				if (preHook != null)
105 					recv.setPreReceiveHook(preHook);
106 				if (oc != null)
107 					recv.setObjectChecker(oc);
108 				return recv;
109 			}
110 
111 		});
112 		app.addServlet(new ServletHolder(gs), "/*");
113 
114 		server.setUp();
115 
116 		srvRepo = srv.getRepository();
117 		srvURI = toURIish(app, repoName);
118 
119 		StoredConfig cfg = srvRepo.getConfig();
120 		cfg.setBoolean("http", null, "receivepack", true);
121 		cfg.save();
122 	}
123 
124 	/**
125 	 * Configure a {@link GitServlet} that faces a {@link IllegalStateException}
126 	 * during executing preReceiveHooks. This used to lead to exceptions with a
127 	 * description of "invalid channel 101" on the client side. Make sure
128 	 * clients receive the correct response on the correct sideband.
129 	 *
130 	 * @throws Exception
131 	 */
132 	@Test
133 	public void testRuntimeExceptionInPreReceiveHook() throws Exception {
134 		final TestRepository client = createTestRepository();
135 		final RevBlob Q_txt = client
136 				.blob("some blob content to measure pack size");
137 		final RevCommit Q = client.commit().add("Q", Q_txt).create();
138 		final Repository clientRepo = client.getRepository();
139 		final String srvBranchName = Constants.R_HEADS + "new.branch";
140 
141 		maxPackSize = 0;
142 		postHook = null;
143 		preHook = (ReceivePack rp, Collection<ReceiveCommand> commands) -> {
144 			throw new IllegalStateException();
145 		};
146 
147 		try (Transport t = Transport.open(clientRepo, srvURI)) {
148 			RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
149 					srvBranchName, false, null, null);
150 			try {
151 				t.push(NullProgressMonitor.INSTANCE,
152 						Collections.singleton(update));
153 				fail("should not reach this line");
154 			} catch (Exception e) {
155 				assertTrue(e instanceof TransportException);
156 			}
157 		}
158 	}
159 
160 	/**
161 	 * Configure a {@link GitServlet} that faces a {@link IllegalStateException}
162 	 * during executing objectChecking.
163 	 *
164 	 * @throws Exception
165 	 */
166 	@Test
167 	public void testObjectCheckerException() throws Exception {
168 		final TestRepository client = createTestRepository();
169 		final RevBlob Q_txt = client
170 				.blob("some blob content to measure pack size");
171 		final RevCommit Q = client.commit().add("Q", Q_txt).create();
172 		final Repository clientRepo = client.getRepository();
173 		final String srvBranchName = Constants.R_HEADS + "new.branch";
174 
175 		maxPackSize = 0;
176 		postHook = null;
177 		preHook = null;
178 		oc = new ObjectChecker() {
179 			@Override
180 			public void checkCommit(AnyObjectId id, byte[] raw)
181 					throws CorruptObjectException {
182 				throw new CorruptObjectException("refusing all commits");
183 			}
184 		};
185 
186 		try (Transport t = Transport.open(clientRepo, srvURI)) {
187 			RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
188 					srvBranchName, false, null, null);
189 			try {
190 				t.push(NullProgressMonitor.INSTANCE,
191 						Collections.singleton(update));
192 				fail("should not reach this line");
193 			} catch (Exception e) {
194 				assertTrue(e instanceof TransportException);
195 			}
196 		}
197 	}
198 
199 	/**
200 	 * Configure a {@link GitServlet} that faces a {@link TooLargePackException}
201 	 * during persisting the pack and a {@link IllegalStateException} during
202 	 * executing postReceiveHooks. This used to lead to exceptions with a
203 	 * description of "invalid channel 101" on the client side. Make sure
204 	 * clients receive the correct response about the too large pack on the
205 	 * correct sideband.
206 	 *
207 	 * @throws Exception
208 	 */
209 	@Test
210 	public void testUnpackErrorWithSubsequentExceptionInPostReceiveHook()
211 			throws Exception {
212 		final TestRepository client = createTestRepository();
213 		final RevBlob Q_txt = client
214 				.blob("some blob content to measure pack size");
215 		final RevCommit Q = client.commit().add("Q", Q_txt).create();
216 		final Repository clientRepo = client.getRepository();
217 		final String srvBranchName = Constants.R_HEADS + "new.branch";
218 
219 		// this maxPackSize leads to an unPackError
220 		maxPackSize = 100;
221 		// this PostReceiveHook when called after an unsuccesfull unpack will
222 		// lead to an IllegalStateException
223 		postHook = (ReceivePack rp, Collection<ReceiveCommand> commands) -> {
224 			// the maxPackSize setting caused that the packfile couldn't be
225 			// saved to disk. Calling getPackSize() now will lead to a
226 			// IllegalStateException.
227 			rp.getPackSize();
228 		};
229 
230 		try (Transport t = Transport.open(clientRepo, srvURI)) {
231 			RemoteRefUpdate update = new RemoteRefUpdate(clientRepo, Q.name(),
232 					srvBranchName, false, null, null);
233 			try {
234 				t.push(NullProgressMonitor.INSTANCE,
235 						Collections.singleton(update));
236 				fail("should not reach this line");
237 			} catch (Exception e) {
238 				assertTrue(e instanceof TooLargePackException);
239 			}
240 		}
241 	}
242 }