@ -44,12 +44,11 @@
package org.eclipse.jgit.transport ;
import static java.util.Collections.unmodifiableMap ;
import static org.eclipse.jgit.util.RefMap.toRefMap ;
import static org.eclipse.jgit.lib.Constants.R_TAGS ;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REF_IN_WANT ;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SERVER_OPTION ;
import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_FETCH ;
import static org.eclipse.jgit.transport.GitProtocolConstants.COMMAND_LS_REFS ;
import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SERVER_OPTION ;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT ;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_REACHABLE_SHA1_IN_WANT ;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_ALLOW_TIP_SHA1_IN_WANT ;
@ -65,6 +64,7 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SHALLOW;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND ;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_SIDE_BAND_64K ;
import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_THIN_PACK ;
import static org.eclipse.jgit.util.RefMap.toRefMap ;
import java.io.ByteArrayOutputStream ;
import java.io.EOFException ;
@ -80,8 +80,10 @@ import java.util.HashSet;
import java.util.List ;
import java.util.Map ;
import java.util.Objects ;
import java.util.Optional ;
import java.util.Set ;
import java.util.TreeMap ;
import java.util.stream.Collectors ;
import org.eclipse.jgit.annotations.NonNull ;
import org.eclipse.jgit.annotations.Nullable ;
@ -104,8 +106,11 @@ import org.eclipse.jgit.lib.RefDatabase;
import org.eclipse.jgit.lib.Repository ;
import org.eclipse.jgit.revwalk.AsyncRevObjectQueue ;
import org.eclipse.jgit.revwalk.BitmapWalker ;
import org.eclipse.jgit.revwalk.BitmappedReachabilityChecker ;
import org.eclipse.jgit.revwalk.DepthWalk ;
import org.eclipse.jgit.revwalk.ObjectWalk ;
import org.eclipse.jgit.revwalk.PedestrianReachabilityChecker ;
import org.eclipse.jgit.revwalk.ReachabilityChecker ;
import org.eclipse.jgit.revwalk.RevCommit ;
import org.eclipse.jgit.revwalk.RevFlag ;
import org.eclipse.jgit.revwalk.RevFlagSet ;
@ -1867,59 +1872,88 @@ public class UploadPack {
private static void checkNotAdvertisedWants ( UploadPack up ,
List < ObjectId > notAdvertisedWants , Set < ObjectId > reachableFrom )
throws MissingObjectException , IncorrectObjectTypeException , IOException {
// Walk the requested commits back to the provided set of commits. If any
// commit exists, a branch was deleted or rewound and the repository owner
// no longer exports that requested item. If the requested commit is merged
// into an advertised branch it will be marked UNINTERESTING and no commits
// return.
throws IOException {
ObjectReader reader = up . getRevWalk ( ) . getObjectReader ( ) ;
try ( RevWalk walk = new RevWalk ( reader ) ) {
walk . setRetainBody ( false ) ;
AsyncRevObjectQueue q = walk . parseAny ( notAdvertisedWants , true ) ;
try {
RevObject obj ;
while ( ( obj = q . next ( ) ) ! = null ) {
if ( ! ( obj instanceof RevCommit ) ) {
// If unadvertized non-commits are requested, use
// bitmaps. If there are no bitmaps, instead of
// incurring the expense of a manual walk, reject
// the request.
BitmapIndex bitmapIndex = reader . getBitmapIndex ( ) ;
if ( bitmapIndex ! = null ) {
checkNotAdvertisedWantsUsingBitmap (
reader ,
bitmapIndex ,
notAdvertisedWants ,
reachableFrom ) ;
return ;
}
throw new WantNotValidException ( obj ) ;
}
walk . markStart ( ( RevCommit ) obj ) ;
// Missing "wants" throw exception here
List < RevObject > wantsAsObjs = objectIdsToRevObjects ( walk ,
notAdvertisedWants ) ;
List < RevCommit > wantsAsCommits = wantsAsObjs . stream ( )
. filter ( obj - > obj instanceof RevCommit )
. map ( obj - > ( RevCommit ) obj )
. collect ( Collectors . toList ( ) ) ;
boolean allWantsAreCommits = wantsAsObjs . size ( ) = = wantsAsCommits
. size ( ) ;
boolean repoHasBitmaps = reader . getBitmapIndex ( ) ! = null ;
if ( ! allWantsAreCommits ) {
if ( ! repoHasBitmaps ) {
// If unadvertized non-commits are requested, use
// bitmaps. If there are no bitmaps, instead of
// incurring the expense of a manual walk, reject
// the request.
RevObject nonCommit = wantsAsObjs
. stream ( )
. filter ( obj - > ! ( obj instanceof RevCommit ) )
. limit ( 1 )
. collect ( Collectors . toList ( ) ) . get ( 0 ) ;
throw new WantNotValidException ( nonCommit ) ;
}
} catch ( MissingObjectException notFound ) {
throw new WantNotValidException ( notFound . getObjectId ( ) ,
notFound ) ;
} finally {
q . release ( ) ;
checkNotAdvertisedWantsUsingBitmap ( reader ,
reader . getBitmapIndex ( ) , notAdvertisedWants ,
reachableFrom ) ;
return ;
}
for ( ObjectId id : reachableFrom ) {
try {
walk . markUninteresting ( walk . parseCommit ( id ) ) ;
} catch ( IncorrectObjectTypeException notCommit ) {
continue ;
}
// All wants are commits, we can use ReachabilityChecker
ReachabilityChecker reachabilityChecker = repoHasBitmaps
? new BitmappedReachabilityChecker ( walk )
: new PedestrianReachabilityChecker ( true , walk ) ;
List < RevCommit > starters = objectIdsToRevCommits ( walk ,
reachableFrom ) ;
Optional < RevCommit > unreachable = reachabilityChecker
. areAllReachable ( wantsAsCommits , starters ) ;
if ( unreachable . isPresent ( ) ) {
throw new WantNotValidException ( unreachable . get ( ) ) ;
}
RevCommit bad = walk . next ( ) ;
if ( bad ! = null ) {
throw new WantNotValidException ( bad ) ;
} catch ( MissingObjectException notFound ) {
throw new WantNotValidException ( notFound . getObjectId ( ) , notFound ) ;
}
}
// Resolve the ObjectIds into RevObjects. Any missing object raises an
// exception
private static List < RevObject > objectIdsToRevObjects ( RevWalk walk ,
Iterable < ObjectId > objectIds )
throws MissingObjectException , IOException {
List < RevObject > result = new ArrayList < > ( ) ;
for ( ObjectId objectId : objectIds ) {
result . add ( walk . parseAny ( objectId ) ) ;
}
return result ;
}
// Get commits from object ids. If the id is not a commit, ignore it. If the
// id doesn't exist, report the missing object in a exception.
private static List < RevCommit > objectIdsToRevCommits ( RevWalk walk ,
Iterable < ObjectId > objectIds )
throws MissingObjectException , IOException {
List < RevCommit > result = new ArrayList < > ( ) ;
for ( ObjectId objectId : objectIds ) {
try {
result . add ( walk . parseCommit ( objectId ) ) ;
} catch ( IncorrectObjectTypeException e ) {
continue ;
}
}
return result ;
}
private void addCommonBase ( RevObject o ) {
if ( ! o . has ( COMMON ) ) {
o . add ( COMMON ) ;