Path: csiph.com!usenet.pasdenom.info!gegeweb.org!eternal-september.org!feeder.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: markspace Newsgroups: comp.lang.java.programmer Subject: Re: [LONG] java.net.URI encoding weirdness Date: Tue, 06 May 2014 12:24:44 -0700 Organization: A noiseless patient Spider Lines: 101 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=windows-1252; format=flowed Content-Transfer-Encoding: 7bit Injection-Date: Tue, 6 May 2014 19:24:47 +0000 (UTC) Injection-Info: mx05.eternal-september.org; posting-host="9358cda03e1e0dfd3c4b757daa608707"; logging-data="432"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/ywm5AtdMAK/yCuAZBnxI80/GAe7g0vzU=" User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Thunderbird/24.5.0 In-Reply-To: Cancel-Lock: sha1:D7afCqcYLZrJ5gzXP/4M0Z6uAuY= Xref: csiph.com comp.lang.java.programmer:28400 On 5/6/2014 10:24 AM, markspace wrote: > On 5/6/2014 12:26 AM, Stanimir Stamenkov wrote: > >> public static void main(String[] args) throws Exception { >> URI u = URI.create("http://server1/path" >> + "?param%3D1=value%261¶m%3F2=value%232" >> + "#fragment"); > >> Note how the 'query' is wrong now. OK, I think I see what is going on. Most of your OP was frankly wrong, however this one represents an actual bug in the URI parsing: public class URITest3 { public static void main(String[] args) throws Exception { URI u = URI.create("http://server1/path" + "?param%3D1=value%261¶m%3F2=value%232" + "#fragment"); System.out.println(u.toASCIIString()); URI v = new URI(u.getScheme(), u.getUserInfo(), "server2", u.getPort(), u.getPath(), u.getQuery(), u.getFragment()); System.out.println(v.toASCIIString()); // "raw" is user error, omitted. } Output: http://server1/path?param%3D1=value%261¶m%3F2=value%232#fragment http://server2/path?param=1=value&1¶m?2=value%232#fragment Yes clearly the query part was not parsed correctly. It's ambiguous and can't be parsed. (Incidentally, '=' and '&' weren't parsed correctly, but I think '?' was, and was incorrectly escaped in your original string. Double check with the spec on that.) To fix this, Oracle should at minimum deprecate this ctor. It's plainly broken. Oracle should consider replacing it with a ctor that allows the query to be parsed correctly: public URI( String scheme, String userInfo, String host, int port, String path, String fragment, String[] ... paramValue ) ... where paramValue is a vararg of pairs of strings which can be then parsed and assembled correctly new URI( ..., {"param=1","value&1"},{"param?2","value#2"} ); However this is getting a bit complicated, so I think Oracle should consider adding a builder class to build URIs a little more conveniently. They should consider adding both parsed (like URI's current multi-argument ctors) and raw (already quoted) for easy "matching" of existing URIs. I think they should also make public some parts of the Parse (currently an private class inside URI) and make at least the various quoting methods available to developers, URLEncoder looks ill-suited for this purpose. public class URI { public static quoteScheme( .. ){... public static quoteUserInfo( .. ){... public static quoteHost( .. ){... public static quotePath( .. ){... ... etc. public class Builder { public Builder() {... public Builder setScheme(... public Builder setHost(... public Builder setPath(... public Builder setRawPath(... public Builder addParameter( String param, String value ).. public Builder changeParameter( String param, String value ).. public Builder addRawParameter( String paramValue).. public Builder setFragment(... public Builder setRawFragment(... public Builder clearParams()... public Builder clearAll()... ... etc. as needed You should double check your test cases and then submit a bug report to the OpenJDK project (I have better luck communicating with them than Oracle's bug reports page). That's about the best I can do right now. To fix an immediate problem, I'm pretty sure all your other test cases were wrong, so you should use test case 3 above as a template and you'll have to deal with parsing the query string yourself, unfortunately.