Merge changes Id81c291a,I15d97ec7

* changes:
  VisibleRefFilter: break out special cases to methods
  Optimize edit handling in VisibleRefFilter
This commit is contained in:
Dave Borowitz
2016-06-21 19:04:11 +00:00
committed by Gerrit Code Review
3 changed files with 77 additions and 96 deletions

View File

@@ -164,29 +164,17 @@ public class RefNames {
* @return reference prefix for this change edit * @return reference prefix for this change edit
*/ */
public static String refsEditPrefix(Account.Id accountId, Change.Id changeId) { public static String refsEditPrefix(Account.Id accountId, Change.Id changeId) {
return new StringBuilder(refsUsers(accountId)) return refsEditPrefix(accountId) + changeId.get() + '/';
.append('/') }
.append(EDIT_PREFIX)
.append(changeId.get()) public static String refsEditPrefix(Account.Id accountId) {
.append('/') return refsUsers(accountId) + '/' + EDIT_PREFIX;
.toString();
} }
public static boolean isRefsEdit(String ref) { public static boolean isRefsEdit(String ref) {
return ref.startsWith(REFS_USERS) && ref.contains(EDIT_PREFIX); return ref.startsWith(REFS_USERS) && ref.contains(EDIT_PREFIX);
} }
public static boolean isRefsEditOf(String ref, Account.Id accountId) {
if (accountId == null) {
return false;
}
String prefix = new StringBuilder(refsUsers(accountId))
.append('/')
.append(EDIT_PREFIX)
.toString();
return ref.startsWith(prefix);
}
static Integer parseShardedRefPart(String name) { static Integer parseShardedRefPart(String name) {
if (name == null) { if (name == null) {
return null; return null;

View File

@@ -80,30 +80,6 @@ public class RefNamesTest {
assertThat(RefNames.isRefsEdit("refs/heads/master")).isFalse(); assertThat(RefNames.isRefsEdit("refs/heads/master")).isFalse();
} }
@Test
public void isRefsEditOf() throws Exception {
assertThat(
RefNames.isRefsEditOf("refs/users/23/1011123/edit-67473/42", accountId))
.isTrue();
// other user
assertThat(
RefNames.isRefsEditOf("refs/users/20/1078620/edit-67473/42", accountId))
.isFalse();
// user ref, but no edit ref
assertThat(RefNames.isRefsEditOf("refs/users/23/1011123", accountId))
.isFalse();
// bad user shard
assertThat(
RefNames.isRefsEditOf("refs/users/77/1011123/edit-67473/42", accountId))
.isFalse();
// other ref
assertThat(RefNames.isRefsEditOf("refs/heads/master", accountId)).isFalse();
}
@Test @Test
public void testParseShardedRefsPart() throws Exception { public void testParseShardedRefsPart() throws Exception {
assertThat(parseShardedRefPart("01/1")).isEqualTo(1); assertThat(parseShardedRefPart("01/1")).isEqualTo(1);

View File

@@ -14,8 +14,12 @@
package com.google.gerrit.server.git; package com.google.gerrit.server.git;
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CACHE_AUTOMERGE;
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CHANGES;
import static com.google.gerrit.reviewdb.client.RefNames.REFS_CONFIG;
import static com.google.gerrit.reviewdb.client.RefNames.REFS_USERS_SELF;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.gerrit.common.Nullable; import com.google.gerrit.common.Nullable;
import com.google.gerrit.reviewdb.client.Account; import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Change; import com.google.gerrit.reviewdb.client.Change;
@@ -60,6 +64,7 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
private final ProjectControl projectCtl; private final ProjectControl projectCtl;
private final ReviewDb reviewDb; private final ReviewDb reviewDb;
private final boolean showMetadata; private final boolean showMetadata;
private String userEditPrefix;
private Set<Change.Id> visibleChanges; private Set<Change.Id> visibleChanges;
public VisibleRefFilter( public VisibleRefFilter(
@@ -81,86 +86,62 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
} }
public Map<String, Ref> filter(Map<String, Ref> refs, boolean filterTagsSeparately) { public Map<String, Ref> filter(Map<String, Ref> refs, boolean filterTagsSeparately) {
if (projectCtl.getProjectState().isAllUsers() if (projectCtl.getProjectState().isAllUsers()) {
&& projectCtl.getUser().isIdentifiedUser()) { refs = addUsersSelfSymref(refs);
Ref userRef =
refs.get(RefNames.refsUsers(projectCtl.getUser().getAccountId()));
if (userRef != null) {
SymbolicRef refsUsersSelf =
new SymbolicRef(RefNames.REFS_USERS_SELF, userRef);
refs = new HashMap<>(refs);
refs.put(refsUsersSelf.getName(), refsUsersSelf);
}
} }
if (projectCtl.allRefsAreVisible(ImmutableSet.of(RefNames.REFS_CONFIG))) { if (projectCtl.allRefsAreVisible(ImmutableSet.of(REFS_CONFIG))) {
Map<String, Ref> r = Maps.newHashMap(refs); return fastHideRefsMetaConfig(refs);
if (!projectCtl.controlForRef(RefNames.REFS_CONFIG).isVisible()) {
r.remove(RefNames.REFS_CONFIG);
}
return r;
} }
Account.Id currAccountId; Account.Id userId;
boolean canViewMetadata; boolean viewMetadata;
if (projectCtl.getUser().isIdentifiedUser()) { if (projectCtl.getUser().isIdentifiedUser()) {
IdentifiedUser user = projectCtl.getUser().asIdentifiedUser(); IdentifiedUser user = projectCtl.getUser().asIdentifiedUser();
currAccountId = user.getAccountId(); userId = user.getAccountId();
canViewMetadata = user.getCapabilities().canAccessDatabase(); viewMetadata = user.getCapabilities().canAccessDatabase();
userEditPrefix = RefNames.refsEditPrefix(userId);
} else { } else {
currAccountId = null; userId = null;
canViewMetadata = false; viewMetadata = false;
} }
Map<String, Ref> result = new HashMap<>(); Map<String, Ref> result = new HashMap<>();
List<Ref> deferredTags = new ArrayList<>(); List<Ref> deferredTags = new ArrayList<>();
for (Ref ref : refs.values()) { for (Ref ref : refs.values()) {
String name = ref.getName();
Change.Id changeId; Change.Id changeId;
Account.Id accountId; Account.Id accountId;
if (ref.getName().startsWith(RefNames.REFS_CACHE_AUTOMERGE)) { if (name.startsWith(REFS_CACHE_AUTOMERGE)
|| (!showMetadata && isMetadata(name))) {
continue; continue;
} else if (showMetadata } else if (RefNames.isRefsEdit(name)) {
&& (RefNames.isRefsEditOf(ref.getLeaf().getName(), currAccountId) // Edits are visible only to the owning user, if change is visible.
|| (RefNames.isRefsEdit(ref.getLeaf().getName()) if (viewMetadata || visibleEdit(name)) {
&& canViewMetadata))) { result.put(name, ref);
// Change edit reference related is visible to the account that owns the }
// change edit. } else if ((changeId = Change.Id.fromRef(name)) != null) {
// // Change ref is visible only if the change is visible.
// TODO(dborowitz): Verify if change is visible (to exclude edits on if (viewMetadata || visible(changeId)) {
// changes that the user has lost access to). result.put(name, ref);
result.put(ref.getName(), ref); }
} else if ((accountId = Account.Id.fromRef(name)) != null) {
} else if ((changeId = Change.Id.fromRef(ref.getName())) != null) { // Account ref is visible only to corresponding account.
// Reference related to a change is visible if the change is visible. if (viewMetadata || (accountId.equals(userId)
if (showMetadata && (canViewMetadata || visible(changeId))) { && projectCtl.controlForRef(name).isVisible())) {
result.put(ref.getName(), ref); result.put(name, ref);
} }
} else if (isTag(ref)) { } else if (isTag(ref)) {
// If its a tag, consider it later. // If its a tag, consider it later.
//
if (ref.getObjectId() != null) { if (ref.getObjectId() != null) {
deferredTags.add(ref); deferredTags.add(ref);
} }
} else if (projectCtl.controlForRef(ref.getLeaf().getName()).isVisible()) { } else if (projectCtl.controlForRef(ref.getLeaf().getName()).isVisible()) {
// Use the leaf to lookup the control data. If the reference is // Use the leaf to lookup the control data. If the reference is
// symbolic we want the control around the final target. If its // symbolic we want the control around the final target. If its
// not symbolic then getLeaf() is a no-op returning ref itself. // not symbolic then getLeaf() is a no-op returning ref itself.
// result.put(name, ref);
if ((accountId =
Account.Id.fromRef(ref.getLeaf().getName())) != null) {
// Reference related to an account is visible only for the current
// account.
if (showMetadata
&& (canViewMetadata || accountId.equals(currAccountId))) {
result.put(ref.getName(), ref);
}
} else {
result.put(ref.getName(), ref);
}
} }
} }
@@ -182,6 +163,28 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
return result; return result;
} }
private Map<String, Ref> fastHideRefsMetaConfig(Map<String, Ref> refs) {
if (refs.containsKey(REFS_CONFIG)
&& !projectCtl.controlForRef(REFS_CONFIG).isVisible()) {
Map<String, Ref> r = new HashMap<>(refs);
r.remove(REFS_CONFIG);
return r;
}
return refs;
}
private Map<String, Ref> addUsersSelfSymref(Map<String, Ref> refs) {
if (projectCtl.getUser().isIdentifiedUser()) {
Ref r = refs.get(RefNames.refsUsers(projectCtl.getUser().getAccountId()));
if (r != null) {
SymbolicRef s = new SymbolicRef(REFS_USERS_SELF, r);
refs = new HashMap<>(refs);
refs.put(s.getName(), s);
}
}
return refs;
}
@Override @Override
protected Map<String, Ref> getAdvertisedRefs(Repository repository, protected Map<String, Ref> getAdvertisedRefs(Repository repository,
RevWalk revWalk) throws ServiceMayNotContinueException { RevWalk revWalk) throws ServiceMayNotContinueException {
@@ -211,6 +214,16 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
return visibleChanges.contains(changeId); return visibleChanges.contains(changeId);
} }
private boolean visibleEdit(String name) {
if (userEditPrefix != null && name.startsWith(userEditPrefix)) {
Change.Id id = Change.Id.fromEditRefPart(name);
if (id != null) {
return visible(id);
}
}
return false;
}
private Set<Change.Id> visibleChangesBySearch() { private Set<Change.Id> visibleChangesBySearch() {
Project project = projectCtl.getProject(); Project project = projectCtl.getProject();
try { try {
@@ -247,6 +260,10 @@ public class VisibleRefFilter extends AbstractAdvertiseRefsHook {
} }
} }
private static boolean isMetadata(String name) {
return name.startsWith(REFS_CHANGES) || RefNames.isRefsEdit(name);
}
private static boolean isTag(Ref ref) { private static boolean isTag(Ref ref) {
return ref.getLeaf().getName().startsWith(Constants.R_TAGS); return ref.getLeaf().getName().startsWith(Constants.R_TAGS);
} }