summaryrefslogtreecommitdiffstats
path: root/gerrit-gwtexpui/src/main/java/com/google/gwtexpui/safehtml/client/LinkFindReplace.java
blob: eaa4f23030634c87f6df11ff6f9b7b9ef7217779 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Copyright (C) 2013 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.gwtexpui.safehtml.client;

import com.google.gwt.regexp.shared.RegExp;

/**
 * A Find/Replace pair whose replacement string is a link.
 * <p>
 * It is safe to pass arbitrary user-provided links to this class. Links are
 * sanitized as follows:
 * <ul>
 * <li>Only http(s) and mailto links are supported; any other scheme results in
 * an {@link IllegalArgumentException} from {@link #replace(String)}.
 * <li>Special characters in the link after regex replacement are escaped with
 * {@link SafeHtmlBuilder}.</li>
 * </ul>
 */
public class LinkFindReplace implements FindReplace {
  public static boolean hasValidScheme(String link) {
    int colon = link.indexOf(':');
    if (colon < 0) {
      return true;
    }
    String scheme = link.substring(0, colon);
    return "http".equalsIgnoreCase(scheme)
        || "https".equalsIgnoreCase(scheme)
        || "mailto".equalsIgnoreCase(scheme);
  }

  private RegExp pat;
  private String link;

  protected LinkFindReplace() {
  }

  /**
   * @param regex regular expression pattern to match substrings with.
   * @param repl replacement link href. Capture groups within
   *        <code>regex</code> can be referenced with <code>$<i>n</i></code>.
   */
  public LinkFindReplace(String find, String link) {
    this.pat = RegExp.compile(find);
    this.link = link;
  }

  @Override
  public RegExp pattern() {
    return pat;
  }

  @Override
  public String replace(String input) {
    String href = pat.replace(input, link);
    if (!hasValidScheme(href)) {
      throw new IllegalArgumentException(
          "Invalid scheme (" + toString() + "): " + href);
    }
    String result = new SafeHtmlBuilder()
        .openAnchor()
        .setAttribute("href", href)
        .append(SafeHtml.asis(input))
        .closeAnchor()
        .asString();
    return result;
  }

  @Override
  public String toString() {
    return "find = " + pat.getSource() + ", link = " + link;
  }
}