Configure deadline with markdown.parseTimeout Allow site admin to increase the deadline from the default of 2s to higher values, allowing more time to parse complex documents. Change-Id: I0189885c84424218f6ee83d7475cb4c9eac44889
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java b/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java index 7013918..91795bb 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/ReadmeHelper.java
@@ -31,6 +31,7 @@ import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.RawParseUtils; +import org.joda.time.Duration; import org.pegdown.ast.RootNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -89,10 +90,13 @@ SanitizedContent render() { try { + Duration parseTimeout = ConfigUtil.getDuration(cfg, "markdown", null, + "parseTimeout", Duration.standardSeconds(2)); int inputLimit = cfg.getInt("markdown", "inputLimit", 5 << 20); byte[] raw = reader.open(readmeId, Constants.OBJ_BLOB).getCachedBytes(inputLimit); String md = RawParseUtils.decode(raw); - RootNode root = GitilesMarkdown.parseFile(view, readmePath, md); + RootNode root = + GitilesMarkdown.parseFile(parseTimeout, view, readmePath, md); if (root == null) { return null; }
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java index 7b7f974..59b8b5c 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/DocServlet.java
@@ -29,6 +29,7 @@ import com.google.common.hash.Hashing; import com.google.common.net.HttpHeaders; import com.google.gitiles.BaseServlet; +import com.google.gitiles.ConfigUtil; import com.google.gitiles.FormatType; import com.google.gitiles.GitilesAccess; import com.google.gitiles.GitilesView; @@ -47,6 +48,7 @@ import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.RawParseUtils; +import org.joda.time.Duration; import org.pegdown.ast.RootNode; import java.io.IOException; @@ -108,10 +110,12 @@ return; } + Duration parseTimeout = ConfigUtil.getDuration(cfg, "markdown", null, + "parseTimeout", Duration.standardSeconds(2)); view = view.toBuilder().setPathPart(srcmd.path).build(); int inputLimit = cfg.getInt("markdown", "inputLimit", 5 << 20); RootNode doc = GitilesMarkdown.parseFile( - view, srcmd.path, + parseTimeout, view, srcmd.path, srcmd.read(rw.getObjectReader(), inputLimit)); if (doc == null) { res.sendRedirect(GitilesView.show().copyFrom(view).toUrl()); @@ -121,7 +125,7 @@ RootNode nav = null; if (navmd != null) { nav = GitilesMarkdown.parseFile( - view, navmd.path, + parseTimeout, view, navmd.path, navmd.read(rw.getObjectReader(), inputLimit)); if (nav == null) { res.setStatus(SC_INTERNAL_SERVER_ERROR);
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java index dcef245..91168b8 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/GitilesMarkdown.java
@@ -17,6 +17,7 @@ import com.google.common.base.Throwables; import com.google.gitiles.GitilesView; +import org.joda.time.Duration; import org.parboiled.Rule; import org.parboiled.common.Factory; import org.parboiled.errors.ParserRuntimeException; @@ -50,20 +51,22 @@ // this impacting the rendered formatting. private static final int MD_OPTIONS = (ALL | SUPPRESS_ALL_HTML) & ~(HARDWRAPS); - public static RootNode parseFile(GitilesView view, String path, String md) { + public static RootNode parseFile(Duration parseTimeout, GitilesView view, + String path, String md) { if (md == null) { return null; } try { try { - return newParser().parseMarkdown(md.toCharArray()); + return newParser(parseTimeout).parseMarkdown(md.toCharArray()); } catch (ParserRuntimeException e) { Throwables.propagateIfInstanceOf(e.getCause(), ParsingTimeoutException.class); throw e; } } catch (ParsingTimeoutException e) { - log.error("timeout rendering {}/{} at {}", + log.error("timeout {} ms rendering {}/{} at {}", + parseTimeout.getMillis(), view.getRepositoryName(), path, view.getRevision().getName()); @@ -71,17 +74,19 @@ } } - private static PegDownProcessor newParser() { + private static PegDownProcessor newParser(Duration parseDeadline) { PegDownPlugins plugins = new PegDownPlugins.Builder() - .withPlugin(GitilesMarkdown.class) + .withPlugin(GitilesMarkdown.class, parseDeadline) .build(); - return new PegDownProcessor(MD_OPTIONS, plugins); + return new PegDownProcessor(MD_OPTIONS, parseDeadline.getMillis(), plugins); } + private final Duration parseTimeout; private PegDownProcessor parser; - GitilesMarkdown() { - super(MD_OPTIONS, 2000L, DefaultParseRunnerProvider); + GitilesMarkdown(Duration parseTimeout) { + super(MD_OPTIONS, parseTimeout.getMillis(), DefaultParseRunnerProvider); + this.parseTimeout = parseTimeout; } @Override @@ -235,7 +240,7 @@ // use its existing parsing rules. Recurse manually for inner text // parsing within a block. if (parser == null) { - parser = newParser(); + parser = newParser(parseTimeout); } return parser.parseMarkdown(body.getChars()).getChildren(); }