FULL PRODUCT VERSION :
java version "1.7.0_147-icedtea"
OpenJDK Runtime Environment (IcedTea7 2.0) (7~b147-2.0-0ubuntu0.11.10.1)
OpenJDK 64-Bit Server VM (build 21.0-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux naushicaa 3.0.0-14-generic #23-Ubuntu SMP Mon Nov 21 20:28:43 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
In java.net.URL class, only the following constructor chain parses the query part in a valid way (RFC 3986, section 3.4 Query):
* public URL(String spec)
* public URL(URL context, String spec)
* public URL(URL context, String spec, URLStreamHandler handler)
While the following java.net.URL constructors and methods (namely readObject) produce a different and invalid result:
* public URL(String protocol, String host, String file)
* public URL(String protocol, String host, int port, String file)
* public URL(String protocol, String host, int port, String file, URLStreamHandler handler)
* private synchronized void readObject(java.io.ObjectInputStream s) (!)
* protected void set(String protocol, String host, int port, String file, String ref)
In addition, the following related classes also produce invalid results at:
* java.net.Parts.Parts(String file)
* java.net.URLStreamHandler.setURL(URL u, String protocol, String host, int port, String file, String ref)
The reason is incorrect splitting into tokens using "file.lastIndexOf('?')" to locate the begining of the query part, in which the '?' is a valid character. Instead, "file.indexOf('?')" should be used.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Construct a URL1 with question marks in query part using the 1-argument constructor: public URL(String spec).
2. Print out its parsed parts, using methods: getFile(), getPath(), getQuery().
3. Construct a URL3 with question marks in query part using the 3-argument constructor: public URL(String protocol, String host, String file).
4. Print out its parsed parts, using methods: getFile(), getPath(), getQuery().
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
URL1.file = /path?query-not?invalid
URL1.path = /path
URL1.query = query-not?invalid
URL3.file = /path?query-not?invalid
URL3.path = /path
URL3.query = query-not?invalid
ACTUAL -
URL1.file = /path?query-not?invalid
URL1.path = /path
URL1.query = query-not?invalid
URL3.file = /path?query-not?invalid
URL3.path = /path?query-not
URL3.query = invalid
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.net.MalformedURLException;
import java.net.URL;
public class URLTest {
public static void main(final String[] args) throws MalformedURLException {
final URL url1 = new URL("http://host/path?query-not?invalid#fragment");
final URL url3 = new URL("http", "host", "/path?query-not?invalid#fragment");
System.out.println("URL1.file = " + url1.getFile());
System.out.println("URL1.path = " + url1.getPath());
System.out.println("URL1.query = " + url1.getQuery());
System.out.println();
System.out.println("URL3.file = " + url3.getFile());
System.out.println("URL3.path = " + url3.getPath());
System.out.println("URL3.query = " + url3.getQuery());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Reparsing the fresh URL (also after deserialization):
final URL workaround = new URL(new URL("http", "host", "/path?query-not?invalid#fragment").toString());
java version "1.7.0_147-icedtea"
OpenJDK Runtime Environment (IcedTea7 2.0) (7~b147-2.0-0ubuntu0.11.10.1)
OpenJDK 64-Bit Server VM (build 21.0-b17, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Linux naushicaa 3.0.0-14-generic #23-Ubuntu SMP Mon Nov 21 20:28:43 UTC 2011 x86_64 x86_64 x86_64 GNU/Linux
A DESCRIPTION OF THE PROBLEM :
In java.net.URL class, only the following constructor chain parses the query part in a valid way (RFC 3986, section 3.4 Query):
* public URL(String spec)
* public URL(URL context, String spec)
* public URL(URL context, String spec, URLStreamHandler handler)
While the following java.net.URL constructors and methods (namely readObject) produce a different and invalid result:
* public URL(String protocol, String host, String file)
* public URL(String protocol, String host, int port, String file)
* public URL(String protocol, String host, int port, String file, URLStreamHandler handler)
* private synchronized void readObject(java.io.ObjectInputStream s) (!)
* protected void set(String protocol, String host, int port, String file, String ref)
In addition, the following related classes also produce invalid results at:
* java.net.Parts.Parts(String file)
* java.net.URLStreamHandler.setURL(URL u, String protocol, String host, int port, String file, String ref)
The reason is incorrect splitting into tokens using "file.lastIndexOf('?')" to locate the begining of the query part, in which the '?' is a valid character. Instead, "file.indexOf('?')" should be used.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Construct a URL1 with question marks in query part using the 1-argument constructor: public URL(String spec).
2. Print out its parsed parts, using methods: getFile(), getPath(), getQuery().
3. Construct a URL3 with question marks in query part using the 3-argument constructor: public URL(String protocol, String host, String file).
4. Print out its parsed parts, using methods: getFile(), getPath(), getQuery().
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
URL1.file = /path?query-not?invalid
URL1.path = /path
URL1.query = query-not?invalid
URL3.file = /path?query-not?invalid
URL3.path = /path
URL3.query = query-not?invalid
ACTUAL -
URL1.file = /path?query-not?invalid
URL1.path = /path
URL1.query = query-not?invalid
URL3.file = /path?query-not?invalid
URL3.path = /path?query-not
URL3.query = invalid
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.net.MalformedURLException;
import java.net.URL;
public class URLTest {
public static void main(final String[] args) throws MalformedURLException {
final URL url1 = new URL("http://host/path?query-not?invalid#fragment");
final URL url3 = new URL("http", "host", "/path?query-not?invalid#fragment");
System.out.println("URL1.file = " + url1.getFile());
System.out.println("URL1.path = " + url1.getPath());
System.out.println("URL1.query = " + url1.getQuery());
System.out.println();
System.out.println("URL3.file = " + url3.getFile());
System.out.println("URL3.path = " + url3.getPath());
System.out.println("URL3.query = " + url3.getQuery());
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Reparsing the fresh URL (also after deserialization):
final URL workaround = new URL(new URL("http", "host", "/path?query-not?invalid#fragment").toString());