View Javadoc
1   /*
2    * Copyright (C) 2015, Google Inc.
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  
44  package org.eclipse.jgit.transport;
45  
46  import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_REPORT_STATUS;
47  import static org.eclipse.jgit.transport.BasePackPushConnection.CAPABILITY_SIDE_BAND_64K;
48  import static org.eclipse.jgit.transport.RemoteRefUpdate.Status.REJECTED_OTHER_REASON;
49  import static org.junit.Assert.assertEquals;
50  import static org.junit.Assert.fail;
51  
52  import java.io.IOException;
53  import java.io.StringWriter;
54  import java.util.HashMap;
55  import java.util.Map;
56  
57  import org.eclipse.jgit.errors.TransportException;
58  import org.eclipse.jgit.internal.storage.dfs.DfsRepositoryDescription;
59  import org.eclipse.jgit.internal.storage.dfs.InMemoryRepository;
60  import org.eclipse.jgit.lib.Constants;
61  import org.eclipse.jgit.lib.NullProgressMonitor;
62  import org.eclipse.jgit.lib.ObjectId;
63  import org.eclipse.jgit.lib.ObjectInserter;
64  import org.eclipse.jgit.lib.RefUpdate;
65  import org.eclipse.jgit.lib.Repository;
66  import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
67  import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
68  import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
69  import org.junit.After;
70  import org.junit.Before;
71  import org.junit.Test;
72  
73  public class PushConnectionTest {
74  	private URIish uri;
75  	private TestProtocol<Object> testProtocol;
76  	private Object ctx = new Object();
77  	private InMemoryRepository server;
78  	private InMemoryRepository client;
79  	private ObjectId obj1;
80  	private ObjectId obj2;
81  	private ObjectId obj3;
82  	private String refName = "refs/tags/blob";
83  
84  	@Before
85  	public void setUp() throws Exception {
86  		server = newRepo("server");
87  		client = newRepo("client");
88  		testProtocol = new TestProtocol<>(
89  				null,
90  				new ReceivePackFactory<Object>() {
91  					@Override
92  					public ReceivePack create(Object req, Repository db)
93  							throws ServiceNotEnabledException,
94  							ServiceNotAuthorizedException {
95  						return new ReceivePack(db);
96  					}
97  				});
98  		uri = testProtocol.register(ctx, server);
99  
100 		try (ObjectInserter ins = server.newObjectInserter()) {
101 			obj1 = ins.insert(Constants.OBJ_BLOB, Constants.encode("test"));
102 			obj3 = ins.insert(Constants.OBJ_BLOB, Constants.encode("not"));
103 			ins.flush();
104 
105 			RefUpdate u = server.updateRef(refName);
106 			u.setNewObjectId(obj1);
107 			assertEquals(RefUpdate.Result.NEW, u.update());
108 		}
109 
110 		try (ObjectInserter ins = client.newObjectInserter()) {
111 			obj2 = ins.insert(Constants.OBJ_BLOB, Constants.encode("file"));
112 			ins.flush();
113 		}
114 	}
115 
116 	@After
117 	public void tearDown() {
118 		Transport.unregister(testProtocol);
119 	}
120 
121 	private static InMemoryRepository newRepo(String name) {
122 		return new InMemoryRepository(new DfsRepositoryDescription(name));
123 	}
124 
125 	@Test
126 	public void testWrongOldIdDoesNotReplace() throws IOException {
127 		RemoteRefUpdate rru = new RemoteRefUpdate(null, null, obj2, refName,
128 				false, null, obj3);
129 
130 		Map<String, RemoteRefUpdate> updates = new HashMap<>();
131 		updates.put(rru.getRemoteName(), rru);
132 
133 		try (Transport tn = testProtocol.open(uri, client, "server");
134 				PushConnection connection = tn.openPush()) {
135 			connection.push(NullProgressMonitor.INSTANCE, updates);
136 		}
137 
138 		assertEquals(REJECTED_OTHER_REASON, rru.getStatus());
139 		assertEquals("invalid old id sent", rru.getMessage());
140 	}
141 
142 	@Test
143 	public void invalidCommand() throws IOException {
144 		try (Transport tn = testProtocol.open(uri, client, "server");
145 				InternalPushConnection c = (InternalPushConnection) tn.openPush()) {
146 			StringWriter msgs = new StringWriter();
147 			PacketLineOut pckOut = c.pckOut;
148 
149 			@SuppressWarnings("resource")
150 			SideBandInputStream in = new SideBandInputStream(c.in,
151 					NullProgressMonitor.INSTANCE, msgs, null);
152 
153 			// Explicitly invalid command, but sane enough capabilities.
154 			StringBuilder buf = new StringBuilder();
155 			buf.append("42");
156 			buf.append(' ');
157 			buf.append(obj2.name());
158 			buf.append(' ');
159 			buf.append("refs/heads/A" + obj2.name());
160 			buf.append('\0').append(CAPABILITY_SIDE_BAND_64K);
161 			buf.append(' ').append(CAPABILITY_REPORT_STATUS);
162 			buf.append('\n');
163 			pckOut.writeString(buf.toString());
164 			pckOut.end();
165 
166 			try {
167 				in.read();
168 				fail("expected TransportException");
169 			} catch (TransportException e) {
170 				assertEquals(
171 						"remote: error: invalid protocol: wanted 'old new ref'",
172 						e.getMessage());
173 			}
174 		}
175 	}
176 
177 	@Test
178 	public void limitCommandBytes() throws IOException {
179 		Map<String, RemoteRefUpdate> updates = new HashMap<>();
180 		for (int i = 0; i < 4; i++) {
181 			RemoteRefUpdate rru = new RemoteRefUpdate(
182 					null, null, obj2, "refs/test/T" + i,
183 					false, null, ObjectId.zeroId());
184 			updates.put(rru.getRemoteName(), rru);
185 		}
186 
187 		server.getConfig().setInt("receive", null, "maxCommandBytes", 195);
188 		try (Transport tn = testProtocol.open(uri, client, "server");
189 				PushConnection connection = tn.openPush()) {
190 			try {
191 				connection.push(NullProgressMonitor.INSTANCE, updates);
192 				fail("server did not abort");
193 			} catch (TransportException e) {
194 				String msg = e.getMessage();
195 				assertEquals("remote: Too many commands", msg);
196 			}
197 		}
198 	}
199 }