Render git:// links in Markdown

README.md and other Markdown pages sometimes contains links to Git
repositories using git:// protocol.  This is by default rejected by
Soy sanitizers, but its reasonable to allow within the context of a
Markdown page in a Git repository.

Change-Id: Ibfa389335a25d2315d929c9f67082b4099328bac
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java b/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java
index 9639176..3239fe1 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/doc/html/HtmlBuilder.java
@@ -85,6 +85,17 @@
   private static final FilterNormalizeUri URI = FilterNormalizeUri.INSTANCE;
   private static final FilterImageDataUri IMAGE_DATA = FilterImageDataUri.INSTANCE;
 
+  private static final Pattern GIT_URI =
+      Pattern.compile(
+          "^"
+              +
+              // Reject paths containing /../ or ending in /..
+              "(?![^#?]*/(?:\\.|%2E){2}(?:[/?#]|\\z))"
+              +
+              // Accept git://host/path
+              "git://[^/]+/.+",
+          Pattern.CASE_INSENSITIVE);
+
   public static boolean isValidCssDimension(String val) {
     return val != null && val.matches("(?:[1-9][0-9]*px|100%|[1-9][0-9]?%)");
   }
@@ -99,6 +110,10 @@
     return IMAGE_DATA.getValueFilter().matcher(url).find();
   }
 
+  public static boolean isValidGitUri(String val) {
+    return GIT_URI.matcher(val).find();
+  }
+
   private final StringBuilder htmlBuf;
   private final Appendable textBuf;
   private String tag;
@@ -159,7 +174,7 @@
   }
 
   private String anchorHref(String val) {
-    if (URI.getValueFilter().matcher(val).find()) {
+    if (URI.getValueFilter().matcher(val).find() || isValidGitUri(val)) {
       return URI.escape(val);
     }
     return URI.getInnocuousOutput();