In source code of Naming#parseURL() in 1.3.1, to parse URL String is hard coded.
On the other hand, to parse URL process in 1.4.X/1.5 is done
by getHost in java.net.URI..
Please assume the URL includes a hostname which has '_'(underscore).
ex.
http://appsrv_k01:12200/
To parse URL process in 1.3.1 doesn't check whether the String includes
'_' or not, which is, that considers '_' no problem.
Then hostname is extracted as specified in URL String
(In the above example, "appsrv_k01" will be extracted.)
=== ./src/share/classes/java/rmi/Naming.java (1.3.1_12) ===
213 private static ParsedNamingURL parseURL(String url)
214 throws MalformedURLException
215 {
216 ParsedNamingURL parsed = new ParsedNamingURL();
217 int startFile = -1;
218
219 // remove the approved protocol
220 if (url.startsWith("rmi:")) {
221 url = url.substring(4);
222 }
223
224 // Anchors (i.e. '#') are meaningless in rmi URLs - disallow them
225 if (url.indexOf('#') >= 0) {
226 throw new MalformedURLException
227 ("Invalid character, '#', in URL: " + url);
228 }
229
230 // No protocol must remain
231 int checkProtocol = url.indexOf(':');
232 if (checkProtocol >= 0 && (checkProtocol < url.indexOf('/')))
233 throw new java.net.MalformedURLException("invalid protocol: " +
234 url.substring(0, checkProtocol));
235
236 if (url.startsWith("//")) {
237 final int startHost = 2;
238 int nextSlash = url.indexOf("/", startHost);
239 if (nextSlash >= 0) {
240 startFile = nextSlash + 1;
241 } else {
242 // no trailing slash implies no name
243 nextSlash = url.length();
244 startFile = nextSlash;
245 }
246
247 int colon = url.indexOf(":", startHost);
248 if ((colon > 1) && (colon < nextSlash)) {
249 // explicit port supplied
250 try {
251 parsed.port =
252 Integer.parseInt(url.substring(colon + 1,
253 nextSlash));
254 } catch (NumberFormatException e) {
255 throw new MalformedURLException(
256 "invalid port number: " + url);
257 }
258 }
259
260 // if have colon then endhost, else end with slash
261 int endHost;
262 if (colon >= startHost) {
263 endHost = colon;
264 } else {
265 endHost = nextSlash;
266 }
267 parsed.host = url.substring(startHost, endHost);
268
269 } else if (url.startsWith("/")) {
270 startFile = 1;
271 } else {
272 startFile = 0;
273 }
274 // set the bind name
275 parsed.name = url.substring(startFile);
276 if (parsed.name.equals("") || parsed.name.equals("/")) {
277 parsed.name = null;
278 }
279
280 return parsed;
281 }
..............
However, in 1.4.X/1.5, URI#getHost() returns null and URI#getPort() returns -1
because "appsrv_k01" doesn't follow RF2396. The hostname includes '_'.
In the above case, Naming#parseURL() seems to consider as hostname and port
are abbreviated . The parseURL sets the hostname and port number to localhost IPaddress and 1089 respectively and keep processing.
=== ./j2se/src/share/classes/java/rmi/Naming.java (1.5b62) ====
.............
216 private static ParsedNamingURL parseURL(String str)
217 throws MalformedURLException
218 {
219 try {
220 URI uri = new URI(str);
221 if (uri.getFragment() != null) {
222 throw new MalformedURLException(
223 "invalid character, '#', in URL name: " + str);
224 } else if (uri.getQuery() != null) {
225 throw new MalformedURLException(
226 "invalid character, '?', in URL name: " + str);
227 } else if (uri.getUserInfo() != null) {
228 throw new MalformedURLException(
229 "invalid character, '@', in URL host: " + str);
230 }
231 String scheme = uri.getScheme();
232 if (scheme != null && !scheme.equals("rmi")) {
233 throw new MalformedURLException("invalid URL scheme: " + str);
234 }
235
236 String name = uri.getPath();
237 if (name != null) {
238 if (name.startsWith("/")) {
239 name = name.substring(1);
240 }
241 if (name.length() == 0) {
242 name = null;
243 }
244 }
245
246 String host = uri.getHost();
247 if (host == null) {
248 host = "";
249 if (uri.getPort() == -1) {
250 /* handle URIs with explicit port but no host
251 * (e.g., "//:1098/foo"); although they do not strictly
252 * conform to RFC 2396, Naming's javadoc explicitly allows
253 * them.
254 */
255 String authority = uri.getAuthority();
256 if (authority != null && authority.startsWith(":")) {
257 authority = "localhost" + authority;
258 uri = new URI(null, authority, null, null, null);
259 }
260 }
261 }
262 int port = uri.getPort();
263 if (port == -1) {
264 port = Registry.REGISTRY_PORT;
265 }
266 return new ParsedNamingURL(host, port, name);
267
268 } catch (URISyntaxException ex) {
...........
PROBLEM :
When a program uses the result of Naming#parseURL() as arguments
for Naming#rebind,
If the specifications is "argument for rebind should follow RFC 2396",
MalformedURLException should be thrown by some method(parseURL or
getHost ...?)
At least, to consider "host name is abbreviated" doesn't seem reasonable.
If the specifications is "argument for rebind may not follow RFC 2396",
the hostname which includes '_' should be extracted. the current behavior
in 1.4.X/1.5 to set hostname to local IP address doesn't seem reasonable.
REQUEST :
To clarify which behaviors is reasonable in rmi, in 1.3.1 and 1.4.X/1.5
TEST PROGRAM:
Please try the following program on the host which name includes '_'.
----- a.java -->
import java.net.*;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
class a
{
public static void main(String[] arg)
{
try {
int p = Integer.parseInt(arg[0]);
String host = InetAddress.getLocalHost().getHostName();
x xr = new x();
LocateRegistry.createRegistry(p);
try {
Naming.rebind("rmi://" + host + ":"+p+"/xxx", xr);
System.out.println("ok");
} catch (Exception e) {
System.out.println("ng");
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);
}
interface z extends Remote {
public void z() throws RemoteException;
}
static class x extends UnicastRemoteObject implements z
{
x() throws RemoteException {}
public void z() {}
}
}
<----
HOW TO CONFIRM:
- Launch the commnads in 1.5 as follows and you will see the similar
message.
K:\shares2\rmi-rfc2396-diff-131-141>javac a.java
K:\shares2\rmi-rfc2396-diff-131-141>rmic a$x
K:\shares2\rmi-rfc2396-diff-131-141>java a 12200
java.rmi.ConnectException: Connection refused to host: xxx.yyy.zzz.uuu; nested exception is:
java.net.ConnectException: Connection refused: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:567)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:185)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:171)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:313)
at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
at java.rmi.Naming.rebind(Naming.java:160)
at a.main(a.java:15)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
at java.net.Socket.connect(Socket.java:452)
at java.net.Socket.connect(Socket.java:402)
at java.net.Socket.<init>(Socket.java:309)
at java.net.Socket.<init>(Socket.java:124)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:562)
... 6 more
K:\shares2\rmi-rfc2396-diff-131-141>
If you try in 1.3.1_0X, you will see only "o.k".
=========================================================================================
On the other hand, to parse URL process in 1.4.X/1.5 is done
by getHost in java.net.URI..
Please assume the URL includes a hostname which has '_'(underscore).
ex.
http://appsrv_k01:12200/
To parse URL process in 1.3.1 doesn't check whether the String includes
'_' or not, which is, that considers '_' no problem.
Then hostname is extracted as specified in URL String
(In the above example, "appsrv_k01" will be extracted.)
=== ./src/share/classes/java/rmi/Naming.java (1.3.1_12) ===
213 private static ParsedNamingURL parseURL(String url)
214 throws MalformedURLException
215 {
216 ParsedNamingURL parsed = new ParsedNamingURL();
217 int startFile = -1;
218
219 // remove the approved protocol
220 if (url.startsWith("rmi:")) {
221 url = url.substring(4);
222 }
223
224 // Anchors (i.e. '#') are meaningless in rmi URLs - disallow them
225 if (url.indexOf('#') >= 0) {
226 throw new MalformedURLException
227 ("Invalid character, '#', in URL: " + url);
228 }
229
230 // No protocol must remain
231 int checkProtocol = url.indexOf(':');
232 if (checkProtocol >= 0 && (checkProtocol < url.indexOf('/')))
233 throw new java.net.MalformedURLException("invalid protocol: " +
234 url.substring(0, checkProtocol));
235
236 if (url.startsWith("//")) {
237 final int startHost = 2;
238 int nextSlash = url.indexOf("/", startHost);
239 if (nextSlash >= 0) {
240 startFile = nextSlash + 1;
241 } else {
242 // no trailing slash implies no name
243 nextSlash = url.length();
244 startFile = nextSlash;
245 }
246
247 int colon = url.indexOf(":", startHost);
248 if ((colon > 1) && (colon < nextSlash)) {
249 // explicit port supplied
250 try {
251 parsed.port =
252 Integer.parseInt(url.substring(colon + 1,
253 nextSlash));
254 } catch (NumberFormatException e) {
255 throw new MalformedURLException(
256 "invalid port number: " + url);
257 }
258 }
259
260 // if have colon then endhost, else end with slash
261 int endHost;
262 if (colon >= startHost) {
263 endHost = colon;
264 } else {
265 endHost = nextSlash;
266 }
267 parsed.host = url.substring(startHost, endHost);
268
269 } else if (url.startsWith("/")) {
270 startFile = 1;
271 } else {
272 startFile = 0;
273 }
274 // set the bind name
275 parsed.name = url.substring(startFile);
276 if (parsed.name.equals("") || parsed.name.equals("/")) {
277 parsed.name = null;
278 }
279
280 return parsed;
281 }
..............
However, in 1.4.X/1.5, URI#getHost() returns null and URI#getPort() returns -1
because "appsrv_k01" doesn't follow RF2396. The hostname includes '_'.
In the above case, Naming#parseURL() seems to consider as hostname and port
are abbreviated . The parseURL sets the hostname and port number to localhost IPaddress and 1089 respectively and keep processing.
=== ./j2se/src/share/classes/java/rmi/Naming.java (1.5b62) ====
.............
216 private static ParsedNamingURL parseURL(String str)
217 throws MalformedURLException
218 {
219 try {
220 URI uri = new URI(str);
221 if (uri.getFragment() != null) {
222 throw new MalformedURLException(
223 "invalid character, '#', in URL name: " + str);
224 } else if (uri.getQuery() != null) {
225 throw new MalformedURLException(
226 "invalid character, '?', in URL name: " + str);
227 } else if (uri.getUserInfo() != null) {
228 throw new MalformedURLException(
229 "invalid character, '@', in URL host: " + str);
230 }
231 String scheme = uri.getScheme();
232 if (scheme != null && !scheme.equals("rmi")) {
233 throw new MalformedURLException("invalid URL scheme: " + str);
234 }
235
236 String name = uri.getPath();
237 if (name != null) {
238 if (name.startsWith("/")) {
239 name = name.substring(1);
240 }
241 if (name.length() == 0) {
242 name = null;
243 }
244 }
245
246 String host = uri.getHost();
247 if (host == null) {
248 host = "";
249 if (uri.getPort() == -1) {
250 /* handle URIs with explicit port but no host
251 * (e.g., "//:1098/foo"); although they do not strictly
252 * conform to RFC 2396, Naming's javadoc explicitly allows
253 * them.
254 */
255 String authority = uri.getAuthority();
256 if (authority != null && authority.startsWith(":")) {
257 authority = "localhost" + authority;
258 uri = new URI(null, authority, null, null, null);
259 }
260 }
261 }
262 int port = uri.getPort();
263 if (port == -1) {
264 port = Registry.REGISTRY_PORT;
265 }
266 return new ParsedNamingURL(host, port, name);
267
268 } catch (URISyntaxException ex) {
...........
PROBLEM :
When a program uses the result of Naming#parseURL() as arguments
for Naming#rebind,
If the specifications is "argument for rebind should follow RFC 2396",
MalformedURLException should be thrown by some method(parseURL or
getHost ...?)
At least, to consider "host name is abbreviated" doesn't seem reasonable.
If the specifications is "argument for rebind may not follow RFC 2396",
the hostname which includes '_' should be extracted. the current behavior
in 1.4.X/1.5 to set hostname to local IP address doesn't seem reasonable.
REQUEST :
To clarify which behaviors is reasonable in rmi, in 1.3.1 and 1.4.X/1.5
TEST PROGRAM:
Please try the following program on the host which name includes '_'.
----- a.java -->
import java.net.*;
import java.rmi.*;
import java.rmi.registry.*;
import java.rmi.server.*;
class a
{
public static void main(String[] arg)
{
try {
int p = Integer.parseInt(arg[0]);
String host = InetAddress.getLocalHost().getHostName();
x xr = new x();
LocateRegistry.createRegistry(p);
try {
Naming.rebind("rmi://" + host + ":"+p+"/xxx", xr);
System.out.println("ok");
} catch (Exception e) {
System.out.println("ng");
e.printStackTrace();
}
} catch (Exception e) {
e.printStackTrace();
}
System.exit(0);
}
interface z extends Remote {
public void z() throws RemoteException;
}
static class x extends UnicastRemoteObject implements z
{
x() throws RemoteException {}
public void z() {}
}
}
<----
HOW TO CONFIRM:
- Launch the commnads in 1.5 as follows and you will see the similar
message.
K:\shares2\rmi-rfc2396-diff-131-141>javac a.java
K:\shares2\rmi-rfc2396-diff-131-141>rmic a$x
K:\shares2\rmi-rfc2396-diff-131-141>java a 12200
java.rmi.ConnectException: Connection refused to host: xxx.yyy.zzz.uuu; nested exception is:
java.net.ConnectException: Connection refused: connect
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:567)
at sun.rmi.transport.tcp.TCPChannel.createConnection(TCPChannel.java:185)
at sun.rmi.transport.tcp.TCPChannel.newConnection(TCPChannel.java:171)
at sun.rmi.server.UnicastRef.newCall(UnicastRef.java:313)
at sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
at java.rmi.Naming.rebind(Naming.java:160)
at a.main(a.java:15)
Caused by: java.net.ConnectException: Connection refused: connect
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:305)
at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:171)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:158)
at java.net.Socket.connect(Socket.java:452)
at java.net.Socket.connect(Socket.java:402)
at java.net.Socket.<init>(Socket.java:309)
at java.net.Socket.<init>(Socket.java:124)
at sun.rmi.transport.proxy.RMIDirectSocketFactory.createSocket(RMIDirectSocketFactory.java:22)
at sun.rmi.transport.proxy.RMIMasterSocketFactory.createSocket(RMIMasterSocketFactory.java:128)
at sun.rmi.transport.tcp.TCPEndpoint.newSocket(TCPEndpoint.java:562)
... 6 more
K:\shares2\rmi-rfc2396-diff-131-141>
If you try in 1.3.1_0X, you will see only "o.k".
=========================================================================================
- relates to
-
JDK-6587184 Underline Problem in java.net.URI VM 1.6.0_01
- Open
-
JDK-4641504 REGRESSION: Space disallowed in URL passed to Naming.lookup()
- Open