TransportGitAnon.java

  1. /*
  2.  * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
  3.  * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
  4.  * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
  5.  * and other copyright owners as documented in the project's IP log.
  6.  *
  7.  * This program and the accompanying materials are made available
  8.  * under the terms of the Eclipse Distribution License v1.0 which
  9.  * accompanies this distribution, is reproduced below, and is
  10.  * available at http://www.eclipse.org/org/documents/edl-v10.php
  11.  *
  12.  * All rights reserved.
  13.  *
  14.  * Redistribution and use in source and binary forms, with or
  15.  * without modification, are permitted provided that the following
  16.  * conditions are met:
  17.  *
  18.  * - Redistributions of source code must retain the above copyright
  19.  *   notice, this list of conditions and the following disclaimer.
  20.  *
  21.  * - Redistributions in binary form must reproduce the above
  22.  *   copyright notice, this list of conditions and the following
  23.  *   disclaimer in the documentation and/or other materials provided
  24.  *   with the distribution.
  25.  *
  26.  * - Neither the name of the Eclipse Foundation, Inc. nor the
  27.  *   names of its contributors may be used to endorse or promote
  28.  *   products derived from this software without specific prior
  29.  *   written permission.
  30.  *
  31.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  32.  * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
  33.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  34.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  35.  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  36.  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  37.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  38.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  39.  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  40.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  41.  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  42.  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  43.  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  44.  */

  45. package org.eclipse.jgit.transport;

  46. import java.io.BufferedInputStream;
  47. import java.io.BufferedOutputStream;
  48. import java.io.IOException;
  49. import java.io.InputStream;
  50. import java.io.OutputStream;
  51. import java.net.ConnectException;
  52. import java.net.InetAddress;
  53. import java.net.InetSocketAddress;
  54. import java.net.Socket;
  55. import java.net.UnknownHostException;
  56. import java.util.Collections;
  57. import java.util.EnumSet;
  58. import java.util.Set;

  59. import org.eclipse.jgit.errors.NotSupportedException;
  60. import org.eclipse.jgit.errors.TransportException;
  61. import org.eclipse.jgit.internal.JGitText;
  62. import org.eclipse.jgit.lib.Repository;

  63. /**
  64.  * Transport through a git-daemon waiting for anonymous TCP connections.
  65.  * <p>
  66.  * This transport supports the <code>git://</code> protocol, usually run on
  67.  * the IANA registered port 9418. It is a popular means for distributing open
  68.  * source projects, as there are no authentication or authorization overheads.
  69.  */
  70. class TransportGitAnon extends TcpTransport implements PackTransport {
  71.     static final int GIT_PORT = Daemon.DEFAULT_PORT;

  72.     static final TransportProtocol PROTO_GIT = new TransportProtocol() {
  73.         @Override
  74.         public String getName() {
  75.             return JGitText.get().transportProtoGitAnon;
  76.         }

  77.         @Override
  78.         public Set<String> getSchemes() {
  79.             return Collections.singleton("git"); //$NON-NLS-1$
  80.         }

  81.         @Override
  82.         public Set<URIishField> getRequiredFields() {
  83.             return Collections.unmodifiableSet(EnumSet.of(URIishField.HOST,
  84.                     URIishField.PATH));
  85.         }

  86.         @Override
  87.         public Set<URIishField> getOptionalFields() {
  88.             return Collections.unmodifiableSet(EnumSet.of(URIishField.PORT));
  89.         }

  90.         @Override
  91.         public int getDefaultPort() {
  92.             return GIT_PORT;
  93.         }

  94.         @Override
  95.         public Transport open(URIish uri, Repository local, String remoteName)
  96.                 throws NotSupportedException {
  97.             return new TransportGitAnon(local, uri);
  98.         }

  99.         @Override
  100.         public Transport open(URIish uri) throws NotSupportedException, TransportException {
  101.             return new TransportGitAnon(uri);
  102.         }
  103.     };

  104.     TransportGitAnon(Repository local, URIish uri) {
  105.         super(local, uri);
  106.     }

  107.     TransportGitAnon(URIish uri) {
  108.         super(uri);
  109.     }

  110.     /** {@inheritDoc} */
  111.     @Override
  112.     public FetchConnection openFetch() throws TransportException {
  113.         return new TcpFetchConnection();
  114.     }

  115.     /** {@inheritDoc} */
  116.     @Override
  117.     public PushConnection openPush() throws TransportException {
  118.         return new TcpPushConnection();
  119.     }

  120.     /** {@inheritDoc} */
  121.     @Override
  122.     public void close() {
  123.         // Resources must be established per-connection.
  124.     }

  125.     Socket openConnection() throws TransportException {
  126.         final int tms = getTimeout() > 0 ? getTimeout() * 1000 : 0;
  127.         final int port = uri.getPort() > 0 ? uri.getPort() : GIT_PORT;
  128.         @SuppressWarnings("resource") // Closed by the caller
  129.         final Socket s = new Socket();
  130.         try {
  131.             final InetAddress host = InetAddress.getByName(uri.getHost());
  132.             s.bind(null);
  133.             s.connect(new InetSocketAddress(host, port), tms);
  134.         } catch (IOException c) {
  135.             try {
  136.                 s.close();
  137.             } catch (IOException closeErr) {
  138.                 // ignore a failure during close, we're already failing
  139.             }
  140.             if (c instanceof UnknownHostException)
  141.                 throw new TransportException(uri, JGitText.get().unknownHost);
  142.             if (c instanceof ConnectException)
  143.                 throw new TransportException(uri, c.getMessage());
  144.             throw new TransportException(uri, c.getMessage(), c);
  145.         }
  146.         return s;
  147.     }

  148.     void service(String name, PacketLineOut pckOut)
  149.             throws IOException {
  150.         final StringBuilder cmd = new StringBuilder();
  151.         cmd.append(name);
  152.         cmd.append(' ');
  153.         cmd.append(uri.getPath());
  154.         cmd.append('\0');
  155.         cmd.append("host="); //$NON-NLS-1$
  156.         cmd.append(uri.getHost());
  157.         if (uri.getPort() > 0 && uri.getPort() != GIT_PORT) {
  158.             cmd.append(":"); //$NON-NLS-1$
  159.             cmd.append(uri.getPort());
  160.         }
  161.         cmd.append('\0');
  162.         pckOut.writeString(cmd.toString());
  163.         pckOut.flush();
  164.     }

  165.     class TcpFetchConnection extends BasePackFetchConnection {
  166.         private Socket sock;

  167.         TcpFetchConnection() throws TransportException {
  168.             super(TransportGitAnon.this);
  169.             sock = openConnection();
  170.             try {
  171.                 InputStream sIn = sock.getInputStream();
  172.                 OutputStream sOut = sock.getOutputStream();

  173.                 sIn = new BufferedInputStream(sIn);
  174.                 sOut = new BufferedOutputStream(sOut);

  175.                 init(sIn, sOut);
  176.                 service("git-upload-pack", pckOut); //$NON-NLS-1$
  177.             } catch (IOException err) {
  178.                 close();
  179.                 throw new TransportException(uri,
  180.                         JGitText.get().remoteHungUpUnexpectedly, err);
  181.             }
  182.             readAdvertisedRefs();
  183.         }

  184.         @Override
  185.         public void close() {
  186.             super.close();

  187.             if (sock != null) {
  188.                 try {
  189.                     sock.close();
  190.                 } catch (IOException err) {
  191.                     // Ignore errors during close.
  192.                 } finally {
  193.                     sock = null;
  194.                 }
  195.             }
  196.         }
  197.     }

  198.     class TcpPushConnection extends BasePackPushConnection {
  199.         private Socket sock;

  200.         TcpPushConnection() throws TransportException {
  201.             super(TransportGitAnon.this);
  202.             sock = openConnection();
  203.             try {
  204.                 InputStream sIn = sock.getInputStream();
  205.                 OutputStream sOut = sock.getOutputStream();

  206.                 sIn = new BufferedInputStream(sIn);
  207.                 sOut = new BufferedOutputStream(sOut);

  208.                 init(sIn, sOut);
  209.                 service("git-receive-pack", pckOut); //$NON-NLS-1$
  210.             } catch (IOException err) {
  211.                 close();
  212.                 throw new TransportException(uri,
  213.                         JGitText.get().remoteHungUpUnexpectedly, err);
  214.             }
  215.             readAdvertisedRefs();
  216.         }

  217.         @Override
  218.         public void close() {
  219.             super.close();

  220.             if (sock != null) {
  221.                 try {
  222.                     sock.close();
  223.                 } catch (IOException err) {
  224.                     // Ignore errors during close.
  225.                 } finally {
  226.                     sock = null;
  227.                 }
  228.             }
  229.         }
  230.     }
  231. }