/******************************************************************************* * Copyright (c) 2011, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.orion.server.git.servlets; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Path; import org.eclipse.jgit.errors.ConfigInvalidException; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; import org.eclipse.orion.internal.server.servlets.ServletResourceHandler; import org.eclipse.orion.internal.server.servlets.workspace.authorization.AuthorizationService; import org.eclipse.orion.server.core.ProtocolConstants; import org.eclipse.orion.server.core.ServerStatus; import org.eclipse.orion.server.git.BaseToCloneConverter; import org.eclipse.orion.server.git.GitConstants; import org.eclipse.orion.server.git.objects.Clone; import org.eclipse.orion.server.git.objects.ConfigOption; import org.eclipse.orion.server.servlets.JsonURIUnqualificationStrategy; import org.eclipse.orion.server.servlets.OrionServlet; import org.eclipse.osgi.util.NLS; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; /** * A handler for Git Clone operation. */ public class GitConfigHandlerV1 extends ServletResourceHandler<String> { private ServletResourceHandler<IStatus> statusHandler; GitConfigHandlerV1(ServletResourceHandler<IStatus> statusHandler) { this.statusHandler = statusHandler; } @Override public boolean handleRequest(HttpServletRequest request, HttpServletResponse response, String path) throws ServletException { try { Path p = new Path(path); IPath filePath = p; if (p.segment(0).equals(Clone.RESOURCE) && p.segment(1).equals("file")) { //$NON-NLS-1$ filePath = p.removeFirstSegments(1); } else if (p.segment(1).equals(Clone.RESOURCE) && p.segment(2).equals("file")) { //$NON-NLS-1$ filePath = p.removeFirstSegments(2); } if (!AuthorizationService.checkRights(request.getRemoteUser(), "/" + filePath.toString(), request.getMethod())) { response.sendError(HttpServletResponse.SC_FORBIDDEN); return true; } switch (getMethod(request)) { case GET: return handleGet(request, response, path); case POST: return handlePost(request, response, path); case PUT: return handlePut(request, response, path); case DELETE: return handleDelete(request, response, path); default: return false; } } catch (Exception e) { String msg = NLS.bind("Failed to process an operation on commits for {0}", path); //$NON-NLS-1$ return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg, e)); } } private boolean handleGet(HttpServletRequest request, HttpServletResponse response, String path) throws IOException, JSONException, ServletException, URISyntaxException, CoreException, ConfigInvalidException { Path p = new Path(path); URI baseLocation = getURI(request); if (p.segment(0).equals(Clone.RESOURCE) && p.segment(1).equals("file")) { //$NON-NLS-1$ // expected path /gitapi/config/clone/file/{path} File gitDir = GitUtils.getGitDir(p.removeFirstSegments(1)); if (gitDir == null) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, NLS.bind("No repository found under {0}", p.removeFirstSegments(1)), null)); Repository db = null; try { db = FileRepositoryBuilder.create(gitDir); URI cloneLocation = BaseToCloneConverter.getCloneLocation(baseLocation, BaseToCloneConverter.CONFIG); ConfigOption configOption = new ConfigOption(cloneLocation, db); OrionServlet.writeJSONResponse(request, response, configOption.toJSON(/* all */), JsonURIUnqualificationStrategy.ALL_NO_GIT); return true; } finally { if (db != null) { db.close(); } } } else if (p.segment(1).equals(Clone.RESOURCE) && p.segment(2).equals("file")) { //$NON-NLS-1$ // expected path /gitapi/config/{key}/clone/file/{path} File gitDir = GitUtils.getGitDir(p.removeFirstSegments(2)); if (gitDir == null) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, NLS.bind("No repository found under {0}", p.removeFirstSegments(2)), null)); URI cloneLocation = BaseToCloneConverter.getCloneLocation(baseLocation, BaseToCloneConverter.CONFIG_OPTION); Repository db = null; try { db = FileRepositoryBuilder.create(gitDir); ConfigOption configOption = new ConfigOption(cloneLocation, db, p.segment(0)); if (!configOption.exists()) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, "There is no config entry with key provided", null)); OrionServlet.writeJSONResponse(request, response, configOption.toJSON(), JsonURIUnqualificationStrategy.ALL_NO_GIT); return true; } catch (IllegalArgumentException e) { return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, e.getMessage(), e)); } finally { if (db != null) { db.close(); } } } return false; } private boolean handlePost(HttpServletRequest request, HttpServletResponse response, String path) throws CoreException, IOException, JSONException, ServletException, URISyntaxException, ConfigInvalidException { Path p = new Path(path); if (p.segment(0).equals(Clone.RESOURCE) && p.segment(1).equals("file")) { //$NON-NLS-1$ // expected path /gitapi/config/clone/file/{path} File gitDir = GitUtils.getGitDir(p.removeFirstSegments(1)); if (gitDir == null) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, NLS.bind("No repository found under {0}", p.removeFirstSegments(1)), null)); URI cloneLocation = BaseToCloneConverter.getCloneLocation(getURI(request), BaseToCloneConverter.CONFIG); JSONObject toPost = OrionServlet.readJSONRequest(request); String key = toPost.optString(GitConstants.KEY_CONFIG_ENTRY_KEY, null); if (key == null || key.isEmpty()) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Config entry key must be provided", null)); String value = toPost.optString(GitConstants.KEY_CONFIG_ENTRY_VALUE, null); if (value == null || value.isEmpty()) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Config entry value must be provided", null)); Repository db = null; try { db = FileRepositoryBuilder.create(gitDir); ConfigOption configOption = new ConfigOption(cloneLocation, db, key); boolean present = configOption.exists(); ArrayList<String> valList = new ArrayList<String>(); if (present) { String[] val = configOption.getValue(); valList.addAll(Arrays.asList(val)); } valList.add(value); save(configOption, valList); JSONObject result = configOption.toJSON(); OrionServlet.writeJSONResponse(request, response, result, JsonURIUnqualificationStrategy.ALL_NO_GIT); response.setHeader(ProtocolConstants.HEADER_LOCATION, result.getString(ProtocolConstants.KEY_LOCATION)); response.setStatus(HttpServletResponse.SC_CREATED); return true; } catch (IllegalArgumentException e) { return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, e.getMessage(), e)); } finally { if (db != null) { db.close(); } } } return false; } private boolean handlePut(HttpServletRequest request, HttpServletResponse response, String path) throws CoreException, IOException, JSONException, ServletException, URISyntaxException, ConfigInvalidException { Path p = new Path(path); if (p.segment(1).equals(Clone.RESOURCE) && p.segment(2).equals("file")) { //$NON-NLS-1$ // expected path /gitapi/config/{key}/clone/file/{path} File gitDir = GitUtils.getGitDir(p.removeFirstSegments(2)); if (gitDir == null) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, NLS.bind("No repository found under {0}", p.removeFirstSegments(2)), null)); Repository db = null; URI cloneLocation = BaseToCloneConverter.getCloneLocation(getURI(request), BaseToCloneConverter.CONFIG_OPTION); try { db = FileRepositoryBuilder.create(gitDir); ConfigOption configOption = new ConfigOption(cloneLocation, db, p.segment(0)); JSONObject toPut = OrionServlet.readJSONRequest(request); JSONArray value = toPut.optJSONArray(GitConstants.KEY_CONFIG_ENTRY_VALUE); if (value == null) { String v = toPut.optString(GitConstants.KEY_CONFIG_ENTRY_VALUE); if (v != null && v.length() > 0) { value = new JSONArray(); value.put(v); } } if (value == null || (value.length() == 1 && value.isNull(0))) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Config entry value must be provided", null)); // PUT allows only to modify existing config entries if (!configOption.exists()) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return true; } ArrayList<String> valList = new ArrayList<String>(); for (int i = 0; i < value.length(); i++) { valList.add(value.getString(i)); } save(configOption, valList); JSONObject result = configOption.toJSON(); OrionServlet.writeJSONResponse(request, response, result); response.setHeader(ProtocolConstants.HEADER_LOCATION, result.getString(ProtocolConstants.KEY_LOCATION)); return true; } catch (IllegalArgumentException e) { return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, e.getMessage(), e)); } finally { if (db != null) { db.close(); } } } return false; } private boolean handleDelete(HttpServletRequest request, HttpServletResponse response, String path) throws CoreException, IOException, ServletException, ConfigInvalidException, URISyntaxException { Path p = new Path(path); if (p.segment(1).equals(Clone.RESOURCE) && p.segment(2).equals("file")) { //$NON-NLS-1$ // expected path /gitapi/config/{key}/clone/file/{path} File gitDir = GitUtils.getGitDir(p.removeFirstSegments(2)); if (gitDir == null) return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_NOT_FOUND, NLS.bind("No repository found under {0}", p.removeFirstSegments(2)), null)); Repository db = null; URI cloneLocation = BaseToCloneConverter.getCloneLocation(getURI(request), BaseToCloneConverter.CONFIG_OPTION); try { db = FileRepositoryBuilder.create(gitDir); ConfigOption configOption = new ConfigOption(cloneLocation, db, GitUtils.decode(p.segment(0))); if (configOption.exists()) { String query = request.getParameter("index"); //$NON-NLS-1$ if (query != null) { List<String> existing = new ArrayList<String>(Arrays.asList(configOption.getValue())); existing.remove(Integer.parseInt(query)); save(configOption, existing); } else { delete(configOption); } response.setStatus(HttpServletResponse.SC_OK); } else { response.setStatus(HttpServletResponse.SC_NOT_FOUND); } return true; } catch (IllegalArgumentException e) { return statusHandler.handleRequest(request, response, new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, e.getMessage(), e)); } finally { if (db != null) { db.close(); } } } return false; } private static void save(ConfigOption co, List<String> value) throws IOException { co.getConfig().setStringList(co.getSection(), co.getSubsection(), co.getName(), value); co.getConfig().save(); } private static void delete(ConfigOption co) throws IOException { co.getConfig().unset(co.getSection(), co.getSubsection(), co.getName()); co.getConfig().save(); } }