Fix infinite loops when walking project hierarchy

Always walk up the tree using a special iterator that knows how
to track visited project names and breaks any cycle, ensuring
All-Projects is always reached.

Change-Id: Ib6ad9505b3225bfa40ba067c799ce18130eafd29
This commit is contained in:
Shawn Pearce
2013-01-15 03:21:14 +00:00
parent 7cbbed1e7d
commit 740a217fac
10 changed files with 174 additions and 123 deletions

View File

@@ -17,7 +17,6 @@ package com.google.gerrit.server.project;
import static com.google.gerrit.server.git.GitRepositoryManager.REFS_DASHBOARDS;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.gerrit.extensions.restapi.ResourceNotFoundException;
import com.google.gerrit.extensions.restapi.RestReadView;
import com.google.gerrit.reviewdb.client.Project;
@@ -39,7 +38,6 @@ import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Set;
class ListDashboards implements RestReadView<ProjectResource> {
private static final Logger log = LoggerFactory.getLogger(DashboardsCollection.class);
@@ -57,16 +55,16 @@ class ListDashboards implements RestReadView<ProjectResource> {
@Override
public Object apply(ProjectResource resource)
throws ResourceNotFoundException, IOException {
ProjectControl ctl = resource.getControl();
ProjectControl ctl = resource.getControl();
String project = ctl.getProject().getName();
if (!inherited) {
return scan(resource.getControl(), project, true);
}
List<List<DashboardInfo>> all = Lists.newArrayList();
Set<Project.NameKey> seen = Sets.newHashSet();
boolean setDefault = true;
for (;;) {
for (ProjectState ps : ctl.getProjectState().tree()) {
ctl = ps.controlFor(ctl.getCurrentUser());
if (ctl.isVisible()) {
List<DashboardInfo> list = scan(ctl, project, setDefault);
for (DashboardInfo d : list) {
@@ -78,12 +76,6 @@ class ListDashboards implements RestReadView<ProjectResource> {
all.add(list);
}
}
ProjectState ps = ctl.getProjectState().getParentState();
if (ps == null || !seen.add(ps.getProject().getNameKey())) {
break;
}
ctl = ps.controlFor(ctl.getCurrentUser());
}
return all;
}