Auto-format plugin HTTP pages from known formats
If we detect the requested plugin resource does not exist, but a file with a .md extension instead does exist, open the .md file and reformat as html. Do that reformatting using the pegdown library. Change-Id: I29e1b1c58607a9faf2acfdc387a7418b545c5b48
This commit is contained in:
		@@ -52,6 +52,7 @@ Included Components
 | 
			
		||||
|JSR 305                    | <<jsr305,New-Style BSD>>
 | 
			
		||||
|dk.brics.automaton         | <<automaton,New-Style BSD>>
 | 
			
		||||
|Java Concurrency in Practice Annotations | <<jcip,Create Commons Attribution License>>
 | 
			
		||||
|pegdown                    | <<apache2,Apache License 2.0>>
 | 
			
		||||
|======================================================================
 | 
			
		||||
 | 
			
		||||
Cryptography Notice
 | 
			
		||||
 
 | 
			
		||||
@@ -18,6 +18,7 @@ import com.google.common.base.Strings;
 | 
			
		||||
import com.google.common.collect.Lists;
 | 
			
		||||
import com.google.common.collect.Maps;
 | 
			
		||||
import com.google.gerrit.extensions.registration.RegistrationHandle;
 | 
			
		||||
import com.google.gerrit.server.documentation.MarkdownFormatter;
 | 
			
		||||
import com.google.gerrit.server.MimeUtilFileTypeRegistry;
 | 
			
		||||
import com.google.gerrit.server.plugins.Plugin;
 | 
			
		||||
import com.google.gerrit.server.plugins.ReloadPluginListener;
 | 
			
		||||
@@ -173,8 +174,15 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    if (file.startsWith("Documentation/") || file.startsWith("static/")) {
 | 
			
		||||
      JarFile jar = holder.plugin.getJarFile();
 | 
			
		||||
      JarEntry entry = jar.getJarEntry(file);
 | 
			
		||||
      if (entry != null && entry.getSize() > 0) {
 | 
			
		||||
        sendResource(jar, entry, res);
 | 
			
		||||
      if (file.startsWith("Documentation/") && !isValidEntry(entry)) {
 | 
			
		||||
        entry = getRealFileEntry(jar, file);
 | 
			
		||||
        if (isValidEntry(entry)) {
 | 
			
		||||
          sendResource(jar, entry, res, holder.plugin.getName(), true);
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (isValidEntry(entry)) {
 | 
			
		||||
        sendResource(jar, entry, res, holder.plugin.getName());
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
@@ -183,8 +191,24 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
    res.sendError(HttpServletResponse.SC_NOT_FOUND);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void sendResource(JarFile jar, JarEntry entry, HttpServletResponse res)
 | 
			
		||||
  private JarEntry getRealFileEntry(JarFile jar, String file) {
 | 
			
		||||
    // TODO: Replace with a loop iterating over possible formatters
 | 
			
		||||
    return jar.getJarEntry(file.replaceAll("\\.html$", ".md"));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private boolean isValidEntry(JarEntry entry) {
 | 
			
		||||
    return entry != null && entry.getSize() > 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void sendResource(JarFile jar, JarEntry entry,
 | 
			
		||||
      HttpServletResponse res, String pluginName) throws IOException {
 | 
			
		||||
    sendResource(jar, entry, res, pluginName, false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private void sendResource(JarFile jar, JarEntry entry,
 | 
			
		||||
      HttpServletResponse res, String pluginName, boolean format)
 | 
			
		||||
      throws IOException {
 | 
			
		||||
    String entryName = entry.getName();
 | 
			
		||||
    byte[] data = null;
 | 
			
		||||
    if (entry.getSize() <= 128 * 1024) {
 | 
			
		||||
      data = new byte[(int) entry.getSize()];
 | 
			
		||||
@@ -194,24 +218,44 @@ class HttpPluginServlet extends HttpServlet
 | 
			
		||||
      } finally {
 | 
			
		||||
        in.close();
 | 
			
		||||
      }
 | 
			
		||||
    } else if (format == true) {
 | 
			
		||||
      log.warn(String.format("Plugin '%s' file '%s' too large to format",
 | 
			
		||||
          pluginName, entryName));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    String contentType = null;
 | 
			
		||||
    String charEnc = null;
 | 
			
		||||
    Attributes atts = entry.getAttributes();
 | 
			
		||||
    if (atts != null) {
 | 
			
		||||
      contentType = Strings.emptyToNull(atts.getValue("Content-Type"));
 | 
			
		||||
      charEnc = Strings.emptyToNull(atts.getValue("Character-Encoding"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (contentType == null) {
 | 
			
		||||
      MimeType type = mimeUtil.getMimeType(entry.getName(), data);
 | 
			
		||||
      MimeType type = mimeUtil.getMimeType(entryName, data);
 | 
			
		||||
      contentType = type.toString();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (format && data != null) {
 | 
			
		||||
      if (charEnc == null) {
 | 
			
		||||
        charEnc = "UTF-8";
 | 
			
		||||
      }
 | 
			
		||||
      MarkdownFormatter fmter = new MarkdownFormatter();
 | 
			
		||||
      data = fmter.getHtmlFromMarkdown(data, charEnc);
 | 
			
		||||
      res.setHeader("Content-Length", Long.toString(data.length));
 | 
			
		||||
      contentType = "text/html";
 | 
			
		||||
    } else {
 | 
			
		||||
      res.setHeader("Content-Length", Long.toString(entry.getSize()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    long time = entry.getTime();
 | 
			
		||||
    if (0 < time) {
 | 
			
		||||
      res.setDateHeader("Last-Modified", time);
 | 
			
		||||
    }
 | 
			
		||||
    res.setContentType(contentType);
 | 
			
		||||
    res.setHeader("Content-Length", Long.toString(entry.getSize()));
 | 
			
		||||
    if (charEnc != null) {
 | 
			
		||||
      res.setCharacterEncoding(charEnc);
 | 
			
		||||
    }
 | 
			
		||||
    if (data != null) {
 | 
			
		||||
      res.getOutputStream().write(data);
 | 
			
		||||
    } else {
 | 
			
		||||
 
 | 
			
		||||
@@ -170,6 +170,11 @@ limitations under the License.
 | 
			
		||||
      <groupId>com.googlecode.prolog-cafe</groupId>
 | 
			
		||||
      <artifactId>PrologCafe</artifactId>
 | 
			
		||||
    </dependency>
 | 
			
		||||
 | 
			
		||||
    <dependency>
 | 
			
		||||
      <groupId>org.pegdown</groupId>
 | 
			
		||||
      <artifactId>pegdown</artifactId>
 | 
			
		||||
    </dependency>
 | 
			
		||||
  </dependencies>
 | 
			
		||||
 | 
			
		||||
  <build>
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,35 @@
 | 
			
		||||
// 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.server.documentation;
 | 
			
		||||
 | 
			
		||||
import static org.pegdown.Extensions.ALL;
 | 
			
		||||
 | 
			
		||||
import org.eclipse.jgit.util.RawParseUtils;
 | 
			
		||||
import org.pegdown.PegDownProcessor;
 | 
			
		||||
 | 
			
		||||
import java.io.UnsupportedEncodingException;
 | 
			
		||||
import java.nio.charset.Charset;
 | 
			
		||||
 | 
			
		||||
public class MarkdownFormatter {
 | 
			
		||||
 | 
			
		||||
  public byte[] getHtmlFromMarkdown(byte[] data, String charEnc)
 | 
			
		||||
      throws UnsupportedEncodingException {
 | 
			
		||||
    String decodedData = RawParseUtils.decode(Charset.forName(charEnc), data);
 | 
			
		||||
    String formatted = new PegDownProcessor(ALL).markdownToHtml(decodedData);
 | 
			
		||||
    data = formatted.getBytes(charEnc);
 | 
			
		||||
    return data;
 | 
			
		||||
  }
 | 
			
		||||
  // TODO: Add a cache
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										11
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								pom.xml
									
									
									
									
									
								
							@@ -822,6 +822,12 @@ limitations under the License.
 | 
			
		||||
        <artifactId>PrologCafe</artifactId>
 | 
			
		||||
        <version>1.3</version>
 | 
			
		||||
      </dependency>
 | 
			
		||||
 | 
			
		||||
      <dependency>
 | 
			
		||||
        <groupId>org.pegdown</groupId>
 | 
			
		||||
        <artifactId>pegdown</artifactId>
 | 
			
		||||
        <version>1.1.0</version>
 | 
			
		||||
      </dependency>
 | 
			
		||||
    </dependencies>
 | 
			
		||||
  </dependencyManagement>
 | 
			
		||||
 | 
			
		||||
@@ -850,5 +856,10 @@ limitations under the License.
 | 
			
		||||
      <id>clojars-repo</id>
 | 
			
		||||
      <url>http://clojars.org/repo</url>
 | 
			
		||||
    </repository>
 | 
			
		||||
 | 
			
		||||
    <repository>
 | 
			
		||||
      <id>scala-tools</id>
 | 
			
		||||
      <url>http://scala-tools.org/repo-releases</url>
 | 
			
		||||
    </repository>
 | 
			
		||||
  </repositories>
 | 
			
		||||
</project>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user