# HG changeset patch # User Jiri Vanek # Date 1341315503 -7200 # Node ID 01ed07070c3c0711a2a0adb2dfeec17bfc34b964 # Parent a49edd57b1b332b431222b1c225189fe51676193 Fixed behavior when encoded/characters needed encoding included in url (PR811) diff -r a49edd57b1b3 -r 01ed07070c3c ChangeLog --- a/ChangeLog Thu Jun 28 12:00:07 2012 -0400 +++ b/ChangeLog Tue Jul 03 13:38:23 2012 +0200 @@ -1,3 +1,17 @@ +2012-05-18 Jiri Vanek + + Fixed behavior when encoded/characters needed encoding included in url + * NEWS: mentioned PR811 + * netx/net/sourceforge/jnlp/cache/CacheUtil.java: (urlEquals) Enhanced + to be able compare encoded/decoded urls correctly. + (notNullUrlEquals) new method to separate comparing of individual parts of + url from null checks + * netx/net/sourceforge/jnlp/cache/ResourceTracker.java: (addResource) + is now encoding url if needed. (normalizeUrl) new method to encode path in + url of all except file protocol. (normalizeChunk) New method for encoding + of atomic piece. + + 2012-06-28 Adam Domurad Allow passing of plugin tables and browser tables in NP_Initialize that diff -r a49edd57b1b3 -r 01ed07070c3c NEWS --- a/NEWS Thu Jun 28 12:00:07 2012 -0400 +++ b/NEWS Tue Jul 03 13:38:23 2012 +0200 @@ -11,6 +11,7 @@ New in release 1.2.1 (2012-XX-XX): * NetX - PR898: signed applications with big jnlp-file doesn't start (webstart affect like "frozen") + - PR811: javaws is not handling urls with spaces (and other characters needing encoding) correctly * Plugin - PR863: Error passing strings to applet methods in Chromium - PR895: IcedTea-Web searches for missing classes on each loadClass or findClass diff -r a49edd57b1b3 -r 01ed07070c3c netx/net/sourceforge/jnlp/cache/CacheUtil.java --- a/netx/net/sourceforge/jnlp/cache/CacheUtil.java Thu Jun 28 12:00:07 2012 -0400 +++ b/netx/net/sourceforge/jnlp/cache/CacheUtil.java Tue Jul 03 13:38:23 2012 +0200 @@ -61,22 +61,40 @@ * ie sourceforge.net and www.sourceforge.net). */ public static boolean urlEquals(URL u1, URL u2) { - if (u1 == u2) + if (u1 == u2) { return true; - if (u1 == null || u2 == null) + } + if (u1 == null || u2 == null) { return false; + } - if (!compare(u1.getProtocol(), u2.getProtocol(), true) || - !compare(u1.getHost(), u2.getHost(), true) || - //u1.getDefaultPort() != u2.getDefaultPort() || // only in 1.4 - !compare(u1.getPath(), u2.getPath(), false) || - !compare(u1.getQuery(), u2.getQuery(), false) || - !compare(u1.getRef(), u2.getRef(), false)) - return false; - else + if (notNullUrlEquals(u1, u2)) { return true; + } + try { + URL nu1 = ResourceTracker.normalizeUrl(u1, false); + URL nu2 = ResourceTracker.normalizeUrl(u2, false); + if (notNullUrlEquals(nu1, nu2)) { + return true; + } + } catch (Exception ex) { + //keep silent here and return false + } + return false; } + private static boolean notNullUrlEquals(URL u1, URL u2) { + if (!compare(u1.getProtocol(), u2.getProtocol(), true) + || !compare(u1.getHost(), u2.getHost(), true) + || //u1.getDefaultPort() != u2.getDefaultPort() || // only in 1.4 + !compare(u1.getPath(), u2.getPath(), false) + || !compare(u1.getQuery(), u2.getQuery(), false) + || !compare(u1.getRef(), u2.getRef(), false)) { + return false; + } else { + return true; + } + } /** * Caches a resource and returns a URL for it in the cache; * blocks until resource is cached. If the resource location is diff -r a49edd57b1b3 -r 01ed07070c3c netx/net/sourceforge/jnlp/cache/ResourceTracker.java --- a/netx/net/sourceforge/jnlp/cache/ResourceTracker.java Thu Jun 28 12:00:07 2012 -0400 +++ b/netx/net/sourceforge/jnlp/cache/ResourceTracker.java Tue Jul 03 13:38:23 2012 +0200 @@ -24,10 +24,13 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; +import java.net.URLDecoder; +import java.net.URLEncoder; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; @@ -108,6 +111,15 @@ private static final int ERROR = Resource.ERROR; private static final int STARTED = Resource.STARTED; + // normalization of url + private static final char PATH_DELIMITER_MARK = '/'; + private static final String PATH_DELIMITER = "" + PATH_DELIMITER_MARK; + private static final char QUERY_DELIMITER_MARK = '&'; + private static final String QUERY_DELIMITER = "" + QUERY_DELIMITER_MARK; + private static final char QUERY_MARK = '?'; + private static final char HREF_MARK = '#'; + private static final String UTF8 = "utf-8"; + /** max threads */ private static final int maxThreads = 5; @@ -173,7 +185,12 @@ public void addResource(URL location, Version version, DownloadOptions options, UpdatePolicy updatePolicy) { if (location == null) throw new IllegalArgumentException("location==null"); - + try { + location = normalizeUrl(location, JNLPRuntime.isDebug()); + } catch (Exception ex) { + System.err.println("Normalization of " + location.toString() + " have failed"); + ex.printStackTrace(); + } Resource resource = Resource.getResource(location, version, updatePolicy); boolean downloaded = false; @@ -1127,4 +1144,115 @@ } }; + private static String normalizeChunk(String base, boolean debug) throws UnsupportedEncodingException { + if (base == null) { + return base; + } + if ("".equals(base)) { + return base; + } + String result = base; + String ssE = URLDecoder.decode(base, UTF8); + // System.out.println("*" + base + "*"); + // System.out.println("-" + ssE + "-"); + if (base.equals(ssE)) { + result = URLEncoder.encode(base, UTF8); + if (debug) { + System.out.println(base + " chunk needs to be encoded => " + result); + } + } else { + if (debug) { + System.out.println(base + " chunk already encoded"); + } + } + return result; + } + + public static URL normalizeUrl(URL u, boolean debug) throws MalformedURLException, UnsupportedEncodingException { + if (u == null) { + return null; + } + String protocol = u.getProtocol(); + if (protocol == null || "file".equals(protocol)) { + return u; + } + String file = u.getPath(); + if (file == null) { + return u; + } + String host = u.getHost(); + String ref = u.getRef(); + int port = u.getPort(); + String query = u.getQuery(); + String[] qq = {}; + if (query != null) { + qq = query.split(QUERY_DELIMITER); + } + String[] ss = file.split(PATH_DELIMITER); + int normalized = 0; + if (debug) { + System.out.println("normalizing path " + file + " in " + u.toString()); + } + for (int i = 0; i < ss.length; i++) { + String base = ss[i]; + String r = normalizeChunk(base, debug); + if (!r.equals(ss[i])) { + normalized++; + } + ss[i] = r; + } + if (debug) { + System.out.println("normalizing query " + query + " in " + u.toString()); + } + for (int i = 0; i < qq.length; i++) { + String base = qq[i]; + String r = normalizeChunk(base, debug); + if (!r.equals(qq[i])) { + normalized++; + } + qq[i] = r; + } + if (normalized == 0) { + if (debug) { + System.out.println("Nothing was normalized in this url"); + } + return u; + } else { + if (debug) { + System.out.println(normalized + " chunks normalized, rejoining url"); + } + } + StringBuilder composed = new StringBuilder(""); + for (int i = 0; i < ss.length; i++) { + String string = ss[i]; + if (ss.length <= 1 || (string != null && !"".equals(string))) { + composed.append(PATH_DELIMITER_MARK).append(string); + } + } + String composed1 = composed.toString(); + if (query != null && !query.trim().equals("")) { + composed.append(QUERY_MARK); + for (int i = 0; i < qq.length; i++) { + String string = qq[i]; + if ((string != null && !"".equals(string))) { + composed.append(string); + if (i != qq.length - 1) { + composed.append(QUERY_DELIMITER_MARK); + } + } + } + } + String composed2 = composed.substring(composed1.length() - 1); + if (ref != null && !ref.trim().equals("")) { + composed.append(HREF_MARK).append(ref); + } + + URL result = new URL(protocol, host, port, composed.toString()); + + if (debug) { + System.out.println("normalized `" + composed1 + "` and `" + composed2 + "` in " + result.toString()); + } + return result; + + } }