Expose GitWeb config via /config/server/info REST endpoint

In the Gerrit Client retrieve the GitWeb configuration via REST and
remove the GitWeb configuration from the config that is embedded in
the host page data.

In order to provide the GitWeb configuration from the REST endpoint
the GitWeb configuration must be bound in the sysinjector (the binding
of the GitWebModule stays in the webinjector).

Change-Id: I640e645f6c9a72d5539f33e28721f0cff93e732d
Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
Edwin Kempin
2015-05-08 13:40:40 +02:00
committed by David Pursehouse
parent e55a72f504
commit 7023f47c4b
24 changed files with 321 additions and 206 deletions

View File

@@ -16,7 +16,6 @@ package com.google.gerrit.httpd;
import com.google.common.base.Optional;
import com.google.gerrit.common.data.GerritConfig;
import com.google.gerrit.common.data.GitwebConfig;
import com.google.gerrit.server.config.AnonymousCowardName;
import com.google.gerrit.server.config.ConfigUtil;
import com.google.gerrit.server.config.GerritServerConfig;
@@ -34,7 +33,6 @@ import javax.servlet.ServletContext;
class GerritConfigProvider implements Provider<GerritConfig> {
private final Config cfg;
private final GitWebConfig gitWebConfig;
private final SshInfo sshInfo;
private final ServletContext servletContext;
@@ -43,12 +41,10 @@ class GerritConfigProvider implements Provider<GerritConfig> {
@Inject
GerritConfigProvider(
@GerritServerConfig Config gsc,
GitWebConfig gwc,
SshInfo si,
ServletContext sc,
@AnonymousCowardName String acn) {
cfg = gsc;
gitWebConfig = gwc;
sshInfo = si;
servletContext = sc;
anonymousCowardName = acn;
@@ -68,11 +64,6 @@ class GerritConfigProvider implements Provider<GerritConfig> {
config.setReportBugUrl(cfg.getString("gerrit", null, "reportBugUrl"));
config.setReportBugText(cfg.getString("gerrit", null, "reportBugText"));
if (gitWebConfig.getUrl() != null) {
config.setGitwebLink(new GitwebConfig(gitWebConfig.getUrl(), gitWebConfig
.getGitWebType()));
}
if (sshInfo != null && !sshInfo.getHostKeys().isEmpty()) {
config.setSshdAddress(sshInfo.getHostKeys().get(0).getHost());
}

View File

@@ -1,245 +0,0 @@
// Copyright (C) 2009 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.httpd;
import static java.nio.file.Files.isExecutable;
import static java.nio.file.Files.isRegularFile;
import com.google.gerrit.common.data.GitWebType;
import com.google.gerrit.server.config.GerritServerConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.inject.Inject;
import org.eclipse.jgit.lib.Config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
import java.nio.file.Paths;
public class GitWebConfig {
private static final Logger log = LoggerFactory.getLogger(GitWebConfig.class);
private final String url;
private final Path gitweb_cgi;
private final Path gitweb_css;
private final Path gitweb_js;
private final Path git_logo_png;
private GitWebType type;
@Inject
GitWebConfig(final SitePaths sitePaths, @GerritServerConfig final Config cfg) {
final String cfgUrl = cfg.getString("gitweb", null, "url");
final String cfgCgi = cfg.getString("gitweb", null, "cgi");
type = GitWebType.fromName(cfg.getString("gitweb", null, "type"));
if (type == null) {
url = null;
gitweb_cgi = null;
gitweb_css = null;
gitweb_js = null;
git_logo_png = null;
return;
}
type.setLinkName(cfg.getString("gitweb", null, "linkname"));
type.setBranch(cfg.getString("gitweb", null, "branch"));
type.setProject(cfg.getString("gitweb", null, "project"));
type.setRevision(cfg.getString("gitweb", null, "revision"));
type.setRootTree(cfg.getString("gitweb", null, "roottree"));
type.setFile(cfg.getString("gitweb", null, "file"));
type.setFileHistory(cfg.getString("gitweb", null, "filehistory"));
type.setLinkDrafts(cfg.getBoolean("gitweb", null, "linkdrafts", true));
type.setUrlEncode(cfg.getBoolean("gitweb", null, "urlencode", true));
String pathSeparator = cfg.getString("gitweb", null, "pathSeparator");
if (pathSeparator != null) {
if (pathSeparator.length() == 1) {
char c = pathSeparator.charAt(0);
if (isValidPathSeparator(c)) {
type.setPathSeparator(c);
} else {
log.warn("Invalid value specified for gitweb.pathSeparator: " + c);
}
} else {
log.warn("Value specified for gitweb.pathSeparator is not a single character:" + pathSeparator);
}
}
if (type.getBranch() == null) {
log.warn("No Pattern specified for gitweb.branch, disabling.");
type = null;
} else if (type.getProject() == null) {
log.warn("No Pattern specified for gitweb.project, disabling.");
type = null;
} else if (type.getRevision() == null) {
log.warn("No Pattern specified for gitweb.revision, disabling.");
type = null;
} else if (type.getRootTree() == null) {
log.warn("No Pattern specified for gitweb.roottree, disabling.");
type = null;
} else if (type.getFile() == null) {
log.warn("No Pattern specified for gitweb.file, disabling.");
type = null;
} else if (type.getFileHistory() == null) {
log.warn("No Pattern specified for gitweb.filehistory, disabling.");
type = null;
}
if ((cfgUrl != null && cfgUrl.isEmpty())
|| (cfgCgi != null && cfgCgi.isEmpty())) {
// Either setting was explicitly set to the empty string disabling
// gitweb for this server. Disable the configuration.
//
url = null;
gitweb_cgi = null;
gitweb_css = null;
gitweb_js = null;
git_logo_png = null;
return;
}
if ((cfgUrl != null) && (cfgCgi == null || cfgCgi.isEmpty())) {
// Use an externally managed gitweb instance, and not an internal one.
//
url = cfgUrl;
gitweb_cgi = null;
gitweb_css = null;
gitweb_js = null;
git_logo_png = null;
return;
}
final Path pkgCgi = Paths.get("/usr/lib/cgi-bin/gitweb.cgi");
String[] resourcePaths = {"/usr/share/gitweb/static", "/usr/share/gitweb",
"/var/www/static", "/var/www"};
Path cgi;
if (cfgCgi != null) {
// Use the CGI script configured by the administrator, failing if it
// cannot be used as specified.
//
cgi = sitePaths.resolve(cfgCgi);
if (!isRegularFile(cgi)) {
throw new IllegalStateException("Cannot find gitweb.cgi: " + cgi);
}
if (!isExecutable(cgi)) {
throw new IllegalStateException("Cannot execute gitweb.cgi: " + cgi);
}
if (!cgi.equals(pkgCgi)) {
// Assume the administrator pointed us to the distribution,
// which also has the corresponding CSS and logo file.
//
String absPath = cgi.getParent().toAbsolutePath().toString();
resourcePaths = new String[] {absPath + "/static", absPath};
}
} else if (isRegularFile(pkgCgi) && isExecutable(pkgCgi)) {
// Use the OS packaged CGI.
//
log.debug("Assuming gitweb at " + pkgCgi);
cgi = pkgCgi;
} else {
log.warn("gitweb not installed (no " + pkgCgi + " found)");
cgi = null;
resourcePaths = new String[] {};
}
Path css = null;
Path js = null;
Path logo = null;
for (String path : resourcePaths) {
Path dir = Paths.get(path);
css = dir.resolve("gitweb.css");
js = dir.resolve("gitweb.js");
logo = dir.resolve("git-logo.png");
if (isRegularFile(css) && isRegularFile(logo)) {
break;
}
}
if (cfgUrl == null || cfgUrl.isEmpty()) {
url = cgi != null ? "gitweb" : null;
} else {
url = cgi != null ? cfgUrl : null;
}
gitweb_cgi = cgi;
gitweb_css = css;
gitweb_js = js;
git_logo_png = logo;
}
/** @return GitWebType for gitweb viewer. */
public GitWebType getGitWebType() {
return type;
}
/**
* @return URL of the entry point into gitweb. This URL may be relative to our
* context if gitweb is hosted by ourselves; or absolute if its hosted
* elsewhere; or null if gitweb has not been configured.
*/
public String getUrl() {
return url;
}
/** @return local path to the CGI executable; null if we shouldn't execute. */
public Path getGitwebCGI() {
return gitweb_cgi;
}
/** @return local path of the {@code gitweb.css} matching the CGI. */
public Path getGitwebCSS() {
return gitweb_css;
}
/** @return local path of the {@code gitweb.js} for the CGI. */
public Path getGitwebJS() {
return gitweb_js;
}
/** @return local path of the {@code git-logo.png} for the CGI. */
public Path getGitLogoPNG() {
return git_logo_png;
}
/**
* Determines if a given character can be used unencoded in an URL as a
* replacement for the path separator '/'.
*
* Reasoning: http://www.ietf.org/rfc/rfc1738.txt § 2.2:
*
* ... only alphanumerics, the special characters "$-_.+!*'(),", and
* reserved characters used for their reserved purposes may be used
* unencoded within a URL.
*
* The following characters might occur in file names, however:
*
* alphanumeric characters,
*
* "$-_.+!',"
*/
static boolean isValidPathSeparator(char c) {
switch (c) {
case '*':
case '(':
case ')':
return true;
default:
return false;
}
}
}

View File

@@ -31,12 +31,11 @@ import com.google.gerrit.server.RemotePeer;
import com.google.gerrit.server.config.AuthConfig;
import com.google.gerrit.server.config.CanonicalWebUrl;
import com.google.gerrit.server.config.GerritRequestModule;
import com.google.gerrit.server.config.GitWebConfig;
import com.google.gerrit.server.git.AsyncReceiveCommits;
import com.google.gerrit.server.util.GuiceRequestScopePropagator;
import com.google.gerrit.server.util.RequestScopePropagator;
import com.google.inject.AbstractModule;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.ProvisionException;
import com.google.inject.servlet.RequestScoped;
@@ -49,21 +48,14 @@ public class WebModule extends LifecycleModule {
private final GerritOptions options;
@Inject
WebModule(final AuthConfig authConfig,
@CanonicalWebUrl @Nullable final String canonicalUrl,
WebModule(AuthConfig authConfig,
@CanonicalWebUrl @Nullable String canonicalUrl,
GerritOptions options,
final Injector creatingInjector) {
GitWebConfig gitWebConfig) {
this.authConfig = authConfig;
this.wantSSL = canonicalUrl != null && canonicalUrl.startsWith("https:");
this.options = options;
this.gitWebConfig =
creatingInjector.createChildInjector(new AbstractModule() {
@Override
protected void configure() {
bind(GitWebConfig.class);
}
}).getInstance(GitWebConfig.class);
this.gitWebConfig = gitWebConfig;
}
@Override
@@ -84,7 +76,6 @@ public class WebModule extends LifecycleModule {
install(new GerritRequestModule());
install(new GitOverHttpServlet.Module(options.enableMasterFeatures()));
bind(GitWebConfig.class).toInstance(gitWebConfig);
if (gitWebConfig.getGitwebCGI() != null) {
install(new GitWebModule());
}

View File

@@ -17,7 +17,7 @@ package com.google.gerrit.httpd.gitweb;
import static com.google.gerrit.common.FileUtil.lastModified;
import com.google.common.io.ByteStreams;
import com.google.gerrit.httpd.GitWebConfig;
import com.google.gerrit.server.config.GitWebConfig;
import com.google.gwtexpui.server.CacheHeaders;
import com.google.inject.Inject;
import com.google.inject.Singleton;

View File

@@ -16,8 +16,8 @@ package com.google.gerrit.httpd.gitweb;
import static com.google.gerrit.common.FileUtil.lastModified;
import com.google.gerrit.httpd.GitWebConfig;
import com.google.gerrit.httpd.HtmlDomUtil;
import com.google.gerrit.server.config.GitWebConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gwtexpui.server.CacheHeaders;
import com.google.gwtjsonrpc.server.RPCServletUtils;

View File

@@ -17,7 +17,7 @@ package com.google.gerrit.httpd.gitweb;
import static com.google.gerrit.common.FileUtil.lastModified;
import com.google.common.io.ByteStreams;
import com.google.gerrit.httpd.GitWebConfig;
import com.google.gerrit.server.config.GitWebConfig;
import com.google.gwtexpui.server.CacheHeaders;
import com.google.inject.Inject;
import com.google.inject.Singleton;

View File

@@ -34,11 +34,11 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.gerrit.common.PageLinks;
import com.google.gerrit.common.data.GerritConfig;
import com.google.gerrit.extensions.restapi.Url;
import com.google.gerrit.httpd.GitWebConfig;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.AnonymousUser;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.config.GitWebConfig;
import com.google.gerrit.server.config.SitePaths;
import com.google.gerrit.server.git.LocalDiskRepositoryManager;
import com.google.gerrit.server.project.NoSuchProjectException;

View File

@@ -1,40 +0,0 @@
// Copyright (C) 2011 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.httpd;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
public class GitWebConfigTest {
private static final String VALID_CHARACTERS = "*()";
private static final String SOME_INVALID_CHARACTERS = "09AZaz$-_.+!',";
@Test
public void testValidPathSeparator() {
for(char c : VALID_CHARACTERS.toCharArray()) {
assertTrue("valid character rejected: " + c, GitWebConfig.isValidPathSeparator(c));
}
}
@Test
public void testInalidPathSeparator() {
for(char c : SOME_INVALID_CHARACTERS.toCharArray()) {
assertFalse("invalid character accepted: " + c, GitWebConfig.isValidPathSeparator(c));
}
}
}