/** Timeout in seconds to wait for client interaction. */
private int timeout;
+ /**
+ * Is the client connection a bi-directional socket or pipe?
+ * <p>
+ * If true, this class assumes it can perform multiple read and write cycles
+ * with the client over the input and output streams. This matches the
+ * functionality available with a standard TCP/IP connection, or a local
+ * operating system or in-memory pipe.
+ * <p>
+ * If false, this class runs in a read everything then output results mode,
+ * making it suitable for single round-trip systems RPCs such as HTTP.
+ */
+ private boolean biDirectionalPipe = true;
+
/** Timer to manage {@link #timeout}. */
private InterruptTimer timer;
timeout = seconds;
}
+ /**
+ * @return true if this class expects a bi-directional pipe opened between
+ * the client and itself. The default is true.
+ */
+ public boolean isBiDirectionalPipe() {
+ return biDirectionalPipe;
+ }
+
+ /**
+ * @param twoWay
+ * if true, this class will assume the socket is a fully
+ * bidirectional pipe between the two peers and takes advantage
+ * of that by first transmitting the known refs, then waiting to
+ * read commands. If false, this class assumes it must read the
+ * commands before writing output and does not perform the
+ * initial advertising.
+ */
+ public void setBiDirectionalPipe(final boolean twoWay) {
+ biDirectionalPipe = twoWay;
+ }
+
/**
* Execute the upload task on the socket.
*
}
private void service() throws IOException {
- sendAdvertisedRefs();
+ if (biDirectionalPipe)
+ sendAdvertisedRefs();
+ else {
+ refs = db.getAllRefs();
+ for (Ref r : refs.values()) {
+ try {
+ walk.parseAny(r.getObjectId()).add(ADVERTISED);
+ } catch (IOException e) {
+ // Skip missing/corrupt objects
+ }
+ }
+ }
+
recvWants();
if (wantAll.isEmpty())
return;
else
multiAck = MultiAck.OFF;
- negotiate();
- sendPack();
+ if (negotiate())
+ sendPack();
}
private void sendAdvertisedRefs() throws IOException {
}
}
- private void negotiate() throws IOException {
+ private boolean negotiate() throws IOException {
ObjectId last = ObjectId.zeroId();
for (;;) {
String line;
if (commonBase.isEmpty() || multiAck != MultiAck.OFF)
pckOut.writeString("NAK\n");
pckOut.flush();
+ if (!biDirectionalPipe)
+ return false;
+
} else if (line.startsWith("have ") && line.length() == 45) {
final ObjectId id = ObjectId.fromString(line.substring(5));
if (matchHave(id)) {
else if (multiAck != MultiAck.OFF)
pckOut.writeString("ACK " + last.name() + "\n");
- break;
+
+ return true;
} else {
throw new PackProtocolException("expected have; got " + line);