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>>
|
|JSR 305 | <<jsr305,New-Style BSD>>
|
||||||
|dk.brics.automaton | <<automaton,New-Style BSD>>
|
|dk.brics.automaton | <<automaton,New-Style BSD>>
|
||||||
|Java Concurrency in Practice Annotations | <<jcip,Create Commons Attribution License>>
|
|Java Concurrency in Practice Annotations | <<jcip,Create Commons Attribution License>>
|
||||||
|
|pegdown | <<apache2,Apache License 2.0>>
|
||||||
|======================================================================
|
|======================================================================
|
||||||
|
|
||||||
Cryptography Notice
|
Cryptography Notice
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import com.google.common.base.Strings;
|
|||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.google.gerrit.extensions.registration.RegistrationHandle;
|
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.MimeUtilFileTypeRegistry;
|
||||||
import com.google.gerrit.server.plugins.Plugin;
|
import com.google.gerrit.server.plugins.Plugin;
|
||||||
import com.google.gerrit.server.plugins.ReloadPluginListener;
|
import com.google.gerrit.server.plugins.ReloadPluginListener;
|
||||||
@@ -173,8 +174,15 @@ class HttpPluginServlet extends HttpServlet
|
|||||||
if (file.startsWith("Documentation/") || file.startsWith("static/")) {
|
if (file.startsWith("Documentation/") || file.startsWith("static/")) {
|
||||||
JarFile jar = holder.plugin.getJarFile();
|
JarFile jar = holder.plugin.getJarFile();
|
||||||
JarEntry entry = jar.getJarEntry(file);
|
JarEntry entry = jar.getJarEntry(file);
|
||||||
if (entry != null && entry.getSize() > 0) {
|
if (file.startsWith("Documentation/") && !isValidEntry(entry)) {
|
||||||
sendResource(jar, entry, res);
|
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;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -183,8 +191,24 @@ class HttpPluginServlet extends HttpServlet
|
|||||||
res.sendError(HttpServletResponse.SC_NOT_FOUND);
|
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 {
|
throws IOException {
|
||||||
|
String entryName = entry.getName();
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
if (entry.getSize() <= 128 * 1024) {
|
if (entry.getSize() <= 128 * 1024) {
|
||||||
data = new byte[(int) entry.getSize()];
|
data = new byte[(int) entry.getSize()];
|
||||||
@@ -194,24 +218,44 @@ class HttpPluginServlet extends HttpServlet
|
|||||||
} finally {
|
} finally {
|
||||||
in.close();
|
in.close();
|
||||||
}
|
}
|
||||||
|
} else if (format == true) {
|
||||||
|
log.warn(String.format("Plugin '%s' file '%s' too large to format",
|
||||||
|
pluginName, entryName));
|
||||||
}
|
}
|
||||||
|
|
||||||
String contentType = null;
|
String contentType = null;
|
||||||
|
String charEnc = null;
|
||||||
Attributes atts = entry.getAttributes();
|
Attributes atts = entry.getAttributes();
|
||||||
if (atts != null) {
|
if (atts != null) {
|
||||||
contentType = Strings.emptyToNull(atts.getValue("Content-Type"));
|
contentType = Strings.emptyToNull(atts.getValue("Content-Type"));
|
||||||
|
charEnc = Strings.emptyToNull(atts.getValue("Character-Encoding"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (contentType == null) {
|
if (contentType == null) {
|
||||||
MimeType type = mimeUtil.getMimeType(entry.getName(), data);
|
MimeType type = mimeUtil.getMimeType(entryName, data);
|
||||||
contentType = type.toString();
|
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();
|
long time = entry.getTime();
|
||||||
if (0 < time) {
|
if (0 < time) {
|
||||||
res.setDateHeader("Last-Modified", time);
|
res.setDateHeader("Last-Modified", time);
|
||||||
}
|
}
|
||||||
res.setContentType(contentType);
|
res.setContentType(contentType);
|
||||||
res.setHeader("Content-Length", Long.toString(entry.getSize()));
|
if (charEnc != null) {
|
||||||
|
res.setCharacterEncoding(charEnc);
|
||||||
|
}
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
res.getOutputStream().write(data);
|
res.getOutputStream().write(data);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -170,6 +170,11 @@ limitations under the License.
|
|||||||
<groupId>com.googlecode.prolog-cafe</groupId>
|
<groupId>com.googlecode.prolog-cafe</groupId>
|
||||||
<artifactId>PrologCafe</artifactId>
|
<artifactId>PrologCafe</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.pegdown</groupId>
|
||||||
|
<artifactId>pegdown</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<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>
|
<artifactId>PrologCafe</artifactId>
|
||||||
<version>1.3</version>
|
<version>1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.pegdown</groupId>
|
||||||
|
<artifactId>pegdown</artifactId>
|
||||||
|
<version>1.1.0</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</dependencyManagement>
|
</dependencyManagement>
|
||||||
|
|
||||||
@@ -850,5 +856,10 @@ limitations under the License.
|
|||||||
<id>clojars-repo</id>
|
<id>clojars-repo</id>
|
||||||
<url>http://clojars.org/repo</url>
|
<url>http://clojars.org/repo</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
|
||||||
|
<repository>
|
||||||
|
<id>scala-tools</id>
|
||||||
|
<url>http://scala-tools.org/repo-releases</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
Reference in New Issue
Block a user