Skip to content
This repository has been archived by the owner on Sep 12, 2018. It is now read-only.

Commit

Permalink
Markdown: Set timeout of rendering to 5 seconds
Browse files Browse the repository at this point in the history
Return the source wrapped by `<pre>` HTML tag, instead of rendered
result, if timeout occurs.

Warning: Thread.stop(), which is danger and deprecated but used in this
commit, may corrupt the script engine. It may be better to add some code
to rebuild the script engine after stopping a thread if you meet some
problem in future.
  • Loading branch information
Yi EungJun committed Jul 7, 2015
1 parent 931e3ab commit ad9b0aa
Showing 1 changed file with 41 additions and 6 deletions.
47 changes: 41 additions & 6 deletions app/utils/Markdown.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
package utils;

import models.Project;
import org.apache.commons.lang.StringEscapeUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
Expand All @@ -33,10 +34,8 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.System;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;

public class Markdown {

Expand Down Expand Up @@ -138,7 +137,7 @@ private static String renderWithHighlight(String source, boolean breaks) {
"highlight : function(sCode, sLang) { " +
"if(sLang) { try { return hljs.highlight(sLang.toLowerCase(), sCode).value;" +
" } catch(oException) { return sCode; } } }});");
String rendered = (String) ((Invocable) engine).invokeFunction("marked", source, options);
String rendered = renderByMarked(source, options);
rendered = removeJavascriptInHref(rendered);
rendered = checkReferrer(rendered);
return sanitize(rendered);
Expand All @@ -147,13 +146,49 @@ private static String renderWithHighlight(String source, boolean breaks) {
}
}

/**
* Renders the source with Marked.
*
* @param source
* @param options
* @return the rendered result or the source if timeout occurs
*/
private static String renderByMarked(@Nonnull String source, Object options) throws InterruptedException {
if (source.isEmpty()) {
return source;
}

// Try to render and wait at most 5 seconds.
final String[] rendered = new String[1];
@SuppressWarnings("deprecation")
Thread marked = new Thread() {
@Override
public void run() {
try {
rendered[0] = (String) ((Invocable) engine).invokeFunction(
"marked", source, options);
} catch (Exception e) {
play.Logger.error("[Markdown] Failed to render: " + source, e);
}
}
};
marked.start();
marked.join(5000);

if (rendered[0] == null) {
// This is the only way to stop the script engine. Thread.interrupt does not work.
marked.stop();
return "<pre>" + StringEscapeUtils.escapeHtml(source) + "</pre>";
} else {
return rendered[0];
}
}

public static String render(@Nonnull String source) {
try {
Object options = engine.eval("new Object({gfm: true, tables: true, breaks: true, " +
"pedantic: false, sanitize: false, smartLists: true});");
String rendered = (String) ((Invocable) engine).invokeFunction("marked", source,
options);
return sanitize(rendered);
return sanitize(renderByMarked(source, options));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
Expand Down

0 comments on commit ad9b0aa

Please sign in to comment.