\r
additions: \r
- Added a server setting to force a particular translation/Locale for all sessions\r
- - Added Git Daemon serving\r
+ - Added smart Git Daemon serving. If enabled, git:// access will be offered for any repository which permits anonymous access. If the repository permits anonymous cloning, anonymous git:// clone will be permitted while anonmymous git:// pushes will be rejected.
- Option to automatically tag branch tips on each push with an incremental revision number\r
- Implemented multiple repository owners\r
- Optional periodic LDAP user and team pre-fetching & synchronization\r
try {\r
gitDaemon = new GitDaemon(bindInterface, port, getRepositoriesFolder());\r
gitDaemon.start();\r
- logger.info(MessageFormat.format("Git daemon is listening on {0}:{1,number,0}", bindInterface, port));\r
} catch (IOException e) {\r
gitDaemon = null;\r
logger.error(MessageFormat.format("Failed to start Git daemon on {0}:{1,number,0}", bindInterface, port), e);\r
/*\r
- * Copyright 2013 gitblit.com.\r
+ * Copyright (C) 2013 gitblit.com\r
+ * Copyright (C) 2008-2009, Google Inc.\r
+ * and other copyright owners as documented in the project's IP log.\r
*\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
+ * This program and the accompanying materials are made available\r
+ * under the terms of the Eclipse Distribution License v1.0 which\r
+ * accompanies this distribution, is reproduced below, and is\r
+ * available at http://www.eclipse.org/org/documents/edl-v10.php\r
*\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
+ * All rights reserved.\r
*\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials provided\r
+ * with the distribution.\r
+ *\r
+ * - Neither the name of the Eclipse Foundation, Inc. nor the\r
+ * names of its contributors may be used to endorse or promote\r
+ * products derived from this software without specific prior\r
+ * written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
*/\r
package com.gitblit.git;\r
\r
import java.io.File;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.InterruptedIOException;\r
+import java.io.OutputStream;\r
import java.net.InetSocketAddress;\r
+import java.net.ServerSocket;\r
+import java.net.Socket;\r
+import java.net.SocketAddress;\r
+import java.text.MessageFormat;\r
+import java.util.concurrent.atomic.AtomicBoolean;\r
\r
-import org.eclipse.jgit.transport.Daemon;\r
-import org.eclipse.jgit.transport.DaemonClient;\r
+import org.eclipse.jgit.errors.RepositoryNotFoundException;\r
+import org.eclipse.jgit.internal.JGitText;\r
+import org.eclipse.jgit.lib.Repository;\r
+import org.eclipse.jgit.transport.ReceivePack;\r
+import org.eclipse.jgit.transport.ServiceMayNotContinueException;\r
+import org.eclipse.jgit.transport.UploadPack;\r
+import org.eclipse.jgit.transport.resolver.ReceivePackFactory;\r
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;\r
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;\r
+import org.eclipse.jgit.transport.resolver.UploadPackFactory;\r
+import org.slf4j.Logger;\r
+import org.slf4j.LoggerFactory;\r
\r
import com.gitblit.utils.StringUtils;\r
\r
/**\r
- * Gitblit's Git Daemon ignores any and all per-repository daemon settings\r
- * and integrates into Gitblit's security model.\r
+ * Gitblit's Git Daemon ignores any and all per-repository daemon settings and\r
+ * integrates into Gitblit's security model.\r
* \r
* @author James Moger\r
- *\r
+ * \r
*/\r
-public class GitDaemon extends Daemon {\r
+public class GitDaemon {\r
+\r
+ private final Logger logger = LoggerFactory.getLogger(GitDaemon.class);\r
+\r
+ /** 9418: IANA assigned port number for Git. */\r
+ public static final int DEFAULT_PORT = 9418;\r
+\r
+ private static final int BACKLOG = 5;\r
+\r
+ private InetSocketAddress myAddress;\r
+\r
+ private final GitDaemonService[] services;\r
+\r
+ private final ThreadGroup processors;\r
+\r
+ private AtomicBoolean run;\r
+\r
+ private ServerSocket acceptSocket;\r
+\r
+ private Thread acceptThread;\r
+\r
+ private int timeout;\r
+\r
+ private RepositoryResolver<GitDaemonClient> repositoryResolver;\r
+\r
+ private UploadPackFactory<GitDaemonClient> uploadPackFactory;\r
+\r
+ private ReceivePackFactory<GitDaemonClient> receivePackFactory;\r
+\r
+ /** Configure a daemon to listen on any available network port. */\r
+ public GitDaemon() {\r
+ this(null);\r
+ }\r
\r
/**\r
* Construct the Gitblit Git daemon.\r
* the folder to serve from\r
*/\r
public GitDaemon(String bindInterface, int port, File folder) {\r
- super(StringUtils.isEmpty(bindInterface) ? new InetSocketAddress(port) : new InetSocketAddress(bindInterface, port));\r
- \r
+ this(StringUtils.isEmpty(bindInterface) ? new InetSocketAddress(port)\r
+ : new InetSocketAddress(bindInterface, port));\r
+\r
// set the repository resolver and pack factories\r
- setRepositoryResolver(new RepositoryResolver<DaemonClient>(folder));\r
- setUploadPackFactory(new GitblitUploadPackFactory<DaemonClient>());\r
- setReceivePackFactory(new GitblitReceivePackFactory<DaemonClient>());\r
- \r
- // configure the git daemon to ignore the per-repository settings,\r
- // daemon.uploadpack and daemon.receivepack\r
- getService("git-upload-pack").setOverridable(false);\r
- getService("git-receive-pack").setOverridable(false);\r
- \r
- // enable both the upload and receive services and let the resolver,\r
- // pack factories, and receive hook handle security\r
- getService("git-upload-pack").setEnabled(true);\r
- getService("git-receive-pack").setEnabled(true);\r
+ repositoryResolver = new RepositoryResolver<GitDaemonClient>(folder);\r
}\r
\r
+ /**\r
+ * Configure a new daemon for the specified network address.\r
+ * \r
+ * @param addr\r
+ * address to listen for connections on. If null, any available\r
+ * port will be chosen on all network interfaces.\r
+ */\r
+ public GitDaemon(final InetSocketAddress addr) {\r
+ myAddress = addr;\r
+ processors = new ThreadGroup("Git-Daemon");\r
+\r
+ run = new AtomicBoolean(false);\r
+ repositoryResolver = null;\r
+ uploadPackFactory = new GitblitUploadPackFactory<GitDaemonClient>();\r
+ receivePackFactory = new GitblitReceivePackFactory<GitDaemonClient>();\r
+\r
+ services = new GitDaemonService[] { new GitDaemonService("upload-pack", "uploadpack") {\r
+ {\r
+ setEnabled(true);\r
+ setOverridable(false);\r
+ }\r
+\r
+ @Override\r
+ protected void execute(final GitDaemonClient dc, final Repository db)\r
+ throws IOException, ServiceNotEnabledException,\r
+ ServiceNotAuthorizedException {\r
+ UploadPack up = uploadPackFactory.create(dc, db);\r
+ InputStream in = dc.getInputStream();\r
+ OutputStream out = dc.getOutputStream();\r
+ up.upload(in, out, null);\r
+ }\r
+ }, new GitDaemonService("receive-pack", "receivepack") {\r
+ {\r
+ setEnabled(true);\r
+ setOverridable(false);\r
+ }\r
+\r
+ @Override\r
+ protected void execute(final GitDaemonClient dc, final Repository db)\r
+ throws IOException, ServiceNotEnabledException,\r
+ ServiceNotAuthorizedException {\r
+ ReceivePack rp = receivePackFactory.create(dc, db);\r
+ InputStream in = dc.getInputStream();\r
+ OutputStream out = dc.getOutputStream();\r
+ rp.receive(in, out, null);\r
+ }\r
+ } };\r
+ }\r
+\r
+ /** @return timeout (in seconds) before aborting an IO operation. */\r
+ public int getTimeout() {\r
+ return timeout;\r
+ }\r
+\r
+ /**\r
+ * Set the timeout before willing to abort an IO call.\r
+ * \r
+ * @param seconds\r
+ * number of seconds to wait (with no data transfer occurring)\r
+ * before aborting an IO read or write operation with the\r
+ * connected client.\r
+ */\r
+ public void setTimeout(final int seconds) {\r
+ timeout = seconds;\r
+ }\r
+\r
+ /**\r
+ * Start this daemon on a background thread.\r
+ * \r
+ * @throws IOException\r
+ * the server socket could not be opened.\r
+ * @throws IllegalStateException\r
+ * the daemon is already running.\r
+ */\r
+ public synchronized void start() throws IOException {\r
+ if (acceptThread != null)\r
+ throw new IllegalStateException(JGitText.get().daemonAlreadyRunning);\r
+\r
+ final ServerSocket listenSock = new ServerSocket(myAddress != null ? myAddress.getPort()\r
+ : 0, BACKLOG, myAddress != null ? myAddress.getAddress() : null);\r
+ myAddress = (InetSocketAddress) listenSock.getLocalSocketAddress();\r
+\r
+ run.set(true);\r
+ acceptSocket = listenSock;\r
+ acceptThread = new Thread(processors, "Git-Daemon-Accept") {\r
+ public void run() {\r
+ while (isRunning()) {\r
+ try {\r
+ startClient(listenSock.accept());\r
+ } catch (InterruptedIOException e) {\r
+ // Test again to see if we should keep accepting.\r
+ } catch (IOException e) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ try {\r
+ listenSock.close();\r
+ } catch (IOException err) {\r
+ //\r
+ } finally {\r
+ acceptSocket = null;\r
+ acceptThread = null;\r
+ }\r
+ }\r
+ };\r
+ acceptThread.start();\r
+ \r
+ logger.info(MessageFormat.format("Git Daemon is listening on {0}:{1,number,0}", myAddress.getAddress().getHostAddress(), myAddress.getPort()));\r
+ }\r
+\r
+ /** @return true if this daemon is receiving connections. */\r
+ public boolean isRunning() {\r
+ return run.get();\r
+ }\r
+\r
+ /** Stop this daemon. */\r
+ public synchronized void stop() {\r
+ if (acceptThread != null) {\r
+ logger.info("Git Daemon stopping...");\r
+ run.set(false);\r
+ try {\r
+ // close the accept socket\r
+ // this throws a SocketException in the accept thread\r
+ acceptSocket.close();\r
+ } catch (IOException e1) {\r
+ }\r
+ try {\r
+ // join the accept thread\r
+ acceptThread.join();\r
+ logger.info("Git Daemon stopped.");\r
+ } catch (InterruptedException e) {\r
+ logger.error("Accept thread join interrupted", e);\r
+ }\r
+ }\r
+ }\r
+\r
+ private void startClient(final Socket s) {\r
+ final GitDaemonClient dc = new GitDaemonClient(this);\r
+\r
+ final SocketAddress peer = s.getRemoteSocketAddress();\r
+ if (peer instanceof InetSocketAddress)\r
+ dc.setRemoteAddress(((InetSocketAddress) peer).getAddress());\r
+\r
+ new Thread(processors, "Git-Daemon-Client " + peer.toString()) {\r
+ public void run() {\r
+ try {\r
+ dc.execute(s);\r
+ } catch (ServiceNotEnabledException e) {\r
+ // Ignored. Client cannot use this repository.\r
+ } catch (ServiceNotAuthorizedException e) {\r
+ // Ignored. Client cannot use this repository.\r
+ } catch (IOException e) {\r
+ // Ignore unexpected IO exceptions from clients\r
+ } finally {\r
+ try {\r
+ s.getInputStream().close();\r
+ } catch (IOException e) {\r
+ // Ignore close exceptions\r
+ }\r
+ try {\r
+ s.getOutputStream().close();\r
+ } catch (IOException e) {\r
+ // Ignore close exceptions\r
+ }\r
+ }\r
+ }\r
+ }.start();\r
+ }\r
+\r
+ synchronized GitDaemonService matchService(final String cmd) {\r
+ for (final GitDaemonService d : services) {\r
+ if (d.handles(cmd))\r
+ return d;\r
+ }\r
+ return null;\r
+ }\r
+\r
+ Repository openRepository(GitDaemonClient client, String name)\r
+ throws ServiceMayNotContinueException {\r
+ // Assume any attempt to use \ was by a Windows client\r
+ // and correct to the more typical / used in Git URIs.\r
+ //\r
+ name = name.replace('\\', '/');\r
+\r
+ // git://thishost/path should always be name="/path" here\r
+ //\r
+ if (!name.startsWith("/")) //$NON-NLS-1$\r
+ return null;\r
+\r
+ try {\r
+ return repositoryResolver.open(client, name.substring(1));\r
+ } catch (RepositoryNotFoundException e) {\r
+ // null signals it "wasn't found", which is all that is suitable\r
+ // for the remote client to know.\r
+ return null;\r
+ } catch (ServiceNotEnabledException e) {\r
+ // null signals it "wasn't found", which is all that is suitable\r
+ // for the remote client to know.\r
+ return null;\r
+ }\r
+ }\r
}\r
--- /dev/null
+package com.gitblit.git;\r
+\r
+/*\r
+ * Copyright (C) 2008-2009, Google Inc.\r
+ * and other copyright owners as documented in the project's IP log.\r
+ *\r
+ * This program and the accompanying materials are made available\r
+ * under the terms of the Eclipse Distribution License v1.0 which\r
+ * accompanies this distribution, is reproduced below, and is\r
+ * available at http://www.eclipse.org/org/documents/edl-v10.php\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials provided\r
+ * with the distribution.\r
+ *\r
+ * - Neither the name of the Eclipse Foundation, Inc. nor the\r
+ * names of its contributors may be used to endorse or promote\r
+ * products derived from this software without specific prior\r
+ * written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+import java.io.BufferedInputStream;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.net.InetAddress;\r
+import java.net.Socket;\r
+\r
+import org.eclipse.jgit.transport.PacketLineIn;\r
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;\r
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;\r
+import org.eclipse.jgit.util.io.SafeBufferedOutputStream;\r
+\r
+/** Active network client of {@link Daemon}. */\r
+public class GitDaemonClient {\r
+ private final GitDaemon daemon;\r
+\r
+ private InetAddress peer;\r
+\r
+ private InputStream rawIn;\r
+\r
+ private OutputStream rawOut;\r
+ \r
+ private String repositoryName;\r
+\r
+ GitDaemonClient(final GitDaemon d) {\r
+ daemon = d;\r
+ }\r
+\r
+ void setRemoteAddress(final InetAddress ia) {\r
+ peer = ia;\r
+ }\r
+\r
+ /** @return the daemon which spawned this client. */\r
+ public GitDaemon getDaemon() {\r
+ return daemon;\r
+ }\r
+\r
+ /** @return Internet address of the remote client. */\r
+ public InetAddress getRemoteAddress() {\r
+ return peer;\r
+ }\r
+\r
+ /** @return input stream to read from the connected client. */\r
+ public InputStream getInputStream() {\r
+ return rawIn;\r
+ }\r
+\r
+ /** @return output stream to send data to the connected client. */\r
+ public OutputStream getOutputStream() {\r
+ return rawOut;\r
+ }\r
+ \r
+ public void setRepositoryName(String repositoryName) {\r
+ this.repositoryName = repositoryName;\r
+ }\r
+ \r
+ /** @return the name of the requested repository. */\r
+ public String getRepositoryName() {\r
+ return repositoryName;\r
+ }\r
+\r
+ void execute(final Socket sock) throws IOException,\r
+ ServiceNotEnabledException, ServiceNotAuthorizedException {\r
+ rawIn = new BufferedInputStream(sock.getInputStream());\r
+ rawOut = new SafeBufferedOutputStream(sock.getOutputStream());\r
+\r
+ if (0 < daemon.getTimeout())\r
+ sock.setSoTimeout(daemon.getTimeout() * 1000);\r
+ String cmd = new PacketLineIn(rawIn).readStringRaw();\r
+ final int nul = cmd.indexOf('\0');\r
+ if (nul >= 0) {\r
+ // Newer clients hide a "host" header behind this byte.\r
+ // Currently we don't use it for anything, so we ignore\r
+ // this portion of the command.\r
+ //\r
+ cmd = cmd.substring(0, nul);\r
+ }\r
+\r
+ final GitDaemonService srv = getDaemon().matchService(cmd);\r
+ if (srv == null)\r
+ return;\r
+ sock.setSoTimeout(0);\r
+ srv.execute(this, cmd);\r
+ }\r
+}
\ No newline at end of file
--- /dev/null
+package com.gitblit.git;\r
+\r
+/*\r
+ * Copyright (C) 2008-2009, Google Inc.\r
+ * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>\r
+ * and other copyright owners as documented in the project's IP log.\r
+ *\r
+ * This program and the accompanying materials are made available\r
+ * under the terms of the Eclipse Distribution License v1.0 which\r
+ * accompanies this distribution, is reproduced below, and is\r
+ * available at http://www.eclipse.org/org/documents/edl-v10.php\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or\r
+ * without modification, are permitted provided that the following\r
+ * conditions are met:\r
+ *\r
+ * - Redistributions of source code must retain the above copyright\r
+ * notice, this list of conditions and the following disclaimer.\r
+ *\r
+ * - Redistributions in binary form must reproduce the above\r
+ * copyright notice, this list of conditions and the following\r
+ * disclaimer in the documentation and/or other materials provided\r
+ * with the distribution.\r
+ *\r
+ * - Neither the name of the Eclipse Foundation, Inc. nor the\r
+ * names of its contributors may be used to endorse or promote\r
+ * products derived from this software without specific prior\r
+ * written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\r
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\r
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+import java.io.IOException;\r
+\r
+import org.eclipse.jgit.lib.Config;\r
+import org.eclipse.jgit.lib.Config.SectionParser;\r
+import org.eclipse.jgit.lib.Repository;\r
+import org.eclipse.jgit.transport.Daemon;\r
+import org.eclipse.jgit.transport.PacketLineOut;\r
+import org.eclipse.jgit.transport.ServiceMayNotContinueException;\r
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;\r
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;\r
+\r
+/** A service exposed by {@link Daemon} over anonymous <code>git://</code>. */\r
+public abstract class GitDaemonService {\r
+ private final String command;\r
+\r
+ private final SectionParser<ServiceConfig> configKey;\r
+\r
+ private boolean enabled;\r
+\r
+ private boolean overridable;\r
+\r
+ GitDaemonService(final String cmdName, final String cfgName) {\r
+ command = cmdName.startsWith("git-") ? cmdName : "git-" + cmdName; //$NON-NLS-1$ //$NON-NLS-2$\r
+ configKey = new SectionParser<ServiceConfig>() {\r
+ public ServiceConfig parse(final Config cfg) {\r
+ return new ServiceConfig(GitDaemonService.this, cfg, cfgName);\r
+ }\r
+ };\r
+ overridable = true;\r
+ }\r
+\r
+ private static class ServiceConfig {\r
+ final boolean enabled;\r
+\r
+ ServiceConfig(final GitDaemonService service, final Config cfg,\r
+ final String name) {\r
+ enabled = cfg.getBoolean("daemon", name, service.isEnabled()); //$NON-NLS-1$\r
+ }\r
+ }\r
+\r
+ /** @return is this service enabled for invocation? */\r
+ public boolean isEnabled() {\r
+ return enabled;\r
+ }\r
+\r
+ /**\r
+ * @param on\r
+ * true to allow this service to be used; false to deny it.\r
+ */\r
+ public void setEnabled(final boolean on) {\r
+ enabled = on;\r
+ }\r
+\r
+ /** @return can this service be configured in the repository config file? */\r
+ public boolean isOverridable() {\r
+ return overridable;\r
+ }\r
+\r
+ /**\r
+ * @param on\r
+ * true to permit repositories to override this service's enabled\r
+ * state with the <code>daemon.servicename</code> config setting.\r
+ */\r
+ public void setOverridable(final boolean on) {\r
+ overridable = on;\r
+ }\r
+\r
+ /** @return name of the command requested by clients. */\r
+ public String getCommandName() {\r
+ return command;\r
+ }\r
+\r
+ /**\r
+ * Determine if this service can handle the requested command.\r
+ *\r
+ * @param commandLine\r
+ * input line from the client.\r
+ * @return true if this command can accept the given command line.\r
+ */\r
+ public boolean handles(final String commandLine) {\r
+ return command.length() + 1 < commandLine.length()\r
+ && commandLine.charAt(command.length()) == ' '\r
+ && commandLine.startsWith(command);\r
+ }\r
+\r
+ void execute(final GitDaemonClient client, final String commandLine)\r
+ throws IOException, ServiceNotEnabledException,\r
+ ServiceNotAuthorizedException {\r
+ final String name = commandLine.substring(command.length() + 1);\r
+ Repository db;\r
+ try {\r
+ db = client.getDaemon().openRepository(client, name);\r
+ } catch (ServiceMayNotContinueException e) {\r
+ // An error when opening the repo means the client is expecting a ref\r
+ // advertisement, so use that style of error.\r
+ PacketLineOut pktOut = new PacketLineOut(client.getOutputStream());\r
+ pktOut.writeString("ERR " + e.getMessage() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$\r
+ db = null;\r
+ }\r
+ if (db == null)\r
+ return;\r
+ try {\r
+ if (isEnabledFor(db))\r
+ execute(client, db);\r
+ } finally {\r
+ db.close();\r
+ }\r
+ }\r
+\r
+ private boolean isEnabledFor(final Repository db) {\r
+ if (isOverridable())\r
+ return db.getConfig().get(configKey).enabled;\r
+ return isEnabled();\r
+ }\r
+\r
+ abstract void execute(GitDaemonClient client, Repository db)\r
+ throws IOException, ServiceNotEnabledException,\r
+ ServiceNotAuthorizedException;\r
+}\r
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.DaemonClient;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
final ReceivePack rp = new ReceivePack(db);
UserModel user = UserModel.ANONYMOUS;
+ String repositoryName = "";
String origin = "";
String gitblitUrl = "";
int timeout = 0;
- // XXX extract the repository name from the config
- // the name is injected by GitRepositoryResolver
- String repositoryName = db.getConfig().getString("gitblit", null, "repositoryName");
-
-
if (req instanceof HttpServletRequest) {
// http/https request may or may not be authenticated
HttpServletRequest request = (HttpServletRequest) req;
+ repositoryName = request.getAttribute("gitblitRepositoryName").toString();
origin = request.getRemoteHost();
gitblitUrl = HttpUtils.getGitblitURL(request);
user = new UserModel(username);
}
}
- } else if (req instanceof DaemonClient) {
+ } else if (req instanceof GitDaemonClient) {
// git daemon request is alway anonymous
- DaemonClient client = (DaemonClient) req;
+ GitDaemonClient client = (GitDaemonClient) req;
+ repositoryName = client.getRepositoryName();
origin = client.getRemoteAddress().getHostAddress();
// set timeout from Git daemon
timeout = client.getDaemon().getTimeout();
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.DaemonClient;
import org.eclipse.jgit.transport.RefFilter;
import org.eclipse.jgit.transport.UploadPack;
import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
if (user == null) {
user = UserModel.ANONYMOUS;
}
- } else if (req instanceof DaemonClient) {
+ } else if (req instanceof GitDaemonClient) {
// git daemon request is always anonymous
- DaemonClient client = (DaemonClient) req;
+ GitDaemonClient client = (GitDaemonClient) req;
// set timeout from Git daemon
timeout = client.getDaemon().getTimeout();
}
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository;
-import org.eclipse.jgit.transport.DaemonClient;
import org.eclipse.jgit.transport.resolver.FileResolver;
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
import org.slf4j.Logger;
public Repository open(final X req, final String name)
throws RepositoryNotFoundException, ServiceNotEnabledException {
Repository repo = super.open(req, name);
- // XXX Set repository name for the pack factories
+
+ // Set repository name for the pack factories
// We do this because the JGit API does not have a consistent way to
// retrieve the repository name from the pack factories or the hooks.
- repo.getConfig().setString("gitblit", null, "repositoryName", name);
+ if (req instanceof HttpServletRequest) {
+ // http/https request
+ HttpServletRequest client = (HttpServletRequest) req;
+ client.setAttribute("gitblitRepositoryName", name);
+ } else if (req instanceof GitDaemonClient) {
+ // git request
+ GitDaemonClient client = (GitDaemonClient) req;
+ client.setRepositoryName(name);
+ }
return repo;
}
UserModel user = null;
String origin = null;
- if (req instanceof DaemonClient) {
+ if (req instanceof GitDaemonClient) {
// git daemon request
// this is an anonymous/unauthenticated protocol
- DaemonClient client = (DaemonClient) req;
+ GitDaemonClient client = (GitDaemonClient) req;
scheme = "git";
origin = client.getRemoteAddress().toString();
user = UserModel.ANONYMOUS;
--- /dev/null
+/*
+ * Copyright 2013 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit.tests;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.gitblit.git.GitDaemon;
+
+public class GitDaemonStopTest extends Assert {
+
+ @Test
+ public void testGitDaemonStop() throws Exception {
+ GitDaemon daemon = new GitDaemon("localhost", GitDaemon.DEFAULT_PORT + 1, GitBlitSuite.REPOSITORIES);
+ daemon.setTimeout(5);
+ daemon.start();
+ Thread.sleep(5000);
+ daemon.stop();
+ }
+}