From 72a7824f2f1d78e9eefde02843e95c9c5b2c4938 Mon Sep 17 00:00:00 2001
From: Vitaly Litvak <vitaliy@fundcount.com>
Date: Tue, 28 Jan 2014 09:18:04 -0500
Subject: [PATCH] Added fisheye hook script
---
src/main/java/com/gitblit/git/GitDaemon.java | 355 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 312 insertions(+), 43 deletions(-)
diff --git a/src/main/java/com/gitblit/git/GitDaemon.java b/src/main/java/com/gitblit/git/GitDaemon.java
index 8ec0563..d026b5e 100644
--- a/src/main/java/com/gitblit/git/GitDaemon.java
+++ b/src/main/java/com/gitblit/git/GitDaemon.java
@@ -1,64 +1,333 @@
/*
- * Copyright 2013 gitblit.com.
+ * Copyright (C) 2013 gitblit.com
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
*
- * 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
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * All rights reserved.
*
- * 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.
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.gitblit.git;
-import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketAddress;
+import java.text.MessageFormat;
+import java.util.concurrent.atomic.AtomicBoolean;
-import org.eclipse.jgit.transport.Daemon;
-import org.eclipse.jgit.transport.DaemonClient;
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.transport.ReceivePack;
+import org.eclipse.jgit.transport.ServiceMayNotContinueException;
+import org.eclipse.jgit.transport.UploadPack;
+import org.eclipse.jgit.transport.resolver.ReceivePackFactory;
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;
+import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;
+import org.eclipse.jgit.transport.resolver.UploadPackFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.gitblit.IStoredSettings;
+import com.gitblit.Keys;
+import com.gitblit.manager.IGitblit;
import com.gitblit.utils.StringUtils;
/**
- * Gitblit's Git Daemon ignores any and all per-repository daemon settings
- * and integrates into Gitblit's security model.
- *
+ * Gitblit's Git Daemon ignores any and all per-repository daemon settings and
+ * integrates into Gitblit's security model.
+ *
* @author James Moger
*
*/
-public class GitDaemon extends Daemon {
+public class GitDaemon {
+
+ private final Logger logger = LoggerFactory.getLogger(GitDaemon.class);
+
+ /** 9418: IANA assigned port number for Git. */
+ public static final int DEFAULT_PORT = 9418;
+
+ private static final int BACKLOG = 5;
+
+ private InetSocketAddress myAddress;
+
+ private final GitDaemonService[] services;
+
+ private final ThreadGroup processors;
+
+ private AtomicBoolean run;
+
+ private ServerSocket acceptSocket;
+
+ private Thread acceptThread;
+
+ private int timeout;
+
+ private RepositoryResolver<GitDaemonClient> repositoryResolver;
+
+ private UploadPackFactory<GitDaemonClient> uploadPackFactory;
+
+ private ReceivePackFactory<GitDaemonClient> receivePackFactory;
+
+ public GitDaemon(IGitblit gitblit) {
+
+ IStoredSettings settings = gitblit.getSettings();
+ int port = settings.getInteger(Keys.git.daemonPort, 0);
+ String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost");
+
+ if (StringUtils.isEmpty(bindInterface)) {
+ myAddress = new InetSocketAddress(port);
+ } else {
+ myAddress = new InetSocketAddress(bindInterface, port);
+ }
+
+ repositoryResolver = new RepositoryResolver<GitDaemonClient>(gitblit);
+ uploadPackFactory = new GitblitUploadPackFactory<GitDaemonClient>(gitblit);
+ receivePackFactory = new GitblitReceivePackFactory<GitDaemonClient>(gitblit);
+
+ run = new AtomicBoolean(false);
+ processors = new ThreadGroup("Git-Daemon");
+ services = new GitDaemonService[] { new GitDaemonService("upload-pack", "uploadpack") {
+ {
+ setEnabled(true);
+ setOverridable(false);
+ }
+
+ @Override
+ protected void execute(final GitDaemonClient dc, final Repository db)
+ throws IOException, ServiceNotEnabledException,
+ ServiceNotAuthorizedException {
+ UploadPack up = uploadPackFactory.create(dc, db);
+ InputStream in = dc.getInputStream();
+ OutputStream out = dc.getOutputStream();
+ up.upload(in, out, null);
+ }
+ }, new GitDaemonService("receive-pack", "receivepack") {
+ {
+ setEnabled(true);
+ setOverridable(false);
+ }
+
+ @Override
+ protected void execute(final GitDaemonClient dc, final Repository db)
+ throws IOException, ServiceNotEnabledException,
+ ServiceNotAuthorizedException {
+ ReceivePack rp = receivePackFactory.create(dc, db);
+ InputStream in = dc.getInputStream();
+ OutputStream out = dc.getOutputStream();
+ rp.receive(in, out, null);
+ }
+ } };
+ }
+
+ public int getPort() {
+ return myAddress.getPort();
+ }
+
+ public String formatUrl(String servername, String repository) {
+ if (getPort() == 9418) {
+ // standard port
+ return MessageFormat.format("git://{0}/{1}", servername, repository);
+ } else {
+ // non-standard port
+ return MessageFormat.format("git://{0}:{1,number,0}/{2}", servername, getPort(), repository);
+ }
+ }
+
+ /** @return timeout (in seconds) before aborting an IO operation. */
+ public int getTimeout() {
+ return timeout;
+ }
/**
- * Construct the Gitblit Git daemon.
- *
- * @param bindInterface
- * the ip address of the interface to bind
- * @param port
- * the port to serve on
- * @param folder
- * the folder to serve from
+ * Set the timeout before willing to abort an IO call.
+ *
+ * @param seconds
+ * number of seconds to wait (with no data transfer occurring)
+ * before aborting an IO read or write operation with the
+ * connected client.
*/
- public GitDaemon(String bindInterface, int port, File folder) {
- super(StringUtils.isEmpty(bindInterface) ? new InetSocketAddress(port) : new InetSocketAddress(bindInterface, port));
-
- // set the repository resolver and pack factories
- setRepositoryResolver(new RepositoryResolver<DaemonClient>(folder));
- setUploadPackFactory(new GitblitUploadPackFactory<DaemonClient>());
- setReceivePackFactory(new GitblitReceivePackFactory<DaemonClient>());
-
- // configure the git daemon to ignore the per-repository settings,
- // daemon.uploadpack and daemon.receivepack
- getService("git-upload-pack").setOverridable(false);
- getService("git-receive-pack").setOverridable(false);
-
- // enable both the upload and receive services and let the resolver,
- // pack factories, and receive hook handle security
- getService("git-upload-pack").setEnabled(true);
- getService("git-receive-pack").setEnabled(true);
+ public void setTimeout(final int seconds) {
+ timeout = seconds;
}
-
+
+ /**
+ * Start this daemon on a background thread.
+ *
+ * @throws IOException
+ * the server socket could not be opened.
+ * @throws IllegalStateException
+ * the daemon is already running.
+ */
+ public synchronized void start() throws IOException {
+ if (acceptThread != null)
+ throw new IllegalStateException(JGitText.get().daemonAlreadyRunning);
+
+ final ServerSocket listenSock = new ServerSocket(myAddress != null ? myAddress.getPort()
+ : 0, BACKLOG, myAddress != null ? myAddress.getAddress() : null);
+ myAddress = (InetSocketAddress) listenSock.getLocalSocketAddress();
+
+ run.set(true);
+ acceptSocket = listenSock;
+ acceptThread = new Thread(processors, "Git-Daemon-Accept") {
+ @Override
+ public void run() {
+ while (isRunning()) {
+ try {
+ startClient(listenSock.accept());
+ } catch (InterruptedIOException e) {
+ // Test again to see if we should keep accepting.
+ } catch (IOException e) {
+ break;
+ }
+ }
+
+ try {
+ listenSock.close();
+ } catch (IOException err) {
+ //
+ } finally {
+ acceptSocket = null;
+ }
+
+ }
+ };
+ acceptThread.start();
+
+ logger.info(MessageFormat.format("Git Daemon is listening on {0}:{1,number,0}", myAddress.getAddress().getHostAddress(), myAddress.getPort()));
+ }
+
+ /** @return true if this daemon is receiving connections. */
+ public boolean isRunning() {
+ return run.get();
+ }
+
+ /** Stop this daemon. */
+ public synchronized void stop() {
+ if (isRunning() && acceptThread != null) {
+ run.set(false);
+ logger.info("Git Daemon stopping...");
+ try {
+ // close the accept socket
+ // this throws a SocketException in the accept thread
+ acceptSocket.close();
+ } catch (IOException e1) {
+ }
+ try {
+ // join the accept thread
+ acceptThread.join();
+ logger.info("Git Daemon stopped.");
+ } catch (InterruptedException e) {
+ logger.error("Accept thread join interrupted", e);
+ } finally {
+ acceptThread = null;
+ }
+ }
+ }
+
+ private void startClient(final Socket s) {
+ final GitDaemonClient dc = new GitDaemonClient(this);
+
+ final SocketAddress peer = s.getRemoteSocketAddress();
+ if (peer instanceof InetSocketAddress)
+ dc.setRemoteAddress(((InetSocketAddress) peer).getAddress());
+
+ new Thread(processors, "Git-Daemon-Client " + peer.toString()) {
+ @Override
+ public void run() {
+ try {
+ dc.execute(s);
+ } catch (ServiceNotEnabledException e) {
+ // Ignored. Client cannot use this repository.
+ } catch (ServiceNotAuthorizedException e) {
+ // Ignored. Client cannot use this repository.
+ } catch (IOException e) {
+ // Ignore unexpected IO exceptions from clients
+ } finally {
+ try {
+ s.getInputStream().close();
+ } catch (IOException e) {
+ // Ignore close exceptions
+ }
+ try {
+ s.getOutputStream().close();
+ } catch (IOException e) {
+ // Ignore close exceptions
+ }
+ }
+ }
+ }.start();
+ }
+
+ synchronized GitDaemonService matchService(final String cmd) {
+ for (final GitDaemonService d : services) {
+ if (d.handles(cmd))
+ return d;
+ }
+ return null;
+ }
+
+ Repository openRepository(GitDaemonClient client, String name)
+ throws ServiceMayNotContinueException {
+ // Assume any attempt to use \ was by a Windows client
+ // and correct to the more typical / used in Git URIs.
+ //
+ name = name.replace('\\', '/');
+
+ // git://thishost/path should always be name="/path" here
+ //
+ if (!name.startsWith("/")) //$NON-NLS-1$
+ return null;
+
+ try {
+ return repositoryResolver.open(client, name.substring(1));
+ } catch (RepositoryNotFoundException e) {
+ // null signals it "wasn't found", which is all that is suitable
+ // for the remote client to know.
+ return null;
+ } catch (ServiceNotEnabledException e) {
+ // null signals it "wasn't found", which is all that is suitable
+ // for the remote client to know.
+ return null;
+ }
+ }
}
--
Gitblit v1.9.1