Skip to content

Commit 4aafd43

Browse files
committed
Poke test during proposal phase.
1 parent b083f5a commit 4aafd43

File tree

6 files changed

+124
-20
lines changed

6 files changed

+124
-20
lines changed

src/com/gitblit/Constants.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ public String toString() {
115115
* Enumeration representing the types of federation requests.
116116
*/
117117
public static enum FederationRequest {
118-
PROPOSAL, PULL_REPOSITORIES, PULL_USERS, PULL_SETTINGS, STATUS;
118+
POKE, PROPOSAL, PULL_REPOSITORIES, PULL_USERS, PULL_SETTINGS, STATUS;
119119

120120
public static FederationRequest fromName(String name) {
121121
for (FederationRequest type : values()) {
@@ -181,4 +181,16 @@ public String toString() {
181181
}
182182
}
183183

184+
/**
185+
* Enumeration representing the possible results of federation proposal
186+
* requests.
187+
*/
188+
public static enum FederationProposalResult {
189+
ERROR, FEDERATION_DISABLED, MISSING_DATA, NO_PROPOSALS, NO_POKE, ACCEPTED;
190+
191+
@Override
192+
public String toString() {
193+
return name();
194+
}
195+
}
184196
}

src/com/gitblit/FederationServlet.java

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import com.gitblit.models.FederationProposal;
3636
import com.gitblit.models.RepositoryModel;
3737
import com.gitblit.models.UserModel;
38+
import com.gitblit.utils.FederationUtils;
3839
import com.gitblit.utils.HttpUtils;
3940
import com.gitblit.utils.StringUtils;
4041
import com.gitblit.utils.TimeUtils;
@@ -110,6 +111,16 @@ public static String asFederationLink(String remoteURL, FederationToken tokenTyp
110111
private void processRequest(javax.servlet.http.HttpServletRequest request,
111112
javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
112113
java.io.IOException {
114+
FederationRequest reqType = FederationRequest.fromName(request.getParameter("req"));
115+
logger.info(MessageFormat.format("Federation {0} request from {1}", reqType,
116+
request.getRemoteAddr()));
117+
118+
if (FederationRequest.POKE.equals(reqType)) {
119+
// Gitblit always responds to POKE requests to verify a connection
120+
logger.info("Received federation POKE from " + request.getRemoteAddr());
121+
return;
122+
}
123+
113124
if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
114125
logger.warn(Keys.git.enableGitServlet + " must be set TRUE for federation requests.");
115126
response.sendError(HttpServletResponse.SC_FORBIDDEN);
@@ -124,11 +135,6 @@ private void processRequest(javax.servlet.http.HttpServletRequest request,
124135
return;
125136
}
126137

127-
String token = request.getParameter("token");
128-
FederationRequest reqType = FederationRequest.fromName(request.getParameter("req"));
129-
logger.info(MessageFormat.format("Federation {0} request from {1}", reqType,
130-
request.getRemoteAddr()));
131-
132138
if (FederationRequest.PROPOSAL.equals(reqType)) {
133139
// Receive a gitblit federation proposal
134140
BufferedReader reader = request.getReader();
@@ -159,6 +165,20 @@ private void processRequest(javax.servlet.http.HttpServletRequest request,
159165
return;
160166
}
161167

168+
// poke the origin Gitblit instance that is proposing federation
169+
boolean poked = false;
170+
try {
171+
poked = FederationUtils.poke(proposal.url);
172+
} catch (Exception e) {
173+
logger.error("Failed to poke origin", e);
174+
}
175+
if (!poked) {
176+
logger.error(MessageFormat.format("Failed to send federation poke to {0}",
177+
proposal.url));
178+
response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
179+
return;
180+
}
181+
162182
String url = HttpUtils.getGitblitURL(request);
163183
GitBlit.self().submitFederationProposal(proposal, url);
164184
logger.info(MessageFormat.format(
@@ -207,6 +227,7 @@ private void processRequest(javax.servlet.http.HttpServletRequest request,
207227
}
208228

209229
// Determine the federation tokens for this gitblit instance
230+
String token = request.getParameter("token");
210231
List<String> tokens = GitBlit.self().getFederationTokens();
211232
if (!tokens.contains(token)) {
212233
logger.warn(MessageFormat.format(

src/com/gitblit/GitBlit.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -971,7 +971,8 @@ public List<FederationModel> getFederationResultRegistrations() {
971971
* @param proposal
972972
* the proposal
973973
* @param gitblitUrl
974-
* the url of your gitblit instance
974+
* the url of your gitblit instance to send an email to
975+
* administrators
975976
* @return true if the proposal was submitted
976977
*/
977978
public boolean submitFederationProposal(FederationProposal proposal, String gitblitUrl) {

src/com/gitblit/utils/FederationUtils.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import org.slf4j.Logger;
4646
import org.slf4j.LoggerFactory;
4747

48+
import com.gitblit.Constants.FederationProposalResult;
4849
import com.gitblit.Constants.FederationRequest;
4950
import com.gitblit.FederationServlet;
5051
import com.gitblit.IStoredSettings;
@@ -82,7 +83,7 @@ public class FederationUtils {
8283
private static final SSLContext SSL_CONTEXT;
8384

8485
private static final DummyHostnameVerifier HOSTNAME_VERIFIER;
85-
86+
8687
private static final Logger LOGGER = LoggerFactory.getLogger(FederationUtils.class);
8788

8889
static {
@@ -181,22 +182,61 @@ public static List<FederationModel> getFederationRegistrations(IStoredSettings s
181182
return federationRegistrations;
182183
}
183184

185+
/**
186+
* Sends a federation poke to the Gitblit instance at remoteUrl. Pokes are
187+
* sent by an pulling Gitblit instance to an origin Gitblit instance as part
188+
* of the proposal process. This is to ensure that the pulling Gitblit
189+
* instance has an IP route to the origin instance.
190+
*
191+
* @param remoteUrl
192+
* the remote Gitblit instance to send a federation proposal to
193+
* @param proposal
194+
* a complete federation proposal
195+
* @return true if there is a route to the remoteUrl
196+
*/
197+
public static boolean poke(String remoteUrl) throws Exception {
198+
String url = FederationServlet.asFederationLink(remoteUrl, null, FederationRequest.POKE);
199+
Gson gson = new Gson();
200+
String json = gson.toJson("POKE");
201+
int status = writeJson(url, json);
202+
return status == HttpServletResponse.SC_OK;
203+
}
204+
184205
/**
185206
* Sends a federation proposal to the Gitblit instance at remoteUrl
186207
*
187208
* @param remoteUrl
188209
* the remote Gitblit instance to send a federation proposal to
189210
* @param proposal
190211
* a complete federation proposal
191-
* @return true if the proposal was received
212+
* @return the federation proposal result code
192213
*/
193-
public static boolean propose(String remoteUrl, FederationProposal proposal) throws Exception {
214+
public static FederationProposalResult propose(String remoteUrl, FederationProposal proposal)
215+
throws Exception {
194216
String url = FederationServlet
195217
.asFederationLink(remoteUrl, null, FederationRequest.PROPOSAL);
196218
Gson gson = new GsonBuilder().setPrettyPrinting().create();
197219
String json = gson.toJson(proposal);
198220
int status = writeJson(url, json);
199-
return status == HttpServletResponse.SC_OK;
221+
switch (status) {
222+
case HttpServletResponse.SC_FORBIDDEN:
223+
// remote Gitblit Federation disabled
224+
return FederationProposalResult.FEDERATION_DISABLED;
225+
case HttpServletResponse.SC_BAD_REQUEST:
226+
// remote Gitblit did not receive any JSON data
227+
return FederationProposalResult.MISSING_DATA;
228+
case HttpServletResponse.SC_METHOD_NOT_ALLOWED:
229+
// remote Gitblit not accepting proposals
230+
return FederationProposalResult.NO_PROPOSALS;
231+
case HttpServletResponse.SC_NOT_ACCEPTABLE:
232+
// remote Gitblit failed to poke this Gitblit instance
233+
return FederationProposalResult.NO_POKE;
234+
case HttpServletResponse.SC_OK:
235+
// received
236+
return FederationProposalResult.ACCEPTED;
237+
default:
238+
return FederationProposalResult.ERROR;
239+
}
200240
}
201241

202242
/**

src/com/gitblit/wicket/pages/SendProposalPage.java

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.apache.wicket.markup.html.form.TextField;
2727
import org.apache.wicket.model.CompoundPropertyModel;
2828

29+
import com.gitblit.Constants.FederationProposalResult;
2930
import com.gitblit.GitBlit;
3031
import com.gitblit.models.FederationProposal;
3132
import com.gitblit.models.RepositoryModel;
@@ -78,17 +79,44 @@ protected void onSubmit() {
7879
error("Please enter a destination url for your proposal!");
7980
return;
8081
}
81-
82+
8283
// build new proposal
8384
FederationProposal proposal = GitBlit.self().createFederationProposal(myUrl, token);
8485
proposal.url = myUrl;
8586
proposal.message = message;
8687
try {
87-
if (FederationUtils.propose(destinationUrl, proposal)) {
88-
info(MessageFormat.format("Proposal successfully received by {0}.", destinationUrl));
88+
FederationProposalResult res = FederationUtils
89+
.propose(destinationUrl, proposal);
90+
switch (res) {
91+
case ACCEPTED:
92+
info(MessageFormat.format("Proposal successfully received by {0}.",
93+
destinationUrl));
8994
setResponsePage(RepositoriesPage.class);
90-
} else {
91-
error(MessageFormat.format("Sorry, {0} rejected your proposal.", destinationUrl));
95+
break;
96+
case NO_POKE:
97+
error(MessageFormat.format(
98+
"Sorry, {0} could not find a Gitblit instance at {1}.",
99+
destinationUrl, myUrl));
100+
break;
101+
case NO_PROPOSALS:
102+
error(MessageFormat.format(
103+
"Sorry, {0} is not accepting proposals at this time.",
104+
destinationUrl));
105+
break;
106+
case FEDERATION_DISABLED:
107+
error(MessageFormat
108+
.format("Sorry, {0} is not configured to federate with any Gitblit instances.",
109+
destinationUrl));
110+
break;
111+
case MISSING_DATA:
112+
error(MessageFormat.format("Sorry, {0} did not receive any proposal data!",
113+
destinationUrl));
114+
break;
115+
case ERROR:
116+
error(MessageFormat.format(
117+
"Sorry, {0} reports that an unexpected error occurred!",
118+
destinationUrl));
119+
break;
92120
}
93121
} catch (Exception e) {
94122
if (!StringUtils.isEmpty(e.getMessage())) {

tests/com/gitblit/tests/FederationTests.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import junit.framework.TestCase;
2525

2626
import com.gitblit.Constants.AccessRestrictionType;
27+
import com.gitblit.Constants.FederationProposalResult;
2728
import com.gitblit.Constants.FederationRequest;
2829
import com.gitblit.Constants.FederationToken;
2930
import com.gitblit.FederationServlet;
@@ -91,14 +92,15 @@ public void testProposal() throws Exception {
9192
"testtoken", repositories);
9293

9394
// propose federation
94-
assertTrue("proposal refused",
95-
FederationUtils.propose("http://localhost:" + port, proposal));
95+
assertEquals("proposal refused",
96+
FederationUtils.propose("http://localhost:" + port, proposal),
97+
FederationProposalResult.NO_PROPOSALS);
9698
}
9799

98100
public void testPullRepositories() throws Exception {
99101
try {
100-
String url = FederationServlet.asFederationLink("http://localhost:" + port, "testtoken",
101-
FederationRequest.PULL_REPOSITORIES);
102+
String url = FederationServlet.asFederationLink("http://localhost:" + port,
103+
"testtoken", FederationRequest.PULL_REPOSITORIES);
102104
String json = FederationUtils.readJson(url);
103105
} catch (IOException e) {
104106
if (!e.getMessage().contains("403")) {

0 commit comments

Comments
 (0)