@ -103,6 +103,19 @@ public class UploadPack {
/** Timeout in seconds to wait for client interaction. */
/** Timeout in seconds to wait for client interaction. */
private int timeout ;
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}. */
/** Timer to manage {@link #timeout}. */
private InterruptTimer timer ;
private InterruptTimer timer ;
@ -198,6 +211,27 @@ public class UploadPack {
timeout = seconds ;
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 .
* Execute the upload task on the socket .
*
*
@ -247,7 +281,19 @@ public class UploadPack {
}
}
private void service ( ) throws IOException {
private void service ( ) throws IOException {
if ( biDirectionalPipe )
sendAdvertisedRefs ( ) ;
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 ( ) ;
recvWants ( ) ;
if ( wantAll . isEmpty ( ) )
if ( wantAll . isEmpty ( ) )
return ;
return ;
@ -259,7 +305,7 @@ public class UploadPack {
else
else
multiAck = MultiAck . OFF ;
multiAck = MultiAck . OFF ;
negotiate ( ) ;
if ( negotiate ( ) )
sendPack ( ) ;
sendPack ( ) ;
}
}
@ -336,7 +382,7 @@ public class UploadPack {
}
}
}
}
private void negotiate ( ) throws IOException {
private boolean negotiate ( ) throws IOException {
ObjectId last = ObjectId . zeroId ( ) ;
ObjectId last = ObjectId . zeroId ( ) ;
for ( ; ; ) {
for ( ; ; ) {
String line ;
String line ;
@ -350,6 +396,9 @@ public class UploadPack {
if ( commonBase . isEmpty ( ) | | multiAck ! = MultiAck . OFF )
if ( commonBase . isEmpty ( ) | | multiAck ! = MultiAck . OFF )
pckOut . writeString ( "NAK\n" ) ;
pckOut . writeString ( "NAK\n" ) ;
pckOut . flush ( ) ;
pckOut . flush ( ) ;
if ( ! biDirectionalPipe )
return false ;
} else if ( line . startsWith ( "have " ) & & line . length ( ) = = 45 ) {
} else if ( line . startsWith ( "have " ) & & line . length ( ) = = 45 ) {
final ObjectId id = ObjectId . fromString ( line . substring ( 5 ) ) ;
final ObjectId id = ObjectId . fromString ( line . substring ( 5 ) ) ;
if ( matchHave ( id ) ) {
if ( matchHave ( id ) ) {
@ -389,7 +438,8 @@ public class UploadPack {
else if ( multiAck ! = MultiAck . OFF )
else if ( multiAck ! = MultiAck . OFF )
pckOut . writeString ( "ACK " + last . name ( ) + "\n" ) ;
pckOut . writeString ( "ACK " + last . name ( ) + "\n" ) ;
break ;
return true ;
} else {
} else {
throw new PackProtocolException ( "expected have; got " + line ) ;
throw new PackProtocolException ( "expected have; got " + line ) ;