1 /*
   2  * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.jndi.cosnaming;
  27 
  28 import javax.naming.Name;
  29 import javax.naming.NamingException;
  30 
  31 import java.net.MalformedURLException;
  32 import java.util.Vector;
  33 import java.util.StringTokenizer;
  34 import com.sun.jndi.toolkit.corba.CorbaUtils;
  35 
  36 /**
  37  * Extract components of an "iiop" or "iiopname" URL.
  38  *
  39  * The format of an iiopname URL is defined in INS 98-10-11 as follows:
  40  *
  41  * <pre>
  42  * iiopname url = "iiopname://" [addr_list]["/" string_name]
  43  * addr_list    = [address ","]* address
  44  * address      = [version host [":" port]]
  45  * host         = DNS style host name | IP address
  46  * version      = major "." minor "@" | empty_string
  47  * port         = number
  48  * major        = number
  49  * minor        = number
  50  * string_name  = stringified name | empty_string
  51  * </pre>
  52  *
  53  * The default port is 9999. The default version is "1.0"
  54  * US-ASCII alphanumeric characters are not escaped. Any characters outside
  55  * of this range are escaped except for the following:
  56  * <pre>{@code
  57  * ; / : ? : @ & = + $ , - _ . ! ~ *  ' ( )
  58  * }</pre>
  59  * Escaped characters is escaped by using a % followed by its 2 hexadecimal
  60  * numbers representing the octet.
  61  *
  62  * For backward compatibility,  the "iiop" URL as defined in INS 97-6-6
  63  * is also supported:
  64  * <pre>{@code
  65  * iiop url     = "iiop://" [host [":" port]] ["/" string_name]
  66  * }</pre>
  67  * The default port is 900.
  68  *
  69  * @author Rosanna Lee
  70  */
  71 
  72 public final class IiopUrl {
  73     static final private int DEFAULT_IIOPNAME_PORT = 9999;
  74     static final private int DEFAULT_IIOP_PORT = 900;
  75     static final private String DEFAULT_HOST = "localhost";
  76     private Vector<Address> addresses;
  77     private String stringName;
  78 
  79     public static class Address {
  80         public int port = -1;
  81         public int major, minor;
  82         public String host;
  83 
  84         public Address(String hostPortVers, boolean oldFormat)
  85             throws MalformedURLException {
  86             // [version host [":" port]]
  87             int start;
  88 
  89             // Parse version
  90             int at;
  91             if (oldFormat || (at = hostPortVers.indexOf('@')) < 0) {
  92                 major = 1;
  93                 minor = 0;
  94                 start = 0;     // start at the beginning
  95             } else {
  96                 int dot = hostPortVers.indexOf('.');
  97                 if (dot < 0) {
  98                     throw new MalformedURLException(
  99                         "invalid version: " + hostPortVers);
 100                 }
 101                 try {
 102                     major = Integer.parseInt(hostPortVers.substring(0, dot));
 103                     minor = Integer.parseInt(hostPortVers.substring(dot+1, at));
 104                 } catch (NumberFormatException e) {
 105                     throw new MalformedURLException(
 106                         "Nonnumeric version: " + hostPortVers);
 107                 }
 108                 start = at + 1;  // skip '@' sign
 109             }
 110 
 111             // Parse host and port
 112             int slash = hostPortVers.indexOf('/', start);
 113             if (slash < 0) {
 114                 slash = hostPortVers.length();
 115             }
 116             if (hostPortVers.startsWith("[", start)) {  // at IPv6 literal
 117                 int brac = hostPortVers.indexOf(']', start + 1);
 118                 if (brac < 0 || brac > slash) {
 119                     throw new IllegalArgumentException(
 120                         "IiopURL: name is an Invalid URL: " + hostPortVers);
 121                 }
 122 
 123                 // include brackets
 124                 host = hostPortVers.substring(start, brac + 1);
 125                 start = brac + 1;
 126             } else {      // at hostname or IPv4
 127                 int colon = hostPortVers.indexOf(':', start);
 128                 int hostEnd = (colon < 0 || colon > slash)
 129                     ? slash
 130                     : colon;
 131                 if (start < hostEnd) {
 132                     host = hostPortVers.substring(start, hostEnd);
 133                 }
 134                 start = hostEnd;   // skip past host
 135             }
 136             if ((start + 1 < slash)) {
 137                 if ( hostPortVers.startsWith(":", start)) { // parse port
 138                     start++;    // skip past ":"
 139                     port = Integer.parseInt(hostPortVers.
 140                                             substring(start, slash));
 141                 } else {
 142                     throw new IllegalArgumentException(
 143                         "IiopURL: name is an Invalid URL: " + hostPortVers);
 144                 }
 145             }
 146             start = slash;
 147             if ("".equals(host) || host == null) {
 148                 host = DEFAULT_HOST ;
 149             }
 150             if (port == -1) {
 151                 port = (oldFormat ? DEFAULT_IIOP_PORT :
 152                                 DEFAULT_IIOPNAME_PORT);
 153             }
 154         }
 155     }
 156 
 157     public Vector<Address> getAddresses() {
 158         return addresses;
 159     }
 160 
 161     /**
 162      * Returns a possibly empty but non-null string that is the "string_name"
 163      * portion of the URL.
 164      */
 165     public String getStringName() {
 166         return stringName;
 167     }
 168 
 169     public Name getCosName() throws NamingException {
 170         return CNCtx.parser.parse(stringName);
 171     }
 172 
 173     public IiopUrl(String url) throws MalformedURLException {
 174         int addrStart;
 175         boolean oldFormat;
 176 
 177         if (url.startsWith("iiopname://")) {
 178             oldFormat = false;
 179             addrStart = 11;
 180         } else if (url.startsWith("iiop://")) {
 181             oldFormat = true;
 182             addrStart = 7;
 183         } else {
 184             throw new MalformedURLException("Invalid iiop/iiopname URL: " + url);
 185         }
 186         int addrEnd = url.indexOf('/', addrStart);
 187         if (addrEnd < 0) {
 188             addrEnd = url.length();
 189             stringName = "";
 190         } else {
 191             stringName = CorbaUtils.decode(url.substring(addrEnd+1));
 192         }
 193         addresses = new Vector<>(3);
 194         if (oldFormat) {
 195             // Only one host:port part, not multiple
 196             addresses.addElement(
 197                 new Address(url.substring(addrStart, addrEnd), oldFormat));
 198         } else {
 199             StringTokenizer tokens =
 200                 new StringTokenizer(url.substring(addrStart, addrEnd), ",");
 201             while (tokens.hasMoreTokens()) {
 202                 addresses.addElement(new Address(tokens.nextToken(), oldFormat));
 203             }
 204             if (addresses.size() == 0) {
 205                 addresses.addElement(new Address("", oldFormat));
 206             }
 207         }
 208     }
 209 
 210     // for testing only
 211     /*public static void main(String[] args) {
 212         try {
 213             IiopUrl url = new IiopUrl(args[0]);
 214             Vector addrs = url.getAddresses();
 215             String name = url.getStringName();
 216 
 217             for (int i = 0; i < addrs.size(); i++) {
 218                 Address addr = (Address)addrs.elementAt(i);
 219                 System.out.println("host: " + addr.host);
 220                 System.out.println("port: " + addr.port);
 221                 System.out.println("version: " + addr.major + " " + addr.minor);
 222             }
 223             System.out.println("name: " + name);
 224         } catch (MalformedURLException e) {
 225             e.printStackTrace();
 226         }
 227     } */
 228 }