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:
Nasser Grainawi
2012-05-08 18:56:39 -07:00
parent e033b2620d
commit bf4fa34606
5 changed files with 101 additions and 5 deletions

View File

@@ -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

View File

@@ -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 {

View File

@@ -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>

View File

@@ -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
View File

@@ -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>