| | |
| | | */
|
| | | package com.gitblit;
|
| | |
|
| | | import java.io.BufferedReader;
|
| | | import java.text.MessageFormat;
|
| | | import java.util.ArrayList;
|
| | | import java.util.Date;
|
| | |
| | | import java.util.List;
|
| | | import java.util.Map;
|
| | |
|
| | | import javax.servlet.http.HttpServlet;
|
| | | import javax.servlet.http.HttpServletResponse;
|
| | |
|
| | | import org.slf4j.Logger;
|
| | | import org.slf4j.LoggerFactory;
|
| | |
|
| | | import com.gitblit.Constants.FederationRequest;
|
| | | import com.gitblit.Constants.FederationToken;
|
| | | import com.gitblit.models.FederationModel;
|
| | | import com.gitblit.models.FederationProposal;
|
| | | import com.gitblit.models.RepositoryModel;
|
| | | import com.gitblit.models.TeamModel;
|
| | | import com.gitblit.models.UserModel;
|
| | | import com.gitblit.utils.FederationUtils;
|
| | | import com.gitblit.utils.HttpUtils;
|
| | | import com.gitblit.utils.StringUtils;
|
| | | import com.gitblit.utils.TimeUtils;
|
| | | import com.google.gson.Gson;
|
| | | import com.google.gson.GsonBuilder;
|
| | |
|
| | | /**
|
| | | * Handles federation requests.
|
| | |
| | | * @author James Moger
|
| | | *
|
| | | */
|
| | | public class FederationServlet extends HttpServlet {
|
| | | public class FederationServlet extends JsonServlet {
|
| | |
|
| | | private static final long serialVersionUID = 1L;
|
| | |
|
| | | private transient Logger logger = LoggerFactory.getLogger(FederationServlet.class);
|
| | |
|
| | | public FederationServlet() {
|
| | | super();
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns an url to this servlet for the specified parameters.
|
| | | * |
| | | * @param sourceURL
|
| | | * the url of the source gitblit instance
|
| | | * @param token
|
| | | * the federation token of the source gitblit instance
|
| | | * @param req
|
| | | * the pull type request
|
| | | */
|
| | | public static String asPullLink(String sourceURL, String token, FederationRequest req) {
|
| | | return asFederationLink(sourceURL, null, token, req, null);
|
| | | }
|
| | |
|
| | | /**
|
| | | * |
| | | * @param remoteURL
|
| | | * the url of the remote gitblit instance
|
| | | * @param tokenType
|
| | | * the type of federation token of a gitblit instance
|
| | | * @param token
|
| | | * the federation token of a gitblit instance
|
| | | * @param req
|
| | | * the pull type request
|
| | | * @param myURL
|
| | | * the url of this gitblit instance
|
| | | * @return
|
| | | */
|
| | | public static String asFederationLink(String remoteURL, FederationToken tokenType,
|
| | | String token, FederationRequest req, String myURL) {
|
| | | if (remoteURL.length() > 0 && remoteURL.charAt(remoteURL.length() - 1) == '/') {
|
| | | remoteURL = remoteURL.substring(0, remoteURL.length() - 1);
|
| | | }
|
| | | if (req == null) {
|
| | | req = FederationRequest.PULL_REPOSITORIES;
|
| | | }
|
| | | return remoteURL + Constants.FEDERATION_PATH + "?req=" + req.name().toLowerCase()
|
| | | + "&token=" + token
|
| | | + (tokenType == null ? "" : ("&tokenType=" + tokenType.name().toLowerCase()))
|
| | | + (myURL == null ? "" : ("&url=" + StringUtils.encodeURL(myURL)));
|
| | | }
|
| | |
|
| | | /**
|
| | | * Returns the list of repositories for federation requests.
|
| | | * Processes a federation request.
|
| | | *
|
| | | * @param request
|
| | | * @param response
|
| | | * @throws javax.servlet.ServletException
|
| | | * @throws java.io.IOException
|
| | | */
|
| | | private void processRequest(javax.servlet.http.HttpServletRequest request,
|
| | |
|
| | | @Override
|
| | | protected void processRequest(javax.servlet.http.HttpServletRequest request,
|
| | | javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
| | | java.io.IOException {
|
| | | FederationRequest reqType = FederationRequest.fromName(request.getParameter("req"));
|
| | | logger.info(MessageFormat.format("Federation {0} request from {1}", reqType,
|
| | | request.getRemoteAddr()));
|
| | |
|
| | | if (FederationRequest.POKE.equals(reqType)) {
|
| | | // Gitblit always responds to POKE requests to verify a connection
|
| | | logger.info("Received federation POKE from " + request.getRemoteAddr());
|
| | | return;
|
| | | }
|
| | |
|
| | | if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
|
| | | logger.warn(Keys.git.enableGitServlet + " must be set TRUE for federation requests.");
|
| | | response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
| | |
| | | return;
|
| | | }
|
| | |
|
| | | String token = request.getParameter("token");
|
| | | FederationRequest reqType = FederationRequest.fromName(request.getParameter("req"));
|
| | | logger.info(MessageFormat.format("Federation {0} request from {1}", reqType,
|
| | | request.getRemoteAddr()));
|
| | |
|
| | | if (FederationRequest.PROPOSAL.equals(reqType)) {
|
| | | // Receive a gitblit federation proposal
|
| | | String url = StringUtils.decodeFromHtml(request.getParameter("url"));
|
| | | FederationToken tokenType = FederationToken.fromName(request.getParameter("tokenType"));
|
| | | FederationProposal proposal = deserialize(request, response, FederationProposal.class);
|
| | | if (proposal == null) {
|
| | | return;
|
| | | }
|
| | |
|
| | | // reject proposal, if not receipt prohibited
|
| | | if (!GitBlit.getBoolean(Keys.federation.allowProposals, false)) {
|
| | | logger.error(MessageFormat.format("Rejected {0} federation proposal from {1}",
|
| | | tokenType.name(), url));
|
| | | proposal.tokenType.name(), proposal.url));
|
| | | response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
|
| | | return;
|
| | | }
|
| | |
|
| | | BufferedReader reader = request.getReader();
|
| | | StringBuilder json = new StringBuilder();
|
| | | String line = null;
|
| | | while ((line = reader.readLine()) != null) {
|
| | | json.append(line);
|
| | | // poke the origin Gitblit instance that is proposing federation
|
| | | boolean poked = false;
|
| | | try {
|
| | | poked = FederationUtils.poke(proposal.url);
|
| | | } catch (Exception e) {
|
| | | logger.error("Failed to poke origin", e);
|
| | | }
|
| | | reader.close();
|
| | |
|
| | | // check to see if we have repository data
|
| | | if (json.length() == 0) {
|
| | | logger.error(MessageFormat.format(
|
| | | "Failed to receive proposed repositories list from {0}", url));
|
| | | response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
| | | if (!poked) {
|
| | | logger.error(MessageFormat.format("Failed to send federation poke to {0}",
|
| | | proposal.url));
|
| | | response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
|
| | | return;
|
| | | }
|
| | |
|
| | | // deserialize the repository data
|
| | | Gson gson = new Gson();
|
| | | Map<String, RepositoryModel> repositories = gson.fromJson(json.toString(),
|
| | | FederationUtils.REPOSITORIES_TYPE);
|
| | |
|
| | | // submit a proposal
|
| | | FederationProposal proposal = new FederationProposal(url, tokenType, token,
|
| | | repositories);
|
| | | String hosturl = HttpUtils.getHostURL(request);
|
| | | String gitblitUrl = hosturl + request.getContextPath();
|
| | | GitBlit.self().submitFederationProposal(proposal, gitblitUrl);
|
| | | String url = HttpUtils.getGitblitURL(request);
|
| | | GitBlit.self().submitFederationProposal(proposal, url);
|
| | | logger.info(MessageFormat.format(
|
| | | "Submitted {0} federation proposal to pull {1} repositories from {2}",
|
| | | tokenType.name(), repositories.size(), url));
|
| | | proposal.tokenType.name(), proposal.repositories.size(), proposal.url));
|
| | | response.setStatus(HttpServletResponse.SC_OK);
|
| | | return;
|
| | | }
|
| | |
| | | String remoteId = StringUtils.decodeFromHtml(request.getParameter("url"));
|
| | | String identification = MessageFormat.format("{0} ({1})", remoteId,
|
| | | request.getRemoteAddr());
|
| | | BufferedReader reader = request.getReader();
|
| | | StringBuilder json = new StringBuilder();
|
| | | String line = null;
|
| | | while ((line = reader.readLine()) != null) {
|
| | | json.append(line);
|
| | | }
|
| | | reader.close();
|
| | |
|
| | | // check to see if we have repository data
|
| | | if (json.length() == 0) {
|
| | | logger.error(MessageFormat.format(
|
| | | "Failed to receive pulled repositories list from {0}", identification));
|
| | | response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
|
| | | // deserialize the status data
|
| | | FederationModel results = deserialize(request, response, FederationModel.class);
|
| | | if (results == null) {
|
| | | return;
|
| | | }
|
| | |
|
| | | // deserialize the status data
|
| | | Gson gson = new Gson();
|
| | | FederationModel results = gson.fromJson(json.toString(), FederationModel.class);
|
| | | // setup the last and netx pull dates
|
| | | results.lastPull = new Date();
|
| | | int mins = TimeUtils.convertFrequencyToMinutes(results.frequency);
|
| | |
| | | }
|
| | |
|
| | | // Determine the federation tokens for this gitblit instance
|
| | | String token = request.getParameter("token");
|
| | | List<String> tokens = GitBlit.self().getFederationTokens();
|
| | | if (!tokens.contains(token)) {
|
| | | logger.warn(MessageFormat.format(
|
| | |
| | |
|
| | | Object result = null;
|
| | | if (FederationRequest.PULL_REPOSITORIES.equals(reqType)) {
|
| | | // Determine the Gitblit clone url
|
| | | StringBuilder sb = new StringBuilder();
|
| | | sb.append(HttpUtils.getHostURL(request));
|
| | | sb.append(Constants.GIT_PATH);
|
| | | sb.append("{0}");
|
| | | String cloneUrl = sb.toString();
|
| | |
|
| | | // Retrieve all available repositories
|
| | | UserModel user = new UserModel(Constants.FEDERATION_USER);
|
| | | user.canAdmin = true;
|
| | | List<RepositoryModel> list = GitBlit.self().getRepositoryModels(user);
|
| | |
|
| | | // create the [cloneurl, repositoryModel] map
|
| | | Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>();
|
| | | for (RepositoryModel model : list) {
|
| | | // by default, setup the url for THIS repository
|
| | | String url = MessageFormat.format(cloneUrl, model.name);
|
| | | switch (model.federationStrategy) {
|
| | | case EXCLUDE:
|
| | | // skip this repository
|
| | | continue;
|
| | | case FEDERATE_ORIGIN:
|
| | | // federate the origin, if it is defined
|
| | | if (!StringUtils.isEmpty(model.origin)) {
|
| | | url = model.origin;
|
| | | }
|
| | | break;
|
| | | }
|
| | | repositories.put(url, model);
|
| | | }
|
| | | result = repositories;
|
| | | String gitblitUrl = HttpUtils.getGitblitURL(request);
|
| | | result = GitBlit.self().getRepositories(gitblitUrl, token);
|
| | | } else {
|
| | | if (FederationRequest.PULL_SETTINGS.equals(reqType)) {
|
| | | // pull settings
|
| | |
| | | }
|
| | | }
|
| | | result = users;
|
| | | } else if (FederationRequest.PULL_TEAMS.equals(reqType)) {
|
| | | // pull teams
|
| | | if (!GitBlit.self().validateFederationRequest(reqType, token)) {
|
| | | // invalid token to pull teams
|
| | | logger.warn(MessageFormat.format(
|
| | | "Federation token from {0} not authorized to pull TEAMS",
|
| | | request.getRemoteAddr()));
|
| | | response.sendError(HttpServletResponse.SC_FORBIDDEN);
|
| | | return;
|
| | | }
|
| | | List<String> teamnames = GitBlit.self().getAllTeamnames();
|
| | | List<TeamModel> teams = new ArrayList<TeamModel>();
|
| | | for (String teamname : teamnames) {
|
| | | TeamModel user = GitBlit.self().getTeamModel(teamname);
|
| | | teams.add(user);
|
| | | }
|
| | | result = teams;
|
| | | }
|
| | | }
|
| | |
|
| | | if (result != null) {
|
| | | // Send JSON response
|
| | | Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
| | | String json = gson.toJson(result);
|
| | | response.getWriter().append(json);
|
| | | }
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void doPost(javax.servlet.http.HttpServletRequest request,
|
| | | javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
| | | java.io.IOException {
|
| | | processRequest(request, response);
|
| | | }
|
| | |
|
| | | @Override
|
| | | protected void doGet(javax.servlet.http.HttpServletRequest request,
|
| | | javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
|
| | | java.io.IOException {
|
| | | processRequest(request, response);
|
| | | // send the result of the request
|
| | | serialize(response, result);
|
| | | }
|
| | | }
|