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 '/'.