summaryrefslogtreecommitdiffstats
path: root/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java')
-rw-r--r--gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java745
1 files changed, 0 insertions, 745 deletions
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
deleted file mode 100644
index 9b55042d06..0000000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/plugins/HttpPluginServlet.java
+++ /dev/null
@@ -1,745 +0,0 @@
-// Copyright (C) 2012 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.plugins;
-
-import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS;
-import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS;
-import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
-import static com.google.common.net.HttpHeaders.ORIGIN;
-import static com.google.common.net.HttpHeaders.VARY;
-import static com.google.gerrit.common.FileUtil.lastModified;
-import static com.google.gerrit.server.plugins.PluginEntry.ATTR_CHARACTER_ENCODING;
-import static com.google.gerrit.server.plugins.PluginEntry.ATTR_CONTENT_TYPE;
-import static java.nio.charset.StandardCharsets.UTF_8;
-import static java.util.stream.Collectors.toList;
-
-import com.google.common.base.CharMatcher;
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.cache.Cache;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.io.ByteStreams;
-import com.google.common.net.HttpHeaders;
-import com.google.gerrit.extensions.registration.RegistrationHandle;
-import com.google.gerrit.httpd.resources.Resource;
-import com.google.gerrit.httpd.resources.ResourceKey;
-import com.google.gerrit.httpd.resources.SmallResource;
-import com.google.gerrit.httpd.restapi.RestApiServlet;
-import com.google.gerrit.server.config.CanonicalWebUrl;
-import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.documentation.MarkdownFormatter;
-import com.google.gerrit.server.mime.MimeUtilFileTypeRegistry;
-import com.google.gerrit.server.plugins.Plugin;
-import com.google.gerrit.server.plugins.Plugin.ApiType;
-import com.google.gerrit.server.plugins.PluginContentScanner;
-import com.google.gerrit.server.plugins.PluginEntry;
-import com.google.gerrit.server.plugins.PluginsCollection;
-import com.google.gerrit.server.plugins.ReloadPluginListener;
-import com.google.gerrit.server.plugins.StartPluginListener;
-import com.google.gerrit.server.ssh.SshInfo;
-import com.google.gerrit.util.http.RequestUtil;
-import com.google.gwtexpui.server.CacheHeaders;
-import com.google.inject.Inject;
-import com.google.inject.Provider;
-import com.google.inject.Singleton;
-import com.google.inject.name.Named;
-import com.google.inject.servlet.GuiceFilter;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.nio.file.Files;
-import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.ConcurrentMap;
-import java.util.function.Predicate;
-import java.util.jar.Attributes;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-import javax.servlet.FilterChain;
-import javax.servlet.ServletConfig;
-import javax.servlet.ServletContext;
-import javax.servlet.ServletException;
-import javax.servlet.ServletRequest;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.lang.StringUtils;
-import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.util.IO;
-import org.eclipse.jgit.util.RawParseUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-@Singleton
-class HttpPluginServlet extends HttpServlet implements StartPluginListener, ReloadPluginListener {
- private static final int SMALL_RESOURCE = 128 * 1024;
- private static final long serialVersionUID = 1L;
- private static final Logger log = LoggerFactory.getLogger(HttpPluginServlet.class);
-
- private final MimeUtilFileTypeRegistry mimeUtil;
- private final Provider<String> webUrl;
- private final Cache<ResourceKey, Resource> resourceCache;
- private final String sshHost;
- private final int sshPort;
- private final RestApiServlet managerApi;
-
- private List<Plugin> pending = new ArrayList<>();
- private ContextMapper wrapper;
- private final ConcurrentMap<String, PluginHolder> plugins = Maps.newConcurrentMap();
- private final Pattern allowOrigin;
-
- @Inject
- HttpPluginServlet(
- MimeUtilFileTypeRegistry mimeUtil,
- @CanonicalWebUrl Provider<String> webUrl,
- @Named(HttpPluginModule.PLUGIN_RESOURCES) Cache<ResourceKey, Resource> cache,
- SshInfo sshInfo,
- RestApiServlet.Globals globals,
- PluginsCollection plugins,
- @GerritServerConfig Config cfg) {
- this.mimeUtil = mimeUtil;
- this.webUrl = webUrl;
- this.resourceCache = cache;
- this.managerApi = new RestApiServlet(globals, plugins);
-
- String sshHost = "review.example.com";
- int sshPort = 29418;
- if (!sshInfo.getHostKeys().isEmpty()) {
- String host = sshInfo.getHostKeys().get(0).getHost();
- int c = host.lastIndexOf(':');
- if (0 <= c) {
- sshHost = host.substring(0, c);
- sshPort = Integer.parseInt(host.substring(c + 1));
- } else {
- sshHost = host;
- sshPort = 22;
- }
- }
- this.sshHost = sshHost;
- this.sshPort = sshPort;
- this.allowOrigin = makeAllowOrigin(cfg);
- }
-
- @Override
- public synchronized void init(ServletConfig config) throws ServletException {
- super.init(config);
-
- wrapper = new ContextMapper(config.getServletContext().getContextPath());
- for (Plugin plugin : pending) {
- install(plugin);
- }
- pending = null;
- }
-
- @Override
- public synchronized void onStartPlugin(Plugin plugin) {
- if (pending != null) {
- pending.add(plugin);
- } else {
- install(plugin);
- }
- }
-
- @Override
- public void onReloadPlugin(Plugin oldPlugin, Plugin newPlugin) {
- install(newPlugin);
- }
-
- private void install(Plugin plugin) {
- GuiceFilter filter = load(plugin);
- final String name = plugin.getName();
- final PluginHolder holder = new PluginHolder(plugin, filter);
- plugin.add(
- new RegistrationHandle() {
- @Override
- public void remove() {
- plugins.remove(name, holder);
- }
- });
- plugins.put(name, holder);
- }
-
- private GuiceFilter load(Plugin plugin) {
- if (plugin.getHttpInjector() != null) {
- final String name = plugin.getName();
- final GuiceFilter filter;
- try {
- filter = plugin.getHttpInjector().getInstance(GuiceFilter.class);
- } catch (RuntimeException e) {
- log.warn("Plugin {} cannot load GuiceFilter", name, e);
- return null;
- }
-
- try {
- ServletContext ctx = PluginServletContext.create(plugin, wrapper.getFullPath(name));
- filter.init(new WrappedFilterConfig(ctx));
- } catch (ServletException e) {
- log.warn("Plugin {} failed to initialize HTTP", name, e);
- return null;
- }
-
- plugin.add(
- new RegistrationHandle() {
- @Override
- public void remove() {
- filter.destroy();
- }
- });
- return filter;
- }
- return null;
- }
-
- @Override
- public void service(HttpServletRequest req, HttpServletResponse res)
- throws IOException, ServletException {
- List<String> parts =
- Lists.newArrayList(
- Splitter.on('/')
- .limit(3)
- .omitEmptyStrings()
- .split(Strings.nullToEmpty(RequestUtil.getEncodedPathInfo(req))));
-
- if (isApiCall(req, parts)) {
- managerApi.service(req, res);
- return;
- }
-
- String name = parts.get(0);
- final PluginHolder holder = plugins.get(name);
- if (holder == null) {
- CacheHeaders.setNotCacheable(res);
- res.sendError(HttpServletResponse.SC_NOT_FOUND);
- return;
- }
-
- HttpServletRequest wr = wrapper.create(req, name);
- FilterChain chain =
- new FilterChain() {
- @Override
- public void doFilter(ServletRequest req, ServletResponse res) throws IOException {
- onDefault(holder, (HttpServletRequest) req, (HttpServletResponse) res);
- }
- };
- if (holder.filter != null) {
- holder.filter.doFilter(wr, res, chain);
- } else {
- chain.doFilter(wr, res);
- }
- }
-
- private static boolean isApiCall(HttpServletRequest req, List<String> parts) {
- String method = req.getMethod();
- int cnt = parts.size();
- return cnt == 0
- || (cnt == 1 && ("PUT".equals(method) || "DELETE".equals(method)))
- || (cnt == 2 && parts.get(1).startsWith("gerrit~"));
- }
-
- private void onDefault(PluginHolder holder, HttpServletRequest req, HttpServletResponse res)
- throws IOException {
- if (!"GET".equals(req.getMethod()) && !"HEAD".equals(req.getMethod())) {
- CacheHeaders.setNotCacheable(res);
- res.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
- return;
- }
-
- String pathInfo = RequestUtil.getEncodedPathInfo(req);
- if (pathInfo.length() < 1) {
- Resource.NOT_FOUND.send(req, res);
- return;
- }
-
- checkCors(req, res);
-
- String file = pathInfo.substring(1);
- PluginResourceKey key = PluginResourceKey.create(holder.plugin, file);
- Resource rsc = resourceCache.getIfPresent(key);
- if (rsc != null && req.getHeader(HttpHeaders.IF_MODIFIED_SINCE) == null) {
- rsc.send(req, res);
- return;
- }
-
- String uri = req.getRequestURI();
- if ("".equals(file)) {
- res.sendRedirect(uri + holder.docPrefix + "index.html");
- return;
- }
-
- if (file.startsWith(holder.staticPrefix)) {
- if (holder.plugin.getApiType() == ApiType.JS) {
- sendJsPlugin(holder.plugin, key, req, res);
- } else {
- PluginContentScanner scanner = holder.plugin.getContentScanner();
- Optional<PluginEntry> entry = scanner.getEntry(file);
- if (entry.isPresent()) {
- if (hasUpToDateCachedResource(rsc, entry.get().getTime())) {
- rsc.send(req, res);
- } else {
- sendResource(scanner, entry.get(), key, res);
- }
- } else {
- resourceCache.put(key, Resource.NOT_FOUND);
- Resource.NOT_FOUND.send(req, res);
- }
- }
- } else if (file.equals(holder.docPrefix.substring(0, holder.docPrefix.length() - 1))) {
- res.sendRedirect(uri + "/index.html");
- } else if (file.startsWith(holder.docPrefix) && file.endsWith("/")) {
- res.sendRedirect(uri + "index.html");
- } else if (file.startsWith(holder.docPrefix)) {
- PluginContentScanner scanner = holder.plugin.getContentScanner();
- Optional<PluginEntry> entry = scanner.getEntry(file);
- if (!entry.isPresent()) {
- entry = findSource(scanner, file);
- }
- if (!entry.isPresent() && file.endsWith("/index.html")) {
- String pfx = file.substring(0, file.length() - "index.html".length());
- long pluginLastModified = lastModified(holder.plugin.getSrcFile());
- if (hasUpToDateCachedResource(rsc, pluginLastModified)) {
- rsc.send(req, res);
- } else {
- sendAutoIndex(scanner, pfx, holder.plugin.getName(), key, res, pluginLastModified);
- }
- } else if (entry.isPresent() && entry.get().getName().endsWith(".md")) {
- if (hasUpToDateCachedResource(rsc, entry.get().getTime())) {
- rsc.send(req, res);
- } else {
- sendMarkdownAsHtml(scanner, entry.get(), holder.plugin.getName(), key, res);
- }
- } else if (entry.isPresent()) {
- if (hasUpToDateCachedResource(rsc, entry.get().getTime())) {
- rsc.send(req, res);
- } else {
- sendResource(scanner, entry.get(), key, res);
- }
- } else {
- resourceCache.put(key, Resource.NOT_FOUND);
- Resource.NOT_FOUND.send(req, res);
- }
- } else {
- resourceCache.put(key, Resource.NOT_FOUND);
- Resource.NOT_FOUND.send(req, res);
- }
- }
-
- private static Pattern makeAllowOrigin(Config cfg) {
- String[] allow = cfg.getStringList("site", null, "allowOriginRegex");
- if (allow.length > 0) {
- return Pattern.compile(Joiner.on('|').join(allow));
- }
- return null;
- }
-
- private void checkCors(HttpServletRequest req, HttpServletResponse res) {
- String origin = req.getHeader(ORIGIN);
- if (!Strings.isNullOrEmpty(origin) && isOriginAllowed(origin)) {
- res.addHeader(VARY, ORIGIN);
- setCorsHeaders(res, origin);
- }
- }
-
- private void setCorsHeaders(HttpServletResponse res, String origin) {
- res.setHeader(ACCESS_CONTROL_ALLOW_ORIGIN, origin);
- res.setHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
- res.setHeader(ACCESS_CONTROL_ALLOW_METHODS, "GET, HEAD");
- }
-
- private boolean isOriginAllowed(String origin) {
- return allowOrigin == null || allowOrigin.matcher(origin).matches();
- }
-
- private boolean hasUpToDateCachedResource(Resource cachedResource, long lastUpdateTime) {
- return cachedResource != null && cachedResource.isUnchanged(lastUpdateTime);
- }
-
- private void appendEntriesSection(
- PluginContentScanner scanner,
- List<PluginEntry> entries,
- String sectionTitle,
- StringBuilder md,
- String prefix,
- int nameOffset)
- throws IOException {
- if (!entries.isEmpty()) {
- md.append("## ").append(sectionTitle).append(" ##\n");
- for (PluginEntry entry : entries) {
- String rsrc = entry.getName().substring(prefix.length());
- String entryTitle;
- if (rsrc.endsWith(".html")) {
- entryTitle = rsrc.substring(nameOffset, rsrc.length() - 5).replace('-', ' ');
- } else if (rsrc.endsWith(".md")) {
- entryTitle = extractTitleFromMarkdown(scanner, entry);
- if (Strings.isNullOrEmpty(entryTitle)) {
- entryTitle = rsrc.substring(nameOffset, rsrc.length() - 3).replace('-', ' ');
- }
- } else {
- entryTitle = rsrc.substring(nameOffset).replace('-', ' ');
- }
- md.append(String.format("* [%s](%s)\n", entryTitle, rsrc));
- }
- md.append("\n");
- }
- }
-
- private void sendAutoIndex(
- PluginContentScanner scanner,
- final String prefix,
- final String pluginName,
- PluginResourceKey cacheKey,
- HttpServletResponse res,
- long lastModifiedTime)
- throws IOException {
- List<PluginEntry> cmds = new ArrayList<>();
- List<PluginEntry> servlets = new ArrayList<>();
- List<PluginEntry> restApis = new ArrayList<>();
- List<PluginEntry> docs = new ArrayList<>();
- PluginEntry about = null;
-
- Predicate<PluginEntry> filter =
- entry -> {
- String name = entry.getName();
- Optional<Long> size = entry.getSize();
- if (name.startsWith(prefix)
- && (name.endsWith(".md") || name.endsWith(".html"))
- && size.isPresent()) {
- if (size.get() <= 0 || size.get() > SMALL_RESOURCE) {
- log.warn(
- "Plugin {}: {} omitted from document index. Size {} out of range (0,{}).",
- pluginName,
- name.substring(prefix.length()),
- size.get(),
- SMALL_RESOURCE);
- return false;
- }
- return true;
- }
- return false;
- };
-
- List<PluginEntry> entries =
- Collections.list(scanner.entries()).stream().filter(filter).collect(toList());
- for (PluginEntry entry : entries) {
- String name = entry.getName().substring(prefix.length());
- if (name.startsWith("cmd-")) {
- cmds.add(entry);
- } else if (name.startsWith("servlet-")) {
- servlets.add(entry);
- } else if (name.startsWith("rest-api-")) {
- restApis.add(entry);
- } else if (name.startsWith("about.")) {
- if (about == null) {
- about = entry;
- } else {
- log.warn(
- "Plugin {}: Multiple 'about' documents found; using {}",
- pluginName,
- about.getName().substring(prefix.length()));
- }
- } else {
- docs.add(entry);
- }
- }
-
- Collections.sort(cmds, PluginEntry.COMPARATOR_BY_NAME);
- Collections.sort(docs, PluginEntry.COMPARATOR_BY_NAME);
-
- StringBuilder md = new StringBuilder();
- md.append(String.format("# Plugin %s #\n", pluginName));
- md.append("\n");
- appendPluginInfoTable(md, scanner.getManifest().getMainAttributes());
-
- if (about != null) {
- InputStreamReader isr = new InputStreamReader(scanner.getInputStream(about), UTF_8);
- StringBuilder aboutContent = new StringBuilder();
- try (BufferedReader reader = new BufferedReader(isr)) {
- String line;
- while ((line = reader.readLine()) != null) {
- line = StringUtils.stripEnd(line, null);
- if (line.isEmpty()) {
- aboutContent.append("\n");
- } else {
- aboutContent.append(line).append("\n");
- }
- }
- }
-
- // Only append the About section if there was anything in it
- if (aboutContent.toString().trim().length() > 0) {
- md.append("## About ##\n");
- md.append("\n").append(aboutContent);
- }
- }
-
- appendEntriesSection(scanner, docs, "Documentation", md, prefix, 0);
- appendEntriesSection(scanner, servlets, "Servlets", md, prefix, "servlet-".length());
- appendEntriesSection(scanner, restApis, "REST APIs", md, prefix, "rest-api-".length());
- appendEntriesSection(scanner, cmds, "Commands", md, prefix, "cmd-".length());
-
- sendMarkdownAsHtml(md.toString(), pluginName, cacheKey, res, lastModifiedTime);
- }
-
- private void sendMarkdownAsHtml(
- String md,
- String pluginName,
- PluginResourceKey cacheKey,
- HttpServletResponse res,
- long lastModifiedTime)
- throws UnsupportedEncodingException, IOException {
- Map<String, String> macros = new HashMap<>();
- macros.put("PLUGIN", pluginName);
- macros.put("SSH_HOST", sshHost);
- macros.put("SSH_PORT", "" + sshPort);
- String url = webUrl.get();
- if (Strings.isNullOrEmpty(url)) {
- url = "http://review.example.com/";
- }
- macros.put("URL", url);
-
- Matcher m = Pattern.compile("(\\\\)?@([A-Z_]+)@").matcher(md);
- StringBuffer sb = new StringBuffer();
- while (m.find()) {
- String key = m.group(2);
- String val = macros.get(key);
- if (m.group(1) != null) {
- m.appendReplacement(sb, "@" + key + "@");
- } else if (val != null) {
- m.appendReplacement(sb, val);
- } else {
- m.appendReplacement(sb, "@" + key + "@");
- }
- }
- m.appendTail(sb);
-
- byte[] html = new MarkdownFormatter().markdownToDocHtml(sb.toString(), UTF_8.name());
- resourceCache.put(
- cacheKey,
- new SmallResource(html)
- .setContentType("text/html")
- .setCharacterEncoding(UTF_8.name())
- .setLastModified(lastModifiedTime));
- res.setContentType("text/html");
- res.setCharacterEncoding(UTF_8.name());
- res.setContentLength(html.length);
- res.setDateHeader("Last-Modified", lastModifiedTime);
- res.getOutputStream().write(html);
- }
-
- private static void appendPluginInfoTable(StringBuilder html, Attributes main) {
- if (main != null) {
- String t = main.getValue(Attributes.Name.IMPLEMENTATION_TITLE);
- String n = main.getValue(Attributes.Name.IMPLEMENTATION_VENDOR);
- String v = main.getValue(Attributes.Name.IMPLEMENTATION_VERSION);
- String a = main.getValue("Gerrit-ApiVersion");
-
- html.append("<table class=\"plugin_info\">");
- if (!Strings.isNullOrEmpty(t)) {
- html.append("<tr><th>Name</th><td>").append(t).append("</td></tr>\n");
- }
- if (!Strings.isNullOrEmpty(n)) {
- html.append("<tr><th>Vendor</th><td>").append(n).append("</td></tr>\n");
- }
- if (!Strings.isNullOrEmpty(v)) {
- html.append("<tr><th>Version</th><td>").append(v).append("</td></tr>\n");
- }
- if (!Strings.isNullOrEmpty(a)) {
- html.append("<tr><th>API Version</th><td>").append(a).append("</td></tr>\n");
- }
- html.append("</table>\n");
- }
- }
-
- private static String extractTitleFromMarkdown(PluginContentScanner scanner, PluginEntry entry)
- throws IOException {
- String charEnc = null;
- Map<Object, String> atts = entry.getAttrs();
- if (atts != null) {
- charEnc = Strings.emptyToNull(atts.get(ATTR_CHARACTER_ENCODING));
- }
- if (charEnc == null) {
- charEnc = UTF_8.name();
- }
- return new MarkdownFormatter()
- .extractTitleFromMarkdown(readWholeEntry(scanner, entry), charEnc);
- }
-
- private static Optional<PluginEntry> findSource(PluginContentScanner scanner, String file)
- throws IOException {
- if (file.endsWith(".html")) {
- int d = file.lastIndexOf('.');
- return scanner.getEntry(file.substring(0, d) + ".md");
- }
- return Optional.empty();
- }
-
- private void sendMarkdownAsHtml(
- PluginContentScanner scanner,
- PluginEntry entry,
- String pluginName,
- PluginResourceKey key,
- HttpServletResponse res)
- throws IOException {
- byte[] rawmd = readWholeEntry(scanner, entry);
- String encoding = null;
- Map<Object, String> atts = entry.getAttrs();
- if (atts != null) {
- encoding = Strings.emptyToNull(atts.get(ATTR_CHARACTER_ENCODING));
- }
-
- String txtmd =
- RawParseUtils.decode(Charset.forName(encoding != null ? encoding : UTF_8.name()), rawmd);
- long time = entry.getTime();
- if (0 < time) {
- res.setDateHeader("Last-Modified", time);
- }
- sendMarkdownAsHtml(txtmd, pluginName, key, res, time);
- }
-
- private void sendResource(
- PluginContentScanner scanner,
- PluginEntry entry,
- PluginResourceKey key,
- HttpServletResponse res)
- throws IOException {
- byte[] data = null;
- Optional<Long> size = entry.getSize();
- if (size.isPresent() && size.get() <= SMALL_RESOURCE) {
- data = readWholeEntry(scanner, entry);
- }
-
- String contentType = null;
- String charEnc = null;
- Map<Object, String> atts = entry.getAttrs();
- if (atts != null) {
- contentType = Strings.emptyToNull(atts.get(ATTR_CONTENT_TYPE));
- charEnc = Strings.emptyToNull(atts.get(ATTR_CHARACTER_ENCODING));
- }
- if (contentType == null) {
- contentType = mimeUtil.getMimeType(entry.getName(), data).toString();
- if ("application/octet-stream".equals(contentType) && entry.getName().endsWith(".js")) {
- contentType = "application/javascript";
- } else if ("application/x-pointplus".equals(contentType)
- && entry.getName().endsWith(".css")) {
- contentType = "text/css";
- }
- }
-
- long time = entry.getTime();
- if (0 < time) {
- res.setDateHeader("Last-Modified", time);
- }
- if (size.isPresent()) {
- res.setHeader("Content-Length", size.get().toString());
- }
- res.setContentType(contentType);
- if (charEnc != null) {
- res.setCharacterEncoding(charEnc);
- }
- if (data != null) {
- resourceCache.put(
- key,
- new SmallResource(data)
- .setContentType(contentType)
- .setCharacterEncoding(charEnc)
- .setLastModified(time));
- res.getOutputStream().write(data);
- } else {
- writeToResponse(res, scanner.getInputStream(entry));
- }
- }
-
- private void sendJsPlugin(
- Plugin plugin, PluginResourceKey key, HttpServletRequest req, HttpServletResponse res)
- throws IOException {
- Path path = plugin.getSrcFile();
- if (req.getRequestURI().endsWith(getJsPluginPath(plugin)) && Files.exists(path)) {
- res.setHeader("Content-Length", Long.toString(Files.size(path)));
- if (path.toString().toLowerCase(Locale.US).endsWith(".html")) {
- res.setContentType("text/html");
- } else {
- res.setContentType("application/javascript");
- }
- writeToResponse(res, Files.newInputStream(path));
- } else {
- resourceCache.put(key, Resource.NOT_FOUND);
- Resource.NOT_FOUND.send(req, res);
- }
- }
-
- private static String getJsPluginPath(Plugin plugin) {
- return String.format(
- "/plugins/%s/static/%s", plugin.getName(), plugin.getSrcFile().getFileName());
- }
-
- private void writeToResponse(HttpServletResponse res, InputStream inputStream)
- throws IOException {
- try (OutputStream out = res.getOutputStream();
- InputStream in = inputStream) {
- ByteStreams.copy(in, out);
- }
- }
-
- private static byte[] readWholeEntry(PluginContentScanner scanner, PluginEntry entry)
- throws IOException {
- try (InputStream in = scanner.getInputStream(entry)) {
- return IO.readWholeStream(in, entry.getSize().get().intValue()).array();
- }
- }
-
- private static class PluginHolder {
- final Plugin plugin;
- final GuiceFilter filter;
- final String staticPrefix;
- final String docPrefix;
-
- PluginHolder(Plugin plugin, GuiceFilter filter) {
- this.plugin = plugin;
- this.filter = filter;
- this.staticPrefix = getPrefix(plugin, "Gerrit-HttpStaticPrefix", "static/");
- this.docPrefix = getPrefix(plugin, "Gerrit-HttpDocumentationPrefix", "Documentation/");
- }
-
- private static String getPrefix(Plugin plugin, String attr, String def) {
- Path path = plugin.getSrcFile();
- PluginContentScanner scanner = plugin.getContentScanner();
- if (path == null || scanner == PluginContentScanner.EMPTY) {
- return def;
- }
- try {
- String prefix = scanner.getManifest().getMainAttributes().getValue(attr);
- if (prefix != null) {
- return CharMatcher.is('/').trimFrom(prefix) + "/";
- }
- return def;
- } catch (IOException e) {
- log.warn("Error getting {} for plugin {}, using default", attr, plugin.getName(), e);
- return null;
- }
- }
- }
-}