private boolean sendWants(final Collection<Ref> want) throws IOException {
    final PacketLineOut p = statelessRPC ? pckState : pckOut;
    boolean first = true;
    for (final Ref r : want) {
      try {
        if (walk.parseAny(r.getObjectId()).has(REACHABLE)) {
          // We already have this object. Asking for it is
          // not a very good idea.
          //
          continue;
        }
      } catch (IOException err) {
        // Its OK, we don't have it, but we want to fix that
        // by fetching the object from the other side.
      }

      final StringBuilder line = new StringBuilder(46);
      line.append("want ");
      line.append(r.getObjectId().name());
      if (first) {
        line.append(enableCapabilities());
        first = false;
      }
      line.append('\n');
      p.writeString(line.toString());
    }
    if (first) return false;
    p.end();
    outNeedsEnd = false;
    return true;
  }
  @Test
  public void testUsingHiddenDeltaBaseFails() throws Exception {
    byte[] delta = {0x1, 0x1, 0x1, 'c'};
    TestRepository<Repository> s = new TestRepository<Repository>(src);
    RevCommit N =
        s.commit()
            .parent(B)
            .add("q", s.blob(BinaryDelta.apply(dst.open(b).getCachedBytes(), delta)))
            .create();

    final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
    packHeader(pack, 3);
    copy(pack, src.open(N));
    copy(pack, src.open(s.parseBody(N).getTree()));
    pack.write((Constants.OBJ_REF_DELTA) << 4 | 4);
    b.copyRawTo(pack);
    deflate(pack, delta);
    digest(pack);

    final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
    final PacketLineOut inPckLine = new PacketLineOut(inBuf);
    inPckLine.writeString(
        ObjectId.zeroId().name()
            + ' '
            + N.name()
            + ' '
            + "refs/heads/s"
            + '\0'
            + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
    inPckLine.end();
    pack.writeTo(inBuf, PM);

    final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
    final ReceivePack rp = new ReceivePack(dst);
    rp.setCheckReceivedObjects(true);
    rp.setCheckReferencedObjectsAreReachable(true);
    rp.setAdvertiseRefsHook(new HidePrivateHook());
    try {
      receive(rp, inBuf, outBuf);
      fail("Expected UnpackException");
    } catch (UnpackException failed) {
      Throwable err = failed.getCause();
      assertTrue(err instanceof MissingObjectException);
      MissingObjectException moe = (MissingObjectException) err;
      assertEquals(b, moe.getObjectId());
    }

    final PacketLineIn r = asPacketLineIn(outBuf);
    String master = r.readString();
    int nul = master.indexOf('\0');
    assertTrue("has capability list", nul > 0);
    assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
    assertSame(PacketLineIn.END, r.readString());

    assertEquals("unpack error Missing blob " + b.name(), r.readString());
    assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
    assertSame(PacketLineIn.END, r.readString());
  }
Beispiel #3
0
  private void service() throws IOException {
    if (biDirectionalPipe) {
      sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
      pckOut.flush();
    } else getAdvertisedRefs();
    if (advertiseError != null) return;
    recvCommands();
    if (!commands.isEmpty()) {
      enableCapabilities();

      if (needPack()) {
        try {
          receivePack();
          if (needCheckConnectivity()) checkConnectivity();
          parser = null;
          unpackError = null;
        } catch (IOException err) {
          unpackError = err;
        } catch (RuntimeException err) {
          unpackError = err;
        } catch (Error err) {
          unpackError = err;
        }
      }

      if (unpackError == null) {
        validateCommands();
        executeCommands();
      }
      unlockPack();

      if (reportStatus) {
        sendStatusReport(
            true,
            new Reporter() {
              void sendString(final String s) throws IOException {
                pckOut.writeString(s + "\n");
              }
            });
        pckOut.end();
      } else if (msgOut != null) {
        sendStatusReport(
            false,
            new Reporter() {
              void sendString(final String s) throws IOException {
                msgOut.write(Constants.encode(s + "\n"));
              }
            });
      }

      postReceive.onPostReceive(this, filterCommands(Result.OK));

      if (unpackError != null) throw new UnpackException(unpackError);
    }
  }
  @Test
  public void testUsingUnknownBlobFails() throws Exception {
    // Try to use the 'n' blob that is not on the server.
    //
    TestRepository<Repository> s = new TestRepository<Repository>(src);
    RevBlob n = s.blob("n");
    RevCommit N = s.commit().parent(B).add("q", n).create();

    // But don't include it in the pack.
    //
    final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(1024);
    packHeader(pack, 2);
    copy(pack, src.open(N));
    copy(pack, src.open(s.parseBody(N).getTree()));
    digest(pack);

    final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(1024);
    final PacketLineOut inPckLine = new PacketLineOut(inBuf);
    inPckLine.writeString(
        ObjectId.zeroId().name()
            + ' '
            + N.name()
            + ' '
            + "refs/heads/s"
            + '\0'
            + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
    inPckLine.end();
    pack.writeTo(inBuf, PM);

    final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
    final ReceivePack rp = new ReceivePack(dst);
    rp.setCheckReceivedObjects(true);
    rp.setCheckReferencedObjectsAreReachable(true);
    rp.setAdvertiseRefsHook(new HidePrivateHook());
    try {
      receive(rp, inBuf, outBuf);
      fail("Expected UnpackException");
    } catch (UnpackException failed) {
      Throwable err = failed.getCause();
      assertTrue(err instanceof MissingObjectException);
      MissingObjectException moe = (MissingObjectException) err;
      assertEquals(n, moe.getObjectId());
    }

    final PacketLineIn r = asPacketLineIn(outBuf);
    String master = r.readString();
    int nul = master.indexOf('\0');
    assertTrue("has capability list", nul > 0);
    assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
    assertSame(PacketLineIn.END, r.readString());

    assertEquals("unpack error Missing blob " + n.name(), r.readString());
    assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
    assertSame(PacketLineIn.END, r.readString());
  }
  @Test
  public void testCreateBranchAtHiddenCommitFails() throws Exception {
    final TemporaryBuffer.Heap pack = new TemporaryBuffer.Heap(64);
    packHeader(pack, 0);
    digest(pack);

    final TemporaryBuffer.Heap inBuf = new TemporaryBuffer.Heap(256);
    final PacketLineOut inPckLine = new PacketLineOut(inBuf);
    inPckLine.writeString(
        ObjectId.zeroId().name()
            + ' '
            + P.name()
            + ' '
            + "refs/heads/s"
            + '\0'
            + BasePackPushConnection.CAPABILITY_REPORT_STATUS);
    inPckLine.end();
    pack.writeTo(inBuf, PM);

    final TemporaryBuffer.Heap outBuf = new TemporaryBuffer.Heap(1024);
    final ReceivePack rp = new ReceivePack(dst);
    rp.setCheckReceivedObjects(true);
    rp.setCheckReferencedObjectsAreReachable(true);
    rp.setAdvertiseRefsHook(new HidePrivateHook());
    try {
      receive(rp, inBuf, outBuf);
      fail("Expected UnpackException");
    } catch (UnpackException failed) {
      Throwable err = failed.getCause();
      assertTrue(err instanceof MissingObjectException);
      MissingObjectException moe = (MissingObjectException) err;
      assertEquals(P, moe.getObjectId());
    }

    final PacketLineIn r = asPacketLineIn(outBuf);
    String master = r.readString();
    int nul = master.indexOf('\0');
    assertTrue("has capability list", nul > 0);
    assertEquals(B.name() + ' ' + R_MASTER, master.substring(0, nul));
    assertSame(PacketLineIn.END, r.readString());

    assertEquals("unpack error Missing commit " + P.name(), r.readString());
    assertEquals("ng refs/heads/s n/a (unpacker error)", r.readString());
    assertSame(PacketLineIn.END, r.readString());
  }
Beispiel #6
0
  private void enableCapabilities() {
    reportStatus = enabledCapablities.contains(CAPABILITY_REPORT_STATUS);

    sideBand = enabledCapablities.contains(CAPABILITY_SIDE_BAND_64K);
    if (sideBand) {
      OutputStream out = rawOut;

      rawOut = new SideBandOutputStream(CH_DATA, MAX_BUF, out);
      msgOut = new SideBandOutputStream(CH_PROGRESS, MAX_BUF, out);

      pckOut = new PacketLineOut(rawOut);
      pckOut.setFlushOnEnd(false);
    }
  }
  private void markCommon(final RevObject obj, final AckNackResult anr) throws IOException {
    if (statelessRPC && anr == AckNackResult.ACK_COMMON && !obj.has(STATE)) {
      StringBuilder s;

      s = new StringBuilder(6 + Constants.OBJECT_ID_STRING_LENGTH);
      s.append("have "); // $NON-NLS-1$
      s.append(obj.name());
      s.append('\n');
      pckState.writeString(s.toString());
      obj.add(STATE);
    }
    obj.add(COMMON);
    if (obj instanceof RevCommit) ((RevCommit) obj).carry(COMMON);
  }
  @Override
  public void write(final byte[] b, int off, int len) throws IOException {
    while (0 < len) {
      int capacity = buffer.length - cnt;
      if (cnt == HDR_SIZE && capacity < len) {
        // Our block to write is bigger than the packet size,
        // stream it out as-is to avoid unnecessary copies.
        PacketLineOut.formatLength(buffer, buffer.length);
        out.write(buffer, 0, HDR_SIZE);
        out.write(b, off, capacity);
        off += capacity;
        len -= capacity;

      } else {
        if (capacity == 0) writeBuffer();

        int n = Math.min(len, capacity);
        System.arraycopy(b, off, buffer, cnt, n);
        cnt += n;
        off += n;
        len -= n;
      }
    }
  }
Beispiel #9
0
  /**
   * Execute the receive task on the socket.
   *
   * @param input raw input to read client commands and pack data from. Caller must ensure the input
   *     is buffered, otherwise read performance may suffer.
   * @param output response back to the Git network client. Caller must ensure the output is
   *     buffered, otherwise write performance may suffer.
   * @param messages secondary "notice" channel to send additional messages out through. When run
   *     over SSH this should be tied back to the standard error channel of the command execution.
   *     For most other network connections this should be null.
   * @throws IOException
   */
  public void receive(
      final InputStream input, final OutputStream output, final OutputStream messages)
      throws IOException {
    try {
      rawIn = input;
      rawOut = output;
      msgOut = messages;

      if (timeout > 0) {
        final Thread caller = Thread.currentThread();
        timer = new InterruptTimer(caller.getName() + "-Timer");
        timeoutIn = new TimeoutInputStream(rawIn, timer);
        TimeoutOutputStream o = new TimeoutOutputStream(rawOut, timer);
        timeoutIn.setTimeout(timeout * 1000);
        o.setTimeout(timeout * 1000);
        rawIn = timeoutIn;
        rawOut = o;
      }

      pckIn = new PacketLineIn(rawIn);
      pckOut = new PacketLineOut(rawOut);
      pckOut.setFlushOnEnd(false);

      enabledCapablities = new HashSet<String>();
      commands = new ArrayList<ReceiveCommand>();

      service();
    } finally {
      walk.release();
      try {
        if (sideBand) {
          // If we are using side band, we need to send a final
          // flush-pkt to tell the remote peer the side band is
          // complete and it should stop decoding. We need to
          // use the original output stream as rawOut is now the
          // side band data channel.
          //
          ((SideBandOutputStream) msgOut).flushBuffer();
          ((SideBandOutputStream) rawOut).flushBuffer();

          PacketLineOut plo = new PacketLineOut(output);
          plo.setFlushOnEnd(false);
          plo.end();
        }

        if (biDirectionalPipe) {
          // If this was a native git connection, flush the pipe for
          // the caller. For smart HTTP we don't do this flush and
          // instead let the higher level HTTP servlet code do it.
          //
          if (!sideBand && msgOut != null) msgOut.flush();
          rawOut.flush();
        }
      } finally {
        unlockPack();
        timeoutIn = null;
        rawIn = null;
        rawOut = null;
        msgOut = null;
        pckIn = null;
        pckOut = null;
        refs = null;
        enabledCapablities = null;
        commands = null;
        if (timer != null) {
          try {
            timer.terminate();
          } finally {
            timer = null;
          }
        }
      }
    }
  }
Beispiel #10
0
 private void writeBuffer() throws IOException {
   PacketLineOut.formatLength(buffer, cnt);
   out.write(buffer, 0, cnt);
   cnt = HDR_SIZE;
 }