UploadPack: allow custom RequestValidator instances

Make the existing concrete implementations public as well so custom
implementations may delegate to them where appropriate. Treat all custom
implementations as providing allow-tip-sha1 in want.

Change-Id: If386fe25c0d3b4551a97c16a22350714453b03e9
This commit is contained in:
Dave Borowitz 2013-06-23 17:28:34 -07:00
parent 68ccc5d213
commit 360d8624ca
1 changed files with 90 additions and 33 deletions

View File

@ -141,8 +141,12 @@ public static enum RequestPolicy {
ANY; ANY;
} }
/** Validator for client requests. */ /**
private interface RequestValidator { * Validator for client requests.
*
* @since 3.1
*/
public interface RequestValidator {
/** /**
* Check a list of client wants against the request policy. * Check a list of client wants against the request policy.
* *
@ -155,6 +159,7 @@ private interface RequestValidator {
* if one or more wants is not valid. * if one or more wants is not valid.
* @throws IOException * @throws IOException
* if a low-level exception occurred. * if a low-level exception occurred.
* @since 3.1
*/ */
void checkWants(UploadPack up, List<RevObject> wants) void checkWants(UploadPack up, List<RevObject> wants)
throws PackProtocolException, IOException; throws PackProtocolException, IOException;
@ -297,7 +302,7 @@ public Set<String> getOptions() {
private final RevFlagSet SAVE; private final RevFlagSet SAVE;
private RequestPolicy requestPolicy; private RequestValidator requestValidator = new AdvertisedRequestValidator();
private MultiAck multiAck = MultiAck.OFF; private MultiAck multiAck = MultiAck.OFF;
@ -414,9 +419,22 @@ public void setBiDirectionalPipe(final boolean twoWay) {
biDirectionalPipe = twoWay; biDirectionalPipe = twoWay;
} }
/** @return policy used by the service to validate client requests. */ /**
* @return policy used by the service to validate client requests, or null for
* a custom request validator.
*/
public RequestPolicy getRequestPolicy() { public RequestPolicy getRequestPolicy() {
return requestPolicy; if (requestValidator instanceof AdvertisedRequestValidator)
return RequestPolicy.ADVERTISED;
if (requestValidator instanceof ReachableCommitRequestValidator)
return RequestPolicy.REACHABLE_COMMIT;
if (requestValidator instanceof TipRequestValidator)
return RequestPolicy.TIP;
if (requestValidator instanceof ReachableCommitTipRequestValidator)
return RequestPolicy.REACHABLE_COMMIT_TIP;
if (requestValidator instanceof AnyRequestValidator)
return RequestPolicy.ANY;
return null;
} }
/** /**
@ -431,7 +449,34 @@ public RequestPolicy getRequestPolicy() {
* Overrides any policy specified in a {@link TransferConfig}. * Overrides any policy specified in a {@link TransferConfig}.
*/ */
public void setRequestPolicy(RequestPolicy policy) { public void setRequestPolicy(RequestPolicy policy) {
requestPolicy = policy; switch (policy) {
case ADVERTISED:
default:
requestValidator = new AdvertisedRequestValidator();
break;
case REACHABLE_COMMIT:
requestValidator = new ReachableCommitRequestValidator();
break;
case TIP:
requestValidator = new TipRequestValidator();
break;
case REACHABLE_COMMIT_TIP:
requestValidator = new ReachableCommitTipRequestValidator();
break;
case ANY:
requestValidator = new AnyRequestValidator();
break;
}
}
/**
* @param validator
* custom validator for client want list.
* @since 3.1
*/
public void setRequestValidator(RequestValidator validator) {
requestValidator = validator != null ? validator
: new AdvertisedRequestValidator();
} }
/** @return the hook used while advertising the refs to the client */ /** @return the hook used while advertising the refs to the client */
@ -509,8 +554,8 @@ public void setPackConfig(PackConfig pc) {
*/ */
public void setTransferConfig(TransferConfig tc) { public void setTransferConfig(TransferConfig tc) {
this.transferConfig = tc != null ? tc : new TransferConfig(db); this.transferConfig = tc != null ? tc : new TransferConfig(db);
this.requestPolicy = transferConfig.isAllowTipSha1InWant() setRequestPolicy(transferConfig.isAllowTipSha1InWant()
? RequestPolicy.TIP : RequestPolicy.ADVERTISED; ? RequestPolicy.TIP : RequestPolicy.ADVERTISED);
} }
/** @return the configured logger. */ /** @return the configured logger. */
@ -619,7 +664,7 @@ private Map<String, Ref> getAdvertisedOrDefaultRefs() {
private void service() throws IOException { private void service() throws IOException {
if (biDirectionalPipe) if (biDirectionalPipe)
sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut)); sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
else if (requestPolicy == RequestPolicy.ANY) else if (requestValidator instanceof AnyRequestValidator)
advertised = Collections.emptySet(); advertised = Collections.emptySet();
else else
advertised = refIdSet(getAdvertisedOrDefaultRefs().values()); advertised = refIdSet(getAdvertisedOrDefaultRefs().values());
@ -758,8 +803,10 @@ public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException,
adv.advertiseCapability(OPTION_SHALLOW); adv.advertiseCapability(OPTION_SHALLOW);
if (!biDirectionalPipe) if (!biDirectionalPipe)
adv.advertiseCapability(OPTION_NO_DONE); adv.advertiseCapability(OPTION_NO_DONE);
if (requestPolicy == RequestPolicy.TIP RequestPolicy policy = getRequestPolicy();
|| requestPolicy == RequestPolicy.REACHABLE_COMMIT_TIP) if (policy == RequestPolicy.TIP
|| policy == RequestPolicy.REACHABLE_COMMIT_TIP
|| policy == null)
adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT); adv.advertiseCapability(OPTION_ALLOW_TIP_SHA1_IN_WANT);
adv.setDerefTags(true); adv.setDerefTags(true);
advertised = adv.send(getAdvertisedOrDefaultRefs()); advertised = adv.send(getAdvertisedOrDefaultRefs());
@ -1008,7 +1055,7 @@ private void parseWants() throws IOException {
} }
} }
if (notAdvertisedWants != null) if (notAdvertisedWants != null)
getRequestValidator().checkWants(this, notAdvertisedWants); requestValidator.checkWants(this, notAdvertisedWants);
wantIds.clear(); wantIds.clear();
} catch (MissingObjectException notFound) { } catch (MissingObjectException notFound) {
ObjectId id = notFound.getObjectId(); ObjectId id = notFound.getObjectId();
@ -1026,23 +1073,13 @@ private void want(RevObject obj) {
} }
} }
private RequestValidator getRequestValidator() { /**
switch (requestPolicy) { * Validator corresponding to {@link RequestPolicy#ADVERTISED}.
case ADVERTISED: *
default: * @since 3.1
return new AdvertisedRequestValidator(); */
case REACHABLE_COMMIT: public static final class AdvertisedRequestValidator
return new ReachableCommitRequestValidator(); implements RequestValidator {
case TIP:
return new TipRequestValidator();
case REACHABLE_COMMIT_TIP:
return new ReachableCommitTipRequestValidator();
case ANY:
return new AnyRequestValidator();
}
}
private static class AdvertisedRequestValidator implements RequestValidator {
public void checkWants(UploadPack up, List<RevObject> wants) public void checkWants(UploadPack up, List<RevObject> wants)
throws PackProtocolException, IOException { throws PackProtocolException, IOException {
if (!up.isBiDirectionalPipe()) if (!up.isBiDirectionalPipe())
@ -1053,7 +1090,12 @@ else if (!wants.isEmpty())
} }
} }
private static class ReachableCommitRequestValidator /**
* Validator corresponding to {@link RequestPolicy#REACHABLE_COMMIT}.
*
* @since 3.1
*/
public static final class ReachableCommitRequestValidator
implements RequestValidator { implements RequestValidator {
public void checkWants(UploadPack up, List<RevObject> wants) public void checkWants(UploadPack up, List<RevObject> wants)
throws PackProtocolException, IOException { throws PackProtocolException, IOException {
@ -1062,7 +1104,12 @@ public void checkWants(UploadPack up, List<RevObject> wants)
} }
} }
private static class TipRequestValidator implements RequestValidator { /**
* Validator corresponding to {@link RequestPolicy#TIP}.
*
* @since 3.1
*/
public static final class TipRequestValidator implements RequestValidator {
public void checkWants(UploadPack up, List<RevObject> wants) public void checkWants(UploadPack up, List<RevObject> wants)
throws PackProtocolException, IOException { throws PackProtocolException, IOException {
if (!up.isBiDirectionalPipe()) if (!up.isBiDirectionalPipe())
@ -1079,7 +1126,12 @@ else if (!wants.isEmpty()) {
} }
} }
private static class ReachableCommitTipRequestValidator /**
* Validator corresponding to {@link RequestPolicy#REACHABLE_COMMIT_TIP}.
*
* @since 3.1
*/
public static final class ReachableCommitTipRequestValidator
implements RequestValidator { implements RequestValidator {
public void checkWants(UploadPack up, List<RevObject> wants) public void checkWants(UploadPack up, List<RevObject> wants)
throws PackProtocolException, IOException { throws PackProtocolException, IOException {
@ -1088,7 +1140,12 @@ public void checkWants(UploadPack up, List<RevObject> wants)
} }
} }
private static class AnyRequestValidator implements RequestValidator { /**
* Validator corresponding to {@link RequestPolicy#ANY}.
*
* @since 3.1
*/
public static final class AnyRequestValidator implements RequestValidator {
public void checkWants(UploadPack up, List<RevObject> wants) public void checkWants(UploadPack up, List<RevObject> wants)
throws PackProtocolException, IOException { throws PackProtocolException, IOException {
// All requests are valid. // All requests are valid.