Ignore:
Timestamp:
2014-12-18T23:47:21+01:00 (9 years ago)
Author:
Don-vip
Message:

fix #10862 - proper validation of IDN (Internationalized Domain Name) URLs, both in their Unicode and ASCII form => patch of Apache DomainValidator routine

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/validation/tests/InternetTags.java

    r7489 r7824  
    33
    44import static org.openstreetmap.josm.tools.I18n.tr;
     5
     6import java.net.IDN;
     7import java.util.regex.Pattern;
    58
    69import org.openstreetmap.josm.command.ChangePropertyCommand;
     
    2326public class InternetTags extends Test {
    2427
    25     protected static final int INVALID_URL = 3301;
    26     protected static final int INVALID_EMAIL = 3302;
     28    /** Error code for an invalid URL */
     29    public static final int INVALID_URL = 3301;
     30    /** Error code for an invalid e-mail */
     31    public static final int INVALID_EMAIL = 3302;
     32
     33    private static final Pattern ASCII_PATTERN = Pattern.compile("^\\p{ASCII}+$");
    2734
    2835    /**
    2936     * List of keys subject to URL validation.
    3037     */
    31     public static String[] URL_KEYS = new String[] {
     38    private static String[] URL_KEYS = new String[] {
    3239        "url", "source:url",
    3340        "website", "contact:website", "heritage:website", "source:website"
     
    3744     * List of keys subject to email validation.
    3845     */
    39     public static String[] EMAIL_KEYS = new String[] {
     46    private static String[] EMAIL_KEYS = new String[] {
    4047        "email", "contact:email"
    4148    };
     
    4855    }
    4956
     57    /**
     58     * Potentially validates a given primitive key against a given validator.
     59     * @param p The OSM primitive to test
     60     * @param k The key to validate
     61     * @param keys The list of keys to check. If {@code k} is not inside this collection, do nothing
     62     * @param validator The validator to run if {@code k} is inside {@code keys}
     63     * @param code The error code to set if the validation fails
     64     * @return {@code true} if the validation fails. In this case, a new error has been created.
     65     */
    5066    private boolean doTest(OsmPrimitive p, String k, String[] keys, AbstractValidator validator, int code) {
    5167        for (String i : keys) {
    5268            if (i.equals(k)) {
    53                 if (!validator.isValid(p.get(k))) {
    54                     TestError error;
    55                     String msg = tr("''{0}'': {1}", k, validator.getErrorMessage());
    56                     String fix = validator.getFix();
    57                     if (fix != null) {
    58                         error = new FixableTestError(this, Severity.WARNING, msg, code, p,
    59                                 new ChangePropertyCommand(p, k, fix));
    60                     } else {
    61                         error = new TestError(this, Severity.WARNING, msg, code, p);
    62                     }
    63                     return errors.add(error);
     69                TestError error = validateTag(p, k, validator, code);
     70                if (error != null) {
     71                    errors.add(error);
    6472                }
    6573                break;
     
    6977    }
    7078
     79    /**
     80     * Validates a given primitive tag against a given validator.
     81     * @param p The OSM primitive to test
     82     * @param k The key to validate
     83     * @param validator The validator to run
     84     * @param code The error code to set if the validation fails
     85     * @return The error if the validation fails, {@code null} otherwise
     86     * @since 7824
     87     */
     88    public TestError validateTag(OsmPrimitive p, String k, AbstractValidator validator, int code) {
     89        TestError error = doValidateTag(p, k, null, validator, code);
     90        if (error != null) {
     91            // Workaround to https://issues.apache.org/jira/browse/VALIDATOR-290
     92            // Apache Commons Validator 1.4.1-SNAPSHOT does not support yet IDN URLs
     93            // To remove if it gets fixed on Apache side
     94            String v = p.get(k);
     95            if (!ASCII_PATTERN.matcher(v).matches()) {
     96                try {
     97                    String protocol = "";
     98                    if (v.contains("://")) {
     99                        protocol = v.substring(0, v.indexOf("://")+3);
     100                    }
     101                    String domain = !protocol.isEmpty() ? v.substring(protocol.length(), v.length()) : v;
     102                    String ending = "";
     103                    if (domain.contains("/")) {
     104                        int idx = domain.indexOf("/");
     105                        ending = domain.substring(idx, domain.length());
     106                        domain = domain.substring(0, idx);
     107                    }
     108                    // Try to apply ToASCII algorithm
     109                    error = doValidateTag(p, k, protocol+IDN.toASCII(domain)+ending, validator, code);
     110                } catch (IllegalArgumentException e) {
     111                    error.setMessage(error.getMessage() +
     112                            tr(" URL cannot be converted to ASCII: {0}", e.getMessage()));
     113                }
     114            }
     115        }
     116        return error;
     117    }
     118
     119    /**
     120     * Validates a given primitive tag against a given validator.
     121     * @param p The OSM primitive to test
     122     * @param k The key to validate
     123     * @param v The value to validate. May be {@code null} to use {@code p.get(k)}
     124     * @param validator The validator to run
     125     * @param code The error code to set if the validation fails
     126     * @return The error if the validation fails, {@code null} otherwise
     127     */
     128    private TestError doValidateTag(OsmPrimitive p, String k, String v, AbstractValidator validator, int code) {
     129        TestError error = null;
     130        if (!validator.isValid(v != null ? v : p.get(k))) {
     131            String msg = tr("''{0}'': {1}", k, validator.getErrorMessage());
     132            String fix = validator.getFix();
     133            if (fix != null) {
     134                error = new FixableTestError(this, Severity.WARNING, msg, code, p,
     135                        new ChangePropertyCommand(p, k, fix));
     136            } else {
     137                error = new TestError(this, Severity.WARNING, msg, code, p);
     138            }
     139        }
     140        return error;
     141    }
     142
    71143    private void test(OsmPrimitive p) {
    72144        for (String k : p.keySet()) {
     145            // Test key against URL validator
    73146            if (!doTest(p, k, URL_KEYS, UrlValidator.getInstance(), INVALID_URL)) {
     147                // Test key against e-mail validator only if the URL validator did not fail
    74148                doTest(p, k, EMAIL_KEYS, EmailValidator.getInstance(), INVALID_EMAIL);
    75149            }
Note: See TracChangeset for help on using the changeset viewer.