From 1b2d47e7a2a0e37177c5c7a79caa509c22384e85 Mon Sep 17 00:00:00 2001 From: Dave Borowitz Date: Fri, 5 Jun 2015 13:54:26 -0700 Subject: [PATCH] Extract CGI configuration from GitWebConfig GitWebConfig was used for two separate things: 1. Encapsulating the (type, GitWebConfig) pair that gets passed through the GerritConfig to the host page. 2. Describing the configuration for the built-in CGI servlet in the gitweb package. Separate these concerns, creating GitWebCgiConfig in the same config package as GitWebConfig. (Although it contains configuration for the httpd functionality, it needs to live in the server package so other server classes can check the configuration status.) Change-Id: I002beb892d415eb41a15829e6c5d540be253e390 --- .../com/google/gerrit/httpd/WebModule.java | 10 +- .../gerrit/httpd/gitweb/GitLogoServlet.java | 6 +- .../gerrit/httpd/gitweb/GitWebCssServlet.java | 6 +- .../httpd/gitweb/GitWebJavaScriptServlet.java | 6 +- .../gerrit/httpd/gitweb/GitWebServlet.java | 6 +- .../gerrit/server/config/GitWebCgiConfig.java | 137 +++++++++++++++ .../gerrit/server/config/GitWebConfig.java | 159 ++++-------------- 7 files changed, 185 insertions(+), 145 deletions(-) create mode 100644 gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebCgiConfig.java diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java index 423e691eb9..d5f11004fa 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/WebModule.java @@ -30,7 +30,7 @@ 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.config.GitWebCgiConfig; import com.google.gerrit.server.git.AsyncReceiveCommits; import com.google.gerrit.server.util.GuiceRequestScopePropagator; import com.google.gerrit.server.util.RequestScopePropagator; @@ -43,18 +43,18 @@ import java.net.SocketAddress; public class WebModule extends LifecycleModule { private final AuthConfig authConfig; private final boolean wantSSL; - private final GitWebConfig gitWebConfig; + private final GitWebCgiConfig gitWebCgiConfig; private final GerritOptions options; @Inject WebModule(AuthConfig authConfig, @CanonicalWebUrl @Nullable String canonicalUrl, GerritOptions options, - GitWebConfig gitWebConfig) { + GitWebCgiConfig gitWebCgiConfig) { this.authConfig = authConfig; this.wantSSL = canonicalUrl != null && canonicalUrl.startsWith("https:"); this.options = options; - this.gitWebConfig = gitWebConfig; + this.gitWebCgiConfig = gitWebCgiConfig; } @Override @@ -75,7 +75,7 @@ public class WebModule extends LifecycleModule { install(new GerritRequestModule()); install(new GitOverHttpServlet.Module(options.enableMasterFeatures())); - if (gitWebConfig.getGitwebCGI() != null) { + if (gitWebCgiConfig.getGitwebCgi() != null) { install(new GitWebModule()); } diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java index 2bb31c7bce..62dfc24a47 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitLogoServlet.java @@ -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.server.config.GitWebConfig; +import com.google.gerrit.server.config.GitWebCgiConfig; import com.google.gwtexpui.server.CacheHeaders; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -41,9 +41,9 @@ class GitLogoServlet extends HttpServlet { private final byte[] raw; @Inject - GitLogoServlet(GitWebConfig gitWebConfig) throws IOException { + GitLogoServlet(GitWebCgiConfig cfg) throws IOException { byte[] png; - Path src = gitWebConfig.getGitLogoPNG(); + Path src = cfg.getGitLogoPng(); if (src != null) { try (InputStream in = Files.newInputStream(src)) { png = ByteStreams.toByteArray(in); diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java index bddcb2396b..5ea2253baa 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebCssServlet.java @@ -17,7 +17,7 @@ package com.google.gerrit.httpd.gitweb; import static com.google.gerrit.common.FileUtil.lastModified; import com.google.gerrit.httpd.HtmlDomUtil; -import com.google.gerrit.server.config.GitWebConfig; +import com.google.gerrit.server.config.GitWebCgiConfig; import com.google.gerrit.server.config.SitePaths; import com.google.gwtexpui.server.CacheHeaders; import com.google.gwtjsonrpc.server.RPCServletUtils; @@ -46,8 +46,8 @@ abstract class GitWebCssServlet extends HttpServlet { @Singleton static class Default extends GitWebCssServlet { @Inject - Default(GitWebConfig gwc) throws IOException { - super(gwc.getGitwebCSS()); + Default(GitWebCgiConfig gwcc) throws IOException { + super(gwcc.getGitwebCss()); } } diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java index 9924f2938f..617167b751 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebJavaScriptServlet.java @@ -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.server.config.GitWebConfig; +import com.google.gerrit.server.config.GitWebCgiConfig; import com.google.gwtexpui.server.CacheHeaders; import com.google.inject.Inject; import com.google.inject.Singleton; @@ -41,9 +41,9 @@ class GitWebJavaScriptServlet extends HttpServlet { private final byte[] raw; @Inject - GitWebJavaScriptServlet(final GitWebConfig gitWebConfig) throws IOException { + GitWebJavaScriptServlet(GitWebCgiConfig gitWebCgiConfig) throws IOException { byte[] png; - Path src = gitWebConfig.getGitwebJS(); + Path src = gitWebCgiConfig.getGitwebJs(); if (src != null) { try (InputStream in = Files.newInputStream(src)) { png = ByteStreams.toByteArray(in); diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java index 2fec04f22a..57126a5642 100644 --- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java +++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/gitweb/GitWebServlet.java @@ -38,6 +38,7 @@ import com.google.gerrit.server.AnonymousUser; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.IdentifiedUser; import com.google.gerrit.server.config.GerritServerConfig; +import com.google.gerrit.server.config.GitWebCgiConfig; import com.google.gerrit.server.config.GitWebConfig; import com.google.gerrit.server.config.SitePaths; import com.google.gerrit.server.git.LocalDiskRepositoryManager; @@ -105,13 +106,14 @@ class GitWebServlet extends HttpServlet { SitePaths site, @GerritServerConfig Config cfg, SshInfo sshInfo, - GitWebConfig gitWebConfig) + GitWebConfig gitWebConfig, + GitWebCgiConfig gitWebCgiConfig) throws IOException { this.repoManager = repoManager; this.projectControl = projectControl; this.anonymousUserProvider = anonymousUserProvider; this.userProvider = userProvider; - this.gitwebCgi = gitWebConfig.getGitwebCGI(); + this.gitwebCgi = gitWebCgiConfig.getGitwebCgi(); this.deniedActions = new HashSet<>(); final String url = gitWebConfig.getUrl(); diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebCgiConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebCgiConfig.java new file mode 100644 index 0000000000..63834f1cec --- /dev/null +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebCgiConfig.java @@ -0,0 +1,137 @@ +// Copyright (C) 2015 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.server.config; + +import static java.nio.file.Files.isExecutable; +import static java.nio.file.Files.isRegularFile; + +import com.google.inject.Inject; +import com.google.inject.Singleton; + +import org.eclipse.jgit.lib.Config; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.nio.file.Paths; + +@Singleton +public class GitWebCgiConfig { + private static final Logger log = + LoggerFactory.getLogger(GitWebCgiConfig.class); + + public GitWebCgiConfig disabled() { + return new GitWebCgiConfig(); + } + + private final Path cgi; + private final Path css; + private final Path js; + private final Path logoPng; + + @Inject + GitWebCgiConfig(SitePaths sitePaths, @GerritServerConfig Config cfg) { + if (GitWebConfig.isDisabled(cfg)) { + cgi = null; + css = null; + js = null; + logoPng = null; + return; + } + + String cfgCgi = cfg.getString("gitweb", null, "cgi"); + 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; + } + } + + this.cgi = cgi; + this.css = css; + this.js = js; + this.logoPng = logo; + } + + private GitWebCgiConfig() { + this.cgi = null; + this.css = null; + this.js = null; + this.logoPng = null; + } + + /** @return local path to the CGI executable; null if we shouldn't execute. */ + public Path getGitwebCgi() { + return cgi; + } + + /** @return local path of the {@code gitweb.css} matching the CGI. */ + public Path getGitwebCss() { + return css; + } + + /** @return local path of the {@code gitweb.js} for the CGI. */ + public Path getGitwebJs() { + return js; + } + + /** @return local path of the {@code git-logo.png} for the CGI. */ + public Path getGitLogoPng() { + return logoPng; + } +} diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebConfig.java index 00767a16e9..671fc7f0d5 100644 --- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebConfig.java +++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GitWebConfig.java @@ -14,8 +14,7 @@ package com.google.gerrit.server.config; -import static java.nio.file.Files.isExecutable; -import static java.nio.file.Files.isRegularFile; +import static com.google.common.base.MoreObjects.firstNonNull; import com.google.common.base.Strings; import com.google.gerrit.common.data.GitWebType; @@ -25,12 +24,14 @@ 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); + public static boolean isDisabled(Config cfg) { + return isEmptyString(cfg, "gitweb", null, "url") + || isEmptyString(cfg, "gitweb", null, "cgi"); + } + private static boolean isEmptyString(Config cfg, String section, String subsection, String name) { // This is currently the only way to check for the empty string in a JGit @@ -40,27 +41,29 @@ public class GitWebConfig { } 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; + private final 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) { + GitWebConfig(GitWebCgiConfig cgiConfig, @GerritServerConfig Config cfg) { + if (isDisabled(cfg)) { + type = null; url = null; - gitweb_cgi = null; - gitweb_css = null; - gitweb_js = null; - git_logo_png = null; return; } + String cfgUrl = cfg.getString("gitweb", null, "url"); + GitWebType type = GitWebType.fromName(cfg.getString("gitweb", null, "type")); + if (type == null) { + this.type = null; + url = null; + return; + } else if (cgiConfig.getGitwebCgi() == null) { + // Use an externally managed gitweb instance, and not an internal one. + url = cfgUrl; + } else { + url = firstNonNull(cfgUrl, "gitweb"); + } + type.setLinkName(cfg.getString("gitweb", null, "linkname")); type.setBranch(cfg.getString("gitweb", null, "branch")); type.setProject(cfg.getString("gitweb", null, "project")); @@ -86,107 +89,25 @@ public class GitWebConfig { if (type.getBranch() == null) { log.warn("No Pattern specified for gitweb.branch, disabling."); - type = null; + this.type = null; } else if (type.getProject() == null) { log.warn("No Pattern specified for gitweb.project, disabling."); - type = null; + this.type = null; } else if (type.getRevision() == null) { log.warn("No Pattern specified for gitweb.revision, disabling."); - type = null; + this.type = null; } else if (type.getRootTree() == null) { log.warn("No Pattern specified for gitweb.roottree, disabling."); - type = null; + this.type = null; } else if (type.getFile() == null) { log.warn("No Pattern specified for gitweb.file, disabling."); - type = null; + this.type = null; } else if (type.getFileHistory() == null) { log.warn("No Pattern specified for gitweb.filehistory, disabling."); - type = null; - } - - if (isEmptyString(cfg, "gitweb", null, "url") - || isEmptyString(cfg, "gitweb", null, "cgi")) { - // 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; - + this.type = null; } else { - log.warn("gitweb not installed (no " + pkgCgi + " found)"); - cgi = null; - resourcePaths = new String[] {}; + this.type = type; } - - 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. */ @@ -203,26 +124,6 @@ public class GitWebConfig { 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 '/'.