8278972: Improve URL supports

Reviewed-by: skoivu, rhalade, alanb
This commit is contained in:
Daniel Fuchs 2022-01-28 11:28:07 +00:00 committed by Henry Jen
parent 395bb5b7f9
commit 9e051d5396
5 changed files with 656 additions and 81 deletions
src
java.naming/share/classes/com/sun/jndi
jdk.naming.dns/share/classes/com/sun/jndi/dns
jdk.naming.rmi/share/classes/com/sun/jndi/url/rmi

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@ -28,6 +28,10 @@ package com.sun.jndi.ldap;
import javax.naming.*;
import java.net.MalformedURLException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.StringTokenizer;
import com.sun.jndi.toolkit.url.Uri;
import com.sun.jndi.toolkit.url.UrlUtil;
@ -64,6 +68,25 @@ import com.sun.jndi.toolkit.url.UrlUtil;
public final class LdapURL extends Uri {
private static final String PARSE_MODE_PROP = "com.sun.jndi.ldapURLParsing";
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
public static final ParseMode PARSE_MODE;
static {
PrivilegedAction<String> action = () ->
System.getProperty(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
ParseMode parseMode = DEFAULT_PARSE_MODE;
try {
@SuppressWarnings("removal")
String mode = AccessController.doPrivileged(action);
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
} catch (Throwable t) {
parseMode = DEFAULT_PARSE_MODE;
} finally {
PARSE_MODE = parseMode;
}
}
private boolean useSsl = false;
private String DN = null;
private String attributes = null;
@ -83,7 +106,7 @@ public final class LdapURL extends Uri {
useSsl = scheme.equalsIgnoreCase("ldaps");
if (! (scheme.equalsIgnoreCase("ldap") || useSsl)) {
throw new MalformedURLException("Not an LDAP URL: " + url);
throw newInvalidURISchemeException(url);
}
parsePathAndQuery(); // DN, attributes, scope, filter, extensions
@ -99,6 +122,21 @@ public final class LdapURL extends Uri {
}
}
@Override
protected MalformedURLException newInvalidURISchemeException(String uri) {
return new MalformedURLException("Not an LDAP URL: " + uri);
}
@Override
protected boolean isSchemeOnly(String uri) {
return isLdapSchemeOnly(uri);
}
@Override
protected ParseMode parseMode() {
return PARSE_MODE;
}
/**
* Returns true if the URL is an LDAPS URL.
*/
@ -151,13 +189,33 @@ public final class LdapURL extends Uri {
StringTokenizer st = new StringTokenizer(urlList, " ");
while (st.hasMoreTokens()) {
urls[i++] = st.nextToken();
// we don't accept scheme-only URLs here
urls[i++] = validateURI(st.nextToken());
}
String[] trimmed = new String[i];
System.arraycopy(urls, 0, trimmed, 0, i);
return trimmed;
}
public static boolean isLdapSchemeOnly(String uri) {
return "ldap:".equals(uri) || "ldaps:".equals(uri);
}
public static String validateURI(String uri) {
// no validation in legacy mode parsing
if (PARSE_MODE == ParseMode.LEGACY) {
return uri;
}
// special case of scheme-only URIs
if (isLdapSchemeOnly(uri)) {
return uri;
}
// use java.net.URI to validate the uri syntax
return URI.create(uri).toString();
}
/**
* Determines whether an LDAP URL has query components.
*/
@ -181,7 +239,8 @@ public final class LdapURL extends Uri {
String p = (port != -1) ? (":" + port) : "";
String d = (dn != null) ? ("/" + UrlUtil.encode(dn, "UTF8")) : "";
return useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d;
String uri = useSsl ? "ldaps://" + h + p + d : "ldap://" + h + p + d;
return validateURI(uri);
} catch (UnsupportedEncodingException e) {
// UTF8 should always be supported
throw new IllegalStateException("UTF-8 encoding unavailable");

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@ -32,6 +32,8 @@ import javax.naming.spi.NamingManager;
import java.util.Hashtable;
import java.net.MalformedURLException;
import com.sun.jndi.toolkit.url.Uri.ParseMode;
/**
* This abstract class is a generic URL context that accepts as the
* name argument either a string URL or a Name whose first component
@ -48,6 +50,7 @@ import java.net.MalformedURLException;
* @author Rosanna Lee
*/
public abstract class GenericURLContext implements Context {
protected Hashtable<String, Object> myEnv = null;
@SuppressWarnings("unchecked") // Expect Hashtable<String, Object>
@ -161,8 +164,18 @@ public abstract class GenericURLContext implements Context {
if (url.startsWith("//", start)) {
start += 2; // skip double slash
// find last slash
int posn = url.indexOf('/', start);
// find where the authority component ends
// and the rest of the URL starts
int slash = url.indexOf('/', start);
int qmark = url.indexOf('?', start);
int fmark = url.indexOf('#', start);
if (fmark > -1 && qmark > fmark) qmark = -1;
if (fmark > -1 && slash > fmark) slash = -1;
if (qmark > -1 && slash > qmark) slash = -1;
int posn = slash > -1 ? slash
: (qmark > -1 ? qmark
: (fmark > -1 ? fmark
: url.length()));
if (posn >= 0) {
start = posn;
} else {

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2001, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -27,6 +27,8 @@ package com.sun.jndi.toolkit.url;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
/**
@ -36,15 +38,17 @@ import java.net.MalformedURLException;
*
* <p> The java.net.URL class cannot be used to parse URIs since it
* requires the installation of URL stream handlers that may not be
* available. The hack of getting around this by temporarily
* replacing the scheme part of a URI is not appropriate here: JNDI
* service providers must work on older Java platforms, and we want
* new features and bug fixes that are not available in old versions
* of the URL class.
* available.
*
* <p> It may be appropriate to drop this code in favor of the
* java.net.URI class. The changes would need to be written so as to
* still run on pre-1.4 platforms not containing that class.
* <p> The {@linkplain ParseMode#STRICT strict} parsing mode uses
* the java.net.URI class to syntactically validate URI strings.
* The {@linkplain ParseMode#COMPAT compat} mode validate the
* URI authority and rejects URI fragments, but doesn't perform any
* additional validation on path and query, other than that
* which may be implemented in the concrete the Uri subclasses.
* The {@linkplain ParseMode#LEGACY legacy} mode should not be
* used unless the application is capable of validating all URI
* strings before any constructors of this class is invoked.
*
* <p> The format of an absolute URI (see the RFCs mentioned above) is:
* <blockquote><pre>{@code
@ -105,6 +109,28 @@ import java.net.MalformedURLException;
public class Uri {
// three parsing modes
public enum ParseMode {
/**
* Strict validation mode.
* Validate the URI syntactically using {@link java.net.URI}.
* Rejects URI fragments unless explicitly supported by the
* subclass.
*/
STRICT,
/**
* Compatibility mode. The URI authority is syntactically validated.
* Rejects URI fragments unless explicitly supported by the
* subclass.
* This is the default.
*/
COMPAT,
/**
* Legacy mode. In this mode, no validation is performed.
*/
LEGACY
}
protected String uri;
protected String scheme;
protected String host = null;
@ -112,6 +138,7 @@ public class Uri {
protected boolean hasAuthority;
protected String path;
protected String query = null;
protected String fragment;
/**
@ -128,6 +155,15 @@ public class Uri {
protected Uri() {
}
/**
* The parse mode for parsing this URI.
* The default is {@link ParseMode#COMPAT}.
* @return the parse mode for parsing this URI.
*/
protected ParseMode parseMode() {
return ParseMode.COMPAT;
}
/**
* Initializes a Uri object given a URI string.
* This method must be called exactly once, and before any other Uri
@ -135,7 +171,7 @@ public class Uri {
*/
protected void init(String uri) throws MalformedURLException {
this.uri = uri;
parse(uri);
parse(uri, parseMode());
}
/**
@ -188,10 +224,229 @@ public class Uri {
return uri;
}
private void parse(String uri, ParseMode mode) throws MalformedURLException {
switch (mode) {
case STRICT -> parseStrict(uri);
case COMPAT -> parseCompat(uri);
case LEGACY -> parseLegacy(uri);
}
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Use java.net.URI to validate the uri string syntax
*/
private void parse(String uri) throws MalformedURLException {
private void parseStrict(String uri) throws MalformedURLException {
try {
if (!isSchemeOnly(uri)) {
URI u = new URI(uri);
scheme = u.getScheme();
if (scheme == null) throw new MalformedURLException("Invalid URI: " + uri);
var auth = u.getRawAuthority();
hasAuthority = auth != null;
if (hasAuthority) {
var host = u.getHost();
var port = u.getPort();
if (host != null) this.host = host;
if (port != -1) this.port = port;
String hostport = (host == null ? "" : host)
+ (port == -1 ? "" : (":" + port));
if (!hostport.equals(auth)) {
// throw if we have user info or regname
throw new MalformedURLException("unsupported authority: " + auth);
}
}
path = u.getRawPath();
if (u.getRawQuery() != null) {
query = "?" + u.getRawQuery();
}
if (u.getRawFragment() != null) {
if (!acceptsFragment()) {
throw new MalformedURLException("URI fragments not supported: " + uri);
}
fragment = "#" + u.getRawFragment();
}
} else {
// scheme-only URIs are not supported by java.net.URI
// validate the URI by appending "/" to the uri string.
var s = uri.substring(0, uri.indexOf(':'));
URI u = new URI(uri + "/");
if (!s.equals(u.getScheme())
|| !checkSchemeOnly(uri, u.getScheme())) {
throw newInvalidURISchemeException(uri);
}
scheme = s;
path = "";
}
} catch (URISyntaxException e) {
var mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Compatibility mode. Use java.net.URI to validate the syntax of
* the uri string authority.
*/
private void parseCompat(String uri) throws MalformedURLException {
int i; // index into URI
i = uri.indexOf(':'); // parse scheme
int slash = uri.indexOf('/');
int qmark = uri.indexOf('?');
int fmark = uri.indexOf('#');
if (i < 0 || slash > 0 && i > slash || qmark > 0 && i > qmark || fmark > 0 && i > fmark) {
throw new MalformedURLException("Invalid URI: " + uri);
}
if (fmark > -1) {
if (!acceptsFragment()) {
throw new MalformedURLException("URI fragments not supported: " + uri);
}
}
if (i == uri.length() - 1) {
if (!isSchemeOnly(uri)) {
throw newInvalidURISchemeException(uri);
}
}
scheme = uri.substring(0, i);
i++; // skip past ":"
hasAuthority = uri.startsWith("//", i);
if (fmark > -1 && qmark > fmark) qmark = -1;
int endp = qmark > -1 ? qmark : fmark > -1 ? fmark : uri.length();
if (hasAuthority) { // parse "//host:port"
i += 2; // skip past "//"
int starta = i;
// authority ends at the first appearance of /, ?, or #
int enda = uri.indexOf('/', i);
if (enda == -1 || qmark > -1 && qmark < enda) enda = qmark;
if (enda == -1 || fmark > -1 && fmark < enda) enda = fmark;
if (enda < 0) {
enda = uri.length();
}
if (uri.startsWith(":", i)) {
// LdapURL supports empty host.
i++;
host = "";
if (enda > i) {
port = Integer.parseInt(uri.substring(i, enda));
}
} else {
// Use URI to parse authority
try {
// URI requires at least one char after authority:
// we use "/" and expect that the resulting URI path
// will be exactly "/".
URI u = new URI(uri.substring(0, enda) + "/");
String auth = uri.substring(starta, enda);
host = u.getHost();
port = u.getPort();
String p = u.getRawPath();
String q = u.getRawQuery();
String f = u.getRawFragment();
String ui = u.getRawUserInfo();
if (ui != null) {
throw new MalformedURLException("user info not supported in authority: " + ui);
}
if (!"/".equals(p)) {
throw new MalformedURLException("invalid authority: " + auth);
}
if (q != null) {
throw new MalformedURLException("invalid trailing characters in authority: ?" + q);
}
if (f != null) {
throw new MalformedURLException("invalid trailing characters in authority: #" + f);
}
String hostport = (host == null ? "" : host)
+ (port == -1?"":(":" + port));
if (!auth.equals(hostport)) {
// throw if we have user info or regname
throw new MalformedURLException("unsupported authority: " + auth);
}
} catch (URISyntaxException e) {
var mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
i = enda;
}
path = uri.substring(i, endp);
// look for query
if (qmark > -1) {
if (fmark > -1) {
query = uri.substring(qmark, fmark);
} else {
query = uri.substring(qmark);
}
}
if (fmark > -1) {
fragment = uri.substring(fmark);
}
}
/**
* A subclass of {@code Uri} that supports scheme only
* URIs can override this method and return true in the
* case where the URI string is a scheme-only URI that
* the subclass supports.
* @implSpec
* The default implementation of this method returns false,
* always.
* @param uri An URI string
* @return if this is a scheme-only URI supported by the subclass
*/
protected boolean isSchemeOnly(String uri) {
return false;
}
/**
* Checks whether the given uri string should be considered
* as a scheme-only URI. For some protocols - e.g. DNS, we
* might accept "dns://" as a valid URL denoting default DNS.
* For others - we might only accept "scheme:".
* @implSpec
* The default implementation of this method returns true if
* the URI is of the form {@code "<scheme>:"} with nothing
* after the scheme delimiter.
* @param uri the URI
* @param scheme the scheme
* @return true if the URI should be considered as a scheme-only
* URI supported by this URI scheme.
*/
protected boolean checkSchemeOnly(String uri, String scheme) {
return uri.equals(scheme + ":");
}
/**
* Creates a {@code MalformedURLException} to be thrown when the
* URI scheme is not supported.
*
* @param uri the URI string
* @return a {@link MalformedURLException}
*/
protected MalformedURLException newInvalidURISchemeException(String uri) {
return new MalformedURLException("Invalid URI scheme: " + uri);
}
/**
* Whether fragments are supported.
* @implSpec
* The default implementation of this method retturns false, always.
* @return true if fragments are supported.
*/
protected boolean acceptsFragment() {
return parseMode() == ParseMode.LEGACY;
}
/*
* Parses a URI string and sets this object's fields accordingly.
* Legacy parsing mode.
*/
private void parseLegacy(String uri) throws MalformedURLException {
int i; // index into URI
i = uri.indexOf(':'); // parse scheme

@ -1,5 +1,5 @@
/*
* Copyright (c) 2000, 2002, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2000, 2022, 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
@ -27,7 +27,11 @@ package com.sun.jndi.dns;
import java.net.MalformedURLException;
import java.util.Hashtable;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Locale;
import java.util.StringTokenizer;
import com.sun.jndi.toolkit.url.Uri;
@ -56,6 +60,24 @@ import com.sun.jndi.toolkit.url.UrlUtil;
public class DnsUrl extends Uri {
private static final String PARSE_MODE_PROP = "com.sun.jndi.dnsURLParsing";
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
public static final ParseMode PARSE_MODE;
static {
PrivilegedAction<String> action = () ->
System.getProperty(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
ParseMode parseMode = DEFAULT_PARSE_MODE;
try {
@SuppressWarnings("removal")
String mode = AccessController.doPrivileged(action);
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
} catch (Throwable t) {
parseMode = DEFAULT_PARSE_MODE;
} finally {
PARSE_MODE = parseMode;
}
}
private String domain; // domain name of the context
@ -71,19 +93,58 @@ public class DnsUrl extends Uri {
StringTokenizer st = new StringTokenizer(urlList, " ");
while (st.hasMoreTokens()) {
urls[i++] = new DnsUrl(st.nextToken());
try {
urls[i++] = new DnsUrl(validateURI(st.nextToken()));
} catch (URISyntaxException e) {
MalformedURLException mue = new MalformedURLException(e.getMessage());
mue.initCause(e);
throw mue;
}
}
DnsUrl[] trimmed = new DnsUrl[i];
System.arraycopy(urls, 0, trimmed, 0, i);
return trimmed;
}
@Override
protected ParseMode parseMode() {
return PARSE_MODE;
}
@Override
protected final boolean isSchemeOnly(String uri) {
return isDnsSchemeOnly(uri);
}
@Override
protected boolean checkSchemeOnly(String uri, String scheme) {
return uri.equals(scheme + ":") || uri.equals(scheme + "://");
}
@Override
protected final MalformedURLException newInvalidURISchemeException(String uri) {
return new MalformedURLException(
uri + " is not a valid DNS pseudo-URL");
}
private static boolean isDnsSchemeOnly(String uri) {
return "dns:".equals(uri) || "dns://".equals(uri);
}
private static String validateURI(String uri) throws URISyntaxException {
// no validation in legacy parsing mode
if (PARSE_MODE == ParseMode.LEGACY) return uri;
// special case of scheme-only URIs
if (isDnsSchemeOnly(uri)) return uri;
// use java.net.URI to validate the uri syntax
return new URI(uri).toString();
}
public DnsUrl(String url) throws MalformedURLException {
super(url);
if (!scheme.equals("dns")) {
throw new MalformedURLException(
url + " is not a valid DNS pseudo-URL");
throw newInvalidURISchemeException(url);
}
domain = path.startsWith("/")

@ -1,5 +1,5 @@
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1999, 2022, 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
@ -25,12 +25,17 @@
package com.sun.jndi.url.rmi;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Hashtable;
import java.util.Locale;
import javax.naming.*;
import javax.naming.spi.ResolveResult;
import com.sun.jndi.toolkit.url.GenericURLContext;
import com.sun.jndi.rmi.registry.RegistryContext;
import com.sun.jndi.toolkit.url.Uri.ParseMode;
/**
@ -47,10 +52,244 @@ import com.sun.jndi.rmi.registry.RegistryContext;
*/
public class rmiURLContext extends GenericURLContext {
private static final String PARSE_MODE_PROP = "com.sun.jndi.rmiURLParsing";
private static final ParseMode DEFAULT_PARSE_MODE = ParseMode.COMPAT;
public static final ParseMode PARSE_MODE;
static {
PrivilegedAction<String> action = () ->
System.getProperty(PARSE_MODE_PROP, DEFAULT_PARSE_MODE.toString());
ParseMode parseMode = DEFAULT_PARSE_MODE;
try {
@SuppressWarnings("removal")
String mode = AccessController.doPrivileged(action);
parseMode = ParseMode.valueOf(mode.toUpperCase(Locale.ROOT));
} catch (Throwable t) {
parseMode = DEFAULT_PARSE_MODE;
} finally {
PARSE_MODE = parseMode;
}
}
public rmiURLContext(Hashtable<?,?> env) {
super(env);
}
public static class Parser {
final String url;
final ParseMode mode;
String host = null;
int port = -1;
String objName = null;
public Parser(String url) {
this(url, PARSE_MODE);
}
public Parser(String url, ParseMode mode) {
this.url = url;
this.mode = mode;
}
public String url() {return url;}
public String host() {return host;}
public int port() {return port;}
public String objName() {return objName;}
public ParseMode mode() {return mode;}
public void parse() throws NamingException {
if (!url.startsWith("rmi:")) {
throw (new IllegalArgumentException(
"rmiURLContext: name is not an RMI URL: " + url));
}
switch (mode) {
case STRICT -> parseStrict();
case COMPAT -> parseCompat();
case LEGACY -> parseLegacy();
}
}
private void parseStrict() throws NamingException {
assert url.startsWith("rmi:");
if (url.equals("rmi:") || url.equals("rmi://")) return;
// index into url, following the "rmi:"
int i = 4;
if (url.startsWith("//", i)) {
i += 2;
try {
URI uri = URI.create(url);
host = uri.getHost();
port = uri.getPort();
String auth = uri.getRawAuthority();
String hostport = (host == null ? "" : host)
+ (port == -1 ? "" : ":" + port);
if (!hostport.equals(auth)) {
boolean failed = true;
if (hostport.equals("") && auth.startsWith(":")) {
// supports missing host
try {
port = Integer.parseInt(auth.substring(1));
failed = false;
} catch (NumberFormatException x) {
failed = true;
}
}
if (failed) {
throw newNamingException(new IllegalArgumentException("invalid authority: "
+ auth));
}
}
i += auth.length();
} catch (IllegalArgumentException iae) {
throw newNamingException(iae);
}
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
}
private void parseCompat() throws NamingException {
assert url.startsWith("rmi:");
int i = 4; // index into url, following the "rmi:"
boolean hasAuthority = url.startsWith("//", i);
if (hasAuthority) i += 2; // skip past "//"
int slash = url.indexOf('/', i);
int qmark = url.indexOf('?', i);
int fmark = url.indexOf('#', i);
if (fmark > -1 && qmark > fmark) qmark = -1;
if (fmark > -1 && slash > fmark) slash = -1;
if (qmark > -1 && slash > qmark) slash = -1;
// The end of the authority component is either the
// slash (slash will be -1 if it doesn't come before
// query or fragment), or the question mark (qmark will
// be -1 if it doesn't come before the fragment), or
// the fragment separator, or the end of the URI
// string if there is no path, no query, and no fragment.
int enda = slash > -1 ? slash
: (qmark > -1 ? qmark
: (fmark > -1 ? fmark
: url.length()));
if (fmark > -1) {
if (!acceptsFragment()) {
throw newNamingException(new IllegalArgumentException("URI fragments not supported: " + url));
}
}
if (hasAuthority && enda > i) { // parse "//host:port"
if (url.startsWith(":", i)) {
// LdapURL supports empty host.
i++;
host = "";
if (enda > i) {
port = Integer.parseInt(url.substring(i, enda));
}
} else {
try {
URI uri = URI.create(url.substring(0, enda));
host = uri.getHost();
port = uri.getPort();
String hostport = (host == null ? "" : host)
+ (port == -1 ? "" : ":" + port);
if (!hostport.equals(uri.getRawAuthority())) {
throw newNamingException(new IllegalArgumentException("invalid authority: "
+ uri.getRawAuthority()));
}
} catch (IllegalArgumentException iae) {
throw newNamingException(iae);
}
}
i = enda;
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
}
// The legacy parsing used to only throw IllegalArgumentException
// and continues to do so
private void parseLegacy() {
assert url.startsWith("rmi:");
// Parse the URL.
int i = 4; // index into url, following the "rmi:"
if (url.startsWith("//", i)) { // parse "//host:port"
i += 2; // skip past "//"
int slash = url.indexOf('/', i);
if (slash < 0) {
slash = url.length();
}
if (url.startsWith("[", i)) { // at IPv6 literal
int brac = url.indexOf(']', i + 1);
if (brac < 0 || brac > slash) {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
host = url.substring(i, brac + 1); // include brackets
i = brac + 1; // skip past "[...]"
} else { // at host name or IPv4
int colon = url.indexOf(':', i);
int hostEnd = (colon < 0 || colon > slash)
? slash
: colon;
if (i < hostEnd) {
host = url.substring(i, hostEnd);
}
i = hostEnd; // skip past host
}
if ((i + 1 < slash)) {
if ( url.startsWith(":", i)) { // parse port
i++; // skip past ":"
port = Integer.parseInt(url.substring(i, slash));
} else {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
}
i = slash;
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
}
NamingException newNamingException(Throwable cause) {
NamingException ne = new NamingException(cause.getMessage());
ne.initCause(cause);
return ne;
}
boolean acceptsFragment() {
return true;
}
}
/**
* Resolves the registry portion of "url" to the corresponding
* RMI registry, and returns the atomic object name as the
@ -59,63 +298,11 @@ public class rmiURLContext extends GenericURLContext {
protected ResolveResult getRootURLContext(String url, Hashtable<?,?> env)
throws NamingException
{
if (!url.startsWith("rmi:")) {
throw (new IllegalArgumentException(
"rmiURLContext: name is not an RMI URL: " + url));
}
// Parse the URL.
String host = null;
int port = -1;
String objName = null;
int i = 4; // index into url, following the "rmi:"
if (url.startsWith("//", i)) { // parse "//host:port"
i += 2; // skip past "//"
int slash = url.indexOf('/', i);
if (slash < 0) {
slash = url.length();
}
if (url.startsWith("[", i)) { // at IPv6 literal
int brac = url.indexOf(']', i + 1);
if (brac < 0 || brac > slash) {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
host = url.substring(i, brac + 1); // include brackets
i = brac + 1; // skip past "[...]"
} else { // at host name or IPv4
int colon = url.indexOf(':', i);
int hostEnd = (colon < 0 || colon > slash)
? slash
: colon;
if (i < hostEnd) {
host = url.substring(i, hostEnd);
}
i = hostEnd; // skip past host
}
if ((i + 1 < slash)) {
if ( url.startsWith(":", i)) { // parse port
i++; // skip past ":"
port = Integer.parseInt(url.substring(i, slash));
} else {
throw new IllegalArgumentException(
"rmiURLContext: name is an Invalid URL: " + url);
}
}
i = slash;
}
if ("".equals(host)) {
host = null;
}
if (url.startsWith("/", i)) { // skip "/" before object name
i++;
}
if (i < url.length()) {
objName = url.substring(i);
}
Parser parser = new Parser(url);
parser.parse();
String host = parser.host;
int port = parser.port;
String objName = parser.objName;
// Represent object name as empty or single-component composite name.
CompositeName remaining = new CompositeName();