5064980: URI compareTo inconsistent with equals for mixed-case escape sequences

Reviewed-by: chegar, dfuchs
This commit is contained in:
Kiran Sidhartha Ravikumar 2019-12-17 16:06:27 +00:00
parent fae788a200
commit a1b2e1042c
2 changed files with 78 additions and 36 deletions

View file

@ -1572,10 +1572,11 @@ public final class URI
* component is undefined but the other is defined then the first is
* considered to be less than the second. Unless otherwise noted, string
* components are ordered according to their natural, case-sensitive
* ordering as defined by the {@link java.lang.String#compareTo(Object)
* ordering as defined by the {@link java.lang.String#compareTo(String)
* String.compareTo} method. String components that are subject to
* encoding are compared by comparing their raw forms rather than their
* encoded forms.
* encoded forms and the hexadecimal digits of escaped octets are compared
* without regard to case.
*
* <p> The ordering of URIs is defined as follows: </p>
*
@ -1838,35 +1839,9 @@ public final class URI
}
private static boolean equal(String s, String t) {
if (s == t) return true;
if ((s != null) && (t != null)) {
if (s.length() != t.length())
return false;
if (s.indexOf('%') < 0)
return s.equals(t);
int n = s.length();
for (int i = 0; i < n;) {
char c = s.charAt(i);
char d = t.charAt(i);
if (c != '%') {
if (c != d)
return false;
i++;
continue;
}
if (d != '%')
return false;
i++;
if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
return false;
i++;
if (toLower(s.charAt(i)) != toLower(t.charAt(i)))
return false;
i++;
}
return true;
}
return false;
boolean testForEquality = true;
int result = percentNormalizedComparison(s, t, testForEquality);
return result == 0;
}
// US-ASCII only
@ -1920,11 +1895,61 @@ public final class URI
}
private static int compare(String s, String t) {
boolean testForEquality = false;
int result = percentNormalizedComparison(s, t, testForEquality);
return result;
}
// The percentNormalizedComparison method does not verify two
// characters that follow the % sign are hexadecimal digits.
// Reason being:
// 1) percentNormalizedComparison method is not called with
// 'decoded' strings
// 2) The only place where a percent can be followed by anything
// other than hexadecimal digits is in the authority component
// (for a IPv6 scope) and the whole authority component is case
// insensitive.
private static int percentNormalizedComparison(String s, String t,
boolean testForEquality) {
if (s == t) return 0;
if (s != null) {
if (t != null)
if (t != null) {
if (s.indexOf('%') < 0) {
return s.compareTo(t);
else
}
int sn = s.length();
int tn = t.length();
if ((sn != tn) && testForEquality)
return sn - tn;
int val = 0;
int n = sn < tn ? sn : tn;
for (int i = 0; i < n; ) {
char c = s.charAt(i);
char d = t.charAt(i);
val = c - d;
if (c != '%') {
if (val != 0)
return val;
i++;
continue;
}
if (d != '%') {
if (val != 0)
return val;
}
i++;
val = toLower(s.charAt(i)) - toLower(t.charAt(i));
if (val != 0)
return val;
i++;
val = toLower(s.charAt(i)) - toLower(t.charAt(i));
if (val != 0)
return val;
i++;
}
return sn - tn;
} else
return +1;
} else {
return -1;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -1412,6 +1412,18 @@ public class Test {
lt(new URI(s), new URI(t));
}
static void gt0(URI u, URI v) throws URISyntaxException {
ne0(u, v);
int c = u.compareTo(v);
if (c <= 0) {
show(u);
show(v);
throw new RuntimeException("Not greater than: " + u + " " + v
+ " " + c);
}
out.println(u + " < " + v);
}
static void gt(URI u, URI v) throws URISyntaxException {
lt(v, u);
}
@ -1423,10 +1435,12 @@ public class Test {
URI o = new URI("mailto:foo@bar.com");
URI r = new URI("reg://some%20registry/b/c/d?q#f");
URI s = new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?q#f");
URI t = new URI("http://example.com/%5bsegment%5d");
eq(o, o);
lt(o, r);
lt(s, o);
lt(s, r);
eq(o, new URI("MaILto:foo@bar.com"));
gt(o, new URI("mailto:foo@bar.COM"));
eq(r, new URI("rEg://some%20registry/b/c/d?q#f"));
@ -1436,6 +1450,9 @@ public class Test {
gt(s, new URI("http://jag:CafeBabe@java.sun.com:94/b/c/d?q#f"));
lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?r#f"));
lt(s, new URI("http://jag:cafebabe@java.sun.com:94/b/c/d?q#g"));
cmp0(t, new URI("http://example.com/%5Bsegment%5D"), true);
gt0(t, new URI("http://example.com/%5BSegment%5D"));
lt(new URI("http://example.com/%5Asegment%5D"), new URI("http://example.com/%5Bsegment%5D"));
eq(new URI("http://host/a%00bcd"), new URI("http://host/a%00bcd"));
ne(new URI("http://host/a%00bcd"), new URI("http://host/aZ00bcd"));
eq0(new URI("http://host/abc%e2def%C3ghi"),