@Override protected void service(final HttpServletRequest req, final HttpServletResponse rsp) throws IOException { if (req.getQueryString() == null || req.getQueryString().isEmpty()) { // No query string? They want the project list, which we don't // currently support. Return to Gerrit's own web UI. // rsp.sendRedirect(req.getContextPath() + "/"); return; } final Map<String, String> params = getParameters(req); String a = params.get("a"); if (a != null) { if (deniedActions.contains(a)) { rsp.sendError(HttpServletResponse.SC_FORBIDDEN); return; } if (a.equals(PROJECT_LIST_ACTION)) { rsp.sendRedirect( req.getContextPath() + "/#" + PageLinks.ADMIN_PROJECTS + "?filter=" + Url.encode(params.get("pf") + "/")); return; } } String name = params.get("p"); if (name == null) { rsp.sendError(HttpServletResponse.SC_NOT_FOUND); return; } if (name.endsWith(".git")) { name = name.substring(0, name.length() - 4); } final Project.NameKey nameKey = new Project.NameKey(name); final ProjectControl project; try { project = projectControl.validateFor(nameKey); if (!project.allRefsAreVisible() && !project.isOwner()) { // Pretend the project doesn't exist throw new NoSuchProjectException(nameKey); } } catch (NoSuchProjectException e) { if (userProvider.get().isIdentifiedUser()) { rsp.sendError(HttpServletResponse.SC_NOT_FOUND); } else { // Allow anonymous users a chance to login. // Avoid leaking information by not distinguishing between // project not existing and no access rights. rsp.sendRedirect(getLoginRedirectUrl(req)); } return; } try (Repository repo = repoManager.openRepository(nameKey)) { CacheHeaders.setNotCacheable(rsp); exec(req, rsp, project); } catch (RepositoryNotFoundException e) { getServletContext().log("Cannot open repository", e); rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } }
private void makeSiteConfig(SitePaths site, Config cfg, SshInfo sshInfo) throws IOException { if (!Files.exists(site.tmp_dir)) { Files.createDirectories(site.tmp_dir); } Path myconf = Files.createTempFile(site.tmp_dir, "gitweb_config", ".perl"); // To make our configuration file only readable or writable by us; // this reduces the chances of someone tampering with the file. // // TODO(dborowitz): Is there a portable way to do this with NIO? File myconfFile = myconf.toFile(); myconfFile.setWritable(false, false /* all */); myconfFile.setReadable(false, false /* all */); myconfFile.setExecutable(false, false /* all */); myconfFile.setWritable(true, true /* owner only */); myconfFile.setReadable(true, true /* owner only */); myconfFile.deleteOnExit(); _env.set("GIT_DIR", "."); _env.set("GITWEB_CONFIG", myconf.toAbsolutePath().toString()); try (PrintWriter p = new PrintWriter(Files.newBufferedWriter(myconf, UTF_8))) { p.print("# Autogenerated by Gerrit Code Review \n"); p.print("# DO NOT EDIT\n"); p.print("\n"); // We are mounted at the same level in the context as the main // UI, so we can include the same header and footer scheme. // Path hdr = site.site_header; if (Files.isRegularFile(hdr)) { p.print("$site_header = " + quoteForPerl(hdr) + ";\n"); } Path ftr = site.site_footer; if (Files.isRegularFile(ftr)) { p.print("$site_footer = " + quoteForPerl(ftr) + ";\n"); } // Top level should return to Gerrit's UI. // p.print("$home_link = $ENV{'GERRIT_CONTEXT_PATH'};\n"); p.print("$home_link_str = 'Code Review';\n"); p.print("$favicon = 'favicon.ico';\n"); p.print("$logo = 'gitweb-logo.png';\n"); p.print("$javascript = 'gitweb.js';\n"); p.print("@stylesheets = ('gitweb-default.css');\n"); Path css = site.site_css; if (Files.isRegularFile(css)) { p.print("push @stylesheets, 'gitweb-site.css';\n"); } // Try to make the title match Gerrit's normal window title // scheme of host followed by 'Code Review'. // p.print("$site_name = $home_link_str;\n"); p.print("$site_name = qq{$1 $site_name} if "); p.print("$ENV{'SERVER_NAME'} =~ m,^([^.]+(?:\\.[^.]+)?)(?:\\.|$),;\n"); // Assume by default that XSS is a problem, and try to prevent it. // p.print("$prevent_xss = 1;\n"); // Generate URLs using smart http:// // p.print("{\n"); p.print(" my $secure = $ENV{'HTTPS'} =~ /^ON$/i;\n"); p.print(" my $http_url = $secure ? 'https://' : 'http://';\n"); p.print(" $http_url .= qq{$ENV{'GERRIT_USER_NAME'}@}\n"); p.print(" unless $ENV{'GERRIT_ANONYMOUS_READ'};\n"); p.print(" $http_url .= $ENV{'SERVER_NAME'};\n"); p.print(" $http_url .= qq{:$ENV{'SERVER_PORT'}}\n"); p.print(" if (( $secure && $ENV{'SERVER_PORT'} != 443)\n"); p.print(" || (!$secure && $ENV{'SERVER_PORT'} != 80)\n"); p.print(" );\n"); p.print(" $http_url .= qq{$ENV{'GERRIT_CONTEXT_PATH'}p};\n"); p.print(" push @git_base_url_list, $http_url;\n"); p.print("}\n"); // Generate URLs using anonymous git:// // String url = cfg.getString("gerrit", null, "canonicalGitUrl"); if (url != null) { if (url.endsWith("/")) { url = url.substring(0, url.length() - 1); } p.print("if ($ENV{'GERRIT_ANONYMOUS_READ'}) {\n"); p.print(" push @git_base_url_list, "); p.print(quoteForPerl(url)); p.print(";\n"); p.print("}\n"); } // Generate URLs using authenticated ssh:// // if (sshInfo != null && !sshInfo.getHostKeys().isEmpty()) { String sshAddr = sshInfo.getHostKeys().get(0).getHost(); p.print("if ($ENV{'GERRIT_USER_NAME'}) {\n"); p.print(" push @git_base_url_list, join('', 'ssh://'"); p.print(", $ENV{'GERRIT_USER_NAME'}"); p.print(", '@'"); if (sshAddr.startsWith("*:") || "".equals(sshAddr)) { p.print(", $ENV{'SERVER_NAME'}"); } if (sshAddr.startsWith("*")) { sshAddr = sshAddr.substring(1); } p.print(", " + quoteForPerl(sshAddr)); p.print(");\n"); p.print("}\n"); } // Link back to Gerrit (when possible, to matching review record). // Supported gitweb's hash values are: // - (missing), // - HEAD, // - refs/heads/<branch>, // - refs/changes/*/<change>/*, // - <revision>. // p.print("sub add_review_link {\n"); p.print(" my $h = shift;\n"); p.print(" my $q;\n"); p.print(" if (!$h || $h eq 'HEAD') {\n"); p.print(" $q = qq{#q,project:$ENV{'GERRIT_PROJECT_NAME'}};\n"); p.print(" } elsif ($h =~ /^refs\\/heads\\/([-\\w]+)$/) {\n"); p.print(" $q = qq{#q,project:$ENV{'GERRIT_PROJECT_NAME'}"); p.print("+branch:$1};\n"); // wrapped p.print(" } elsif ($h =~ /^refs\\/changes\\/\\d{2}\\/(\\d+)\\/\\d+$/) "); p.print("{\n"); // wrapped p.print(" $q = qq{#/c/$1};\n"); p.print(" } else {\n"); p.print(" $q = qq{#/q/$h};\n"); p.print(" }\n"); p.print(" my $r = qq{$ENV{'GERRIT_CONTEXT_PATH'}$q};\n"); p.print(" push @{$feature{'actions'}{'default'}},\n"); p.print(" ('review',$r,'commitdiff');\n"); p.print("}\n"); p.print("if ($cgi->param('hb')) {\n"); p.print(" add_review_link($cgi->param('hb'));\n"); p.print("} elsif ($cgi->param('h')) {\n"); p.print(" add_review_link($cgi->param('h'));\n"); p.print("} else {\n"); p.print(" add_review_link();\n"); p.print("}\n"); // If the administrator has created a site-specific gitweb_config, // load that before we perform any final overrides. // Path sitecfg = site.site_gitweb; if (Files.isRegularFile(sitecfg)) { p.print("$GITWEB_CONFIG = " + quoteForPerl(sitecfg) + ";\n"); p.print("if (-e $GITWEB_CONFIG) {\n"); p.print(" do " + quoteForPerl(sitecfg) + ";\n"); p.print("}\n"); } Path root = repoManager.getBasePath(); p.print("$projectroot = " + quoteForPerl(root) + ";\n"); // Permit exporting only the project we were started for. // We use the name under $projectroot in case symlinks // were involved in the path. // p.print("$export_auth_hook = sub {\n"); p.print(" my $dir = shift;\n"); p.print(" my $name = $ENV{'GERRIT_PROJECT_NAME'};\n"); p.print(" my $allow = qq{$projectroot/$name.git};\n"); p.print(" return $dir eq $allow;\n"); p.print(" };\n"); // Do not allow the administrator to enable path info, its // not a URL format we currently support. // p.print("$feature{'pathinfo'}{'override'} = 0;\n"); p.print("$feature{'pathinfo'}{'default'} = [0];\n"); // We don't do forking, so don't allow it to be enabled. // p.print("$feature{'forks'}{'override'} = 0;\n"); p.print("$feature{'forks'}{'default'} = [0];\n"); } myconfFile.setReadOnly(); }