Merge "Rename "master" to "primary" in documentation and comments" into stable-3.1
diff --git a/java/com/google/gerrit/pgm/Daemon.java b/java/com/google/gerrit/pgm/Daemon.java
index e6860c2..71994e0 100644
--- a/java/com/google/gerrit/pgm/Daemon.java
+++ b/java/com/google/gerrit/pgm/Daemon.java
@@ -536,14 +536,14 @@
 
   private Injector createWebInjector() {
     final List<Module> modules = new ArrayList<>();
-    if (sshd) {
-      modules.add(new ProjectQoSFilter.Module());
-    }
     modules.add(RequestContextFilter.module());
     modules.add(RequestMetricsFilter.module());
     modules.add(H2CacheBasedWebSession.module());
     modules.add(sysInjector.getInstance(GerritAuthModule.class));
     modules.add(sysInjector.getInstance(GitOverHttpModule.class));
+    if (sshd) {
+      modules.add(new ProjectQoSFilter.Module());
+    }
     modules.add(AllRequestFilter.module());
     modules.add(sysInjector.getInstance(WebModule.class));
     modules.add(sysInjector.getInstance(RequireSslFilter.Module.class));
diff --git a/javatests/com/google/gerrit/integration/git/GitProtocolV2IT.java b/javatests/com/google/gerrit/integration/git/GitProtocolV2IT.java
index 9c4bdef4..8577c16 100644
--- a/javatests/com/google/gerrit/integration/git/GitProtocolV2IT.java
+++ b/javatests/com/google/gerrit/integration/git/GitProtocolV2IT.java
@@ -35,6 +35,7 @@
 import com.google.gerrit.entities.RefNames;
 import com.google.gerrit.extensions.api.GerritApi;
 import com.google.gerrit.extensions.common.ChangeInput;
+import com.google.gerrit.server.config.AllProjectsName;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.group.SystemGroupBackend;
 import com.google.inject.Inject;
@@ -47,12 +48,15 @@
 
 @UseSsh
 public class GitProtocolV2IT extends StandaloneSiteTest {
+  private static final String ADMIN_PASSWORD = "secret";
   private final String[] SSH_KEYGEN_CMD =
       new String[] {"ssh-keygen", "-t", "rsa", "-q", "-P", "", "-f"};
   private final String[] GIT_LS_REMOTE =
       new String[] {"git", "-c", "protocol.version=2", "ls-remote", "-o", "trace=12345"};
   private final String[] GIT_CLONE_MIRROR =
       new String[] {"git", "-c", "protocol.version=2", "clone", "--mirror"};
+  private final String[] GIT_FETCH = new String[] {"git", "-c", "protocol.version=2", "fetch"};
+  private final String[] GIT_INIT = new String[] {"git", "init"};
   private final String GIT_SSH_COMMAND =
       "ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i";
 
@@ -61,6 +65,7 @@
   @Inject private ProjectOperations projectOperations;
   @Inject private @TestSshServerAddress InetSocketAddress sshAddress;
   @Inject private @GerritServerConfig Config config;
+  @Inject private AllProjectsName allProjectsName;
 
   @BeforeClass
   public static void assertGitClientVersion() throws Exception {
@@ -131,7 +136,7 @@
               .commit;
 
       // Prepare new change on secret branch
-      in = new ChangeInput(project.get(), "secret", "Test secret change");
+      in = new ChangeInput(project.get(), ADMIN_PASSWORD, "Test secret change");
       in.newBranch = true;
 
       // Create new change and retrieve SHA1 for the created patch set
@@ -257,9 +262,82 @@
     }
   }
 
+  @Test
+  public void testGitWireProtocolV2FetchIndividualRef() throws Exception {
+    try (ServerContext ctx = startServer()) {
+      ctx.getInjector().injectMembers(this);
+
+      // Setup admin password
+      gApi.accounts().id(admin.username()).setHttpPassword(ADMIN_PASSWORD);
+
+      // Get authenticated Git/HTTP URL
+      String urlWithCredentials =
+          config
+              .getString("gerrit", null, "canonicalweburl")
+              .replace("http://", "http://" + admin.username() + ":" + ADMIN_PASSWORD + "@");
+
+      // Create project
+      Project.NameKey privateProject = Project.nameKey("private-project");
+      gApi.projects().create(privateProject.get());
+
+      // Set protocol.version=2 in target repository
+      execute(
+          ImmutableList.of("git", "config", "protocol.version", "2"),
+          sitePaths
+              .site_path
+              .resolve("git")
+              .resolve(privateProject.get() + Constants.DOT_GIT)
+              .toFile());
+
+      // Disallow general read permissions for anonymous users
+      projectOperations
+          .project(allProjectsName)
+          .forUpdate()
+          .add(deny(Permission.READ).ref("refs/*").group(SystemGroupBackend.ANONYMOUS_USERS))
+          .add(
+              allow(Permission.READ)
+                  .ref("refs/heads/master")
+                  .group(SystemGroupBackend.REGISTERED_USERS))
+          .update();
+
+      // Set up project permission to allow registered users fetching changes/*
+      projectOperations
+          .project(privateProject)
+          .forUpdate()
+          .add(
+              allow(Permission.READ)
+                  .ref("refs/changes/*")
+                  .group(SystemGroupBackend.REGISTERED_USERS))
+          .update();
+
+      // Create new change and retrieve refs for the created patch set
+      ChangeInput visibleChangeIn =
+          new ChangeInput(privateProject.get(), "master", "Test private change");
+      visibleChangeIn.newBranch = true;
+      int visibleChangeNumber = gApi.changes().create(visibleChangeIn).info()._number;
+      Change.Id changeId = Change.id(visibleChangeNumber);
+      String visibleChangeNumberRef = RefNames.patchSetRef(PatchSet.id(changeId, 1));
+
+      // Fetch a single ref using git wire protocol v2 over HTTP with authentication
+      execute(GIT_INIT);
+
+      String outFetchRef =
+          execute(
+              ImmutableList.<String>builder()
+                  .add(GIT_FETCH)
+                  .add(urlWithCredentials + "/" + privateProject.get())
+                  .add(visibleChangeNumberRef)
+                  .build(),
+              ImmutableMap.of("GIT_TRACE_PACKET", "1"));
+
+      assertThat(outFetchRef).contains("git< version 2");
+      assertThat(outFetchRef).contains(visibleChangeNumberRef);
+    }
+  }
+
   private void setUpUserAuthentication(String username) throws Exception {
     // Assign HTTP password to user
-    gApi.accounts().id(username).setHttpPassword("secret");
+    gApi.accounts().id(username).setHttpPassword(ADMIN_PASSWORD);
 
     // Generate private/public key for user
     execute(
@@ -285,6 +363,10 @@
     assertThat(out).contains(commit);
   }
 
+  private String execute(String... cmds) throws Exception {
+    return execute(ImmutableList.<String>builder().add(cmds).build());
+  }
+
   private String execute(ImmutableList<String> cmd) throws Exception {
     return execute(cmd, sitePaths.data_dir.toFile(), ImmutableMap.of());
   }
diff --git a/plugins/replication b/plugins/replication
index 505f2c6..0d91ffd 160000
--- a/plugins/replication
+++ b/plugins/replication
@@ -1 +1 @@
-Subproject commit 505f2c63c41100d215e706c7df6932854d213bd7
+Subproject commit 0d91ffd189297f511c93d40a864978b5774805c1