diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalFetchConnection.java new file mode 100644 index 000000000..7fc404811 --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalFetchConnection.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2015, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * 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 + * + * All rights reserved. + * + * 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 org.eclipse.jgit.transport; + +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; +import org.eclipse.jgit.transport.resolver.UploadPackFactory; + +class InternalFetchConnection extends BasePackFetchConnection { + private Thread worker; + + public InternalFetchConnection(PackTransport transport, + final UploadPackFactory uploadPackFactory, + final C req, final Repository remote) throws TransportException { + super(transport); + + final PipedInputStream in_r; + final PipedOutputStream in_w; + + final PipedInputStream out_r; + final PipedOutputStream out_w; + try { + in_r = new PipedInputStream(); + in_w = new PipedOutputStream(in_r); + + out_r = new PipedInputStream() { + // The client (BasePackFetchConnection) can write + // a huge burst before it reads again. We need to + // force the buffer to be big enough, otherwise it + // will deadlock both threads. + { + buffer = new byte[MIN_CLIENT_BUFFER]; + } + }; + out_w = new PipedOutputStream(out_r); + } catch (IOException err) { + remote.close(); + throw new TransportException(uri, JGitText.get().cannotConnectPipes, err); + } + + worker = new Thread("JGit-Upload-Pack") { //$NON-NLS-1$ + public void run() { + try { + final UploadPack rp = uploadPackFactory.create(req, remote); + rp.upload(out_r, in_w, null); + } catch (ServiceNotEnabledException e) { + // Ignored. Client cannot use this repository. + } catch (ServiceNotAuthorizedException e) { + // Ignored. Client cannot use this repository. + } catch (IOException err) { + // Client side of the pipes should report the problem. + err.printStackTrace(); + } catch (RuntimeException err) { + // Client side will notice we went away, and report. + err.printStackTrace(); + } finally { + try { + out_r.close(); + } catch (IOException e2) { + // Ignore close failure, we probably crashed above. + } + + try { + in_w.close(); + } catch (IOException e2) { + // Ignore close failure, we probably crashed above. + } + + remote.close(); + } + } + }; + worker.start(); + + init(in_r, out_w); + readAdvertisedRefs(); + } + + @Override + public void close() { + super.close(); + + try { + if (worker != null) { + worker.join(); + } + } catch (InterruptedException ie) { + // Stop waiting and return anyway. + } finally { + worker = null; + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalPushConnection.java new file mode 100644 index 000000000..ab76e0f1e --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/InternalPushConnection.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2015, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * 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 + * + * All rights reserved. + * + * 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 org.eclipse.jgit.transport; + +import java.io.IOException; +import java.io.PipedInputStream; +import java.io.PipedOutputStream; + +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.transport.resolver.ReceivePackFactory; +import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException; +import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException; + +class InternalPushConnection extends BasePackPushConnection { + private Thread worker; + + public InternalPushConnection(PackTransport transport, + final ReceivePackFactory receivePackFactory, + final C req, final Repository remote) throws TransportException { + super(transport); + + final PipedInputStream in_r; + final PipedOutputStream in_w; + + final PipedInputStream out_r; + final PipedOutputStream out_w; + try { + in_r = new PipedInputStream(); + in_w = new PipedOutputStream(in_r); + + out_r = new PipedInputStream(); + out_w = new PipedOutputStream(out_r); + } catch (IOException err) { + remote.close(); + throw new TransportException(uri, JGitText.get().cannotConnectPipes, err); + } + + worker = new Thread("JGit-Receive-Pack") { //$NON-NLS-1$ + public void run() { + try { + final ReceivePack rp = receivePackFactory.create(req, remote); + rp.receive(out_r, in_w, System.err); + } catch (ServiceNotEnabledException e) { + // Ignored. Client cannot use this repository. + } catch (ServiceNotAuthorizedException e) { + // Ignored. Client cannot use this repository. + } catch (IOException err) { + // Client side of the pipes should report the problem. + } catch (RuntimeException err) { + // Clients side will notice we went away, and report. + } finally { + try { + out_r.close(); + } catch (IOException e2) { + // Ignore close failure, we probably crashed above. + } + + try { + in_w.close(); + } catch (IOException e2) { + // Ignore close failure, we probably crashed above. + } + + remote.close(); + } + } + }; + worker.start(); + + init(in_r, out_w); + readAdvertisedRefs(); + } + + @Override + public void close() { + super.close(); + + if (worker != null) { + try { + worker.join(); + } catch (InterruptedException ie) { + // Stop waiting and return anyway. + } finally { + worker = null; + } + } + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java index 81caf6649..292ba7ed8 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportLocal.java @@ -52,8 +52,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; import java.util.Collections; import java.util.Map; import java.util.Set; @@ -65,6 +63,8 @@ import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.RepositoryBuilder; import org.eclipse.jgit.lib.RepositoryCache; +import org.eclipse.jgit.transport.resolver.ReceivePackFactory; +import org.eclipse.jgit.transport.resolver.UploadPackFactory; import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.io.MessageWriter; import org.eclipse.jgit.util.io.SafeBufferedOutputStream; @@ -168,21 +168,44 @@ ReceivePack createReceivePack(final Repository dst) { return new ReceivePack(dst); } - @Override - public FetchConnection openFetch() throws TransportException { - final String up = getOptionUploadPack(); - if ("git-upload-pack".equals(up) || "git upload-pack".equals(up)) //$NON-NLS-1$ //$NON-NLS-2$ - return new InternalLocalFetchConnection(); - return new ForkLocalFetchConnection(); + private Repository openRepo() throws TransportException { + try { + return new RepositoryBuilder().setGitDir(remoteGitDir).build(); + } catch (IOException err) { + throw new TransportException(uri, JGitText.get().notAGitDirectory); + } } @Override - public PushConnection openPush() throws NotSupportedException, - TransportException { + public FetchConnection openFetch() throws TransportException { + final String up = getOptionUploadPack(); + if (!"git-upload-pack".equals(up) //$NON-NLS-1$ + && !"git upload-pack".equals(up)) //$NON-NLS-1$ + return new ForkLocalFetchConnection(); + + UploadPackFactory upf = new UploadPackFactory() { + @Override + public UploadPack create(Void req, Repository db) { + return createUploadPack(db); + } + }; + return new InternalFetchConnection(this, upf, null, openRepo()); + } + + @Override + public PushConnection openPush() throws TransportException { final String rp = getOptionReceivePack(); - if ("git-receive-pack".equals(rp) || "git receive-pack".equals(rp)) //$NON-NLS-1$ //$NON-NLS-2$ - return new InternalLocalPushConnection(); - return new ForkLocalPushConnection(); + if (!"git-receive-pack".equals(rp) //$NON-NLS-1$ + && !"git receive-pack".equals(rp)) //$NON-NLS-1$ + return new ForkLocalPushConnection(); + + ReceivePackFactory rpf = new ReceivePackFactory() { + @Override + public ReceivePack create(Void req, Repository db) { + return createReceivePack(db); + } + }; + return new InternalPushConnection(this, rpf, null, openRepo()); } @Override @@ -214,93 +237,6 @@ protected Process spawn(final String cmd) } } - class InternalLocalFetchConnection extends BasePackFetchConnection { - private Thread worker; - - InternalLocalFetchConnection() throws TransportException { - super(TransportLocal.this); - - final Repository dst; - try { - dst = new RepositoryBuilder().setGitDir(remoteGitDir).build(); - } catch (IOException err) { - throw new TransportException(uri, JGitText.get().notAGitDirectory); - } - - final PipedInputStream in_r; - final PipedOutputStream in_w; - - final PipedInputStream out_r; - final PipedOutputStream out_w; - try { - in_r = new PipedInputStream(); - in_w = new PipedOutputStream(in_r); - - out_r = new PipedInputStream() { - // The client (BasePackFetchConnection) can write - // a huge burst before it reads again. We need to - // force the buffer to be big enough, otherwise it - // will deadlock both threads. - { - buffer = new byte[MIN_CLIENT_BUFFER]; - } - }; - out_w = new PipedOutputStream(out_r); - } catch (IOException err) { - dst.close(); - throw new TransportException(uri, JGitText.get().cannotConnectPipes, err); - } - - worker = new Thread("JGit-Upload-Pack") { //$NON-NLS-1$ - public void run() { - try { - final UploadPack rp = createUploadPack(dst); - rp.upload(out_r, in_w, null); - } catch (IOException err) { - // Client side of the pipes should report the problem. - err.printStackTrace(); - } catch (RuntimeException err) { - // Clients side will notice we went away, and report. - err.printStackTrace(); - } finally { - try { - out_r.close(); - } catch (IOException e2) { - // Ignore close failure, we probably crashed above. - } - - try { - in_w.close(); - } catch (IOException e2) { - // Ignore close failure, we probably crashed above. - } - - dst.close(); - } - } - }; - worker.start(); - - init(in_r, out_w); - readAdvertisedRefs(); - } - - @Override - public void close() { - super.close(); - - if (worker != null) { - try { - worker.join(); - } catch (InterruptedException ie) { - // Stop waiting and return anyway. - } finally { - worker = null; - } - } - } - } - class ForkLocalFetchConnection extends BasePackFetchConnection { private Process uploadPack; @@ -354,83 +290,6 @@ public void close() { } } - class InternalLocalPushConnection extends BasePackPushConnection { - private Thread worker; - - InternalLocalPushConnection() throws TransportException { - super(TransportLocal.this); - - final Repository dst; - try { - dst = new RepositoryBuilder().setGitDir(remoteGitDir).build(); - } catch (IOException err) { - throw new TransportException(uri, JGitText.get().notAGitDirectory); - } - - final PipedInputStream in_r; - final PipedOutputStream in_w; - - final PipedInputStream out_r; - final PipedOutputStream out_w; - try { - in_r = new PipedInputStream(); - in_w = new PipedOutputStream(in_r); - - out_r = new PipedInputStream(); - out_w = new PipedOutputStream(out_r); - } catch (IOException err) { - dst.close(); - throw new TransportException(uri, JGitText.get().cannotConnectPipes, err); - } - - worker = new Thread("JGit-Receive-Pack") { //$NON-NLS-1$ - public void run() { - try { - final ReceivePack rp = createReceivePack(dst); - rp.receive(out_r, in_w, System.err); - } catch (IOException err) { - // Client side of the pipes should report the problem. - } catch (RuntimeException err) { - // Clients side will notice we went away, and report. - } finally { - try { - out_r.close(); - } catch (IOException e2) { - // Ignore close failure, we probably crashed above. - } - - try { - in_w.close(); - } catch (IOException e2) { - // Ignore close failure, we probably crashed above. - } - - dst.close(); - } - } - }; - worker.start(); - - init(in_r, out_w); - readAdvertisedRefs(); - } - - @Override - public void close() { - super.close(); - - if (worker != null) { - try { - worker.join(); - } catch (InterruptedException ie) { - // Stop waiting and return anyway. - } finally { - worker = null; - } - } - } - } - class ForkLocalPushConnection extends BasePackPushConnection { private Process receivePack;