Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java127
1 files changed, 103 insertions, 24 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
index 6602de49ed..0d79110289 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/ReceivePack.java
@@ -134,6 +134,9 @@ public class ReceivePack {
/** Identity to record action as within the reflog. */
private PersonIdent refLogIdent;
+ /** Hook used while advertising the refs to the client. */
+ private AdvertiseRefsHook advertiseRefsHook;
+
/** Filter used while advertising the refs to the client. */
private RefFilter refFilter;
@@ -213,6 +216,7 @@ public class ReceivePack {
allowDeletes = cfg.allowDeletes;
allowNonFastForwards = cfg.allowNonFastForwards;
allowOfsDelta = cfg.allowOfsDelta;
+ advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
refFilter = RefFilter.DEFAULT;
preReceive = PreReceiveHook.NULL;
postReceive = PostReceiveHook.NULL;
@@ -304,27 +308,59 @@ public class ReceivePack {
return walk;
}
- /** @return all refs which were advertised to the client. */
+ /**
+ * Get refs which were advertised to the client.
+ *
+ * @return all refs which were advertised to the client, or null if
+ * {@link #setAdvertisedRefs(Map, Set)} has not been called yet.
+ */
public final Map<String, Ref> getAdvertisedRefs() {
- if (refs == null) {
- refs = refFilter.filter(db.getAllRefs());
-
- Ref head = refs.get(Constants.HEAD);
- if (head != null && head.isSymbolic())
- refs.remove(Constants.HEAD);
+ return refs;
+ }
- for (Ref ref : refs.values()) {
- if (ref.getObjectId() != null)
- advertisedHaves.add(ref.getObjectId());
- }
- advertisedHaves.addAll(db.getAdditionalHaves());
+ /**
+ * Set the refs advertised by this ReceivePack.
+ * <p>
+ * Intended to be called from a {@link PreReceiveHook}.
+ *
+ * @param allRefs
+ * explicit set of references to claim as advertised by this
+ * ReceivePack instance. This overrides any references that
+ * may exist in the source repository. The map is passed
+ * to the configured {@link #getRefFilter()}. If null, assumes
+ * all refs were advertised.
+ * @param additionalHaves
+ * explicit set of additional haves to claim as advertised. If
+ * null, assumes the default set of additional haves from the
+ * repository.
+ */
+ public void setAdvertisedRefs(Map<String, Ref> allRefs,
+ Set<ObjectId> additionalHaves) {
+ refs = allRefs != null ? allRefs : db.getAllRefs();
+ refs = refFilter.filter(refs);
+
+ Ref head = refs.get(Constants.HEAD);
+ if (head != null && head.isSymbolic())
+ refs.remove(Constants.HEAD);
+
+ for (Ref ref : refs.values()) {
+ if (ref.getObjectId() != null)
+ advertisedHaves.add(ref.getObjectId());
}
- return refs;
+ if (additionalHaves != null)
+ advertisedHaves.addAll(additionalHaves);
+ else
+ advertisedHaves.addAll(db.getAdditionalHaves());
}
- /** @return the set of objects advertised as present in this repository. */
+ /**
+ * Get objects advertised to the client.
+ *
+ * @return the set of objects advertised to the as present in this repository,
+ * or null if {@link #setAdvertisedRefs(Map, Set)} has not been called
+ * yet.
+ */
public final Set<ObjectId> getAdvertisedObjects() {
- getAdvertisedRefs();
return advertisedHaves;
}
@@ -342,13 +378,13 @@ public class ReceivePack {
* <p>
* If enabled, this instance will verify that references to objects not
* contained within the received pack are already reachable through at least
- * one other reference selected by the {@link #getRefFilter()} and displayed
- * as part of {@link #getAdvertisedRefs()}.
+ * one other reference displayed as part of {@link #getAdvertisedRefs()}.
* <p>
* This feature is useful when the application doesn't trust the client to
* not provide a forged SHA-1 reference to an object, in an attempt to
* access parts of the DAG that they aren't allowed to see and which have
- * been hidden from them via the configured {@link RefFilter}.
+ * been hidden from them via the configured {@link AdvertiseRefsHook} or
+ * {@link RefFilter}.
* <p>
* Enabling this feature may imply at least some, if not all, of the same
* functionality performed by {@link #setCheckReceivedObjects(boolean)}.
@@ -464,18 +500,42 @@ public class ReceivePack {
refLogIdent = pi;
}
+ /** @return the hook used while advertising the refs to the client */
+ public AdvertiseRefsHook getAdvertiseRefsHook() {
+ return advertiseRefsHook;
+ }
+
/** @return the filter used while advertising the refs to the client */
public RefFilter getRefFilter() {
return refFilter;
}
/**
+ * Set the hook used while advertising the refs to the client.
+ * <p>
+ * If the {@link AdvertiseRefsHook} chooses to call
+ * {@link #setAdvertisedRefs(Map,Set)}, only refs set by this hook
+ * <em>and</em> selected by the {@link RefFilter} will be shown to the client.
+ * Clients may still attempt to create or update a reference not advertised by
+ * the configured {@link AdvertiseRefsHook}. These attempts should be rejected
+ * by a matching {@link PreReceiveHook}.
+ *
+ * @param advertiseRefsHook
+ * the hook; may be null to show all refs.
+ */
+ public void setAdvertiseRefsHook(final AdvertiseRefsHook advertiseRefsHook) {
+ if (advertiseRefsHook != null)
+ this.advertiseRefsHook = advertiseRefsHook;
+ else
+ this.advertiseRefsHook = AdvertiseRefsHook.DEFAULT;
+ }
+
+ /**
* Set the filter used while advertising the refs to the client.
* <p>
* Only refs allowed by this filter will be shown to the client.
- * Clients may still attempt to create or update a reference hidden
- * by the configured {@link RefFilter}. These attempts should be
- * rejected by a matching {@link PreReceiveHook}.
+ * The filter is run against the refs specified by the
+ * {@link AdvertiseRefsHook} (if applicable).
*
* @param refFilter
* the filter; may be null to show all refs.
@@ -706,12 +766,18 @@ public class ReceivePack {
}
}
+ private Map<String, Ref> getAdvertisedOrDefaultRefs() {
+ if (refs == null)
+ setAdvertisedRefs(null, null);
+ return refs;
+ }
+
private void service() throws IOException {
if (biDirectionalPipe) {
sendAdvertisedRefs(new PacketLineOutRefAdvertiser(pckOut));
pckOut.flush();
} else
- getAdvertisedRefs();
+ getAdvertisedOrDefaultRefs();
if (advertiseError != null)
return;
recvCommands();
@@ -776,20 +842,33 @@ public class ReceivePack {
* the advertisement formatter.
* @throws IOException
* the formatter failed to write an advertisement.
+ * @throws ServiceMayNotContinueException
+ * the hook denied advertisement.
*/
- public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException {
+ public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException,
+ ServiceMayNotContinueException {
if (advertiseError != null) {
adv.writeOne("ERR " + advertiseError);
return;
}
+ try {
+ advertiseRefsHook.advertiseRefs(this);
+ } catch (ServiceMayNotContinueException fail) {
+ if (fail.getMessage() != null) {
+ adv.writeOne("ERR " + fail.getMessage());
+ fail.setOutput();
+ }
+ throw fail;
+ }
+
adv.init(db);
adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
adv.advertiseCapability(CAPABILITY_DELETE_REFS);
adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
if (allowOfsDelta)
adv.advertiseCapability(CAPABILITY_OFS_DELTA);
- adv.send(getAdvertisedRefs());
+ adv.send(getAdvertisedOrDefaultRefs());
for (ObjectId obj : advertisedHaves)
adv.advertiseHave(obj);
if (adv.isEmpty())

Back to the top